Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/c7n_gcp/filters/labels.py: 23%

52 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-08 06:51 +0000

1# Copyright The Cloud Custodian Authors. 

2# SPDX-License-Identifier: Apache-2.0 

3 

4from datetime import datetime, timedelta 

5 

6from c7n.utils import type_schema 

7from c7n.filters import Filter, FilterValidationError 

8from c7n.filters.offhours import Time 

9 

10DEFAULT_TAG = "custodian_status" 

11 

12 

13class LabelActionFilter(Filter): 

14 """Filter resources for label specified future action 

15 

16 Filters resources by a 'custodian_status' label which specifies a future 

17 date for an action. 

18 

19 The filter parses the label values looking for an 'op@date' 

20 string. The date is parsed and compared to do today's date, the 

21 filter succeeds if today's date is gte to the target date. 

22 

23 The optional 'skew' parameter provides for incrementing today's 

24 date a number of days into the future. An example use case might 

25 be sending a final notice email a few days before terminating an 

26 instance, or snapshotting a volume prior to deletion. 

27 

28 The optional 'skew_hours' parameter provides for incrementing the current 

29 time a number of hours into the future. 

30 

31 Optionally, the 'tz' parameter can get used to specify the timezone 

32 in which to interpret the clock (default value is 'utc') 

33 

34 :example: 

35 

36 .. code-block :: yaml 

37 

38 policies: 

39 - name: vm-stop-marked 

40 resource: gcp.instance 

41 filters: 

42 - type: marked-for-op 

43 # The default label used is custodian_status 

44 # but that is configurable 

45 label: custodian_status 

46 op: stop 

47 # Another optional label is skew 

48 tz: utc 

49 

50 

51 """ 

52 schema = type_schema( 

53 'marked-for-op', 

54 label={'type': 'string'}, 

55 tz={'type': 'string'}, 

56 skew={'type': 'number', 'minimum': 0}, 

57 skew_hours={'type': 'number', 'minimum': 0}, 

58 op={'type': 'string'}) 

59 

60 def validate(self): 

61 op = self.data.get('op') 

62 if self.manager and op not in self.manager.action_registry.keys(): 

63 raise FilterValidationError( 

64 "Invalid marked-for-op op:%s in %s" % (op, self.manager.data)) 

65 

66 tz = Time.get_tz(self.data.get('tz', 'utc')) 

67 if not tz: 

68 raise FilterValidationError( 

69 "Invalid timezone specified '%s' in %s" % ( 

70 self.data.get('tz'), self.manager.data)) 

71 self.valid_actions = sorted( 

72 self.manager.action_registry.keys(), key=lambda k: len(k), reverse=True) 

73 return self 

74 

75 def process(self, resources, event=None): 

76 self.label = self.data.get('label', DEFAULT_TAG) 

77 self.op = self.data.get('op', 'stop') 

78 self.skew = self.data.get('skew', 0) 

79 self.skew_hours = self.data.get('skew_hours', 0) 

80 self.tz = Time.get_tz(self.data.get('tz', 'utc')) 

81 return super(LabelActionFilter, self).process(resources, event) 

82 

83 def parse(self, v: str): 

84 remainder, action_date = v.rsplit('-', 1) 

85 found = False 

86 msg = "" 

87 for a in self.valid_actions: 

88 if remainder.endswith(a): 

89 found = a 

90 msg = remainder[:-len(a) - 1] 

91 break 

92 return msg, found, action_date 

93 

94 def __call__(self, i): 

95 v = i.get('labels', {}).get(self.label, None) 

96 

97 if v is None: 

98 return False 

99 if '-' not in v or '_' not in v: 

100 return False 

101 

102 msg, action, action_date_str = self.parse(v) 

103 

104 if action != self.op or not action: 

105 return False 

106 

107 try: 

108 action_date = datetime.strptime(action_date_str, '%Y_%m_%d__%H_%M') 

109 except Exception: 

110 self.log.error("could not parse label:%s value:%s on %s" % ( 

111 self.label, v, i['name'])) 

112 return False 

113 

114 # current_date must match timezones with the parsed date string 

115 if action_date.tzinfo: 

116 action_date = action_date.astimezone(self.tz) 

117 current_date = datetime.now(tz=self.tz) 

118 else: 

119 current_date = datetime.now() 

120 

121 return current_date >= (action_date - timedelta(days=self.skew, hours=self.skew_hours))