comparison env/lib/python3.9/site-packages/boto/gs/lifecycle.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 # Copyright 2013 Google Inc.
2 #
3 # Permission is hereby granted, free of charge, to any person obtaining a
4 # copy of this software and associated documentation files (the
5 # "Software"), to deal in the Software without restriction, including
6 # without limitation the rights to use, copy, modify, merge, publish, dis-
7 # tribute, sublicense, and/or sell copies of the Software, and to permit
8 # persons to whom the Software is furnished to do so, subject to the fol-
9 # lowing conditions:
10 #
11 # The above copyright notice and this permission notice shall be included
12 # in all copies or substantial portions of the Software.
13 #
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
17 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 # IN THE SOFTWARE.
21
22 from boto.exception import InvalidLifecycleConfigError
23
24 # Relevant tags for the lifecycle configuration XML document.
25 LIFECYCLE_CONFIG = 'LifecycleConfiguration'
26 RULE = 'Rule'
27 ACTION = 'Action'
28 DELETE = 'Delete'
29 SET_STORAGE_CLASS = 'SetStorageClass'
30 CONDITION = 'Condition'
31 AGE = 'Age'
32 CREATED_BEFORE = 'CreatedBefore'
33 NUM_NEWER_VERSIONS = 'NumberOfNewerVersions'
34 IS_LIVE = 'IsLive'
35 MATCHES_STORAGE_CLASS = 'MatchesStorageClass'
36
37 # List of all action elements.
38 LEGAL_ACTIONS = [DELETE, SET_STORAGE_CLASS]
39 # List of all condition elements.
40 LEGAL_CONDITIONS = [AGE, CREATED_BEFORE, NUM_NEWER_VERSIONS, IS_LIVE,
41 MATCHES_STORAGE_CLASS]
42 # List of conditions elements that may be repeated.
43 LEGAL_REPEATABLE_CONDITIONS = [MATCHES_STORAGE_CLASS]
44
45 class Rule(object):
46 """
47 A lifecycle rule for a bucket.
48
49 :ivar action: Action to be taken.
50
51 :ivar action_text: The text value for the specified action, if any.
52
53 :ivar conditions: A dictionary of conditions that specify when the action
54 should be taken. Each item in the dictionary represents the name and
55 value (or a list of multiple values, if applicable) of a condition.
56 """
57
58 def __init__(self, action=None, action_text=None, conditions=None):
59 self.action = action
60 self.action_text = action_text
61 self.conditions = conditions or {}
62
63 # Name of the current enclosing tag (used to validate the schema).
64 self.current_tag = RULE
65
66 def validateStartTag(self, tag, parent):
67 """Verify parent of the start tag."""
68 if self.current_tag != parent:
69 raise InvalidLifecycleConfigError(
70 'Invalid tag %s found inside %s tag' % (tag, self.current_tag))
71
72 def validateEndTag(self, tag):
73 """Verify end tag against the start tag."""
74 if tag != self.current_tag:
75 raise InvalidLifecycleConfigError(
76 'Mismatched start and end tags (%s/%s)' %
77 (self.current_tag, tag))
78
79 def startElement(self, name, attrs, connection):
80 if name == ACTION:
81 self.validateStartTag(name, RULE)
82 elif name in LEGAL_ACTIONS:
83 self.validateStartTag(name, ACTION)
84 # Verify there is only one action tag in the rule.
85 if self.action is not None:
86 raise InvalidLifecycleConfigError(
87 'Only one action tag is allowed in each rule')
88 self.action = name
89 elif name == CONDITION:
90 self.validateStartTag(name, RULE)
91 elif name in LEGAL_CONDITIONS:
92 self.validateStartTag(name, CONDITION)
93 # Verify there is no duplicate conditions.
94 if (name in self.conditions and
95 name not in LEGAL_REPEATABLE_CONDITIONS):
96 raise InvalidLifecycleConfigError(
97 'Found duplicate non-repeatable conditions %s' % name)
98 else:
99 raise InvalidLifecycleConfigError('Unsupported tag ' + name)
100 self.current_tag = name
101
102 def endElement(self, name, value, connection):
103 self.validateEndTag(name)
104 if name == RULE:
105 # We have to validate the rule after it is fully populated because
106 # the action and condition elements could be in any order.
107 self.validate()
108 elif name == ACTION:
109 self.current_tag = RULE
110 elif name in LEGAL_ACTIONS:
111 if name == SET_STORAGE_CLASS and value is not None:
112 self.action_text = value.strip()
113 self.current_tag = ACTION
114 elif name == CONDITION:
115 self.current_tag = RULE
116 elif name in LEGAL_CONDITIONS:
117 self.current_tag = CONDITION
118 # Some conditions specify a list of values.
119 if name in LEGAL_REPEATABLE_CONDITIONS:
120 if name not in self.conditions:
121 self.conditions[name] = []
122 self.conditions[name].append(value.strip())
123 else:
124 self.conditions[name] = value.strip()
125 else:
126 raise InvalidLifecycleConfigError('Unsupported end tag ' + name)
127
128 def validate(self):
129 """Validate the rule."""
130 if not self.action:
131 raise InvalidLifecycleConfigError(
132 'No action was specified in the rule')
133 if not self.conditions:
134 raise InvalidLifecycleConfigError(
135 'No condition was specified for action %s' % self.action)
136
137 def to_xml(self):
138 """Convert the rule into XML string representation."""
139 s = ['<' + RULE + '>']
140 s.append('<' + ACTION + '>')
141 if self.action_text:
142 s.extend(['<' + self.action + '>',
143 self.action_text,
144 '</' + self.action + '>'])
145 else:
146 s.append('<' + self.action + '/>')
147 s.append('</' + ACTION + '>')
148 s.append('<' + CONDITION + '>')
149 for condition_name in self.conditions:
150 if condition_name not in LEGAL_CONDITIONS:
151 continue
152 if condition_name in LEGAL_REPEATABLE_CONDITIONS:
153 condition_values = self.conditions[condition_name]
154 else:
155 # Wrap condition value in a list, allowing us to iterate over
156 # all condition values using the same logic.
157 condition_values = [self.conditions[condition_name]]
158 for condition_value in condition_values:
159 s.extend(['<' + condition_name + '>',
160 condition_value,
161 '</' + condition_name + '>'])
162 s.append('</' + CONDITION + '>')
163 s.append('</' + RULE + '>')
164 return ''.join(s)
165
166 class LifecycleConfig(list):
167 """
168 A container of rules associated with a lifecycle configuration.
169 """
170
171 def __init__(self):
172 # Track if root tag has been seen.
173 self.has_root_tag = False
174
175 def startElement(self, name, attrs, connection):
176 if name == LIFECYCLE_CONFIG:
177 if self.has_root_tag:
178 raise InvalidLifecycleConfigError(
179 'Only one root tag is allowed in the XML')
180 self.has_root_tag = True
181 elif name == RULE:
182 if not self.has_root_tag:
183 raise InvalidLifecycleConfigError('Invalid root tag ' + name)
184 rule = Rule()
185 self.append(rule)
186 return rule
187 else:
188 raise InvalidLifecycleConfigError('Unsupported tag ' + name)
189
190 def endElement(self, name, value, connection):
191 if name == LIFECYCLE_CONFIG:
192 pass
193 else:
194 raise InvalidLifecycleConfigError('Unsupported end tag ' + name)
195
196 def to_xml(self):
197 """Convert LifecycleConfig object into XML string representation."""
198 s = ['<?xml version="1.0" encoding="UTF-8"?>']
199 s.append('<' + LIFECYCLE_CONFIG + '>')
200 for rule in self:
201 s.append(rule.to_xml())
202 s.append('</' + LIFECYCLE_CONFIG + '>')
203 return ''.join(s)
204
205 def add_rule(self, action, action_text, conditions):
206 """
207 Add a rule to this Lifecycle configuration. This only adds the rule to
208 the local copy. To install the new rule(s) on the bucket, you need to
209 pass this Lifecycle config object to the configure_lifecycle method of
210 the Bucket object.
211
212 :type action: str
213 :param action: Action to be taken.
214
215 :type action_text: str
216 :param action_text: Value for the specified action.
217
218 :type conditions: dict
219 :param conditions: A dictionary of conditions that specify when the
220 action should be taken. Each item in the dictionary represents the name
221 and value of a condition.
222 """
223 rule = Rule(action, action_text, conditions)
224 self.append(rule)