32
32
try :
33
33
import pyinotify
34
34
HAS_PYINOTIFY = True
35
- DEFAULT_MASK = pyinotify .IN_CREATE | pyinotify .IN_DELETE | pyinotify .IN_MODIFY
35
+ DEFAULT_MASK = pyinotify .IN_CREATE | pyinotify .IN_DELETE | pyinotify .IN_DELETE_SELF | pyinotify .IN_MODIFY
36
+ RM_WATCH_MASK = pyinotify .IN_DELETE | pyinotify .IN_DELETE_SELF | pyinotify .IN_IGNORED
36
37
MASKS = {}
37
38
for var in dir (pyinotify ):
38
39
if var .startswith ('IN_' ):
@@ -73,6 +74,18 @@ def _enqueue(revent):
73
74
"""
74
75
__context__ ['pulsar.queue' ].append (revent )
75
76
77
+ def _maskname_filter (name ):
78
+ """ deleting a directly watched file produces IN_DELETE_SELF (not
79
+ IN_DELETE) and also kicks up a an IN_IGNORED (whether you mask for it
80
+ or not) to indicate the file is nolonger watched.
81
+
82
+ We avoid returning IN_IGNORED if we can... but IN_DELETE_SELF is
83
+ corrected to IN_DELETE
84
+ """
85
+ if name == 'IN_DELETE_SELF' :
86
+ return 'IN_DELETE'
87
+ return name
88
+
76
89
class ConfigManager (object ):
77
90
_config = {}
78
91
_last_update = 0
@@ -360,9 +373,9 @@ def watch(self, path, mask=None, **kw):
360
373
kw ['rec' ] = kw .get ('rec' )
361
374
if kw ['rec' ] is None :
362
375
kw ['rec' ] = pconf ['recurse' ]
363
- self .add_watch (path ,mask ,** kw )
364
- log .debug ('add-watch wd={0} path={1} watch_files={2} recurse={3}' .format (
365
- self .watch_db .get (path ), path , pconf ['watch_files' ], kw ['rec' ]))
376
+ self .add_watch (path , mask , ** kw )
377
+ log .debug ('add-watch wd={0} path={1} watch_files={2} recurse={3} mask={4} ' .format (
378
+ self .watch_db .get (path ), path , pconf ['watch_files' ], kw ['rec' ], mask ))
366
379
367
380
if new_file : # process() says this is a new file
368
381
self ._add_recursed_file_watch (path )
@@ -772,10 +785,11 @@ def process(configfile='salt://hubblestack_pulsar/hubblestack_pulsar_config.yaml
772
785
773
786
excludes = _preprocess_excludes ( config [cpath ].get ('exclude' ) )
774
787
_append = not excludes (pathname )
788
+
775
789
if _append :
776
790
config_path = config ['paths' ][0 ]
777
791
pulsar_config = config_path [config_path .rfind ('/' ) + 1 :len (config_path )]
778
- sub = { 'change' : event .maskname ,
792
+ sub = { 'change' : _maskname_filter ( event .maskname ) ,
779
793
'path' : abspath , # goes to object_path in splunk
780
794
'tag' : dirname , # goes to file_path in splunk
781
795
'name' : basename , # goes to file_name in splunk
@@ -816,20 +830,19 @@ def process(configfile='salt://hubblestack_pulsar/hubblestack_pulsar_config.yaml
816
830
if os .path .isfile (pathname ):
817
831
sub ['size' ] = os .path .getsize (pathname )
818
832
819
-
820
-
821
- ret .append (sub )
833
+ if event .mask != pyinotify .IN_IGNORED :
834
+ ret .append (sub )
822
835
823
836
if not event .mask & pyinotify .IN_ISDIR :
824
837
if event .mask & pyinotify .IN_CREATE :
825
838
watch_this = config [cpath ].get ('watch_new_files' , False ) \
826
839
or config [cpath ].get ('watch_files' , False )
827
840
if watch_this :
828
841
if not excludes (pathname ):
829
- log .debug ("add file-watch path={0}" .format (pathname ))
842
+ log .debug ("add file-watch path={0} mask={1}" .format (pathname ,
843
+ pyinotify .IN_MODIFY ))
830
844
wm .watch (pathname , pyinotify .IN_MODIFY , new_file = True )
831
-
832
- elif event .mask & pyinotify .IN_DELETE :
845
+ elif event .mask & RM_WATCH_MASK :
833
846
wm .rm_watch (pathname )
834
847
else :
835
848
log .debug ('Excluding {0} from event for {1}' .format (pathname , cpath ))
@@ -847,22 +860,18 @@ def process(configfile='salt://hubblestack_pulsar/hubblestack_pulsar_config.yaml
847
860
continue
848
861
if isinstance (config [path ], dict ):
849
862
mask = config [path ].get ('mask' , DEFAULT_MASK )
850
- ## commented out on 2019-08-05
851
- # watch_files = config[path].get('watch_files', DEFAULT_MASK)
852
- ## note: it seems like the below was commented out because the above seems to be bugged
853
- ## clearly watch_files should default to False, not DEFAULT_MASK
854
- ## (aka true); that probably seemd like spurious watches from ##
855
- ## duplications or whatever caused the below to be commented out.
856
- ## Regardless, the above is probably wrong *and* seems unused.
857
- ## commented out previous to 2019-08-05
858
- # if watch_files:
859
- # # we're going to get dup modify events if watch_files is set
860
- # # and we still monitor modify for the dir
861
- # a = mask & pyinotify.IN_MODIFY
862
- # if a:
863
- # log.debug("mask={0} -= mask & pyinotify.IN_MODIFY={1} ==> {2}".format(
864
- # mask, a, mask-a))
865
- # mask -= mask & pyinotify.IN_MODIFY
863
+ watch_files = config [path ].get ('watch_files' , False )
864
+ if watch_files :
865
+ # we're going to get dup modify events if watch_files is set
866
+ # and we still monitor modify for the dir
867
+ mask_and_modify = mask & pyinotify .IN_MODIFY
868
+ if mask_and_modify :
869
+ log .debug ("mask={0} -= mask & pyinotify.IN_MODIFY={1}" \
870
+ " ==> {2}" .format (
871
+ mask ,
872
+ mask_and_modify ,
873
+ mask - mask_and_modify ))
874
+ mask -= mask_and_modify
866
875
excludes = _preprocess_excludes ( config [path ].get ('exclude' ) )
867
876
if isinstance (mask , list ):
868
877
r_mask = 0
@@ -880,7 +889,32 @@ def process(configfile='salt://hubblestack_pulsar/hubblestack_pulsar_config.yaml
880
889
rec = False
881
890
auto_add = False
882
891
892
+ if os .path .isfile (path ) and not wm .get_wd (path ):
893
+ # We were not previously watching this file generate a fake
894
+ # IN_CREATE to announce this fact. We'd like to only generate
895
+ # CREATE events when files are created, but we can't actually
896
+ # watch files that don't exist yet (not with inotify anyway).
897
+ # The kernel would rather be watching directories anyway.
898
+ #
899
+ # You might worry we'll get lots of spurious IN_CREATEs when
900
+ # the database is cleared or at startup or whatever. We
901
+ # actually watch everyhthing from config at startup anyway; so
902
+ # we avoid these fake IN_CREATE events at startup. They only
903
+ # happen when we add a watch during update, which means the
904
+ # file really is new since the last time we thought about it
905
+ # (aka the last time we ran the process() function).
906
+ _ , abspath , dirname , basename = cm .format_path (path )
907
+ config_path = config ['paths' ][0 ]
908
+ pulsar_config = config_path [config_path .rfind ('/' ) + 1 :len (config_path )]
909
+ fake_sub = { 'change' : 'IN_CREATE' ,
910
+ 'path' : abspath , # goes to object_path in splunk
911
+ 'tag' : dirname , # goes to file_path in splunk
912
+ 'name' : basename , # goes to file_name in splunk
913
+ 'pulsar_config' : pulsar_config }
914
+ ret .append (fake_sub )
915
+
883
916
wm .watch (path , mask , rec = rec , auto_add = auto_add , exclude_filter = excludes )
917
+
884
918
dt .fin ()
885
919
dt .mark ('prune_watches' )
886
920
wm .prune ()
0 commit comments