humidifier 0.7.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/ext/humidifier/humidifier.c +1 -16
- data/ext/humidifier/humidifier.h +0 -1
- data/lib/humidifier/configuration.rb +2 -0
- data/lib/humidifier/fn.rb +2 -1
- data/lib/humidifier/humidifier.bundle +0 -0
- data/lib/humidifier/loader.rb +42 -19
- data/lib/humidifier/props/base.rb +49 -0
- data/lib/humidifier/props/boolean_prop.rb +21 -0
- data/lib/humidifier/props/double_prop.rb +17 -0
- data/lib/humidifier/props/integer_prop.rb +17 -0
- data/lib/humidifier/props/json_prop.rb +11 -0
- data/lib/humidifier/props/list_prop.rb +20 -0
- data/lib/humidifier/props/map_prop.rb +20 -0
- data/lib/humidifier/props/string_prop.rb +17 -0
- data/lib/humidifier/props/structure_prop.rb +26 -0
- data/lib/humidifier/props/timestamp_prop.rb +17 -0
- data/lib/humidifier/props.rb +13 -126
- data/lib/humidifier/sdk_payload.rb +3 -2
- data/lib/humidifier/serializer.rb +4 -2
- data/lib/humidifier/version.rb +1 -1
- data/lib/humidifier.rb +5 -0
- data/specs/CloudFormationResourceSpecification.json +14332 -0
- data/specs/fixer.rb +360 -0
- metadata +14 -174
- data/specs/ApiGateway-Account.cf +0 -6
- data/specs/ApiGateway-ApiKey.cf +0 -9
- data/specs/ApiGateway-Authorizer.cf +0 -14
- data/specs/ApiGateway-BasePathMapping.cf +0 -9
- data/specs/ApiGateway-ClientCertificate.cf +0 -6
- data/specs/ApiGateway-Deployment.cf +0 -9
- data/specs/ApiGateway-Method.cf +0 -15
- data/specs/ApiGateway-Model.cf +0 -10
- data/specs/ApiGateway-Resource.cf +0 -8
- data/specs/ApiGateway-RestApi.cf +0 -12
- data/specs/ApiGateway-Stage.cf +0 -14
- data/specs/ApiGateway-UsagePlan.cf +0 -10
- data/specs/ApplicationAutoScaling-ScalableTarget.cf +0 -11
- data/specs/ApplicationAutoScaling-ScalingPolicy.cf +0 -12
- data/specs/AutoScaling-AutoScalingGroup.cf +0 -22
- data/specs/AutoScaling-LaunchConfiguration.cf +0 -22
- data/specs/AutoScaling-LifecycleHook.cf +0 -12
- data/specs/AutoScaling-ScalingPolicy.cf +0 -14
- data/specs/AutoScaling-ScheduledAction.cf +0 -12
- data/specs/CertificateManager-Certificate.cf +0 -9
- data/specs/CloudFormation-Authentication.cf +0 -17
- data/specs/CloudFormation-CustomResource.cf +0 -8
- data/specs/CloudFormation-Interface.cf +0 -9
- data/specs/CloudFormation-Stack.cf +0 -10
- data/specs/CloudFormation-WaitCondition.cf +0 -8
- data/specs/CloudFormation-WaitConditionHandle.cf +0 -5
- data/specs/CloudFront-Distribution.cf +0 -6
- data/specs/CloudTrail-Trail.cf +0 -16
- data/specs/CloudWatch-Alarm.cf +0 -20
- data/specs/CodeCommit-Repository.cf +0 -8
- data/specs/CodeDeploy-Application.cf +0 -6
- data/specs/CodeDeploy-DeploymentConfig.cf +0 -7
- data/specs/CodeDeploy-DeploymentGroup.cf +0 -13
- data/specs/CodePipeline-CustomActionType.cf +0 -12
- data/specs/CodePipeline-Pipeline.cf +0 -11
- data/specs/Config-ConfigRule.cf +0 -11
- data/specs/Config-ConfigurationRecorder.cf +0 -8
- data/specs/Config-DeliveryChannel.cf +0 -10
- data/specs/DataPipeline-Pipeline.cf +0 -12
- data/specs/DirectoryService-MicrosoftAD.cf +0 -11
- data/specs/DirectoryService-SimpleAD.cf +0 -13
- data/specs/DynamoDB-Table.cf +0 -12
- data/specs/EC2-CustomerGateway.cf +0 -9
- data/specs/EC2-DHCPOptions.cf +0 -11
- data/specs/EC2-EIP.cf +0 -7
- data/specs/EC2-EIPAssociation.cf +0 -10
- data/specs/EC2-FlowLog.cf +0 -10
- data/specs/EC2-Host.cf +0 -8
- data/specs/EC2-Instance.cf +0 -32
- data/specs/EC2-InternetGateway.cf +0 -6
- data/specs/EC2-NatGateway.cf +0 -7
- data/specs/EC2-NetworkAcl.cf +0 -7
- data/specs/EC2-NetworkAclEntry.cf +0 -13
- data/specs/EC2-NetworkInterface.cf +0 -13
- data/specs/EC2-NetworkInterfaceAttachment.cf +0 -9
- data/specs/EC2-PlacementGroup.cf +0 -6
- data/specs/EC2-Route.cf +0 -12
- data/specs/EC2-RouteTable.cf +0 -7
- data/specs/EC2-SecurityGroup.cf +0 -10
- data/specs/EC2-SecurityGroupEgress.cf +0 -12
- data/specs/EC2-SecurityGroupIngress.cf +0 -14
- data/specs/EC2-SpotFleet.cf +0 -6
- data/specs/EC2-Subnet.cf +0 -10
- data/specs/EC2-SubnetNetworkAclAssociation.cf +0 -5
- data/specs/EC2-SubnetRouteTableAssociation.cf +0 -7
- data/specs/EC2-VPC.cf +0 -10
- data/specs/EC2-VPCDHCPOptionsAssociation.cf +0 -7
- data/specs/EC2-VPCEndpoint.cf +0 -9
- data/specs/EC2-VPCGatewayAttachment.cf +0 -8
- data/specs/EC2-VPCPeeringConnection.cf +0 -8
- data/specs/EC2-VPNConnection.cf +0 -10
- data/specs/EC2-VPNConnectionRoute.cf +0 -7
- data/specs/EC2-VPNGateway.cf +0 -7
- data/specs/EC2-VPNGatewayRoutePropagation.cf +0 -7
- data/specs/EC2-Volume.cf +0 -14
- data/specs/EC2-VolumeAttachment.cf +0 -8
- data/specs/ECR-Repository.cf +0 -7
- data/specs/ECS-Cluster.cf +0 -6
- data/specs/ECS-Service.cf +0 -11
- data/specs/ECS-TaskDefinition.cf +0 -9
- data/specs/EFS-FileSystem.cf +0 -7
- data/specs/EFS-MountTarget.cf +0 -9
- data/specs/EMR-Cluster.cf +0 -17
- data/specs/EMR-InstanceGroupConfig.cf +0 -14
- data/specs/EMR-Step.cf +0 -9
- data/specs/ElastiCache-CacheCluster.cf +0 -27
- data/specs/ElastiCache-ParameterGroup.cf +0 -8
- data/specs/ElastiCache-ReplicationGroup.cf +0 -31
- data/specs/ElastiCache-SecurityGroup.cf +0 -7
- data/specs/ElastiCache-SecurityGroupIngress.cf +0 -9
- data/specs/ElastiCache-SubnetGroup.cf +0 -8
- data/specs/ElasticBeanstalk-Application.cf +0 -7
- data/specs/ElasticBeanstalk-ApplicationVersion.cf +0 -8
- data/specs/ElasticBeanstalk-ConfigurationTemplate.cf +0 -11
- data/specs/ElasticBeanstalk-Environment.cf +0 -15
- data/specs/ElasticLoadBalancing-LoadBalancer.cf +0 -21
- data/specs/ElasticLoadBalancingV2-Listener.cf +0 -11
- data/specs/ElasticLoadBalancingV2-ListenerRule.cf +0 -9
- data/specs/ElasticLoadBalancingV2-LoadBalancer.cf +0 -11
- data/specs/ElasticLoadBalancingV2-TargetGroup.cf +0 -20
- data/specs/Elasticsearch-Domain.cf +0 -13
- data/specs/Events-Rule.cf +0 -12
- data/specs/GameLift-Alias.cf +0 -8
- data/specs/GameLift-Build.cf +0 -8
- data/specs/GameLift-Fleet.cf +0 -16
- data/specs/IAM-AccessKey.cf +0 -8
- data/specs/IAM-Group.cf +0 -9
- data/specs/IAM-InstanceProfile.cf +0 -7
- data/specs/IAM-ManagedPolicy.cf +0 -11
- data/specs/IAM-Policy.cf +0 -10
- data/specs/IAM-Role.cf +0 -10
- data/specs/IAM-User.cf +0 -11
- data/specs/IAM-UserToGroupAddition.cf +0 -7
- data/specs/IoT-Certificate.cf +0 -7
- data/specs/IoT-Policy.cf +0 -7
- data/specs/IoT-PolicyPrincipalAttachment.cf +0 -7
- data/specs/IoT-Thing.cf +0 -7
- data/specs/IoT-ThingPrincipalAttachment.cf +0 -7
- data/specs/IoT-TopicRule.cf +0 -7
- data/specs/KMS-Alias.cf +0 -7
- data/specs/KMS-Key.cf +0 -9
- data/specs/Kinesis-Stream.cf +0 -8
- data/specs/KinesisFirehose-DeliveryStream.cf +0 -9
- data/specs/Lambda-Alias.cf +0 -9
- data/specs/Lambda-EventSourceMapping.cf +0 -10
- data/specs/Lambda-Function.cf +0 -14
- data/specs/Lambda-Permission.cf +0 -10
- data/specs/Lambda-Version.cf +0 -8
- data/specs/Logs-Destination.cf +0 -9
- data/specs/Logs-LogGroup.cf +0 -7
- data/specs/Logs-LogStream.cf +0 -7
- data/specs/Logs-MetricFilter.cf +0 -8
- data/specs/Logs-SubscriptionFilter.cf +0 -9
- data/specs/OpsWorks-App.cf +0 -16
- data/specs/OpsWorks-ElasticLoadBalancerAttachment.cf +0 -7
- data/specs/OpsWorks-Instance.cf +0 -19
- data/specs/OpsWorks-Layer.cf +0 -21
- data/specs/OpsWorks-Stack.cf +0 -23
- data/specs/RDS-DBCluster.cf +0 -23
- data/specs/RDS-DBClusterParameterGroup.cf +0 -9
- data/specs/RDS-DBInstance.cf +0 -42
- data/specs/RDS-DBParameterGroup.cf +0 -9
- data/specs/RDS-DBSecurityGroup.cf +0 -10
- data/specs/RDS-DBSecurityGroupIngress.cf +0 -9
- data/specs/RDS-DBSubnetGroup.cf +0 -8
- data/specs/RDS-EventSubscription.cf +0 -10
- data/specs/RDS-OptionGroup.cf +0 -10
- data/specs/Redshift-Cluster.cf +0 -30
- data/specs/Redshift-ClusterParameterGroup.cf +0 -8
- data/specs/Redshift-ClusterSecurityGroup.cf +0 -6
- data/specs/Redshift-ClusterSecurityGroupIngress.cf +0 -9
- data/specs/Redshift-ClusterSubnetGroup.cf +0 -7
- data/specs/Route53-HealthCheck.cf +0 -7
- data/specs/Route53-HostedZone.cf +0 -9
- data/specs/Route53-RecordSet.cf +0 -19
- data/specs/Route53-RecordSetGroup.cf +0 -9
- data/specs/S3-Bucket.cf +0 -15
- data/specs/S3-BucketPolicy.cf +0 -7
- data/specs/SDB-Domain.cf +0 -6
- data/specs/SNS-Topic.cf +0 -8
- data/specs/SNS-TopicPolicy.cf +0 -8
- data/specs/SQS-Queue.cf +0 -12
- data/specs/SQS-QueuePolicy.cf +0 -7
- data/specs/SSM-Document.cf +0 -6
- data/specs/WAF-ByteMatchSet.cf +0 -7
- data/specs/WAF-IPSet.cf +0 -7
- data/specs/WAF-Rule.cf +0 -8
- data/specs/WAF-SizeConstraintSet.cf +0 -7
- data/specs/WAF-SqlInjectionMatchSet.cf +0 -7
- data/specs/WAF-WebACL.cf +0 -9
- data/specs/WAF-XssMatchSet.cf +0 -7
- data/specs/WorkSpaces-Workspace.cf +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe5b415f92136b9b0615485635bed3a6eaa1216c
|
4
|
+
data.tar.gz: 234763b8d4472cc9d50f3b63b222552e081bb522
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8bffb418bb9316b042ed596a175a7a38f3b4e7cf494a5710a3509113f82b2cf0c02476be8a6673d6ddd301859b41c62201cdc4e021d66335384b8dde9ea02f5
|
7
|
+
data.tar.gz: fcf7020a824041b984bc221b279a806f7c67b93f7e73a14db570f8def9689b720c7ee0312ec8d3716f521c01f20ea04021abe1cc5f43711742829495b3503a44
|
data/README.md
CHANGED
@@ -20,7 +20,7 @@ Stacks are represented by the `Humidifier::Stack` class. You can set any of the
|
|
20
20
|
stack = Humidifier::Stack.new(name: 'Example-Stack', aws_template_format_version: '2010-09-09')
|
21
21
|
|
22
22
|
load_balancer = Humidifier::ElasticLoadBalancing::LoadBalancer.new(
|
23
|
-
listeners: [{
|
23
|
+
listeners: [{ load_balancer_port: 80, protocol: 'http', instance_port: 80, instance_protocol: 'http' }]
|
24
24
|
)
|
25
25
|
load_balancer.scheme = 'internal'
|
26
26
|
|
@@ -92,7 +92,7 @@ The default rake task runs the tests. Coverage is reported on the command line,
|
|
92
92
|
|
93
93
|
### Specs
|
94
94
|
|
95
|
-
The specs pulled from the CFN docs
|
95
|
+
The specs pulled from the CFN docs lives in `specs/CloudFormationResourceSpecification.json`. You can update it by running `bundle exec rake specs`. This script will pull down the latest [resource specification](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-resource-specification.html) to be used with Humidifier.
|
96
96
|
|
97
97
|
### Extension
|
98
98
|
|
data/ext/humidifier/humidifier.c
CHANGED
@@ -1,20 +1,5 @@
|
|
1
1
|
#include <humidifier.h>
|
2
2
|
|
3
|
-
// copies from the source string to the destination string after passing through a character whitelist filter
|
4
|
-
// note that this is exclusively built for AWS::CloudFormation::Interface, so if AWS ever fixes their docs this can
|
5
|
-
// be replaced by strcpy
|
6
|
-
static void filter(char* dest, const char* source)
|
7
|
-
{
|
8
|
-
int source_idx, dest_idx;
|
9
|
-
|
10
|
-
for (source_idx = 0, dest_idx = 0; source[source_idx] != '\0'; source_idx++) {
|
11
|
-
if (source[source_idx] != ':') {
|
12
|
-
dest[dest_idx++] = source[source_idx];
|
13
|
-
}
|
14
|
-
}
|
15
|
-
dest[dest_idx] = '\0';
|
16
|
-
}
|
17
|
-
|
18
3
|
// takes a substring from underscore_preprocess like EC2T or AWST and converts it to Ec2T or AwsT
|
19
4
|
static void format_substring(char* substr, const int substr_idx, const int capitalize)
|
20
5
|
{
|
@@ -64,7 +49,7 @@ static VALUE underscore(VALUE self, VALUE str)
|
|
64
49
|
char *str_value = rb_string_value_cstr(&str);
|
65
50
|
char orig_str[strlen(str_value) + 1];
|
66
51
|
|
67
|
-
|
52
|
+
strcpy(orig_str, str_value);
|
68
53
|
preprocess(orig_str);
|
69
54
|
|
70
55
|
// manually null-terminating the string because on Fedora for strings of length 16 this breaks otherwise
|
data/ext/humidifier/humidifier.h
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
#include <ctype.h>
|
5
5
|
#include <ruby.h>
|
6
6
|
|
7
|
-
static void filter(char* dest, const char* source);
|
8
7
|
static void format_substring(char* substr, const int substr_idx, const int capitalize);
|
9
8
|
static void preprocess(char* str);
|
10
9
|
static VALUE underscore(VALUE self, VALUE str);
|
@@ -3,6 +3,8 @@ module Humidifier
|
|
3
3
|
# a container for user params
|
4
4
|
class Configuration
|
5
5
|
|
6
|
+
# The message that gets displayed when the stack body is too large to use
|
7
|
+
# the template_body option
|
6
8
|
UPLOAD_MESSAGE = <<-MSG.freeze
|
7
9
|
The %{identifier} stack's body is too large to be use the template_body option, and therefore must use the
|
8
10
|
template_url option instead. You can configure Humidifier to do this automatically by setting up the s3 config
|
data/lib/humidifier/fn.rb
CHANGED
@@ -5,7 +5,8 @@ module Humidifier
|
|
5
5
|
|
6
6
|
# The list of all internal functions provided by AWS from
|
7
7
|
# http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html
|
8
|
-
FUNCTIONS = Utils.underscored(%w[And Base64 Equals FindInMap GetAtt GetAZs
|
8
|
+
FUNCTIONS = Utils.underscored(%w[And Base64 Equals FindInMap GetAtt GetAZs
|
9
|
+
If ImportValue Join Not Or Select Sub])
|
9
10
|
|
10
11
|
attr_accessor :name, :value
|
11
12
|
|
Binary file
|
data/lib/humidifier/loader.rb
CHANGED
@@ -6,13 +6,44 @@ module Humidifier
|
|
6
6
|
module Config
|
7
7
|
end
|
8
8
|
|
9
|
-
# Reads
|
9
|
+
# Reads the specs/CloudFormationResourceSpecification.json file and load each resource as a class
|
10
10
|
class Loader
|
11
|
+
# The path to the specification file
|
12
|
+
SPECPATH = File.expand_path(
|
13
|
+
File.join('..', '..', '..', 'specs', 'CloudFormationResourceSpecification.json'),
|
14
|
+
__FILE__
|
15
|
+
)
|
16
|
+
|
17
|
+
# Handles searching the PropertyTypes specifications for a specific resource type
|
18
|
+
class StructureContainer
|
19
|
+
attr_reader :structs
|
20
|
+
|
21
|
+
def initialize(structs)
|
22
|
+
@structs = structs
|
23
|
+
end
|
24
|
+
|
25
|
+
# find the substructures necessary for the given resource key
|
26
|
+
def search(key)
|
27
|
+
results = structs.keys.grep(/#{key}/)
|
28
|
+
Hash[results.map { |result| result.gsub("#{key}.", '') }.zip(structs.values_at(*results))].merge(global)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def global
|
34
|
+
@global ||= structs.select { |key, _| !key.match(/AWS/) }
|
35
|
+
end
|
36
|
+
end
|
11
37
|
|
12
38
|
# loop through the specs and register each class
|
13
39
|
def load
|
14
|
-
|
15
|
-
|
40
|
+
parsed = JSON.parse(File.read(SPECPATH))
|
41
|
+
structs = StructureContainer.new(parsed['PropertyTypes'])
|
42
|
+
|
43
|
+
parsed['ResourceTypes'].each do |key, spec|
|
44
|
+
match = key.match(/\AAWS::(\w+)::(\w+)\z/)
|
45
|
+
register(match[1], match[2], spec, structs.search(key))
|
46
|
+
end
|
16
47
|
end
|
17
48
|
|
18
49
|
# convenience class method to build a new loader and call load
|
@@ -22,28 +53,20 @@ module Humidifier
|
|
22
53
|
|
23
54
|
private
|
24
55
|
|
25
|
-
def build_class(aws_name, spec)
|
56
|
+
def build_class(aws_name, spec, substructs)
|
26
57
|
Class.new(Resource) do
|
27
58
|
self.aws_name = aws_name
|
28
|
-
self.props =
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
def load_from(filepath)
|
36
|
-
group, resource = Pathname.new(filepath).basename('.cf').to_s.split('-')
|
37
|
-
spec = File.readlines(filepath).select do |line|
|
38
|
-
# flipflop operator (http://stackoverflow.com/questions/14456634)
|
39
|
-
true if line.include?('Properties')...(line.strip == '}')
|
59
|
+
self.props =
|
60
|
+
Utils.enumerable_to_h(spec['Properties']) do |(key, config)|
|
61
|
+
prop = Props.from(key, config, substructs)
|
62
|
+
[prop.name, prop]
|
63
|
+
end
|
40
64
|
end
|
41
|
-
register(group, resource, spec[1..-2])
|
42
65
|
end
|
43
66
|
|
44
|
-
def register(group, resource, spec)
|
67
|
+
def register(group, resource, spec, substructs)
|
45
68
|
aws_name = "AWS::#{group}::#{resource}"
|
46
|
-
resource_class = build_class(aws_name, spec)
|
69
|
+
resource_class = build_class(aws_name, spec, substructs)
|
47
70
|
|
48
71
|
Humidifier.const_set(group, Module.new) unless Humidifier.const_defined?(group)
|
49
72
|
Humidifier.const_get(group).const_set(resource, resource_class)
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Humidifier
|
2
|
+
module Props
|
3
|
+
# Superclass for all CFN properties
|
4
|
+
class Base
|
5
|
+
|
6
|
+
# The list of classes that are valid beyond the normal values for each prop
|
7
|
+
WHITELIST = [Fn, Ref].freeze
|
8
|
+
|
9
|
+
attr_reader :key, :name, :spec, :substructs
|
10
|
+
|
11
|
+
def initialize(key, spec = {}, substructs = {})
|
12
|
+
@key = key
|
13
|
+
@name = Utils.underscore(key)
|
14
|
+
@spec = spec
|
15
|
+
after_initialize(substructs) if respond_to?(:after_initialize, true)
|
16
|
+
end
|
17
|
+
|
18
|
+
# true if the property type knows how to convert its values
|
19
|
+
def convertable?
|
20
|
+
respond_to?(:convert)
|
21
|
+
end
|
22
|
+
|
23
|
+
# the link to the AWS docs
|
24
|
+
def documentation
|
25
|
+
spec['Documentation']
|
26
|
+
end
|
27
|
+
|
28
|
+
# true if this property is required by the resource
|
29
|
+
def required?
|
30
|
+
spec['Required']
|
31
|
+
end
|
32
|
+
|
33
|
+
# CFN stack syntax
|
34
|
+
def to_cf(value)
|
35
|
+
[key, Serializer.dump(value)]
|
36
|
+
end
|
37
|
+
|
38
|
+
# the type of update that occurs when this property is updated on its associated resource
|
39
|
+
def update_type
|
40
|
+
spec['UpdateType']
|
41
|
+
end
|
42
|
+
|
43
|
+
# true if the given value is of a type contained in the whitelist
|
44
|
+
def whitelisted_value?(value)
|
45
|
+
WHITELIST.any? { |clazz| value.is_a?(clazz) }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Humidifier
|
2
|
+
module Props
|
3
|
+
# A boolean property
|
4
|
+
class BooleanProp < Base
|
5
|
+
# converts through value == 'true'
|
6
|
+
def convert(value)
|
7
|
+
if %w[true false].include?(value)
|
8
|
+
puts "WARNING: Property #{name} should be a boolean, not a string"
|
9
|
+
value == 'true'
|
10
|
+
else
|
11
|
+
value
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# true if it is a boolean
|
16
|
+
def valid?(value)
|
17
|
+
value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Humidifier
|
2
|
+
module Props
|
3
|
+
# A double property
|
4
|
+
class DoubleProp < Base
|
5
|
+
# converts the value through #to_f unless it is whitelisted
|
6
|
+
def convert(value)
|
7
|
+
puts "WARNING: Property #{name} should be a double" unless valid?(value)
|
8
|
+
value.to_f
|
9
|
+
end
|
10
|
+
|
11
|
+
# true if it is whitelisted, an Integer, or a Float
|
12
|
+
def valid?(value)
|
13
|
+
whitelisted_value?(value) || value.is_a?(Integer) || value.is_a?(Float)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Humidifier
|
2
|
+
module Props
|
3
|
+
# An integer property
|
4
|
+
class IntegerProp < Base
|
5
|
+
# converts the value through #to_i unless it is whitelisted
|
6
|
+
def convert(value)
|
7
|
+
puts "WARNING: Property #{name} should be an integer" unless valid?(value)
|
8
|
+
value.to_i
|
9
|
+
end
|
10
|
+
|
11
|
+
# true if it is whitelisted or a Integer
|
12
|
+
def valid?(value)
|
13
|
+
whitelisted_value?(value) || value.is_a?(Integer)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Humidifier
|
2
|
+
module Props
|
3
|
+
# A property that is contained in a list
|
4
|
+
class ListProp < Base
|
5
|
+
attr_reader :subprop
|
6
|
+
|
7
|
+
# Valid if the value is whitelisted or every value in the list is valid on the subprop
|
8
|
+
def valid?(list)
|
9
|
+
whitelisted_value?(list) || (list.is_a?(Enumerable) && list.all? { |value| subprop.valid?(value) })
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
# Finds the subprop that's specified in the spec
|
15
|
+
def after_initialize(substructs)
|
16
|
+
@subprop = Props.singular_from(key, spec, substructs)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Humidifier
|
2
|
+
module Props
|
3
|
+
# A property that is contained in a Map
|
4
|
+
class MapProp < Base
|
5
|
+
attr_reader :subprop
|
6
|
+
|
7
|
+
# Valid if the value is whitelisted or every value in the map is valid on the subprop
|
8
|
+
def valid?(map)
|
9
|
+
whitelisted_value?(map) || (map.is_a?(Hash) && map.values.all? { |value| subprop.valid?(value) })
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
# Finds the subprop that's specified in the spec
|
15
|
+
def after_initialize(substructs)
|
16
|
+
@subprop = Props.singular_from(key, spec, substructs)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Humidifier
|
2
|
+
module Props
|
3
|
+
# A string property
|
4
|
+
class StringProp < Base
|
5
|
+
# converts the value through #to_s unless it is whitelisted
|
6
|
+
def convert(value)
|
7
|
+
puts "WARNING: Property #{name} should be a string" unless valid?(value)
|
8
|
+
whitelisted_value?(value) ? value : value.to_s
|
9
|
+
end
|
10
|
+
|
11
|
+
# true if it is whitelisted or a String
|
12
|
+
def valid?(value)
|
13
|
+
whitelisted_value?(value) || value.is_a?(String)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Humidifier
|
2
|
+
module Props
|
3
|
+
# A structure property that references a structure from the specification
|
4
|
+
class StructureProp < Base
|
5
|
+
attr_reader :subprops
|
6
|
+
|
7
|
+
# true if the value is whitelisted or Hash and all keys are valid for their corresponding props
|
8
|
+
def valid?(struct)
|
9
|
+
whitelisted_value?(struct) ||
|
10
|
+
(struct.is_a?(Hash) &&
|
11
|
+
struct.all? { |key, value| subprops.key?(key.to_s) && subprops[key.to_s].valid?(value) })
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def after_initialize(substructs)
|
17
|
+
type = spec['ItemType'] || spec['Type']
|
18
|
+
@subprops =
|
19
|
+
Utils.enumerable_to_h(substructs[type]['Properties']) do |(key, config)|
|
20
|
+
subprop = config['ItemType'] == type ? self : Props.from(nil, config, substructs)
|
21
|
+
[Utils.underscore(key), subprop]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Humidifier
|
2
|
+
module Props
|
3
|
+
# A timestamp (ISO 8601) property
|
4
|
+
class TimestampProp < Base
|
5
|
+
# converts the value through #to_s unless it is whitelisted
|
6
|
+
def convert(value)
|
7
|
+
puts "WARNING: Property #{name} should be a Date or Time" unless valid?(value)
|
8
|
+
valid?(value) ? value : DateTime.parse(value)
|
9
|
+
end
|
10
|
+
|
11
|
+
# true if it is whitelisted, a Time, or a Date
|
12
|
+
def valid?(value)
|
13
|
+
whitelisted_value?(value) || value.is_a?(Time) || value.is_a?(Date)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/humidifier/props.rb
CHANGED
@@ -2,139 +2,26 @@ module Humidifier
|
|
2
2
|
|
3
3
|
# Container for property of CFN resources
|
4
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 Integer
|
81
|
-
def valid?(value)
|
82
|
-
whitelisted_value?(value) || value.is_a?(Integer)
|
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
|
-
# An number property
|
101
|
-
class NumberProp < Base
|
102
|
-
# converts the value through #to_i unless it is whitelisted
|
103
|
-
def convert(value)
|
104
|
-
puts "WARNING: Property #{name} should be a number" unless valid?(value)
|
105
|
-
value.to_i
|
106
|
-
end
|
107
|
-
|
108
|
-
# true if it is whitelisted or a Integer
|
109
|
-
def valid?(value)
|
110
|
-
whitelisted_value?(value) || value.is_a?(Integer)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
5
|
class << self
|
115
6
|
# builds the appropriate prop object from the given spec line
|
116
|
-
def from(
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
when 'Integer' then IntegerProp.new(key)
|
122
|
-
when 'String' then StringProp.new(key)
|
123
|
-
when 'Number' then NumberProp.new(key)
|
124
|
-
when /\[.*?\]/ then ArrayProp.new(key)
|
125
|
-
else JSONProp.new(key)
|
7
|
+
def from(key, spec, substructs = {})
|
8
|
+
case spec['Type']
|
9
|
+
when 'List' then ListProp.new(key, spec, substructs)
|
10
|
+
when 'Map' then MapProp.new(key, spec, substructs)
|
11
|
+
else singular_from(key, spec, substructs)
|
126
12
|
end
|
127
13
|
end
|
128
14
|
|
129
|
-
#
|
130
|
-
|
131
|
-
|
15
|
+
# builds a prop that is not a List or Map type
|
16
|
+
# PrimitiveType is one of Boolean, Double, Integer, Json, String, or Timestamp
|
17
|
+
def singular_from(key, spec, substructs)
|
18
|
+
primitive = spec['PrimitiveItemType'] || spec['PrimitiveType']
|
132
19
|
|
133
|
-
if
|
134
|
-
|
135
|
-
|
20
|
+
if primitive
|
21
|
+
primitive = 'Integer' if primitive == 'Long'
|
22
|
+
const_get(:"#{primitive}Prop").new(key, spec)
|
136
23
|
else
|
137
|
-
|
24
|
+
StructureProp.new(key, spec, substructs)
|
138
25
|
end
|
139
26
|
end
|
140
27
|
end
|
@@ -82,9 +82,10 @@ MSG
|
|
82
82
|
|
83
83
|
def template_param
|
84
84
|
@template_param ||= begin
|
85
|
-
|
85
|
+
bytesize = template_body.bytesize
|
86
|
+
raise TemplateTooLargeError, bytesize if bytesize > MAX_TEMPLATE_URL_SIZE
|
86
87
|
|
87
|
-
if
|
88
|
+
if bytesize > MAX_TEMPLATE_BODY_SIZE
|
88
89
|
{ template_url: AwsShim.upload(self) }
|
89
90
|
else
|
90
91
|
{ template_body: template_body }
|
@@ -7,9 +7,11 @@ module Humidifier
|
|
7
7
|
# dumps the given object out to CFN syntax recursively
|
8
8
|
def dump(node)
|
9
9
|
case node
|
10
|
-
when Hash
|
11
|
-
when Array
|
10
|
+
when Hash then Utils.enumerable_to_h(node) { |(key, value)| [key, dump(value)] }
|
11
|
+
when Array then node.map { |value| dump(value) }
|
12
12
|
when Ref, Fn then dump(node.to_cf)
|
13
|
+
when Date then node.iso8601
|
14
|
+
when Time then node.to_datetime.iso8601
|
13
15
|
else node
|
14
16
|
end
|
15
17
|
end
|
data/lib/humidifier/version.rb
CHANGED
data/lib/humidifier.rb
CHANGED
@@ -10,6 +10,11 @@ require 'humidifier/fn'
|
|
10
10
|
require 'humidifier/ref'
|
11
11
|
require 'humidifier/props'
|
12
12
|
|
13
|
+
require 'humidifier/props/base'
|
14
|
+
%w[boolean double integer json list map string structure timestamp].each do |type|
|
15
|
+
require "humidifier/props/#{type}_prop"
|
16
|
+
end
|
17
|
+
|
13
18
|
require 'humidifier/aws_shim'
|
14
19
|
require 'humidifier/condition'
|
15
20
|
require 'humidifier/configuration'
|