humidifier 0.7.0 → 1.0.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 +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'
|