git-svn-id: https://s3tools.svn.sourceforge.net/svnroot/s3tools/s3cmd/branches/s3cmd-airlock@345 830e0280-6d2a-0410-9c65-932aecc39d9d
Michal Ludvig authored on 2009/01/17 22:24:07... | ... |
@@ -1,5 +1,12 @@ |
1 | 1 |
2009-01-18 Michal Ludvig <michal@logix.cz> |
2 | 2 |
|
3 |
+ * S3/CloudFront.py: Implemented DeleteDistribution(), |
|
4 |
+ GetDistConfig() and SetDistConfig(), |
|
5 |
+ fixed CreateDistribution(). |
|
6 |
+ * s3cmd: Enabled cfdelete. |
|
7 |
+ |
|
8 |
+2009-01-18 Michal Ludvig <michal@logix.cz> |
|
9 |
+ |
|
3 | 10 |
* S3/CloudFront.py: Added Cmd.info() that handles both |
4 | 11 |
cflist and cfinfo commands (in fact they're aliases). |
5 | 12 |
Made DistributionConfig() class consistent with other |
... | ... |
@@ -124,7 +124,7 @@ class DistributionConfig(object): |
124 | 124 |
## <Enabled>true</Enabled> |
125 | 125 |
## </DistributionConfig> |
126 | 126 |
|
127 |
- EMPTY_CONFIG = "<DistributionConfig></DistributionConfig>" |
|
127 |
+ EMPTY_CONFIG = "<DistributionConfig><Origin/><CallerReference/><Enabled>true</Enabled></DistributionConfig>" |
|
128 | 128 |
xmlns = "http://cloudfront.amazonaws.com/doc/2008-06-30/" |
129 | 129 |
def __init__(self, xml = None, tree = None): |
130 | 130 |
if not xml: |
... | ... |
@@ -140,16 +140,22 @@ class DistributionConfig(object): |
140 | 140 |
def parse(self, tree): |
141 | 141 |
self.info = getDictFromTree(tree) |
142 | 142 |
self.info['Enabled'] = (self.info['Enabled'].lower() == "true") |
143 |
+ if not self.info.has_key("CNAME"): |
|
144 |
+ self.info['CNAME'] = [] |
|
145 |
+ if type(self.info['CNAME']) != list: |
|
146 |
+ self.info['CNAME'] = [self.info['CNAME']] |
|
143 | 147 |
self.info['CNAME'] = [cname.lower() for cname in self.info['CNAME']] |
148 |
+ if not self.info.has_key("Comment"): |
|
149 |
+ self.info['Comment'] = "" |
|
144 | 150 |
|
145 | 151 |
def __str__(self): |
146 |
- tree = getTreeFromXml(DistributionConfig.EMPTY_CONFIG) |
|
152 |
+ tree = ET.Element("DistributionConfig") |
|
147 | 153 |
tree.attrib['xmlns'] = DistributionConfig.xmlns |
148 | 154 |
|
149 | 155 |
## Retain the order of the following calls! |
150 | 156 |
appendXmlTextNode("Origin", self.info['Origin'], tree) |
151 | 157 |
appendXmlTextNode("CallerReference", self.info['CallerReference'], tree) |
152 |
- if self.Comment: |
|
158 |
+ if self.info['Comment']: |
|
153 | 159 |
appendXmlTextNode("Comment", self.info['Comment'], tree) |
154 | 160 |
for cname in self.info['CNAME']: |
155 | 161 |
appendXmlTextNode("CNAME", cname.lower(), tree) |
... | ... |
@@ -186,14 +192,14 @@ class CloudFront(object): |
186 | 186 |
return response |
187 | 187 |
|
188 | 188 |
def CreateDistribution(self, uri, cnames = []): |
189 |
- dist_conf = DistributionConfig() |
|
190 |
- dist_conf.info['Enabled'] = True |
|
191 |
- dist_conf.info['Origin'] = uri.host_name() |
|
192 |
- dist_conf.info['CallerReference'] = str(uri) |
|
193 |
- dist_conf.info['Comment'] = uri.public_url() |
|
189 |
+ dist_config = DistributionConfig() |
|
190 |
+ dist_config.info['Enabled'] = True |
|
191 |
+ dist_config.info['Origin'] = uri.host_name() |
|
192 |
+ dist_config.info['CallerReference'] = str(uri) |
|
193 |
+ dist_config.info['Comment'] = uri.public_url() |
|
194 | 194 |
if cnames: |
195 |
- dist_conf.info['Cnames'] = cnames |
|
196 |
- request_body = str(dist_conf) |
|
195 |
+ dist_config.info['Cnames'] = cnames |
|
196 |
+ request_body = str(dist_config) |
|
197 | 197 |
debug("CreateDistribution(): request_body: %s" % request_body) |
198 | 198 |
response = self.send_request("CreateDist", body = request_body) |
199 | 199 |
response['distribution'] = Distribution(response['data']) |
... | ... |
@@ -202,9 +208,29 @@ class CloudFront(object): |
202 | 202 |
def DeleteDistribution(self, cfuri): |
203 | 203 |
if cfuri.type != "cf": |
204 | 204 |
raise ValueError("Expected CFUri instead of: %s" % cfuri) |
205 |
- raise NotImplementedError() |
|
206 |
- # DisableDistribution |
|
207 |
- # response = self.send_request("DeleteDist", dist_id = cfuri.dist_id()) |
|
205 |
+ # Get current dist status (enabled/disabled) and Etag |
|
206 |
+ info("Checking current status of %s" % cfuri) |
|
207 |
+ response = self.GetDistConfig(cfuri) |
|
208 |
+ if response['dist_config'].info['Enabled']: |
|
209 |
+ info("Distribution is ENABLED. Disabling first.") |
|
210 |
+ response['dist_config'].info['Enabled'] = False |
|
211 |
+ response = self.SetDistConfig(cfuri, response['dist_config'], |
|
212 |
+ response['headers']['etag']) |
|
213 |
+ warning("Waiting for Distribution to become disabled.") |
|
214 |
+ warning("This may take several minutes, please wait.") |
|
215 |
+ while True: |
|
216 |
+ response = self.GetDistInfo(cfuri) |
|
217 |
+ d = response['distribution'] |
|
218 |
+ if d.info['Status'] == "Deployed" and d.info['Enabled'] == False: |
|
219 |
+ info("Distribution is now disabled") |
|
220 |
+ break |
|
221 |
+ warning("Still waiting...") |
|
222 |
+ time.sleep(10) |
|
223 |
+ headers = {} |
|
224 |
+ headers['if-match'] = response['headers']['etag'] |
|
225 |
+ response = self.send_request("DeleteDist", dist_id = cfuri.dist_id(), |
|
226 |
+ headers = headers) |
|
227 |
+ return response |
|
208 | 228 |
|
209 | 229 |
def GetDistInfo(self, cfuri): |
210 | 230 |
if cfuri.type != "cf": |
... | ... |
@@ -213,13 +239,32 @@ class CloudFront(object): |
213 | 213 |
response['distribution'] = Distribution(response['data']) |
214 | 214 |
return response |
215 | 215 |
|
216 |
+ def GetDistConfig(self, cfuri): |
|
217 |
+ if cfuri.type != "cf": |
|
218 |
+ raise ValueError("Expected CFUri instead of: %s" % cfuri) |
|
219 |
+ response = self.send_request("GetDistConfig", dist_id = cfuri.dist_id()) |
|
220 |
+ response['dist_config'] = DistributionConfig(response['data']) |
|
221 |
+ return response |
|
222 |
+ |
|
223 |
+ def SetDistConfig(self, cfuri, dist_config, etag = None): |
|
224 |
+ if etag == None: |
|
225 |
+ debug("SetDistConfig(): Etag not set. Fetching it first.") |
|
226 |
+ etag = self.GetDistConfig(cfuri)['headers']['etag'] |
|
227 |
+ debug("SetDistConfig(): Etag = %s" % etag) |
|
228 |
+ request_body = str(dist_config) |
|
229 |
+ debug("SetDistConfig(): request_body: %s" % request_body) |
|
230 |
+ headers = {} |
|
231 |
+ headers['if-match'] = etag |
|
232 |
+ response = self.send_request("SetDistConfig", dist_id = cfuri.dist_id(), |
|
233 |
+ body = request_body, headers = headers) |
|
234 |
+ return response |
|
235 |
+ |
|
216 | 236 |
## -------------------------------------------------- |
217 | 237 |
## Low-level methods for handling CloudFront requests |
218 | 238 |
## -------------------------------------------------- |
219 | 239 |
|
220 |
- def send_request(self, op_name, dist_id = None, body = None, retries = _max_retries): |
|
240 |
+ def send_request(self, op_name, dist_id = None, body = None, headers = {}, retries = _max_retries): |
|
221 | 241 |
operation = self.operations[op_name] |
222 |
- headers = {} |
|
223 | 242 |
if body: |
224 | 243 |
headers['content-type'] = 'text/plain' |
225 | 244 |
request = self.create_request(operation, dist_id, headers) |
... | ... |
@@ -352,3 +397,18 @@ class Cmd(object): |
352 | 352 |
pretty_output("DomainName", d.info['DomainName']) |
353 | 353 |
pretty_output("Status", d.info['Status']) |
354 | 354 |
pretty_output("Enabled", dc.info['Enabled']) |
355 |
+ |
|
356 |
+ @staticmethod |
|
357 |
+ def delete(args): |
|
358 |
+ cf = CloudFront(Config()) |
|
359 |
+ cfuris = [] |
|
360 |
+ for arg in args: |
|
361 |
+ cfuris.append(S3Uri(arg)) |
|
362 |
+ if cfuris[-1].type != 'cf': |
|
363 |
+ raise ParameterError("CloudFront URI required instead of: %s" % arg) |
|
364 |
+ for cfuri in cfuris: |
|
365 |
+ response = cf.DeleteDistribution(cfuri) |
|
366 |
+ if response['status'] >= 400: |
|
367 |
+ output("Distribution %s deleted" % cfuri) |
|
368 |
+ else: |
|
369 |
+ error("Distribution %s could not be deleted: %s" % (cfuri, response['reason'])) |
... | ... |
@@ -72,9 +72,9 @@ def getDictFromTree(tree): |
72 | 72 |
if ret_dict.has_key(child.tag): |
73 | 73 |
if not type(ret_dict[child.tag]) == list: |
74 | 74 |
ret_dict[child.tag] = [ret_dict[child.tag]] |
75 |
- ret_dict[child.tag].append(child.text) |
|
75 |
+ ret_dict[child.tag].append(child.text or "") |
|
76 | 76 |
else: |
77 |
- ret_dict[child.tag] = child.text |
|
77 |
+ ret_dict[child.tag] = child.text or "" |
|
78 | 78 |
return ret_dict |
79 | 79 |
|
80 | 80 |
def getTextFromXml(xml, xpath): |
... | ... |
@@ -1121,7 +1121,7 @@ def get_commands_list(): |
1121 | 1121 |
{"cmd":"cflist", "label":"List CloudFront distribution points", "param":"", "func":CfCmd.info, "argc":0}, |
1122 | 1122 |
{"cmd":"cfinfo", "label":"Display CloudFront distribution point parameters", "param":"[cf://DIST_ID]", "func":CfCmd.info, "argc":0}, |
1123 | 1123 |
{"cmd":"cfcreate", "label":"Create CloudFront distribution point", "param":"s3://BUCKET", "func":CfCmd.create, "argc":1}, |
1124 |
- #{"cmd":"cfdelete", "label":"Delete CloudFront distribution point", "param":"cf://DIST_ID", "func":CfCmd.delete, "argc":1}, |
|
1124 |
+ {"cmd":"cfdelete", "label":"Delete CloudFront distribution point", "param":"cf://DIST_ID", "func":CfCmd.delete, "argc":1}, |
|
1125 | 1125 |
#{"cmd":"cfmodify", "label":"Change CloudFront distribution point parameters", "param":"cf://DIST_ID", "func":cmd_cf_modify, "argc":1}, |
1126 | 1126 |
] |
1127 | 1127 |
|