humidifier 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 49e71afc90f25c69c4186ef0d296bb6a4709c8c4
4
- data.tar.gz: 249d24a729f0d5c92dee6987eefc974c6ff947c6
3
+ metadata.gz: 9de50c50176d088372a188ac60aea7e4087f2389
4
+ data.tar.gz: f613c462e5ee7ed74403409d7b6b82ff87eb4632
5
5
  SHA512:
6
- metadata.gz: b483ce9400693c726c93a8a50aa703fc446d2dc20d7efa8c7dd03a3ad1e10f13ccc1a030679103ef0c05fd701b423a7d592b1d37dec0d0f18f41e4c1cc52160b
7
- data.tar.gz: 244bf6664b9b54a2ecf69d72a19df94d10c65e464fc0912f12773d7729e9417816eabe25b6b38bbcb53274c093a66088eb1adaaeed927f70b36ff5ef53dcb274
6
+ metadata.gz: 9c7fcc5768d0f2a7d2cbeefbb3f6a3497a5977542e1990d9d811284b72a5f04d9ffc1bd45c153a4a4dcd4ac6a281c3f5ff3fc46af38bbf006ba75bb59e2c100a
7
+ data.tar.gz: 586ecf805909463042c9310272bd348a5c8c33273fc5860115151644a2297496e8db7f35489b73c59eb009f0b121a755e0febd0d9f8d037125573d78120d5bd0
data/README.md CHANGED
@@ -59,6 +59,17 @@ Humidifier itself contains a registry of all possible resources that it supports
59
59
 
60
60
  Resources have an `aws_name` method to see how AWS references them. They also contain a `props` method that contains a hash of the name that Humidifier uses to reference the prop pointing to the appropriate prop object.
61
61
 
62
+ ### Large templates
63
+
64
+ When templates are especially large (larger than 51,200 bytes), they cannot be uploaded directly through the AWS SDK. You can configure Humidifier to seemlessly upload the templates to S3 and reference them using an S3 URL instead by:
65
+
66
+ ```ruby
67
+ Humidifier.configure do |config|
68
+ config.s3_bucket = 'my.s3.bucket'
69
+ config.s3_prefix = 'my-prefix/' # optional
70
+ end
71
+ ```
72
+
62
73
  ## Development
63
74
 
64
75
  To get started, ensure you have ruby installed, version 2.0 or later. From there, install the `bundler` gem: `gem install bundler` and then `bundle install` in the root of the repository.
@@ -9,8 +9,7 @@ module Humidifier
9
9
  # Create a CFN stack
10
10
  def create(payload)
11
11
  try_valid do
12
- params = { stack_name: payload.name, template_body: payload.to_cf }.merge(payload.options)
13
- response = client.create_stack(params)
12
+ response = client.create_stack(payload.create_params)
14
13
  payload.id = response.stack_id
15
14
  response
16
15
  end
@@ -18,7 +17,7 @@ module Humidifier
18
17
 
19
18
  # Delete a CFN stack
20
19
  def delete(payload)
21
- client.delete_stack({ stack_name: payload.identifier }.merge(payload.options))
20
+ client.delete_stack(payload.delete_params)
22
21
  true
23
22
  end
24
23
 
@@ -29,15 +28,18 @@ module Humidifier
29
28
 
30
29
  # Update a CFN stack
31
30
  def update(payload)
32
- try_valid do
33
- params = { stack_name: payload.identifier, template_body: payload.to_cf }.merge(payload.options)
34
- client.update_stack(params)
35
- end
31
+ try_valid { client.update_stack(payload.update_params) }
32
+ end
33
+
34
+ # Upload a CFN stack to S3 so that it can be referenced via template_url
35
+ def upload(payload)
36
+ Humidifier.config.ensure_upload_configured!(payload)
37
+ upload_object(payload, "#{Humidifier.config.s3_prefix}#{payload.identifier}.json")
36
38
  end
37
39
 
38
40
  # Validate a template in CFN
39
41
  def valid?(payload)
40
- try_valid { client.validate_template({ template_body: payload.to_cf }.merge(payload.options)) }
42
+ try_valid { client.validate_template(payload.validate_params) }
41
43
  end
42
44
 
43
45
  %i[create delete deploy update].each do |method|
@@ -47,6 +47,12 @@ module Humidifier
47
47
  response
48
48
  end
49
49
 
50
+ def upload_object(payload, key)
51
+ base_module.config(region: AwsShim::REGION)
52
+ @s3 ||= base_module::S3.new
53
+ @s3.buckets[Humidifier.config.s3_bucket].objects.create(key, payload.template_body).url_for(:read)
54
+ end
55
+
50
56
  def unsupported(method)
51
57
  puts "WARNING: Cannot #{method} because that functionality is not supported in V1 of aws-sdk."
52
58
  false
@@ -7,8 +7,7 @@ module Humidifier
7
7
  # Create a change set in CFN
8
8
  def create_change_set(payload)
9
9
  payload.merge(change_set_name: "changeset-#{Time.now.strftime('%Y-%m-%d-%H-%M-%S')}")
10
- params = { stack_name: payload.identifier, template_body: payload.to_cf }.merge(payload.options)
11
- try_valid { client.create_change_set(params) }
10
+ try_valid { client.create_change_set(payload.create_change_set_params) }
12
11
  end
13
12
 
14
13
  # Create a change set if the stack exists, otherwise create the stack
@@ -38,6 +37,13 @@ module Humidifier
38
37
 
39
38
  response
40
39
  end
40
+
41
+ def upload_object(payload, key)
42
+ base_module.config.update(region: AwsShim::REGION)
43
+ @s3_client ||= base_module::S3::Client.new
44
+ @s3_client.put_object(body: payload.template_body, bucket: Humidifier.config.s3_bucket, key: key)
45
+ base_module::S3::Object.new(Humidifier.config.s3_bucket, key).presigned_url(:get)
46
+ end
41
47
  end
42
48
  end
43
49
  end
@@ -13,7 +13,7 @@ module Humidifier
13
13
 
14
14
  # Methods that are sent over to the aws adapter from the stack
15
15
  STACK_METHODS = %i[
16
- create delete deploy exists? update valid?
16
+ create delete deploy exists? update upload valid?
17
17
  create_and_wait delete_and_wait deploy_and_wait update_and_wait
18
18
  create_change_set deploy_change_set
19
19
  ].freeze
@@ -0,0 +1,29 @@
1
+ module Humidifier
2
+
3
+ # a container for user params
4
+ class Configuration
5
+
6
+ UPLOAD_MESSAGE = <<-MSG.freeze
7
+ The %{identifier} stack's body is too large to be use the template_body option, and therefore must use the
8
+ template_url option instead. You can configure Humidifier to do this automatically by setting up the s3 config
9
+ on the top-level Humidifier object like so:
10
+
11
+ Humidifier.configure do |config|
12
+ config.s3_bucket = 'my.s3.bucket'
13
+ config.s3_prefix = 'my-prefix/' # optional
14
+ end
15
+ MSG
16
+
17
+ attr_accessor :s3_bucket, :s3_prefix
18
+
19
+ def initialize(opts = {})
20
+ self.s3_bucket = opts[:s3_bucket]
21
+ self.s3_prefix = opts[:s3_prefix]
22
+ end
23
+
24
+ # raise an error unless the s3_bucket field is set
25
+ def ensure_upload_configured!(payload)
26
+ raise UPLOAD_MESSAGE.gsub('%{identifier}', payload.identifier) if s3_bucket.nil?
27
+ end
28
+ end
29
+ end
@@ -3,13 +3,30 @@ module Humidifier
3
3
  # The payload sent to the shim methods, representing the stack and the options
4
4
  class SdkPayload
5
5
 
6
+ # The maximum size a template body can be before it has to be put somewhere and referenced through a URL
7
+ MAX_TEMPLATE_BODY_SIZE = 51_200
8
+
9
+ # The maximum size a template body can be inside of an S3 bucket
10
+ MAX_TEMPLATE_URL_SIZE = 460_800
11
+
6
12
  # The maximum amount of time that Humidifier should wait for a stack to complete a CRUD operation
7
13
  MAX_WAIT = 600
8
14
 
15
+ # Thrown when a template is too large to use the template_url option
16
+ class TemplateTooLargeError < StandardError
17
+ def initialize(bytesize)
18
+ message = <<-MSG
19
+ Cannot use a template > #{MAX_TEMPLATE_URL_SIZE} bytes (currently #{bytesize} bytes), consider using nested stacks
20
+ (http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stack.html)
21
+ MSG
22
+ super(message)
23
+ end
24
+ end
25
+
9
26
  attr_accessor :stack, :options, :max_wait
10
27
 
11
28
  extend Forwardable
12
- def_delegators :stack, :id=, :identifier, :name, :to_cf
29
+ def_delegators :stack, :id=, :identifier, :name
13
30
 
14
31
  def initialize(stack, options)
15
32
  self.stack = stack
@@ -26,5 +43,53 @@ module Humidifier
26
43
  def merge(new_options)
27
44
  self.options = new_options.merge(options)
28
45
  end
46
+
47
+ # The body of the template
48
+ def template_body
49
+ @template_body ||= stack.to_cf
50
+ end
51
+
52
+ ###
53
+ # Param sets
54
+ ###
55
+
56
+ # Param set for the #create_change_set SDK method
57
+ def create_change_set_params
58
+ { stack_name: stack.identifier }.merge(template_param).merge(options)
59
+ end
60
+
61
+ # Param set for the #create_stack SDK method
62
+ def create_params
63
+ { stack_name: stack.name }.merge(template_param).merge(options)
64
+ end
65
+
66
+ # Param set for the #delete_stack SDK method
67
+ def delete_params
68
+ { stack_name: stack.identifier }.merge(options)
69
+ end
70
+
71
+ # Param set for the #update_stack SDK method
72
+ def update_params
73
+ { stack_name: stack.identifier }.merge(template_param).merge(options)
74
+ end
75
+
76
+ # Param set for the #validate_template SDK method
77
+ def validate_params
78
+ template_param.merge(options)
79
+ end
80
+
81
+ private
82
+
83
+ def template_param
84
+ @template_param ||= begin
85
+ raise TemplateTooLargeError, template_body.bytesize if template_body.bytesize > MAX_TEMPLATE_URL_SIZE
86
+
87
+ if template_body.bytesize > MAX_TEMPLATE_BODY_SIZE
88
+ { template_url: AwsShim.upload(self) }
89
+ else
90
+ { template_body: template_body }
91
+ end
92
+ end
93
+ end
29
94
  end
30
95
  end
@@ -14,6 +14,7 @@ module Humidifier
14
14
  def initialize(opts = {})
15
15
  self.name = opts[:name]
16
16
  self.id = opts[:id]
17
+ self.default_identifier = self.class.next_default_identifier
17
18
 
18
19
  ENUMERABLE_RESOURCES.values.each { |prop| send(:"#{prop}=", opts.fetch(prop, {})) }
19
20
  STATIC_RESOURCES.values.each { |prop| send(:"#{prop}=", opts[prop]) }
@@ -28,7 +29,7 @@ module Humidifier
28
29
 
29
30
  # The identifier used by the shim to find the stack in CFN, prefers id to name
30
31
  def identifier
31
- id || name
32
+ id || name || default_identifier
32
33
  end
33
34
 
34
35
  # A string representation of the stack that's valid for CFN
@@ -46,8 +47,16 @@ module Humidifier
46
47
  define_method(method) { |opts = {}| AwsShim.send(method, SdkPayload.new(self, opts)) }
47
48
  end
48
49
 
50
+ # Increment the default identifier
51
+ def self.next_default_identifier
52
+ @count = (@count || 0) + 1
53
+ "humidifier-stack-template-#{@count}"
54
+ end
55
+
49
56
  private
50
57
 
58
+ attr_accessor :default_identifier
59
+
51
60
  def enumerable_resources
52
61
  ENUMERABLE_RESOURCES.each_with_object({}) do |(name, prop), list|
53
62
  resources = send(prop)
@@ -1,4 +1,4 @@
1
1
  module Humidifier
2
2
  # Gem version
3
- VERSION = '0.2.0'.freeze
3
+ VERSION = '0.3.0'.freeze
4
4
  end
data/lib/humidifier.rb CHANGED
@@ -11,6 +11,7 @@ require 'humidifier/props'
11
11
 
12
12
  require 'humidifier/aws_shim'
13
13
  require 'humidifier/condition'
14
+ require 'humidifier/configuration'
14
15
  require 'humidifier/loader'
15
16
  require 'humidifier/mapping'
16
17
  require 'humidifier/output'
@@ -25,6 +26,16 @@ require 'humidifier/version'
25
26
  # container module for all gem classes
26
27
  module Humidifier
27
28
  class << self
29
+ # the configuration instance
30
+ def config
31
+ @config ||= Configuration.new
32
+ end
33
+
34
+ # yield the config object to the block for setting user params
35
+ def configure
36
+ yield config
37
+ end
38
+
28
39
  # convenience method for calling cloudformation functions
29
40
  def fn
30
41
  Fn
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: humidifier
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Localytics
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-18 00:00:00.000000000 Z
11
+ date: 2016-07-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '5.0'
47
+ version: '5.9'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '5.0'
54
+ version: '5.9'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: nokogiri
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -157,6 +157,7 @@ files:
157
157
  - lib/humidifier/aws_adapters/sdkv2.rb
158
158
  - lib/humidifier/aws_shim.rb
159
159
  - lib/humidifier/condition.rb
160
+ - lib/humidifier/configuration.rb
160
161
  - lib/humidifier/fn.rb
161
162
  - lib/humidifier/humidifier.bundle
162
163
  - lib/humidifier/loader.rb