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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +88 -0
- data/ext/humidifier/extconf.rb +2 -0
- data/ext/humidifier/humidifier.c +93 -0
- data/ext/humidifier/humidifier.h +14 -0
- data/lib/humidifier/aws_adapters/base.rb +64 -0
- data/lib/humidifier/aws_adapters/noop.rb +18 -0
- data/lib/humidifier/aws_adapters/sdkv1.rb +56 -0
- data/lib/humidifier/aws_adapters/sdkv2.rb +43 -0
- data/lib/humidifier/aws_shim.rb +60 -0
- data/lib/humidifier/condition.rb +17 -0
- data/lib/humidifier/fn.rb +28 -0
- data/lib/humidifier/humidifier.bundle +0 -0
- data/lib/humidifier/loader.rb +53 -0
- data/lib/humidifier/mapping.rb +17 -0
- data/lib/humidifier/output.rb +20 -0
- data/lib/humidifier/parameter.rb +27 -0
- data/lib/humidifier/props.rb +127 -0
- data/lib/humidifier/ref.rb +17 -0
- data/lib/humidifier/resource.rb +108 -0
- data/lib/humidifier/sdk_payload.rb +30 -0
- data/lib/humidifier/serializer.rb +18 -0
- data/lib/humidifier/sleeper.rb +25 -0
- data/lib/humidifier/stack.rb +66 -0
- data/lib/humidifier/utils.rb +21 -0
- data/lib/humidifier/version.rb +4 -0
- data/lib/humidifier.rb +50 -0
- data/specs/ApiGateway-Account.cf +6 -0
- data/specs/ApiGateway-ApiKey.cf +9 -0
- data/specs/ApiGateway-Authorizer.cf +13 -0
- data/specs/ApiGateway-BasePathMapping.cf +9 -0
- data/specs/ApiGateway-ClientCertificate.cf +6 -0
- data/specs/ApiGateway-Deployment.cf +9 -0
- data/specs/ApiGateway-Method.cf +15 -0
- data/specs/ApiGateway-Model.cf +10 -0
- data/specs/ApiGateway-Resource.cf +8 -0
- data/specs/ApiGateway-RestApi.cf +12 -0
- data/specs/ApiGateway-Stage.cf +14 -0
- data/specs/AutoScaling-AutoScalingGroup.cf +21 -0
- data/specs/AutoScaling-LaunchConfiguration.cf +22 -0
- data/specs/AutoScaling-LifecycleHook.cf +12 -0
- data/specs/AutoScaling-ScalingPolicy.cf +14 -0
- data/specs/AutoScaling-ScheduledAction.cf +12 -0
- data/specs/CloudFormation-Authentication.cf +18 -0
- data/specs/CloudFormation-CustomResource.cf +8 -0
- data/specs/CloudFormation-Interface.cf +9 -0
- data/specs/CloudFormation-Stack.cf +10 -0
- data/specs/CloudFormation-WaitCondition.cf +8 -0
- data/specs/CloudFormation-WaitConditionHandle.cf +5 -0
- data/specs/CloudFront-Distribution.cf +6 -0
- data/specs/CloudTrail-Trail.cf +16 -0
- data/specs/CloudWatch-Alarm.cf +20 -0
- data/specs/CodeDeploy-Application.cf +6 -0
- data/specs/CodeDeploy-DeploymentConfig.cf +7 -0
- data/specs/CodeDeploy-DeploymentGroup.cf +13 -0
- data/specs/CodePipeline-CustomActionType.cf +12 -0
- data/specs/CodePipeline-Pipeline.cf +11 -0
- data/specs/Config-ConfigRule.cf +11 -0
- data/specs/Config-ConfigurationRecorder.cf +8 -0
- data/specs/Config-DeliveryChannel.cf +10 -0
- data/specs/DataPipeline-Pipeline.cf +12 -0
- data/specs/DirectoryService-MicrosoftAD.cf +11 -0
- data/specs/DirectoryService-SimpleAD.cf +13 -0
- data/specs/DynamoDB-Table.cf +12 -0
- data/specs/EC2-CustomerGateway.cf +9 -0
- data/specs/EC2-DHCPOptions.cf +11 -0
- data/specs/EC2-EIP.cf +7 -0
- data/specs/EC2-EIPAssociation.cf +10 -0
- data/specs/EC2-FlowLog.cf +10 -0
- data/specs/EC2-Host.cf +8 -0
- data/specs/EC2-Instance.cf +32 -0
- data/specs/EC2-InternetGateway.cf +6 -0
- data/specs/EC2-NatGateway.cf +7 -0
- data/specs/EC2-NetworkAcl.cf +7 -0
- data/specs/EC2-NetworkAclEntry.cf +13 -0
- data/specs/EC2-NetworkInterface.cf +13 -0
- data/specs/EC2-NetworkInterfaceAttachment.cf +9 -0
- data/specs/EC2-PlacementGroup.cf +6 -0
- data/specs/EC2-Route.cf +12 -0
- data/specs/EC2-RouteTable.cf +7 -0
- data/specs/EC2-SecurityGroup.cf +10 -0
- data/specs/EC2-SecurityGroupEgress.cf +11 -0
- data/specs/EC2-SecurityGroupIngress.cf +14 -0
- data/specs/EC2-SpotFleet.cf +6 -0
- data/specs/EC2-Subnet.cf +10 -0
- data/specs/EC2-SubnetNetworkAclAssociation.cf +5 -0
- data/specs/EC2-SubnetRouteTableAssociation.cf +7 -0
- data/specs/EC2-VPC.cf +10 -0
- data/specs/EC2-VPCDHCPOptionsAssociation.cf +7 -0
- data/specs/EC2-VPCEndpoint.cf +9 -0
- data/specs/EC2-VPCGatewayAttachment.cf +8 -0
- data/specs/EC2-VPCPeeringConnection.cf +8 -0
- data/specs/EC2-VPNConnection.cf +10 -0
- data/specs/EC2-VPNConnectionRoute.cf +7 -0
- data/specs/EC2-VPNGateway.cf +7 -0
- data/specs/EC2-VPNGatewayRoutePropagation.cf +7 -0
- data/specs/EC2-Volume.cf +14 -0
- data/specs/EC2-VolumeAttachment.cf +8 -0
- data/specs/ECR-Repository.cf +7 -0
- data/specs/ECS-Cluster.cf +6 -0
- data/specs/ECS-Service.cf +11 -0
- data/specs/ECS-TaskDefinition.cf +7 -0
- data/specs/EFS-FileSystem.cf +6 -0
- data/specs/EFS-MountTarget.cf +9 -0
- data/specs/EMR-Cluster.cf +17 -0
- data/specs/EMR-InstanceGroupConfig.cf +14 -0
- data/specs/EMR-Step.cf +9 -0
- data/specs/ElastiCache-CacheCluster.cf +27 -0
- data/specs/ElastiCache-ParameterGroup.cf +8 -0
- data/specs/ElastiCache-ReplicationGroup.cf +23 -0
- data/specs/ElastiCache-SecurityGroup.cf +7 -0
- data/specs/ElastiCache-SecurityGroupIngress.cf +9 -0
- data/specs/ElastiCache-SubnetGroup.cf +7 -0
- data/specs/ElasticBeanstalk-Application.cf +7 -0
- data/specs/ElasticBeanstalk-ApplicationVersion.cf +8 -0
- data/specs/ElasticBeanstalk-ConfigurationTemplate.cf +11 -0
- data/specs/ElasticBeanstalk-Environment.cf +15 -0
- data/specs/ElasticLoadBalancing-LoadBalancer.cf +21 -0
- data/specs/Elasticsearch-Domain.cf +12 -0
- data/specs/Events-Rule.cf +12 -0
- data/specs/GameLift-Alias.cf +8 -0
- data/specs/GameLift-Build.cf +8 -0
- data/specs/GameLift-Fleet.cf +16 -0
- data/specs/IAM-AccessKey.cf +8 -0
- data/specs/IAM-Group.cf +8 -0
- data/specs/IAM-InstanceProfile.cf +7 -0
- data/specs/IAM-ManagedPolicy.cf +11 -0
- data/specs/IAM-Policy.cf +10 -0
- data/specs/IAM-Role.cf +9 -0
- data/specs/IAM-User.cf +10 -0
- data/specs/IAM-UserToGroupAddition.cf +7 -0
- data/specs/KMS-Key.cf +9 -0
- data/specs/Kinesis-Stream.cf +8 -0
- data/specs/KinesisFirehose-DeliveryStream.cf +9 -0
- data/specs/Lambda-Alias.cf +9 -0
- data/specs/Lambda-EventSourceMapping.cf +10 -0
- data/specs/Lambda-Function.cf +14 -0
- data/specs/Lambda-Permission.cf +10 -0
- data/specs/Lambda-Version.cf +8 -0
- data/specs/Logs-Destination.cf +9 -0
- data/specs/Logs-LogGroup.cf +6 -0
- data/specs/Logs-LogStream.cf +7 -0
- data/specs/Logs-MetricFilter.cf +8 -0
- data/specs/Logs-SubscriptionFilter.cf +9 -0
- data/specs/OpsWorks-App.cf +16 -0
- data/specs/OpsWorks-ElasticLoadBalancerAttachment.cf +7 -0
- data/specs/OpsWorks-Instance.cf +19 -0
- data/specs/OpsWorks-Layer.cf +21 -0
- data/specs/OpsWorks-Stack.cf +23 -0
- data/specs/RDS-DBCluster.cf +23 -0
- data/specs/RDS-DBClusterParameterGroup.cf +9 -0
- data/specs/RDS-DBInstance.cf +38 -0
- data/specs/RDS-DBParameterGroup.cf +9 -0
- data/specs/RDS-DBSecurityGroup.cf +10 -0
- data/specs/RDS-DBSecurityGroupIngress.cf +10 -0
- data/specs/RDS-DBSubnetGroup.cf +8 -0
- data/specs/RDS-EventSubscription.cf +10 -0
- data/specs/RDS-OptionGroup.cf +10 -0
- data/specs/Redshift-Cluster.cf +30 -0
- data/specs/Redshift-ClusterParameterGroup.cf +8 -0
- data/specs/Redshift-ClusterSecurityGroup.cf +6 -0
- data/specs/Redshift-ClusterSecurityGroupIngress.cf +9 -0
- data/specs/Redshift-ClusterSubnetGroup.cf +7 -0
- data/specs/Route53-HealthCheck.cf +7 -0
- data/specs/Route53-HostedZone.cf +9 -0
- data/specs/Route53-RecordSet.cf +19 -0
- data/specs/Route53-RecordSetGroup.cf +9 -0
- data/specs/S3-Bucket.cf +15 -0
- data/specs/S3-BucketPolicy.cf +7 -0
- data/specs/SDB-Domain.cf +6 -0
- data/specs/SNS-Topic.cf +8 -0
- data/specs/SNS-TopicPolicy.cf +8 -0
- data/specs/SQS-Queue.cf +12 -0
- data/specs/SQS-QueuePolicy.cf +7 -0
- data/specs/SSM-Document.cf +6 -0
- data/specs/WAF-ByteMatchSet.cf +7 -0
- data/specs/WAF-IPSet.cf +7 -0
- data/specs/WAF-Rule.cf +8 -0
- data/specs/WAF-SizeConstraintSet.cf +7 -0
- data/specs/WAF-SqlInjectionMatchSet.cf +7 -0
- data/specs/WAF-WebACL.cf +9 -0
- data/specs/WAF-XssMatchSet.cf +7 -0
- data/specs/WorkSpaces-Workspace.cf +11 -0
- 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,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
|
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,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,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,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
|
+
}
|