~0x44/nova/bug838466

« back to all changes in this revision

Viewing changes to vendor/boto/boto/cloudfront/distribution.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/
 
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
import uuid
 
23
from boto.cloudfront.identity import OriginAccessIdentity
 
24
from boto.cloudfront.object import Object, StreamingObject
 
25
from boto.cloudfront.signers import ActiveTrustedSigners, TrustedSigners
 
26
from boto.cloudfront.logging import LoggingInfo
 
27
from boto.s3.acl import ACL
 
28
 
 
29
class DistributionConfig:
 
30
 
 
31
    def __init__(self, connection=None, origin='', enabled=False,
 
32
                 caller_reference='', cnames=None, comment='',
 
33
                 origin_access_identity=None, trusted_signers=None):
 
34
        self.connection = connection
 
35
        self.origin = origin
 
36
        self.enabled = enabled
 
37
        if caller_reference:
 
38
            self.caller_reference = caller_reference
 
39
        else:
 
40
            self.caller_reference = str(uuid.uuid4())
 
41
        self.cnames = []
 
42
        if cnames:
 
43
            self.cnames = cnames
 
44
        self.comment = comment
 
45
        self.origin_access_identity = origin_access_identity
 
46
        self.trusted_signers = trusted_signers
 
47
        self.logging = None
 
48
 
 
49
    def get_oai_value(self):
 
50
        if isinstance(self.origin_access_identity, OriginAccessIdentity):
 
51
            return self.origin_access_identity.uri()
 
52
        else:
 
53
            return self.origin_access_identity
 
54
                
 
55
    def to_xml(self):
 
56
        s = '<?xml version="1.0" encoding="UTF-8"?>\n'
 
57
        s += '<DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2008-12-01/">\n'
 
58
        s += '  <Origin>%s</Origin>\n' % self.origin
 
59
        s += '  <CallerReference>%s</CallerReference>\n' % self.caller_reference
 
60
        for cname in self.cnames:
 
61
            s += '  <CNAME>%s</CNAME>\n' % cname
 
62
        if self.comment:
 
63
            s += '  <Comment>%s</Comment>\n' % self.comment
 
64
        s += '  <Enabled>'
 
65
        if self.enabled:
 
66
            s += 'true'
 
67
        else:
 
68
            s += 'false'
 
69
        s += '</Enabled>\n'
 
70
        if self.origin_access_identity:
 
71
            val = self.get_oai_value()
 
72
            s += '<OriginAccessIdentity>%s</OriginAccessIdentity>\n' % val
 
73
        if self.trusted_signers:
 
74
            s += '<TrustedSigners>\n'
 
75
            for signer in self.trusted_signers:
 
76
                if signer == 'Self':
 
77
                    s += '  <Self></Self>\n'
 
78
                else:
 
79
                    s += '  <AwsAccountNumber>%s</AwsAccountNumber>\n' % signer
 
80
            s += '</TrustedSigners>\n'
 
81
        if self.logging:
 
82
            s += '<Logging>\n'
 
83
            s += '  <Bucket>%s</Bucket>\n' % self.logging.bucket
 
84
            s += '  <Prefix>%s</Prefix>\n' % self.logging.prefix
 
85
            s += '</Logging>\n'
 
86
        s += '</DistributionConfig>\n'
 
87
        return s
 
88
 
 
89
    def startElement(self, name, attrs, connection):
 
90
        if name == 'TrustedSigners':
 
91
            self.trusted_signers = TrustedSigners()
 
92
            return self.trusted_signers
 
93
        elif name == 'Logging':
 
94
            self.logging = LoggingInfo()
 
95
            return self.logging
 
96
        else:
 
97
            return None
 
98
 
 
99
    def endElement(self, name, value, connection):
 
100
        if name == 'CNAME':
 
101
            self.cnames.append(value)
 
102
        elif name == 'Origin':
 
103
            self.origin = value
 
104
        elif name == 'Comment':
 
105
            self.comment = value
 
106
        elif name == 'Enabled':
 
107
            if value.lower() == 'true':
 
108
                self.enabled = True
 
109
            else:
 
110
                self.enabled = False
 
111
        elif name == 'CallerReference':
 
112
            self.caller_reference = value
 
113
        elif name == 'OriginAccessIdentity':
 
114
            self.origin_access_identity = value
 
115
        else:
 
116
            setattr(self, name, value)
 
117
 
 
118
class StreamingDistributionConfig(DistributionConfig):
 
119
 
 
120
    def __init__(self, connection=None, origin='', enabled=False,
 
121
                 caller_reference='', cnames=None, comment=''):
 
122
        DistributionConfig.__init__(self, connection, origin,
 
123
                                    enabled, caller_reference,
 
124
                                    cnames, comment)
 
125
 
 
126
    def to_xml(self):
 
127
        s = '<?xml version="1.0" encoding="UTF-8"?>\n'
 
128
        s += '<StreamingDistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2009-12-01/">\n'
 
129
        s += '  <Origin>%s</Origin>\n' % self.origin
 
130
        s += '  <CallerReference>%s</CallerReference>\n' % self.caller_reference
 
131
        for cname in self.cnames:
 
132
            s += '  <CNAME>%s</CNAME>\n' % cname
 
133
        if self.comment:
 
134
            s += '  <Comment>%s</Comment>\n' % self.comment
 
135
        s += '  <Enabled>'
 
136
        if self.enabled:
 
137
            s += 'true'
 
138
        else:
 
139
            s += 'false'
 
140
        s += '</Enabled>\n'
 
141
        s += '</StreamingDistributionConfig>\n'
 
142
        return s
 
143
 
 
144
    def startElement(self, name, attrs, connection):
 
145
        pass
 
146
 
 
147
class DistributionSummary:
 
148
 
 
149
    def __init__(self, connection=None, domain_name='', id='',
 
150
                 last_modified_time=None, status='', origin='',
 
151
                 cname='', comment='', enabled=False):
 
152
        self.connection = connection
 
153
        self.domain_name = domain_name
 
154
        self.id = id
 
155
        self.last_modified_time = last_modified_time
 
156
        self.status = status
 
157
        self.origin = origin
 
158
        self.enabled = enabled
 
159
        self.cnames = []
 
160
        if cname:
 
161
            self.cnames.append(cname)
 
162
        self.comment = comment
 
163
        self.trusted_signers = None
 
164
        self.etag = None
 
165
        self.streaming = False
 
166
 
 
167
    def startElement(self, name, attrs, connection):
 
168
        if name == 'TrustedSigners':
 
169
            self.trusted_signers = TrustedSigners()
 
170
            return self.trusted_signers
 
171
        return None
 
172
 
 
173
    def endElement(self, name, value, connection):
 
174
        if name == 'Id':
 
175
            self.id = value
 
176
        elif name == 'Status':
 
177
            self.status = value
 
178
        elif name == 'LastModifiedTime':
 
179
            self.last_modified_time = value
 
180
        elif name == 'DomainName':
 
181
            self.domain_name = value
 
182
        elif name == 'Origin':
 
183
            self.origin = value
 
184
        elif name == 'CNAME':
 
185
            self.cnames.append(value)
 
186
        elif name == 'Comment':
 
187
            self.comment = value
 
188
        elif name == 'Enabled':
 
189
            if value.lower() == 'true':
 
190
                self.enabled = True
 
191
            else:
 
192
                self.enabled = False
 
193
        elif name == 'StreamingDistributionSummary':
 
194
            self.streaming = True
 
195
        else:
 
196
            setattr(self, name, value)
 
197
 
 
198
    def get_distribution(self):
 
199
        return self.connection.get_distribution_info(self.id)
 
200
 
 
201
class StreamingDistributionSummary(DistributionSummary):
 
202
 
 
203
    def get_distribution(self):
 
204
        return self.connection.get_streaming_distribution_info(self.id)
 
205
    
 
206
class Distribution:
 
207
 
 
208
    def __init__(self, connection=None, config=None, domain_name='',
 
209
                 id='', last_modified_time=None, status=''):
 
210
        self.connection = connection
 
211
        self.config = config
 
212
        self.domain_name = domain_name
 
213
        self.id = id
 
214
        self.last_modified_time = last_modified_time
 
215
        self.status = status
 
216
        self.active_signers = None
 
217
        self.etag = None
 
218
        self._bucket = None
 
219
 
 
220
    def startElement(self, name, attrs, connection):
 
221
        if name == 'DistributionConfig':
 
222
            self.config = DistributionConfig()
 
223
            return self.config
 
224
        elif name == 'ActiveTrustedSigners':
 
225
            self.active_signers = ActiveTrustedSigners()
 
226
            return self.active_signers
 
227
        else:
 
228
            return None
 
229
 
 
230
    def endElement(self, name, value, connection):
 
231
        if name == 'Id':
 
232
            self.id = value
 
233
        elif name == 'LastModifiedTime':
 
234
            self.last_modified_time = value
 
235
        elif name == 'Status':
 
236
            self.status = value
 
237
        elif name == 'DomainName':
 
238
            self.domain_name = value
 
239
        else:
 
240
            setattr(self, name, value)
 
241
 
 
242
    def update(self, enabled=None, cnames=None, comment=None,
 
243
               origin_access_identity=None,
 
244
               trusted_signers=None):
 
245
        """
 
246
        Update the configuration of the Distribution.
 
247
 
 
248
        :type enabled: bool
 
249
        :param enabled: Whether the Distribution is active or not.
 
250
 
 
251
        :type cnames: list of str
 
252
        :param cnames: The DNS CNAME's associated with this
 
253
                        Distribution.  Maximum of 10 values.
 
254
 
 
255
        :type comment: str or unicode
 
256
        :param comment: The comment associated with the Distribution.
 
257
 
 
258
        :type origin_access_identity: :class:`boto.cloudfront.identity.OriginAccessIdentity`
 
259
        :param origin_access_identity: The CloudFront origin access identity
 
260
                                       associated with the distribution.  This
 
261
                                       must be provided if you want the
 
262
                                       distribution to serve private content.
 
263
 
 
264
        :type trusted_signers: :class:`boto.cloudfront.signers.TrustedSigner`
 
265
        :param trusted_signers: The AWS users who are authorized to sign
 
266
                                URL's for private content in this Distribution.
 
267
 
 
268
        """
 
269
        new_config = DistributionConfig(self.connection, self.config.origin,
 
270
                                        self.config.enabled, self.config.caller_reference,
 
271
                                        self.config.cnames, self.config.comment,
 
272
                                        self.config.origin_access_identity,
 
273
                                        self.config.trusted_signers)
 
274
        if enabled != None:
 
275
            new_config.enabled = enabled
 
276
        if cnames != None:
 
277
            new_config.cnames = cnames
 
278
        if comment != None:
 
279
            new_config.comment = comment
 
280
        if origin_access_identity != None:
 
281
            new_config.origin_access_identity = origin_access_identity
 
282
        if trusted_signers:
 
283
            new_config.trusted_signers = trusted_signers
 
284
        self.etag = self.connection.set_distribution_config(self.id, self.etag, new_config)
 
285
        self.config = new_config
 
286
        self._object_class = Object
 
287
 
 
288
    def enable(self):
 
289
        """
 
290
        Deactivate the Distribution.  A convenience wrapper around
 
291
        the update method.
 
292
        """
 
293
        self.update(enabled=True)
 
294
 
 
295
    def disable(self):
 
296
        """
 
297
        Activate the Distribution.  A convenience wrapper around
 
298
        the update method.
 
299
        """
 
300
        self.update(enabled=False)
 
301
 
 
302
    def delete(self):
 
303
        """
 
304
        Delete this CloudFront Distribution.  The content
 
305
        associated with the Distribution is not deleted from
 
306
        the underlying Origin bucket in S3.
 
307
        """
 
308
        self.connection.delete_distribution(self.id, self.etag)
 
309
 
 
310
    def _get_bucket(self):
 
311
        if not self._bucket:
 
312
            bucket_name = self.config.origin.split('.')[0]
 
313
            from boto.s3.connection import S3Connection
 
314
            s3 = S3Connection(self.connection.aws_access_key_id,
 
315
                              self.connection.aws_secret_access_key,
 
316
                              proxy=self.connection.proxy,
 
317
                              proxy_port=self.connection.proxy_port,
 
318
                              proxy_user=self.connection.proxy_user,
 
319
                              proxy_pass=self.connection.proxy_pass)
 
320
            self._bucket = s3.get_bucket(bucket_name)
 
321
            self._bucket.distribution = self
 
322
            self._bucket.set_key_class(self._object_class)
 
323
        return self._bucket
 
324
    
 
325
    def get_objects(self):
 
326
        """
 
327
        Return a list of all content objects in this distribution.
 
328
        
 
329
        :rtype: list of :class:`boto.cloudfront.object.Object`
 
330
        :return: The content objects
 
331
        """
 
332
        bucket = self._get_bucket()
 
333
        objs = []
 
334
        for key in bucket:
 
335
            objs.append(key)
 
336
        return objs
 
337
 
 
338
    def set_permissions(self, object, replace=False):
 
339
        """
 
340
        Sets the S3 ACL grants for the given object to the appropriate
 
341
        value based on the type of Distribution.  If the Distribution
 
342
        is serving private content the ACL will be set to include the
 
343
        Origin Access Identity associated with the Distribution.  If
 
344
        the Distribution is serving public content the content will
 
345
        be set up with "public-read".
 
346
 
 
347
        :type object: :class:`boto.cloudfront.object.Object`
 
348
        :param enabled: The Object whose ACL is being set
 
349
 
 
350
        :type replace: bool
 
351
        :param replace: If False, the Origin Access Identity will be
 
352
                        appended to the existing ACL for the object.
 
353
                        If True, the ACL for the object will be
 
354
                        completely replaced with one that grants
 
355
                        READ permission to the Origin Access Identity.
 
356
 
 
357
        """
 
358
        if self.config.origin_access_identity:
 
359
            id = self.config.origin_access_identity.split('/')[-1]
 
360
            oai = self.connection.get_origin_access_identity_info(id)
 
361
            policy = object.get_acl()
 
362
            if replace:
 
363
                policy.acl = ACL()
 
364
            policy.acl.add_user_grant('READ', oai.s3_user_id)
 
365
            object.set_acl(policy)
 
366
        else:
 
367
            object.set_canned_acl('public-read')
 
368
 
 
369
    def set_permissions_all(self, replace=False):
 
370
        """
 
371
        Sets the S3 ACL grants for all objects in the Distribution
 
372
        to the appropriate value based on the type of Distribution.
 
373
 
 
374
        :type replace: bool
 
375
        :param replace: If False, the Origin Access Identity will be
 
376
                        appended to the existing ACL for the object.
 
377
                        If True, the ACL for the object will be
 
378
                        completely replaced with one that grants
 
379
                        READ permission to the Origin Access Identity.
 
380
 
 
381
        """
 
382
        bucket = self._get_bucket()
 
383
        for key in bucket:
 
384
            self.set_permissions(key)
 
385
 
 
386
    def add_object(self, name, content, headers=None, replace=True):
 
387
        """
 
388
        Adds a new content object to the Distribution.  The content
 
389
        for the object will be copied to a new Key in the S3 Bucket
 
390
        and the permissions will be set appropriately for the type
 
391
        of Distribution.
 
392
 
 
393
        :type name: str or unicode
 
394
        :param name: The name or key of the new object.
 
395
 
 
396
        :type content: file-like object
 
397
        :param content: A file-like object that contains the content
 
398
                        for the new object.
 
399
 
 
400
        :type headers: dict
 
401
        :param headers: A dictionary containing additional headers
 
402
                        you would like associated with the new
 
403
                        object in S3.
 
404
 
 
405
        :rtype: :class:`boto.cloudfront.object.Object`
 
406
        :return: The newly created object.
 
407
        """
 
408
        if self.config.origin_access_identity:
 
409
            policy = 'private'
 
410
        else:
 
411
            policy = 'public-read'
 
412
        bucket = self._get_bucket()
 
413
        object = bucket.new_key(name)
 
414
        object.set_contents_from_file(content, headers=headers, policy=policy)
 
415
        if self.config.origin_access_identity:
 
416
            self.set_permissions(object, replace)
 
417
        return object
 
418
            
 
419
class StreamingDistribution(Distribution):
 
420
 
 
421
    def __init__(self, connection=None, config=None, domain_name='',
 
422
                 id='', last_modified_time=None, status=''):
 
423
        Distribution.__init__(self, connection, config, domain_name,
 
424
                              id, last_modified_time, status)
 
425
        self._object_class = StreamingObject
 
426
 
 
427
    def startElement(self, name, attrs, connection):
 
428
        if name == 'StreamingDistributionConfig':
 
429
            self.config = StreamingDistributionConfig()
 
430
            return self.config
 
431
        else:
 
432
            return None
 
433
 
 
434
    def update(self, enabled=None, cnames=None, comment=None):
 
435
        """
 
436
        Update the configuration of the Distribution.
 
437
 
 
438
        :type enabled: bool
 
439
        :param enabled: Whether the Distribution is active or not.
 
440
 
 
441
        :type cnames: list of str
 
442
        :param cnames: The DNS CNAME's associated with this
 
443
                        Distribution.  Maximum of 10 values.
 
444
 
 
445
        :type comment: str or unicode
 
446
        :param comment: The comment associated with the Distribution.
 
447
 
 
448
        """
 
449
        new_config = StreamingDistributionConfig(self.connection,
 
450
                                                 self.config.origin,
 
451
                                                 self.config.enabled,
 
452
                                                 self.config.caller_reference,
 
453
                                                 self.config.cnames,
 
454
                                                 self.config.comment)
 
455
        if enabled != None:
 
456
            new_config.enabled = enabled
 
457
        if cnames != None:
 
458
            new_config.cnames = cnames
 
459
        if comment != None:
 
460
            new_config.comment = comment
 
461
            
 
462
        self.etag = self.connection.set_streaming_distribution_config(self.id,
 
463
                                                                      self.etag,
 
464
                                                                      new_config)
 
465
        self.config = new_config
 
466
 
 
467
    def delete(self):
 
468
        self.connection.delete_streaming_distribution(self.id, self.etag)
 
469
            
 
470