cloudfront 0.0.1 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/Gemfile +11 -8
  2. data/LICENSE.txt +1 -1
  3. data/README.rdoc +64 -7
  4. data/Rakefile +11 -14
  5. data/cloudfront.gemspec +85 -27
  6. data/lib/cloudfront.rb +39 -0
  7. data/lib/cloudfront/connection.rb +25 -0
  8. data/lib/cloudfront/distribution/distribution.rb +136 -0
  9. data/lib/cloudfront/distribution/download_distribution.rb +54 -0
  10. data/lib/cloudfront/distribution/streaming_distribution.rb +53 -0
  11. data/lib/cloudfront/errors/cloudfront_error.rb +13 -0
  12. data/lib/cloudfront/errors/cname_already_exists_error.rb +7 -0
  13. data/lib/cloudfront/errors/distribution_already_exists_error.rb +7 -0
  14. data/lib/cloudfront/errors/illegal_update_error.rb +7 -0
  15. data/lib/cloudfront/errors/invalid_origin_access_identity_error.rb +7 -0
  16. data/lib/cloudfront/errors/invalid_origin_error.rb +7 -0
  17. data/lib/cloudfront/errors/invalid_required_protocol_error.rb +7 -0
  18. data/lib/cloudfront/errors/missing_body_error.rb +7 -0
  19. data/lib/cloudfront/errors/precondition_failed_error.rb +7 -0
  20. data/lib/cloudfront/errors/too_many_distribution_cnames_error.rb +7 -0
  21. data/lib/cloudfront/errors/too_many_distributions_error.rb +7 -0
  22. data/lib/cloudfront/errors/too_many_trusted_signers_error.rb +7 -0
  23. data/lib/cloudfront/errors/trusted_signer_does_not_exist_error.rb +7 -0
  24. data/lib/cloudfront/exceptions/delete_enabled_distribution_exception.rb +7 -0
  25. data/lib/cloudfront/exceptions/distribution_already_disabled_exception.rb +7 -0
  26. data/lib/cloudfront/exceptions/distribution_already_enabled_exception.rb +7 -0
  27. data/lib/cloudfront/exceptions/distribution_configuration_exception.rb +7 -0
  28. data/lib/cloudfront/exceptions/missing_etag_exception.rb +7 -0
  29. data/lib/cloudfront/helpers/aliases.rb +71 -0
  30. data/lib/cloudfront/helpers/cache_behavior.rb +166 -0
  31. data/lib/cloudfront/helpers/cache_behaviors.rb +108 -0
  32. data/lib/cloudfront/helpers/download_distribution.rb +157 -0
  33. data/lib/cloudfront/helpers/invalidation.rb +83 -0
  34. data/lib/cloudfront/helpers/logging.rb +71 -0
  35. data/lib/cloudfront/helpers/origin.rb +101 -0
  36. data/lib/cloudfront/helpers/origin_access_identity.rb +58 -0
  37. data/lib/cloudfront/helpers/origins.rb +94 -0
  38. data/lib/cloudfront/helpers/s3_origin.rb +51 -0
  39. data/lib/cloudfront/helpers/streaming_distribution.rb +150 -0
  40. data/lib/cloudfront/helpers/trusted_signers.rb +73 -0
  41. data/lib/cloudfront/invalidation/invalidations.rb +57 -0
  42. data/lib/cloudfront/origin_access_identity/origin_access_identity.rb +60 -0
  43. data/lib/cloudfront/utils/api.rb +18 -0
  44. data/lib/cloudfront/utils/array.rb +5 -0
  45. data/lib/cloudfront/utils/configuration_checker.rb +19 -0
  46. data/lib/cloudfront/utils/string.rb +11 -0
  47. data/lib/cloudfront/utils/util.rb +20 -0
  48. data/lib/cloudfront/utils/xml_serializer.rb +18 -0
  49. data/lib/faraday/request/cloudfront_signer.rb +35 -0
  50. data/lib/faraday/request/xml_content_type.rb +18 -0
  51. metadata +198 -31
  52. data/.document +0 -5
  53. data/Gemfile.lock +0 -27
  54. data/test/helper.rb +0 -19
  55. data/test/test_cloudfront.rb +0 -7
@@ -0,0 +1,108 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative 'trusted_signers'
4
+ require_relative 'cache_behavior'
5
+
6
+ class Cloudfront
7
+ module Helpers
8
+ class CacheBehaviors
9
+ include Cloudfront::Utils::ConfigurationChecker
10
+ include Cloudfront::Utils::XmlSerializer
11
+
12
+ attr_accessor :cache_behaviors
13
+
14
+ def initialize(&block)
15
+ #set default values
16
+ @cache_behaviors = []
17
+
18
+ #set values from block
19
+ instance_eval &block if block_given?
20
+ end
21
+
22
+ def validate
23
+ # some wrapping
24
+ @cache_behaviors = Array.wrap @cache_behaviors
25
+
26
+ # Error checking
27
+ for cache_behavior in @cache_behaviors
28
+ if cache_behavior.is_a?(CacheBehavior)
29
+ cache_behavior.check_configuration
30
+ else
31
+ error_messages.push "cache_behaviors list contains a non CacheBehavior element #{cache_behavior}"
32
+ end
33
+ end
34
+ end
35
+
36
+ # hash = {
37
+ # "CacheBehaviors" => {
38
+ # "Quantity" => "2",
39
+ # "Items" => {
40
+ # "CacheBehavior" => [
41
+ # {
42
+ # #see CacheBehavior
43
+ # }, {
44
+ # #...
45
+ # }
46
+ # ]
47
+ # }
48
+ # }
49
+ # }
50
+ def self.from_hash(hash)
51
+ hash = hash["CacheBehaviors"] || hash
52
+ self.new do
53
+ for cache_behavior in [(hash["Items"]|| {})["CacheBehavior"]]
54
+ unless cache_behavior.nil?
55
+ self.cache_behaviors.push(CacheBehavior.from_hash(cache_behavior))
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ # The cache behavior class container
62
+ # <CacheBehaviors>
63
+ # <Quantity>1</Quantity>
64
+ # <Items>
65
+ # <CacheBehavior>
66
+ # <PathPattern>pattern that specifies files that this cache behavior applies to</PathPattern>
67
+ # <TargetOriginId>ID of the origin that this cache behavior applies to</TargetOriginId>
68
+ # <ForwardedValues>
69
+ # <QueryString>true | false</QueryString>
70
+ # <Cookies>
71
+ # <Forward>all | whitelist | none</Forward>
72
+ # <!-- Required when Forward = whitelist, omitted otherwise. -->
73
+ # <WhitelistedNames>
74
+ # <Quantity>number of cookie names to forward to origin</Quantity>
75
+ # <Items>
76
+ # <Name>name of a cookie to forward to the origin</Name>
77
+ # </Items>
78
+ # </WhitelistedNames>
79
+ # </Cookies>
80
+ # </ForwardedValues>
81
+ # <TrustedSigners>
82
+ # ... see TrustedSigners class
83
+ # </TrustedSigners>
84
+ # <ViewerProtocolPolicy>allow-all | https-only</ViewerProtocolPolicy>
85
+ # <MinTTL>minimum TTL in seconds for files specified by PathPattern</MinTTL>
86
+ # </CacheBehavior>
87
+ def build_xml(xml)
88
+ check_configuration
89
+ xml.CacheBehaviors {
90
+ xml.Quantity @cache_behaviors.size
91
+ if @cache_behaviors.size > 0
92
+ xml.Items {
93
+ for cache_behavior in @cache_behaviors
94
+ cache_behavior.build_xml(xml)
95
+ end
96
+ }
97
+ end
98
+ }
99
+ end
100
+
101
+ end
102
+ end
103
+ end
104
+
105
+
106
+
107
+
108
+
@@ -0,0 +1,157 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative 'logging'
4
+ require_relative 'origins'
5
+ require_relative 'aliases'
6
+ require_relative 'cache_behavior'
7
+ require_relative 'cache_behaviors'
8
+
9
+ class Cloudfront
10
+ module Helpers
11
+ class DownloadDistribution
12
+ include Cloudfront::Utils::ConfigurationChecker
13
+ include Cloudfront::Utils::XmlSerializer
14
+
15
+ attr_accessor :caller_reference,
16
+ :cnames,
17
+ :default_root_object,
18
+ :origins,
19
+ :default_cache_behavior,
20
+ :cache_behaviors,
21
+ :comment,
22
+ :logging,
23
+ :price_class,
24
+ :enabled
25
+
26
+ def initialize(&block)
27
+ #setting default values
28
+ @caller_reference = Cloudfront::Utils::Util.generate_caller_reference
29
+ @cnames = []
30
+ @default_root_object = "/index.html"
31
+ @origins = []
32
+ @default_cache_behavior = CacheBehavior.new do
33
+ self.is_default = true
34
+ end
35
+ @cache_behaviors = []
36
+ @comment = "Created with cloudfront Gem, visit https://github.com/Belkacem/cloudfront"
37
+ @logging = Logging.new
38
+ @price_class = "PriceClass_All"
39
+ @enabled = false
40
+
41
+ #set value from block
42
+ instance_eval &block if block_given?
43
+ end
44
+
45
+ def validate
46
+ this = self
47
+
48
+ # aliases and behaviors are internal structures.
49
+ @aliases = Aliases.new do
50
+ self.cnames = this.cnames
51
+ end
52
+
53
+ @behaviors = CacheBehaviors.new do
54
+ self.cache_behaviors = this.cache_behaviors
55
+ end
56
+
57
+ @origins_container = Origins.new do
58
+ self.origins = this.origins
59
+ end
60
+
61
+ # Error checking
62
+ error_messages.push "The caller_reference shouldn't be empty" if @caller_reference.empty?
63
+ @aliases.check_configuration
64
+ @origins_container.check_configuration
65
+ @default_cache_behavior.check_configuration
66
+ # Making the default cache behavior to true
67
+ @default_cache_behavior.is_default = true
68
+ @behaviors.check_configuration
69
+ @logging.check_configuration
70
+ error_messages.push "price_class is invalid should be in #{Cloudfront::Utils::Util::PRICE_CLASS.join(', ')}" unless Cloudfront::Utils::Util::PRICE_CLASS.include?(@price_class)
71
+ error_messages.push "enabled should be a boolean" unless !!@enabled == @enabled
72
+ end
73
+
74
+ # Creates a distribution configuration wrapper from a hash
75
+ # {
76
+ # "DistributionConfig" => {
77
+ # "CallerReference" => "unique description for this distribution config",
78
+ # "Aliases" => "Aliases class",
79
+ # "DefaultRootObject" => "URL for default root object",
80
+ # "Origins" => ... see Origins class",
81
+ # "DefaultCacheBehavior" =>
82
+ # "\n... see CacheBehaviour class\n ",
83
+ # "CacheBehaviors" => {
84
+ # ... see CacheBehaviors
85
+ # },
86
+ # "Comment" => "comment about the distribution",
87
+ # "Logging" =>
88
+ # "... see Logging class",
89
+ # "PriceClass" => "maximum price class for the distribution",
90
+ # "Enabled" => "true | false"
91
+ # }
92
+ # }
93
+ def self.from_hash(hash)
94
+ hash = hash["DistributionConfig"] || hash
95
+ self.new do
96
+ self.caller_reference = hash["CallerReference"]
97
+ self.cnames = Aliases.from_hash(hash["Aliases"]).cnames # Aliases class contains the code that extract cnames
98
+ self.default_root_object = hash["DefaultRootObject"]
99
+ self.origins = Origins.from_hash(hash["Origins"]).origins
100
+ self.default_cache_behavior = CacheBehavior.from_hash(hash["DefaultCacheBehavior"])
101
+ self.cache_behaviors = CacheBehaviors.from_hash(hash["CacheBehaviors"]).cache_behaviors
102
+ self.comment = hash["Comment"]
103
+ self.logging = Logging.from_hash(hash["Logging"])
104
+ self.price_class = hash["PriceClass"] || "PriceClass_All"
105
+ self.enabled = (hash["Enabled"] || "false").to_bool
106
+ end
107
+ end
108
+
109
+ #<?xml version="1.0" encoding="UTF-8"?>
110
+ #<DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2012-07-01/">
111
+ # <CallerReference>unique description for this distribution config</CallerReference>
112
+ # <Aliases>
113
+ # ... see Alias class
114
+ # </Aliases>
115
+ # <DefaultRootObject>URL for default root object</DefaultRootObject>
116
+ # <Origins>
117
+ # <Quantity>number of origins</Quantity>
118
+ # <Items>
119
+ # ... see Origin class
120
+ # </Items>
121
+ # </Origins>
122
+ # <DefaultCacheBehavior>
123
+ # ... see CacheBehaviour class
124
+ # </DefaultCacheBehavior>
125
+ # <CacheBehaviors>
126
+ # <Quantity>number of cache behaviors</Quantity>
127
+ # <!-- Optional. Omit when Quantity = 0. -->
128
+ # <Items>
129
+ # ... see CacheBehaviour class
130
+ # </Items>
131
+ # </CacheBehaviors>
132
+ # <Comment>comment about the distribution</Comment>
133
+ # <Logging>
134
+ # ... see Logging class
135
+ # </Logging>
136
+ # <PriceClass>maximum price class for the distribution</PriceClass>
137
+ # <Enabled>true | false</Enabled>
138
+ #</DistributionConfig>
139
+ def build_xml(xml)
140
+ check_configuration
141
+ xml.DistributionConfig('xmlns' => "http://cloudfront.amazonaws.com/doc/#{Cloudfront::Utils::Api.version}/") {
142
+ xml.CallerReference @caller_reference
143
+ @aliases.build_xml(xml)
144
+ xml.DefaultRootObject @default_root_object
145
+ @origins_container.build_xml(xml)
146
+ @default_cache_behavior.build_xml(xml)
147
+ @behaviors.build_xml(xml)
148
+ xml.Comment @comment
149
+ @logging.build_xml(xml)
150
+ xml.PriceClass @price_class
151
+ xml.Enabled @enabled
152
+ }
153
+ end
154
+
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,83 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'cloudfront/helpers/invalidation'
4
+
5
+ class Cloudfront
6
+ module Helpers
7
+ class Invalidation
8
+ include Cloudfront::Utils::ConfigurationChecker
9
+ include Cloudfront::Utils::XmlSerializer
10
+
11
+ attr_accessor :caller_reference,
12
+ :files
13
+
14
+ def initialize(&block)
15
+ #setting default values
16
+ @caller_reference = Cloudfront::Utils::Util.generate_caller_reference
17
+ @files = []
18
+
19
+ #set value from block
20
+ instance_eval &block if block_given?
21
+ end
22
+
23
+ def validate
24
+ @files = Array.wrap @files
25
+
26
+ # Error checking
27
+ error_messages.push "files shouldn't be empty" unless @files.any?
28
+ for file in @files
29
+ error_messages.push "the file '#{file}' isn't valid, it should start with '/'" unless file.start_with? '/'
30
+ end
31
+ end
32
+
33
+ # Creates a Invalidation from a hash
34
+ # {
35
+ # "InvalidationBatch" => {
36
+ # "Paths" => {
37
+ # "Quantity" => "number of objects to invalidate",
38
+ # "Items" => {
39
+ # "Path" => "/path to object to invalidate"
40
+ # }
41
+ # },
42
+ # "CallerReference" => "unique identifier for this invalidation batch"
43
+ # }
44
+ # }
45
+ def self.from_hash(hash)
46
+ hash = hash["InvalidationBatch"] || hash
47
+ self.new do
48
+ self.caller_reference = hash["CallerReference"]
49
+ items = (hash["Paths"] || {})["Items"]
50
+ self.files = Array.wrap (items["Path"])
51
+ end
52
+ end
53
+
54
+ # <?xml version="1.0" encoding="UTF-8"?>
55
+ # <InvalidationBatch xmlns="http://cloudfront.amazonaws.com/doc/2012-07-01/">
56
+ # <Paths>
57
+ # <Quantity>number of objects to invalidate</Quantity>
58
+ # <Items>
59
+ # <Path>/path to object to invalidate</Path>
60
+ # </Items>
61
+ # </Paths>
62
+ # <CallerReference>unique identifier for this invalidation batch</CallerReference>
63
+ # </InvalidationBatch>
64
+ def build_xml(xml)
65
+ check_configuration
66
+ xml.InvalidationBatch('xmlns' => "http://cloudfront.amazonaws.com/doc/#{Cloudfront::Utils::Api.version}/") {
67
+ xml.Paths {
68
+ xml.Quantity @files.size
69
+ if @files.size > 0
70
+ xml.Items {
71
+ for file in Array.wrap @files
72
+ xml.Path file
73
+ end
74
+ }
75
+ end
76
+ }
77
+ xml.CallerReference @caller_reference
78
+ }
79
+ end
80
+
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,71 @@
1
+ # encoding: UTF-8
2
+
3
+ class Cloudfront
4
+ module Helpers
5
+ class Logging
6
+ include Cloudfront::Utils::ConfigurationChecker
7
+ include Cloudfront::Utils::XmlSerializer
8
+
9
+ attr_accessor :enabled,
10
+ :include_cookies,
11
+ :bucket,
12
+ :prefix
13
+
14
+ def initialize(&block)
15
+ #set default values
16
+ @enabled = false
17
+ @include_cookies = false
18
+ #set values from block
19
+ instance_eval &block if block_given?
20
+ end
21
+
22
+ def validate
23
+ error_messages.push "enabled should be a boolean" unless !!@enabled == @enabled
24
+ error_messages.push "include_cookies should be a boolean or 'undefined'" unless !!@include_cookies == @include_cookies || @include_cookies == "undefined"
25
+ error_messages.push "You must specify a bucket" if @enabled && @bucket.nil?
26
+ end
27
+
28
+ # A factory method that creates a Logging instance from a hash
29
+ # Input example
30
+ # hash = {
31
+ # "Logging" => {
32
+ # "Enabled" => "true | false",
33
+ # "IncludeCookies" => "true | false",
34
+ # "Bucket" => "Amazon S3 bucket to save logs in",
35
+ # "Prefix" => "prefix for log filenames"
36
+ # }
37
+ # }
38
+ def self.from_hash(hash)
39
+ hash = hash["Logging"] || hash
40
+ self.new do
41
+ self.enabled = (hash["Enabled"] || "false").to_bool
42
+ self.include_cookies = hash["IncludeCookies"].nil? ? "undefined" : hash["IncludeCookies"].to_bool
43
+ if self.enabled
44
+ self.bucket = hash["Bucket"]
45
+ self.prefix = hash["Prefix"]
46
+ end
47
+ end
48
+ end
49
+
50
+ # build the xml
51
+ # <Logging>
52
+ # <Enabled>true | false</Enabled>
53
+ # <IncludeCookies>true | false</IncludeCookies>
54
+ # <Bucket>Amazon S3 bucket to save logs in</Bucket>
55
+ # <Prefix>prefix for log filenames</Prefix>
56
+ # </Logging>
57
+ def build_xml(xml)
58
+ check_configuration
59
+ xml.Logging {
60
+ xml.Enabled @enabled
61
+ xml.IncludeCookies @include_cookies unless @include_cookies == "undefined"
62
+ if @enabled
63
+ xml.Bucket @bucket
64
+ xml.Prefix @prefix
65
+ end
66
+ }
67
+ end
68
+
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,101 @@
1
+ # encoding: UTF-8
2
+
3
+ class Cloudfront
4
+ module Helpers
5
+ class Origin
6
+ include Cloudfront::Utils::ConfigurationChecker
7
+ include Cloudfront::Utils::XmlSerializer
8
+
9
+ attr_accessor :id,
10
+ :domain_name,
11
+ :origin_access_identity,
12
+ :http_port,
13
+ :https_port,
14
+ :origin_protocol_policy
15
+
16
+ def initialize(&block)
17
+ #set default values
18
+ @http_port = 80
19
+ @https_port = 443
20
+ @origin_protocol_policy = "match-viewer"
21
+ #set value from block
22
+ instance_eval &block if block_given?
23
+ end
24
+
25
+ def validate
26
+ error_messages.push "http_port is invalid" unless @http_port.between?(0, 65535)
27
+ error_messages.push "https_port is invalid" unless @https_port.between?(0, 65535)
28
+ error_messages.push "id can't be null" if @id.nil?
29
+ error_messages.push "origin_protocol_policy is invalid should be in #{Cloudfront::Utils::Util::MATCH_VIEWER_VALUES.join(', ')}" unless Cloudfront::Utils::Util::MATCH_VIEWER_VALUES.include?(@origin_protocol_policy)
30
+ end
31
+
32
+ # {
33
+ # "Origin"=> {
34
+ # "Id"=>"unique identifier for this origin",
35
+ # "DomainName"=>"domain name of origin",
36
+ # "S3OriginConfig"=> {
37
+ # "OriginAccessIdentity"=> "origin-access-identity/cloudfront/ID"
38
+ # },
39
+ # "CustomOriginConfig"=> {
40
+ # "HTTPPort"=> 80,
41
+ # "HTTPSPort"=> 443,
42
+ # "OriginProtocolPolicy"=>"match-viewer"
43
+ # }
44
+ # }
45
+ # }
46
+ def self.from_hash(hash)
47
+ hash = hash["Origin"] || hash
48
+ self.new do
49
+ self.id = hash["Id"]
50
+ self.domain_name = hash["DomainName"]
51
+ if hash.has_key? "S3OriginConfig"
52
+ self.origin_access_identity = hash["S3OriginConfig"]["OriginAccessIdentity"]
53
+ else
54
+ custom_origin_config = hash["CustomOriginConfig"]
55
+ if custom_origin_config
56
+ self.http_port = (custom_origin_config["HTTPPort"] || "80").to_i
57
+ self.https_port = (custom_origin_config["HTTPSPort"] || "443").to_i
58
+ self.origin_protocol_policy = custom_origin_config["OriginProtocolPolicy"] || "match-viewer"
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ # The origin class container
65
+ # <Origin>
66
+ # <Id>unique identifier for this origin</Id>
67
+ # <DomainName>domain name of origin</DomainName>
68
+ # <!-- Include the S3OriginConfig element only if you use an Amazon S3 origin for your distribution. -->
69
+ # <S3OriginConfig>
70
+ # <OriginAccessIdentity>origin-access-identity/cloudfront/ID</OriginAccessIdentity>
71
+ # </S3OriginConfig>
72
+ # <!-- Include the CustomOriginConfig element only if you use a custom origin for your distribution. -->
73
+ # <CustomOriginConfig>
74
+ # <HTTPPort>80</HTTPPort>
75
+ # <HTTPSPort>443</HTTPSPort>
76
+ # <OriginProtocolPolicy>http-only |
77
+ # match-viewer</OriginProtocolPolicy>
78
+ # </CustomOriginConfig>
79
+ # </Origin>
80
+ def build_xml(xml)
81
+ check_configuration
82
+ xml.Origin {
83
+ xml.Id @id
84
+ xml.DomainName @domain_name
85
+ if (!@origin_access_identity.nil?)
86
+ xml.S3OriginConfig {
87
+ xml.OriginAccessIdentity @origin_access_identity
88
+ }
89
+ else
90
+ xml.CustomOriginConfig {
91
+ xml.HTTPPort @http_port
92
+ xml.HTTPSPort @https_port
93
+ xml.OriginProtocolPolicy @origin_protocol_policy
94
+ }
95
+ end
96
+ }
97
+ end
98
+
99
+ end
100
+ end
101
+ end