humidifier 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +88 -0
  4. data/ext/humidifier/extconf.rb +2 -0
  5. data/ext/humidifier/humidifier.c +93 -0
  6. data/ext/humidifier/humidifier.h +14 -0
  7. data/lib/humidifier/aws_adapters/base.rb +64 -0
  8. data/lib/humidifier/aws_adapters/noop.rb +18 -0
  9. data/lib/humidifier/aws_adapters/sdkv1.rb +56 -0
  10. data/lib/humidifier/aws_adapters/sdkv2.rb +43 -0
  11. data/lib/humidifier/aws_shim.rb +60 -0
  12. data/lib/humidifier/condition.rb +17 -0
  13. data/lib/humidifier/fn.rb +28 -0
  14. data/lib/humidifier/humidifier.bundle +0 -0
  15. data/lib/humidifier/loader.rb +53 -0
  16. data/lib/humidifier/mapping.rb +17 -0
  17. data/lib/humidifier/output.rb +20 -0
  18. data/lib/humidifier/parameter.rb +27 -0
  19. data/lib/humidifier/props.rb +127 -0
  20. data/lib/humidifier/ref.rb +17 -0
  21. data/lib/humidifier/resource.rb +108 -0
  22. data/lib/humidifier/sdk_payload.rb +30 -0
  23. data/lib/humidifier/serializer.rb +18 -0
  24. data/lib/humidifier/sleeper.rb +25 -0
  25. data/lib/humidifier/stack.rb +66 -0
  26. data/lib/humidifier/utils.rb +21 -0
  27. data/lib/humidifier/version.rb +4 -0
  28. data/lib/humidifier.rb +50 -0
  29. data/specs/ApiGateway-Account.cf +6 -0
  30. data/specs/ApiGateway-ApiKey.cf +9 -0
  31. data/specs/ApiGateway-Authorizer.cf +13 -0
  32. data/specs/ApiGateway-BasePathMapping.cf +9 -0
  33. data/specs/ApiGateway-ClientCertificate.cf +6 -0
  34. data/specs/ApiGateway-Deployment.cf +9 -0
  35. data/specs/ApiGateway-Method.cf +15 -0
  36. data/specs/ApiGateway-Model.cf +10 -0
  37. data/specs/ApiGateway-Resource.cf +8 -0
  38. data/specs/ApiGateway-RestApi.cf +12 -0
  39. data/specs/ApiGateway-Stage.cf +14 -0
  40. data/specs/AutoScaling-AutoScalingGroup.cf +21 -0
  41. data/specs/AutoScaling-LaunchConfiguration.cf +22 -0
  42. data/specs/AutoScaling-LifecycleHook.cf +12 -0
  43. data/specs/AutoScaling-ScalingPolicy.cf +14 -0
  44. data/specs/AutoScaling-ScheduledAction.cf +12 -0
  45. data/specs/CloudFormation-Authentication.cf +18 -0
  46. data/specs/CloudFormation-CustomResource.cf +8 -0
  47. data/specs/CloudFormation-Interface.cf +9 -0
  48. data/specs/CloudFormation-Stack.cf +10 -0
  49. data/specs/CloudFormation-WaitCondition.cf +8 -0
  50. data/specs/CloudFormation-WaitConditionHandle.cf +5 -0
  51. data/specs/CloudFront-Distribution.cf +6 -0
  52. data/specs/CloudTrail-Trail.cf +16 -0
  53. data/specs/CloudWatch-Alarm.cf +20 -0
  54. data/specs/CodeDeploy-Application.cf +6 -0
  55. data/specs/CodeDeploy-DeploymentConfig.cf +7 -0
  56. data/specs/CodeDeploy-DeploymentGroup.cf +13 -0
  57. data/specs/CodePipeline-CustomActionType.cf +12 -0
  58. data/specs/CodePipeline-Pipeline.cf +11 -0
  59. data/specs/Config-ConfigRule.cf +11 -0
  60. data/specs/Config-ConfigurationRecorder.cf +8 -0
  61. data/specs/Config-DeliveryChannel.cf +10 -0
  62. data/specs/DataPipeline-Pipeline.cf +12 -0
  63. data/specs/DirectoryService-MicrosoftAD.cf +11 -0
  64. data/specs/DirectoryService-SimpleAD.cf +13 -0
  65. data/specs/DynamoDB-Table.cf +12 -0
  66. data/specs/EC2-CustomerGateway.cf +9 -0
  67. data/specs/EC2-DHCPOptions.cf +11 -0
  68. data/specs/EC2-EIP.cf +7 -0
  69. data/specs/EC2-EIPAssociation.cf +10 -0
  70. data/specs/EC2-FlowLog.cf +10 -0
  71. data/specs/EC2-Host.cf +8 -0
  72. data/specs/EC2-Instance.cf +32 -0
  73. data/specs/EC2-InternetGateway.cf +6 -0
  74. data/specs/EC2-NatGateway.cf +7 -0
  75. data/specs/EC2-NetworkAcl.cf +7 -0
  76. data/specs/EC2-NetworkAclEntry.cf +13 -0
  77. data/specs/EC2-NetworkInterface.cf +13 -0
  78. data/specs/EC2-NetworkInterfaceAttachment.cf +9 -0
  79. data/specs/EC2-PlacementGroup.cf +6 -0
  80. data/specs/EC2-Route.cf +12 -0
  81. data/specs/EC2-RouteTable.cf +7 -0
  82. data/specs/EC2-SecurityGroup.cf +10 -0
  83. data/specs/EC2-SecurityGroupEgress.cf +11 -0
  84. data/specs/EC2-SecurityGroupIngress.cf +14 -0
  85. data/specs/EC2-SpotFleet.cf +6 -0
  86. data/specs/EC2-Subnet.cf +10 -0
  87. data/specs/EC2-SubnetNetworkAclAssociation.cf +5 -0
  88. data/specs/EC2-SubnetRouteTableAssociation.cf +7 -0
  89. data/specs/EC2-VPC.cf +10 -0
  90. data/specs/EC2-VPCDHCPOptionsAssociation.cf +7 -0
  91. data/specs/EC2-VPCEndpoint.cf +9 -0
  92. data/specs/EC2-VPCGatewayAttachment.cf +8 -0
  93. data/specs/EC2-VPCPeeringConnection.cf +8 -0
  94. data/specs/EC2-VPNConnection.cf +10 -0
  95. data/specs/EC2-VPNConnectionRoute.cf +7 -0
  96. data/specs/EC2-VPNGateway.cf +7 -0
  97. data/specs/EC2-VPNGatewayRoutePropagation.cf +7 -0
  98. data/specs/EC2-Volume.cf +14 -0
  99. data/specs/EC2-VolumeAttachment.cf +8 -0
  100. data/specs/ECR-Repository.cf +7 -0
  101. data/specs/ECS-Cluster.cf +6 -0
  102. data/specs/ECS-Service.cf +11 -0
  103. data/specs/ECS-TaskDefinition.cf +7 -0
  104. data/specs/EFS-FileSystem.cf +6 -0
  105. data/specs/EFS-MountTarget.cf +9 -0
  106. data/specs/EMR-Cluster.cf +17 -0
  107. data/specs/EMR-InstanceGroupConfig.cf +14 -0
  108. data/specs/EMR-Step.cf +9 -0
  109. data/specs/ElastiCache-CacheCluster.cf +27 -0
  110. data/specs/ElastiCache-ParameterGroup.cf +8 -0
  111. data/specs/ElastiCache-ReplicationGroup.cf +23 -0
  112. data/specs/ElastiCache-SecurityGroup.cf +7 -0
  113. data/specs/ElastiCache-SecurityGroupIngress.cf +9 -0
  114. data/specs/ElastiCache-SubnetGroup.cf +7 -0
  115. data/specs/ElasticBeanstalk-Application.cf +7 -0
  116. data/specs/ElasticBeanstalk-ApplicationVersion.cf +8 -0
  117. data/specs/ElasticBeanstalk-ConfigurationTemplate.cf +11 -0
  118. data/specs/ElasticBeanstalk-Environment.cf +15 -0
  119. data/specs/ElasticLoadBalancing-LoadBalancer.cf +21 -0
  120. data/specs/Elasticsearch-Domain.cf +12 -0
  121. data/specs/Events-Rule.cf +12 -0
  122. data/specs/GameLift-Alias.cf +8 -0
  123. data/specs/GameLift-Build.cf +8 -0
  124. data/specs/GameLift-Fleet.cf +16 -0
  125. data/specs/IAM-AccessKey.cf +8 -0
  126. data/specs/IAM-Group.cf +8 -0
  127. data/specs/IAM-InstanceProfile.cf +7 -0
  128. data/specs/IAM-ManagedPolicy.cf +11 -0
  129. data/specs/IAM-Policy.cf +10 -0
  130. data/specs/IAM-Role.cf +9 -0
  131. data/specs/IAM-User.cf +10 -0
  132. data/specs/IAM-UserToGroupAddition.cf +7 -0
  133. data/specs/KMS-Key.cf +9 -0
  134. data/specs/Kinesis-Stream.cf +8 -0
  135. data/specs/KinesisFirehose-DeliveryStream.cf +9 -0
  136. data/specs/Lambda-Alias.cf +9 -0
  137. data/specs/Lambda-EventSourceMapping.cf +10 -0
  138. data/specs/Lambda-Function.cf +14 -0
  139. data/specs/Lambda-Permission.cf +10 -0
  140. data/specs/Lambda-Version.cf +8 -0
  141. data/specs/Logs-Destination.cf +9 -0
  142. data/specs/Logs-LogGroup.cf +6 -0
  143. data/specs/Logs-LogStream.cf +7 -0
  144. data/specs/Logs-MetricFilter.cf +8 -0
  145. data/specs/Logs-SubscriptionFilter.cf +9 -0
  146. data/specs/OpsWorks-App.cf +16 -0
  147. data/specs/OpsWorks-ElasticLoadBalancerAttachment.cf +7 -0
  148. data/specs/OpsWorks-Instance.cf +19 -0
  149. data/specs/OpsWorks-Layer.cf +21 -0
  150. data/specs/OpsWorks-Stack.cf +23 -0
  151. data/specs/RDS-DBCluster.cf +23 -0
  152. data/specs/RDS-DBClusterParameterGroup.cf +9 -0
  153. data/specs/RDS-DBInstance.cf +38 -0
  154. data/specs/RDS-DBParameterGroup.cf +9 -0
  155. data/specs/RDS-DBSecurityGroup.cf +10 -0
  156. data/specs/RDS-DBSecurityGroupIngress.cf +10 -0
  157. data/specs/RDS-DBSubnetGroup.cf +8 -0
  158. data/specs/RDS-EventSubscription.cf +10 -0
  159. data/specs/RDS-OptionGroup.cf +10 -0
  160. data/specs/Redshift-Cluster.cf +30 -0
  161. data/specs/Redshift-ClusterParameterGroup.cf +8 -0
  162. data/specs/Redshift-ClusterSecurityGroup.cf +6 -0
  163. data/specs/Redshift-ClusterSecurityGroupIngress.cf +9 -0
  164. data/specs/Redshift-ClusterSubnetGroup.cf +7 -0
  165. data/specs/Route53-HealthCheck.cf +7 -0
  166. data/specs/Route53-HostedZone.cf +9 -0
  167. data/specs/Route53-RecordSet.cf +19 -0
  168. data/specs/Route53-RecordSetGroup.cf +9 -0
  169. data/specs/S3-Bucket.cf +15 -0
  170. data/specs/S3-BucketPolicy.cf +7 -0
  171. data/specs/SDB-Domain.cf +6 -0
  172. data/specs/SNS-Topic.cf +8 -0
  173. data/specs/SNS-TopicPolicy.cf +8 -0
  174. data/specs/SQS-Queue.cf +12 -0
  175. data/specs/SQS-QueuePolicy.cf +7 -0
  176. data/specs/SSM-Document.cf +6 -0
  177. data/specs/WAF-ByteMatchSet.cf +7 -0
  178. data/specs/WAF-IPSet.cf +7 -0
  179. data/specs/WAF-Rule.cf +8 -0
  180. data/specs/WAF-SizeConstraintSet.cf +7 -0
  181. data/specs/WAF-SqlInjectionMatchSet.cf +7 -0
  182. data/specs/WAF-WebACL.cf +9 -0
  183. data/specs/WAF-XssMatchSet.cf +7 -0
  184. data/specs/WorkSpaces-Workspace.cf +11 -0
  185. metadata +356 -0
@@ -0,0 +1,127 @@
1
+ module Humidifier
2
+
3
+ # Container for property of CFN resources
4
+ module Props
5
+
6
+ # Superclass for all CFN properties
7
+ class Base
8
+
9
+ # The list of classes that are valid beyond the normal values for each prop
10
+ WHITELIST = [Fn, Ref].freeze
11
+
12
+ attr_accessor :key
13
+ attr_reader :value
14
+
15
+ def initialize(key = nil)
16
+ self.key = key
17
+ end
18
+
19
+ # true if the property type knows how to convert its values
20
+ def convertable?
21
+ respond_to?(:convert)
22
+ end
23
+
24
+ # the name of the property
25
+ def name
26
+ @name ||= Utils.underscore(key)
27
+ end
28
+
29
+ # CFN stack syntax
30
+ def to_cf(value)
31
+ [key, Serializer.dump(value)]
32
+ end
33
+
34
+ # true if the given value is of a type contained in the whitelist
35
+ def whitelisted_value?(value)
36
+ WHITELIST.any? { |clazz| value.is_a?(clazz) }
37
+ end
38
+ end
39
+
40
+ # An array property
41
+ class ArrayProp < Base
42
+ def valid?(value)
43
+ value.is_a?(Array)
44
+ end
45
+ end
46
+
47
+ # A boolean property
48
+ class BooleanProp < Base
49
+ # converts through value == 'true'
50
+ def convert(value)
51
+ if %w[true false].include?(value)
52
+ puts "WARNING: Property #{name} should be a boolean, not a string"
53
+ value == 'true'
54
+ else
55
+ value
56
+ end
57
+ end
58
+
59
+ # true if it is a boolean
60
+ def valid?(value)
61
+ value.is_a?(TrueClass) || value.is_a?(FalseClass)
62
+ end
63
+ end
64
+
65
+ # A JSON property (and the default)
66
+ class JSONProp < Base
67
+ def valid?(value)
68
+ whitelisted_value?(value) || value.is_a?(Hash) || value.is_a?(Array)
69
+ end
70
+ end
71
+
72
+ # An integer property
73
+ class IntegerProp < Base
74
+ # converts the value through #to_i unless it is whitelisted
75
+ def convert(value)
76
+ puts "WARNING: Property #{name} should be an integer" unless valid?(value)
77
+ value.to_i
78
+ end
79
+
80
+ # true if it is whitelisted or a Fixnum
81
+ def valid?(value)
82
+ whitelisted_value?(value) || value.is_a?(Fixnum)
83
+ end
84
+ end
85
+
86
+ # A string property
87
+ class StringProp < Base
88
+ # converts the value through #to_s unless it is whitelisted
89
+ def convert(value)
90
+ puts "WARNING: Property #{name} should be a string" unless valid?(value)
91
+ whitelisted_value?(value) ? value : value.to_s
92
+ end
93
+
94
+ # true if it is whitelisted or a String
95
+ def valid?(value)
96
+ whitelisted_value?(value) || value.is_a?(String)
97
+ end
98
+ end
99
+
100
+ class << self
101
+ # builds the appropriate prop object from the given spec line
102
+ def from(spec_line)
103
+ key, type = parse(spec_line)
104
+
105
+ case type
106
+ when 'Boolean' then BooleanProp.new(key)
107
+ when 'Integer' then IntegerProp.new(key)
108
+ when 'String' then StringProp.new(key)
109
+ when /\[.*?\]/ then ArrayProp.new(key)
110
+ else JSONProp.new(key)
111
+ end
112
+ end
113
+
114
+ # parses a spec line to return a key and type
115
+ def parse(spec_line)
116
+ spec_line.strip!
117
+
118
+ if spec_line.include?(':')
119
+ key, type = spec_line.gsub(/,\z/, '').split(': ').map(&:strip)
120
+ [key[1..-2], type]
121
+ else
122
+ [nil, spec_line]
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,17 @@
1
+ module Humidifier
2
+
3
+ # Builds CFN references
4
+ class Ref
5
+
6
+ attr_accessor :reference
7
+
8
+ def initialize(reference)
9
+ self.reference = reference
10
+ end
11
+
12
+ # Builds CFN syntax
13
+ def to_cf
14
+ { 'Ref' => reference }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,108 @@
1
+ module Humidifier
2
+
3
+ # Superclass for all AWS resources
4
+ class Resource
5
+
6
+ # Attributes that are available to every stack
7
+ COMMON_ATTRIBUTES =
8
+ Utils.underscored(%w[Condition CreationPolicy DeletionPolicy DependsOn Metadata UpdatePolicy])
9
+
10
+ attr_accessor :properties, *COMMON_ATTRIBUTES.values
11
+
12
+ def initialize(properties = {}, raw = false)
13
+ self.properties = {}
14
+ update(properties, raw)
15
+ end
16
+
17
+ # Patches method_missing to include property accessors
18
+ # After the first method call, builds the accessor methods to get a speed boost
19
+ def method_missing(name, *args)
20
+ if !valid_accessor?(name)
21
+ super
22
+ elsif self.class.prop?(name.to_s)
23
+ self.class.build_property_reader(name)
24
+ send(name)
25
+ else
26
+ self.class.build_property_writer(name)
27
+ send(name, args.first)
28
+ end
29
+ end
30
+
31
+ # Patches respond_to_missing? to include property accessors
32
+ def respond_to_missing?(name, *)
33
+ valid_accessor?(name) || super
34
+ end
35
+
36
+ # CFN stack syntax
37
+ def to_cf
38
+ props_cf = Utils.enumerable_to_h(properties) { |(key, value)| self.class.props[key].to_cf(value) }
39
+ { 'Type' => self.class.aws_name, 'Properties' => props_cf }.merge(common_attributes)
40
+ end
41
+
42
+ # Update a set of properties defined by the given properties hash
43
+ def update(properties, raw = false)
44
+ properties.each { |property, value| update_property(property, value, raw) }
45
+ end
46
+
47
+ # Update an individual property on this resource
48
+ def update_property(property, value, raw = false)
49
+ property = property.to_s
50
+ property = validate_property(property, raw)
51
+ value = validate_value(property, value, raw)
52
+ properties[property] = value
53
+ end
54
+
55
+ class << self
56
+ attr_accessor :aws_name, :props
57
+
58
+ # @private builds a cached method for a property reader
59
+ def build_property_reader(name)
60
+ define_method(name) do
61
+ properties[name.to_s]
62
+ end
63
+ end
64
+
65
+ # @private builds a cached method for a property writer
66
+ def build_property_writer(name)
67
+ define_method(name) do |value|
68
+ update_property(name.to_s[0..-2], value)
69
+ end
70
+ end
71
+
72
+ # true if this resource has the given property
73
+ def prop?(prop)
74
+ props.key?(prop)
75
+ end
76
+ end
77
+
78
+ private
79
+
80
+ def common_attributes
81
+ COMMON_ATTRIBUTES.each_with_object({}) do |(name, prop), result|
82
+ value = send(prop)
83
+ result[name] = value if value
84
+ end
85
+ end
86
+
87
+ def valid_accessor?(method)
88
+ (self.class.props.keys & [method.to_s, method.to_s[0..-2]]).any?
89
+ end
90
+
91
+ def validate_property(property, raw)
92
+ property = Utils.underscore(property) if raw
93
+ unless self.class.prop?(property)
94
+ raise ArgumentError, "Attempting to set invalid property for #{self.class.name}: #{property}"
95
+ end
96
+ property
97
+ end
98
+
99
+ def validate_value(property, value, raw)
100
+ prop = self.class.props[property]
101
+ value = prop.convert(value) if raw && prop.convertable?
102
+ unless prop.valid?(value)
103
+ raise ArgumentError, "Invalid value for #{property}: #{value.inspect}"
104
+ end
105
+ value
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,30 @@
1
+ module Humidifier
2
+
3
+ # The payload sent to the shim methods, representing the stack and the options
4
+ class SdkPayload
5
+
6
+ # The maximum amount of time that Humidifier should wait for a stack to complete a CRUD operation
7
+ MAX_WAIT = 180
8
+
9
+ attr_accessor :stack, :options, :max_wait
10
+
11
+ extend Forwardable
12
+ def_delegators :stack, :id=, :identifier, :name, :to_cf
13
+
14
+ def initialize(stack, options)
15
+ self.stack = stack
16
+ self.options = options
17
+ self.max_wait = options.delete(:max_wait) || MAX_WAIT
18
+ end
19
+
20
+ # True if the stack and options are the same as the other (used for testing)
21
+ def ==(other)
22
+ stack == other.stack && options == other.options
23
+ end
24
+
25
+ # Merge in options
26
+ def merge(new_options)
27
+ self.options = new_options.merge(options)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ module Humidifier
2
+
3
+ # Dumps an object to CFN syntax
4
+ class Serializer
5
+
6
+ class << self
7
+ # dumps the given object out to CFN syntax recursively
8
+ def dump(node)
9
+ case node
10
+ when Hash then Utils.enumerable_to_h(node) { |(key, value)| [key, dump(value)] }
11
+ when Array then node.map { |value| dump(value) }
12
+ when Ref, Fn then dump(node.to_cf)
13
+ else node
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ module Humidifier
2
+
3
+ # Manages waiting for stack events for v1 of the SDK
4
+ class Sleeper
5
+
6
+ attr_accessor :attempts
7
+
8
+ # Store attempts and wait for the block to return true
9
+ def initialize(attempts, &block)
10
+ self.attempts = attempts
11
+ hibernate_until(&block)
12
+ end
13
+
14
+ private
15
+
16
+ def hibernate_until(&block)
17
+ raise 'Waited too long, giving up' if attempts.zero?
18
+ return if yield
19
+
20
+ self.attempts -= 1
21
+ sleep 1
22
+ hibernate_until(&block)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,66 @@
1
+ module Humidifier
2
+
3
+ # Represents a CFN stack
4
+ class Stack
5
+
6
+ # Single settings on the stack
7
+ STATIC_RESOURCES = Utils.underscored(%w[AWSTemplateFormatVersion Description Metadata])
8
+
9
+ # Lists of objects linked to the stack
10
+ ENUMERABLE_RESOURCES = Utils.underscored(%w[Conditions Mappings Outputs Parameters Resources])
11
+
12
+ attr_accessor :id, :name, *ENUMERABLE_RESOURCES.values, *STATIC_RESOURCES.values
13
+
14
+ def initialize(opts = {})
15
+ self.name = opts[:name]
16
+ self.id = opts[:id]
17
+
18
+ ENUMERABLE_RESOURCES.values.each { |prop| send(:"#{prop}=", opts.fetch(prop, {})) }
19
+ STATIC_RESOURCES.values.each { |prop| send(:"#{prop}=", opts[prop]) }
20
+ end
21
+
22
+ # Add a resource to the stack
23
+ def add(name, resource)
24
+ resources[name] = resource
25
+ end
26
+
27
+ # The identifier used by the shim to find the stack in CFN, prefers id to name
28
+ def identifier
29
+ id || name
30
+ end
31
+
32
+ # A string representation of the stack that's valid for CFN
33
+ def to_cf
34
+ JSON.pretty_generate(enumerable_resources.merge(static_resources))
35
+ end
36
+
37
+ %i[condition mapping output parameter].each do |resource_type|
38
+ define_method(:"add_#{resource_type}") do |name, opts = {}|
39
+ send(:"#{resource_type}s")[name] = Humidifier.const_get(resource_type.capitalize).new(opts)
40
+ end
41
+ end
42
+
43
+ AwsShim::STACK_METHODS.each do |method|
44
+ define_method(method) { |opts = {}| AwsShim.send(method, SdkPayload.new(self, opts)) }
45
+ end
46
+
47
+ private
48
+
49
+ def enumerable_resources
50
+ ENUMERABLE_RESOURCES.each_with_object({}) do |(name, prop), list|
51
+ resources = send(prop)
52
+ next if resources.empty?
53
+ list[name] = Utils.enumerable_to_h(resources) do |resource_name, resource|
54
+ [resource_name, resource.to_cf]
55
+ end
56
+ end
57
+ end
58
+
59
+ def static_resources
60
+ STATIC_RESOURCES.each_with_object({}) do |(name, prop), list|
61
+ resource = send(prop)
62
+ list[name] = resource if resource
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,21 @@
1
+ module Humidifier
2
+
3
+ # Dumps an object to CFN syntax
4
+ module Utils
5
+
6
+ class << self
7
+ # back-supporting ruby 2.0's lack of Enumerable#to_h
8
+ def enumerable_to_h(enumerable)
9
+ enumerable.each_with_object({}) do |item, result|
10
+ key, value = yield item
11
+ result[key] = value
12
+ end
13
+ end
14
+
15
+ # a frozen hash of the given names mapped to their underscored version
16
+ def underscored(names)
17
+ names.each_with_object({}) { |name, map| map[name] = underscore(name).to_sym }.freeze
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ module Humidifier
2
+ # Gem version
3
+ VERSION = '0.1.0'.freeze
4
+ end
data/lib/humidifier.rb ADDED
@@ -0,0 +1,50 @@
1
+ require 'forwardable'
2
+ require 'json'
3
+ require 'pathname'
4
+
5
+ require 'humidifier/humidifier'
6
+ require 'humidifier/utils'
7
+
8
+ require 'humidifier/fn'
9
+ require 'humidifier/ref'
10
+ require 'humidifier/props'
11
+
12
+ require 'humidifier/aws_shim'
13
+ require 'humidifier/condition'
14
+ require 'humidifier/loader'
15
+ require 'humidifier/mapping'
16
+ require 'humidifier/output'
17
+ require 'humidifier/parameter'
18
+ require 'humidifier/resource'
19
+ require 'humidifier/sdk_payload'
20
+ require 'humidifier/serializer'
21
+ require 'humidifier/sleeper'
22
+ require 'humidifier/stack'
23
+ require 'humidifier/version'
24
+
25
+ # container module for all gem classes
26
+ module Humidifier
27
+ class << self
28
+ # convenience method for calling cloudformation functions
29
+ def fn
30
+ Fn
31
+ end
32
+
33
+ # convenience method for creating references
34
+ def ref(reference)
35
+ Ref.new(reference)
36
+ end
37
+
38
+ # the list of all registered resources
39
+ def registry
40
+ @registry ||= {}
41
+ end
42
+
43
+ # convenience method for finding classes by AWS name
44
+ def [](aws_name)
45
+ registry[aws_name]
46
+ end
47
+ end
48
+ end
49
+
50
+ Humidifier::Loader.load
@@ -0,0 +1,6 @@
1
+ {
2
+ "Type" : "AWS::ApiGateway::Account",
3
+ "Properties" : {
4
+ "CloudWatchRoleArn" : String
5
+ }
6
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "Type" : "AWS::ApiGateway::ApiKey",
3
+ "Properties" : {
4
+ "Description" : String,
5
+ "Enabled" : Boolean,
6
+ "Name" : String,
7
+ "StageKeys" : [ StageKey, ... ]
8
+ }
9
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "Type" : "AWS::ApiGateway::Authorizer",
3
+ "Properties" : {
4
+ "AuthorizerCredentials" : String,
5
+ "AuthorizerResultTtlInSeconds" : Integer,
6
+ "AuthorizerUri" : String,
7
+ "IdentitySource" : String,
8
+ "IdentityValidationExpression" : String,
9
+ "Name" : String,
10
+ "RestApiId" : String,
11
+ "Type" : String
12
+ }
13
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "Type" : "AWS::ApiGateway::BasePathMapping",
3
+ "Properties" : {
4
+ "BasePath" : String,
5
+ "DomainName" : String,
6
+ "RestApiId" : String,
7
+ "Stage" : String
8
+ }
9
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "Type" : "AWS::ApiGateway::ClientCertificate",
3
+ "Properties" : {
4
+ "Description" : String
5
+ }
6
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "Type" : "AWS::ApiGateway::Deployment",
3
+ "Properties" : {
4
+ "Description" : String,
5
+ "RestApiId" : String,
6
+ "StageDescription" : StageDescription,
7
+ "StageName" : String
8
+ }
9
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "Type" : "AWS::ApiGateway::Method",
3
+ "Properties" : {
4
+ "ApiKeyRequired" : Boolean,
5
+ "AuthorizationType" : String,
6
+ "AuthorizerId" : String,
7
+ "HttpMethod" : String,
8
+ "Integration" : Integration,
9
+ "MethodResponses" : [ MethodResponse, ... ],
10
+ "RequestModels" : { String:String, ... },
11
+ "RequestParameters" : { String:Boolean, ... },
12
+ "ResourceId" : String,
13
+ "RestApiId" : String
14
+ }
15
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "Type" : "AWS::ApiGateway::Model",
3
+ "Properties" : {
4
+ "ContentType" : String,
5
+ "Description" : String,
6
+ "Name" : String,
7
+ "RestApiId" : String,
8
+ "Schema" : String
9
+ }
10
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "Type" : "AWS::ApiGateway::Resource",
3
+ "Properties" : {
4
+ "ParentId" : String,
5
+ "PathPart" : String,
6
+ "RestApiId" : String
7
+ }
8
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "Type" : "AWS::ApiGateway::RestApi",
3
+ "Properties" : {
4
+ "Body" : String,
5
+ "BodyS3Location" : S3Location,
6
+ "CloneFrom" : String,
7
+ "Description" : String,
8
+ "FailOnWarnings" : Boolean,
9
+ "Name" : String,
10
+ "Parameters" : [ String, ... ]
11
+ }
12
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "Type" : "AWS::ApiGateway::Stage",
3
+ "Properties" : {
4
+ "CacheClusterEnabled" : Boolean,
5
+ "CacheClusterSize" : String,
6
+ "ClientCertificateId" : String,
7
+ "DeploymentId" : String,
8
+ "Description" : String,
9
+ "MethodSettings" : [ MethodSetting ],
10
+ "RestApiId" : String,
11
+ "StageName" : String,
12
+ "Variables" : { String:String, ... }
13
+ }
14
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "Type" : "AWS::AutoScaling::AutoScalingGroup",
3
+ "Properties" : {
4
+ "AvailabilityZones" : [ String, ... ],
5
+ "Cooldown" : String,
6
+ "DesiredCapacity" : String,
7
+ "HealthCheckGracePeriod" : Integer,
8
+ "HealthCheckType" : String,
9
+ "InstanceId" : String,
10
+ "LaunchConfigurationName" : String,
11
+ "LoadBalancerNames" : [ String, ... ],
12
+ "MaxSize" : String,
13
+ "MetricsCollection" : [ MetricsCollection, ... ]
14
+ "MinSize" : String,
15
+ "NotificationConfigurations" : [ NotificationConfigurations, ... ],
16
+ "PlacementGroup" : String,
17
+ "Tags" : [ Auto Scaling Tag, ..., ],
18
+ "TerminationPolicies" : [ String, ..., ],
19
+ "VPCZoneIdentifier" : [ String, ... ]
20
+ }
21
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "Type" : "AWS::AutoScaling::LaunchConfiguration",
3
+ "Properties" : {
4
+ "AssociatePublicIpAddress" : Boolean,
5
+ "BlockDeviceMappings" : [ BlockDeviceMapping, ... ],
6
+ "ClassicLinkVPCId" : String,
7
+ "ClassicLinkVPCSecurityGroups" : [ String, ... ],
8
+ "EbsOptimized" : Boolean,
9
+ "IamInstanceProfile" : String,
10
+ "ImageId" : String,
11
+ "InstanceId" : String,
12
+ "InstanceMonitoring" : Boolean,
13
+ "InstanceType" : String,
14
+ "KernelId" : String,
15
+ "KeyName" : String,
16
+ "PlacementTenancy" : String,
17
+ "RamDiskId" : String,
18
+ "SecurityGroups" : [ SecurityGroup, ... ],
19
+ "SpotPrice" : String,
20
+ "UserData" : String
21
+ }
22
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "Type" : "AWS::AutoScaling::LifecycleHook",
3
+ "Properties" : {
4
+ "AutoScalingGroupName" : String,
5
+ "DefaultResult" : String,
6
+ "HeartbeatTimeout" : Integer,
7
+ "LifecycleTransition" : String,
8
+ "NotificationMetadata" : String,
9
+ "NotificationTargetARN" : String,
10
+ "RoleARN" : String
11
+ }
12
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "Type" : "AWS::AutoScaling::ScalingPolicy",
3
+ "Properties" : {
4
+ "AdjustmentType" : String,
5
+ "AutoScalingGroupName" : String,
6
+ "Cooldown" : String,
7
+ "EstimatedInstanceWarmup" : Integer,
8
+ "MetricAggregationType" : String,
9
+ "MinAdjustmentMagnitude" : Integer,
10
+ "PolicyType" : String,
11
+ "ScalingAdjustment" : Integer,
12
+ "StepAdjustments" : [ StepAdjustments, ... ]
13
+ }
14
+ }