From d3c369cb1d83c73b2a0b9751a1fa2bdfdffac01c Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Mon, 14 Nov 2016 13:31:00 +0000 Subject: [PATCH 01/72] Add fix for using ec2_launchconfiguration with existing configs but no block_device_mappings (defaults to []) --- lib/puppet/provider/ec2_launchconfiguration/v2.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/puppet/provider/ec2_launchconfiguration/v2.rb b/lib/puppet/provider/ec2_launchconfiguration/v2.rb index edb98143..f84288d8 100644 --- a/lib/puppet/provider/ec2_launchconfiguration/v2.rb +++ b/lib/puppet/provider/ec2_launchconfiguration/v2.rb @@ -62,7 +62,11 @@ def self.config_to_hash(region, config) spot_price: config.spot_price, ebs_optimized: config.ebs_optimized, } - config[:block_device_mappings] = devices unless devices.empty? + if devices.empty? + config[:block_device_mappings] = [ ] + else + config[:block_device_mappings] = devices + end config end From 4b9f200fd8aa68c8a67bf831405abc459f1001f7 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Tue, 13 Dec 2016 21:50:53 +0000 Subject: [PATCH 02/72] initial work adding elbv2 loadbalancer and targetgroup --- README.md | 79 ++++++++++ lib/puppet/provider/elbv2_loadbalancer/v2.rb | 0 lib/puppet/provider/elbv2_targetgroup/v2.rb | 102 +++++++++++++ lib/puppet/type/elbv2_loadbalancer.rb | 132 ++++++++++++++++ lib/puppet/type/elbv2_targetgroup.rb | 152 +++++++++++++++++++ 5 files changed, 465 insertions(+) create mode 100644 lib/puppet/provider/elbv2_loadbalancer/v2.rb create mode 100644 lib/puppet/provider/elbv2_targetgroup/v2.rb create mode 100644 lib/puppet/type/elbv2_loadbalancer.rb create mode 100644 lib/puppet/type/elbv2_targetgroup.rb diff --git a/README.md b/README.md index 7a25ad0c..6e88bab3 100644 --- a/README.md +++ b/README.md @@ -308,6 +308,8 @@ You can use the aws module to audit AWS resources, launch autoscaling groups in * `ec2_securitygroup`: Sets up an EC2 security group. * `ec2_volume`: Sets up an EC2 EBS volume. * `elb_loadbalancer`: Sets up an ELB load balancer. +* `elbv2_loadbalancer`: Sets up an ELBv2 load balancer. +* `elbv2_targetgroup`: Sets up a ELBv2 target group. * `cloudwatch_alarm`: Sets up a Cloudwatch Alarm. * `ec2_autoscalinggroup`: Sets up an EC2 auto scaling group. * `ec2_elastic_ip`: Sets up an Elastic IP and its association. @@ -697,6 +699,83 @@ back- end instances. Accepts a hash with the following keys: ##### `snapshot_id` *Optional* The snapshot from which to create the volume. +#### Type: elbv2_loadbalancer + +#####`name` +*Required* The name of the load balancer. This is the value of the AWS Name tag. + +#####`region` +*Required* The region in which to launch the target group. For valid values, see [AWS Regions](http://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region). + +#####`listeners` + +#####`health_check` + +#####`subnets` + +#####`security_groups` + +#####`scheme` +#####`instancs` +#####`availability_zones` +#####`dns_name` + +#####`tags` +*Optional* The tags for the target group. This parameter is set at creation only; it is not affected by updates. Accepts a 'key => value' hash of tags. + +#### Type: elbv2_targetgroup + +#####`name` +*Required* The name of the target group. This is the value of the AWS Name tag. + +#####`region` +*Required* The region in which to launch the target group. For valid values, see [AWS Regions](http://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region). + +#####`protocol` +*Required* + +#####`port` +*Required* + +#####`vpc` +*Required* + +#####`health_check_success_codes` +*Optional* + +#####`health_check_path` +*Optional* + +#####`health_check_port` +*Optional* + +#####`health_check_protocol` +*Optional* + +#####`health_check_interval` +*Optional* + +#####`health_check_timeout` +*Optional* + +#####`healthy_threshold` +*Optional* + +#####`unhealthy_threshold` +*Optional* + +#####`deregistration_delay` +*Optional* + +#####`stickiness` +*Optional* + +#####`stickiness_duration` +*Optional* + +#####`tags` +*Optional* The tags for the target group. This parameter is set at creation only; it is not affected by updates. Accepts a 'key => value' hash of tags. + #### Type: cloudwatch_alarm ##### `name` diff --git a/lib/puppet/provider/elbv2_loadbalancer/v2.rb b/lib/puppet/provider/elbv2_loadbalancer/v2.rb new file mode 100644 index 00000000..e69de29b diff --git a/lib/puppet/provider/elbv2_targetgroup/v2.rb b/lib/puppet/provider/elbv2_targetgroup/v2.rb new file mode 100644 index 00000000..4f229fed --- /dev/null +++ b/lib/puppet/provider/elbv2_targetgroup/v2.rb @@ -0,0 +1,102 @@ +require_relative '../../../puppet_x/puppetlabs/aws.rb' + +Puppet::Type.type(:elbv2_targetgroup).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do + + confine feature: :aws + + mk_resource_methods + + def self.instances() + Puppet.debug('Fetching ELBv2 Target Groups (instances)') + regions.collect do |region| + Puppet.debug("instances region: #{region}") + target_groups = [] + tgs(region) do |tg| + target_groups << new(target_group_to_hash(region, tg) ) + end + + target_groups + end.flatten + end + + def self.tgs(region) + Puppet.debug('Fetching ELBv2 Target Groups (tgs)') +# regions.collect do |region| + region_client = elbv2_client(region) + + response = region_client.describe_target_groups() + marker = response.next_marker + + response.target_groups.each do |tg| + yield tg + end + + while marker + Puppet.debug("Calling for marked TargetGroup description") + response = region_client.describe_target_groups( { + marker: marker + }) + marker = response.next_marker + response.target_group_descriptions.each do |tg| + yield tg + end + end +# end + end + + def self.target_group_to_hash(region, target_group) + Puppet.debug("target_group_to_hash for #{target_group.target_group_name}") + + attributes = { } + response = elbv2_client(region).describe_target_group_attributes(target_group_arn: target_group.target_group_arn) + response.attributes.collect do |attribute| + attributes[attribute.key] = attribute.value + end + + tag_response = elbv2_client(region).describe_tags( + resource_arns: [ target_group.target_group_arn ] + ) + tags = {} + unless tag_response.tag_descriptions.nil? || tag_response.tag_descriptions.empty? + tag_response.tag_descriptions.first.tags.each do |tag| + tags[tag.key] = tag.value + end + end + + load_balancers = [] + + { + name: target_group.target_group_name, + ensure: :present, + region: region, + vpc: target_group.vpc_id, + protocol: target_group.protocol, + port: target_group.port, + load_balancers: load_balancers, + healthy_threshold: target_group.healthy_threshold_count, + unhealthy_threshold: target_group.unhealthy_threshold_count, + health_check_path: target_group.health_check_path, + health_check_port: target_group.health_check_port, + health_check_protocol: target_group.health_check_protocol, + health_check_interval: target_group.health_check_interval_seconds, + health_check_success_codes: target_group.matcher.http_code, + health_check_timeout: target_group.health_check_timeout_seconds, + deregistration_delay: attributes['deregistration_delay.timeout_seconds'], + stickiness: attributes['stickiness.enabled'], + stickiness_duration: attributes['stickiness.lb_cookie.duration_seconds'], + tags: tags, + } + end + + def exists? + @property_hash[:ensure] == :present + end + + def create + Puppet.info("Creating target group #{name} #{resource[:protocol]} #{resource[:port]} in region #{target_region}") + fail('You must specify the AWS region') unless target_region != :absent + fail('You must specify the Target protocol') if resource[:protocol].nil? + fail('You must specify the Target port') if resource[:port].nil? + + end +end diff --git a/lib/puppet/type/elbv2_loadbalancer.rb b/lib/puppet/type/elbv2_loadbalancer.rb new file mode 100644 index 00000000..2451f33f --- /dev/null +++ b/lib/puppet/type/elbv2_loadbalancer.rb @@ -0,0 +1,132 @@ +require_relative '../../puppet_x/puppetlabs/property/tag.rb' + +Puppet::Type.newtype(:elbv2_loadbalancer) do + @doc = 'Type representing an ELBv2 load balancer.' + + ensurable + + newparam(:name, namevar: true) do + desc 'The name of the load balancer.' + validate do |value| + fail 'Load Balancers must have a name' if value == '' + fail 'name should be a String' unless value.is_a?(String) + end + end + + newproperty(:region) do + desc 'The region in which to launch the load balancer.' + validate do |value| + fail 'region must not contain spaces' if value =~ /\s/ + fail 'region should be a String' unless value.is_a?(String) + end + end + + newproperty(:listeners, :array_matching => :all) do + desc 'The ports and protocols the load balancer listens to.' + def insync?(is) + normalise(is).to_set == normalise(should).to_set + end + def normalise(listeners) + listeners.collect do |obj| + obj.each { |k,v| obj[k] = v.to_s.downcase } + end + end + validate do |value| + value = [value] unless value.is_a?(Array) + fail "you must provide a set of listeners for the load balancer" if value.empty? + value.each do |listener| + ['protocol', 'load_balancer_port', 'instance_protocol', 'instance_port'].each do |key| + fail "listeners must include #{key}" unless listener.keys.include?(key) + end + end + end + end + + newproperty(:health_check) do + desc 'The health check configuration for the load balancer' + def insync?(is) + provider.class.normalize_values(is) == provider.class.normalize_values(should) + end + validate do |value| + ['target', 'interval', 'timeout', 'unhealthy_threshold', 'healthy_threshold'].each do |key| + fail "health_check must include #{key}" unless value.keys.include?(key) + end + end + end + + newproperty(:tags, :parent => PuppetX::Property::AwsTag) do + desc 'The tags for the load balancer.' + end + + newproperty(:subnets, :array_matching => :all) do + desc 'The region in which to launch the load balancer.' + validate do |value| + fail 'subnets should be a String' unless value.is_a?(String) + end + def insync?(is) + is.to_set == should.to_set + end + end + + newproperty(:security_groups, :array_matching => :all) do + desc 'The security groups to associate the load balancer (VPC only).' + validate do |value| + fail 'security_groups should be a String' unless value.is_a?(String) + end + def insync?(is) + is.to_set == should.to_set + end + end + + newproperty(:availability_zones, :array_matching => :all) do + desc 'The availability zones in which to launch the load balancer.' + def insync?(is) + is.to_set == should.to_set + end + end + + newproperty(:instances, :array_matching => :all) do + desc 'The instances to associate with the load balancer.' + validate do |value| + fail 'instances should be a String' unless value.is_a?(String) + end + def insync?(is) + is.to_set == should.to_set + end + end + + newproperty(:scheme) do + desc 'Whether the load balancer is internal or public facing.' + defaultto :'internet-facing' + newvalues(:'internet-facing', :internal) + def insync?(is) + is.to_s == should.to_s + end + end + + newproperty(:dns_name) do + desc 'The DNS name of the load balancer' + end + + validate do + subnets = self[:subnets] || [] + zones = self[:availability_zones] || [] + fail "You can specify either subnets or availability_zones for the ELB #{self[:name]}" if !zones.empty? && !subnets.empty? + end + + autorequire(:ec2_instance) do + instances = self[:instances] + instances.is_a?(Array) ? instances : [instances] + end + + autorequire(:ec2_securitygroup) do + groups = self[:security_groups] + groups.is_a?(Array) ? groups : [groups] + end + + autorequire(:ec2_vpc_subnet) do + subnets = self[:subnets] + subnets.is_a?(Array) ? subnets : [subnets] + end + +end diff --git a/lib/puppet/type/elbv2_targetgroup.rb b/lib/puppet/type/elbv2_targetgroup.rb new file mode 100644 index 00000000..a35d674f --- /dev/null +++ b/lib/puppet/type/elbv2_targetgroup.rb @@ -0,0 +1,152 @@ +require_relative '../../puppet_x/puppetlabs/property/tag.rb' + +Puppet::Type.newtype(:elbv2_targetgroup) do + @doc = 'Type representing an ELBv2 target group.' + + ensurable + + newparam(:name, namevar: true) do + desc 'The name of the target group.' + validate do |value| + fail 'Target Groups must have a name' if value == '' + fail 'name should be a String' unless value.is_a?(String) + end + end + + newproperty(:region) do + desc 'The region in which to launch the load balancer.' + validate do |value| + fail 'region must be specified' unless value + fail 'region must not contain spaces' if value =~ /\s/ + fail 'region should be a String' unless value.is_a?(String) + end + end + + newproperty(:protocol) do + desc 'Protocol to use for routing traffic to targets (HTTP/HTTPS)' + newvalues(:HTTP, :HTTPS) + validate do |value| + file 'protocol must be specified' unless value + fail 'Invalid protocol - must be HTTP or HTTPS' unless value =~ /^HTTPS?$/ + end + end + + newproperty(:port) do + desc 'Port on which the targets receive traffic' + validate do |value| + file 'Target port must be specified' unless value + end + munge do |value| + value.to_i + end + end + +# newproperty(:vpc) do +# desc 'Id of the virtual private cloud (VPC)' +# validate do |value| +# fail 'VPC ID must be specified' unless value +# end +# end + + newproperty(:load_balancers) do + desc 'The load balancer to assign this target group too' + end + + newproperty(:health_check_success_codes) do + desc 'HTTP state codes to use when checking for a successful response from a target' + end + + newproperty(:health_check_path) do + desc 'Path to request when performing health checks' + end + + newproperty(:health_check_port) do + desc 'The port the elb uses when performing health checks' + validate do |value| + fail 'Invalid health check port - must be traffic-port or port number' unless value.downcase =~ /^(traffic-port|[0-9]+)$/ + end + end + + newproperty(:health_check_protocol) do + desc 'The protocol the elb uses when performing health checks on targets (HTTP/HTTPS)' + newvalues(:HTTP, :HTTPS) + validate do |value| + fail 'Invalid health check protocol - must be HTTP or HTTPS' unless value.upcase =~ /^HTTPS?$/ + end + end + + newproperty(:health_check_interval) do + desc 'Approximate time (seconds) between health checks' + validate do |value| + fail 'health_check_interval must be a number' unless value =~ /^[0-9]+$/ + end + munge do |value| + value.to_i + end + end + + newproperty(:health_check_timeout) do + desc 'Amount of time (seconds) during which no response means a failed health check' + validate do |value| + fail 'health_check_timeout must be a number' unless value =~ /^[0-9]+$/ + end + munge do |value| + value.to_i + end + end + + newproperty(:healthy_threshold) do + desc 'Number of consecutive health check successes required before considering an unhealthy target healthy' + validate do |value| + fail 'healthy_threshold must be a number' unless value =~ /^[0-9]+$/ + end + munge do |value| + value.to_i + end + end + + newproperty(:unhealthy_threshold) do + desc 'Number of consecutive health check failures required before considering a healthy target unhealthy' + validate do |value| + fail 'unhealthy_threshold must be a number' unless value =~ /^[0-9]+$/ + end + munge do |value| + value.to_i + end + end + + newproperty(:deregistration_delay) do + desc 'Amount of time (seconds) for elb to wait before changing state of deregistering target from draining to unused (0-3600)' + validate do |value| + fail 'deregistration_delay must be a number' unless value =~ /^[0-9]+$/ + fail 'Invalid deregistration time - must be between 0 and 3600' if value.to_i < 0 or value.to_i > 3600 + end + munge do |value| + value.to_i + end + end + + newproperty(:stickiness, parent: Puppet::Property::Boolean) do + desc 'Indicates whether sticky sessions are enabled' + end + + newproperty(:stickiness_duration) do + desc 'Amount of time (seconds) where requests should be routed to the same target (1-604800)' + validate do |value| + fail 'stickiness_duration must be a number' unless value =~ /^[0-9]+$/ + fail 'Invalid stickiness duration - must be between 1 and 604800' if value.to_i < 1 or value.to_i > 604800 + end + munge do |value| + value.to_i + end + end + + newproperty(:tags, :parent => PuppetX::Property::AwsTag) do + desc 'The tags for the instance.' + end + + autorequire(:ec2_vpc) do + self[:vpc] + end + +end From 6ae92a77ffce6ef4e8651f99d89e8db2b37eff7d Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Wed, 14 Dec 2016 07:40:47 +0000 Subject: [PATCH 03/72] add missing Boolean require --- lib/puppet/type/elbv2_targetgroup.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/puppet/type/elbv2_targetgroup.rb b/lib/puppet/type/elbv2_targetgroup.rb index a35d674f..da3a172e 100644 --- a/lib/puppet/type/elbv2_targetgroup.rb +++ b/lib/puppet/type/elbv2_targetgroup.rb @@ -1,4 +1,5 @@ require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require 'puppet/property/boolean' Puppet::Type.newtype(:elbv2_targetgroup) do @doc = 'Type representing an ELBv2 target group.' From dc5c51960f47c239c640fae85a69a7002d2804dd Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Thu, 22 Dec 2016 23:17:22 +0000 Subject: [PATCH 04/72] add create/delete functionality --- lib/puppet/provider/elbv2_targetgroup/v2.rb | 80 ++++++++++++++++++++- lib/puppet/type/elbv2_targetgroup.rb | 19 +++-- 2 files changed, 90 insertions(+), 9 deletions(-) diff --git a/lib/puppet/provider/elbv2_targetgroup/v2.rb b/lib/puppet/provider/elbv2_targetgroup/v2.rb index 4f229fed..bb195ac4 100644 --- a/lib/puppet/provider/elbv2_targetgroup/v2.rb +++ b/lib/puppet/provider/elbv2_targetgroup/v2.rb @@ -9,16 +9,31 @@ def self.instances() Puppet.debug('Fetching ELBv2 Target Groups (instances)') regions.collect do |region| + vpc_names = {} + vpc_response = ec2_client(region).describe_vpcs() + vpc_response.data.vpcs.each do |vpc| + vpc_name = name_from_tag(vpc) + vpc_names[vpc.vpc_id] = vpc_name if vpc_name + end Puppet.debug("instances region: #{region}") target_groups = [] tgs(region) do |tg| - target_groups << new(target_group_to_hash(region, tg) ) + target_groups << new(target_group_to_hash(region, tg, vpc_names) ) end target_groups end.flatten end + def self.prefetch(resources) + instances.each do |prov| + Puppet.debug("Prefetching #{prov.name}") + if resource = resources[prov.name] # rubocop:disable Lint/AssignmentInCondition + resource.provider = prov if resource[:region] == prov.region + end + end + end + def self.tgs(region) Puppet.debug('Fetching ELBv2 Target Groups (tgs)') # regions.collect do |region| @@ -44,7 +59,7 @@ def self.tgs(region) # end end - def self.target_group_to_hash(region, target_group) + def self.target_group_to_hash(region, target_group, vpcs) Puppet.debug("target_group_to_hash for #{target_group.target_group_name}") attributes = { } @@ -67,9 +82,10 @@ def self.target_group_to_hash(region, target_group) { name: target_group.target_group_name, + arn: target_group.target_group_arn, ensure: :present, region: region, - vpc: target_group.vpc_id, + vpc: vpcs[target_group.vpc_id], protocol: target_group.protocol, port: target_group.port, load_balancers: load_balancers, @@ -92,11 +108,69 @@ def exists? @property_hash[:ensure] == :present end + def health_check_success_codes= + Puppet.info("Updating target group #{name}") + + end + def create Puppet.info("Creating target group #{name} #{resource[:protocol]} #{resource[:port]} in region #{target_region}") fail('You must specify the AWS region') unless target_region != :absent fail('You must specify the Target protocol') if resource[:protocol].nil? fail('You must specify the Target port') if resource[:port].nil? + vpc_name = resource[:vpc] + if vpc_name + Puppet.info("Step3 #{vpc_name}") + vpc_response = ec2_client(target_region).describe_vpcs(filters: [ + {name: 'tag:Name', values: [vpc_name]} + ]) + Puppet.info("Step4") + fail("No VPC found called #{vpc_name}") if vpc_response.data.vpcs.count == 0 + vpc_id = vpc_response.data.vpcs.first.vpc_id + Puppet.info("Step5 #{vpc_id}") + Puppet.warning "Multiple VPCs found called #{vpc_name}, using #{vpc_id}" if vpc_response.data.vpcs.count > 1 + @property_hash[:vpc_id] = vpc_id + @property_hash[:vpc] = vpc_name + end + + config = { + name: resource[:name], + vpc_id: vpc_id, + protocol: resource[:protocol], + port: resource[:port], + } + + config[:health_check_protocol] = resource[:health_check_protocol] unless resource[:health_check_protocol].nil? + config[:health_check_port] = resource[:health_check_port] unless resource[:health_check_port].nil? + config[:health_check_path] = resource[:health_check_path] unless resource[:health_check_path].nil? + config[:health_check_interval_seconds] = resource[:health_check_interval] unless resource[:health_check_interval].nil? + config[:health_check_timeout_seconds] = resource[:health_check_timeout] unless resource[:health_check_timeout].nil? + config[:healthy_threshold_count] = resource[:healthy_threshold] unless resource[:healthy_threshold].nil? + config[:unhealthy_threshold_count] = resource[:unhealthy_threshold] unless resource[:unhealthy_threshold].nil? + config[:matcher] = { http_code: resource[:health_check_success_codes] } unless resource[:health_check_success_codes].nil? + + tg_response = elbv2_client(target_region).create_target_group(config) + Puppet.info("Config: #{tg_response.data}") + + tg_arn = tg_response.data.target_groups.first.target_group_arn + + Puppet.info("TargetGroup Arn: #{tg_arn}") + attrs = {} + attrs['stickiness.enabled'] = resource[:stickiness] unless resource[:stickiness].nil? + attrs['stickiness.lb_cookie.duration_seconds'] = resource[:stickiness_duration] unless resource[:stickiness_duration].nil? + + mtga_response = elbv2_client(target_region).modify_target_group_attributes( { + targetgrouparn: tg_arn, + attributes: attrs, + }) unless attrs.empty? + + end + + def destroy + Puppet.info("Deleting target group #{name} in region #{target_region} #{resources}") + elbv2 = elbv2_client(target_region) + elbv2.delete_target_group(target_group_arn: arn) + @property_hash[:ensure] = :absent end end diff --git a/lib/puppet/type/elbv2_targetgroup.rb b/lib/puppet/type/elbv2_targetgroup.rb index da3a172e..b1647bba 100644 --- a/lib/puppet/type/elbv2_targetgroup.rb +++ b/lib/puppet/type/elbv2_targetgroup.rb @@ -42,12 +42,12 @@ end end -# newproperty(:vpc) do -# desc 'Id of the virtual private cloud (VPC)' -# validate do |value| -# fail 'VPC ID must be specified' unless value -# end -# end + newproperty(:vpc) do + desc 'Id of the virtual private cloud (VPC)' + validate do |value| + fail 'VPC ID must be specified' unless value + end + end newproperty(:load_balancers) do desc 'The load balancer to assign this target group too' @@ -127,6 +127,13 @@ end end + newproperty(:arn) do + desc 'ARN of target group' + validate do |value| + fail 'arn is a readonly property' + end + end + newproperty(:stickiness, parent: Puppet::Property::Boolean) do desc 'Indicates whether sticky sessions are enabled' end From b2800e08171974c61ae2a8cf80805975a65c3785 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Sat, 24 Dec 2016 19:57:39 +0000 Subject: [PATCH 05/72] destroy now working, updating of target group parameters and attributes mostly working Todo :- stickiness - enabled/disabled not updating --- lib/puppet/provider/elbv2_targetgroup/v2.rb | 101 +++++++++++++++++--- lib/puppet/type/elbv2_targetgroup.rb | 6 +- 2 files changed, 94 insertions(+), 13 deletions(-) diff --git a/lib/puppet/provider/elbv2_targetgroup/v2.rb b/lib/puppet/provider/elbv2_targetgroup/v2.rb index bb195ac4..075e920c 100644 --- a/lib/puppet/provider/elbv2_targetgroup/v2.rb +++ b/lib/puppet/provider/elbv2_targetgroup/v2.rb @@ -98,7 +98,7 @@ def self.target_group_to_hash(region, target_group, vpcs) health_check_success_codes: target_group.matcher.http_code, health_check_timeout: target_group.health_check_timeout_seconds, deregistration_delay: attributes['deregistration_delay.timeout_seconds'], - stickiness: attributes['stickiness.enabled'], + stickiness: (attributes['stickiness.enabled'] == true ? :enabled : :disabled), stickiness_duration: attributes['stickiness.lb_cookie.duration_seconds'], tags: tags, } @@ -108,27 +108,103 @@ def exists? @property_hash[:ensure] == :present end - def health_check_success_codes= - Puppet.info("Updating target group #{name}") + def healthy_threshold=(value) + Puppet.debug("Updating target group #{name} healthy_threshold") + elbv2_client(region).modify_target_group( { + target_group_arn: arn, + healthy_threshold_count: value, + }) + end + + def unhealthy_threshold=(value) + Puppet.debug("Updating target group #{name} unhealthy_threshold") + elbv2_client(region).modify_target_group( { + target_group_arn: arn, + unhealthy_threshold_count: value, + }) + end + + def health_check_path=(value) + Puppet.debug("Updating target group #{name} health_check_path") + elbv2_client(region).modify_target_group( { + target_group_arn: arn, + health_check_path: value, + }) + end + + def health_check_port=(value) + Puppet.debug("Updating target group #{name} health_check_port") + elbv2_client(region).modify_target_group( { + target_group_arn: arn, + health_check_port: value, + }) + end + + def health_check_protocol=(value) + Puppet.debug("Updating target group #{name} health_check_protocol") + elbv2_client(region).modify_target_group( { + target_group_arn: arn, + health_check_protocol: value, + }) + end + + def health_check_interval=(value) + Puppet.debug("Updating target group #{name} health_check_interval") + elbv2_client(region).modify_target_group( { + target_group_arn: arn, + health_check_interval_seconds: value, + }) + end + + def health_check_success_codes=(value) + Puppet.debug("Updating target group #{name} #{arn} health_check_success_codes") + elbv2_client(region).modify_target_group( { + target_group_arn: arn, + matcher: { http_code: value }, + }) + end + + def health_check_timeout=(value) + Puppet.debug("Updating target group #{name} health_check_timeout") + elbv2_client(region).modify_target_group( { + target_group_arn: arn, + health_check_timeout_seconds: value, + }) + end + + def stickiness=(value) + Puppet.debug("Updating target group #{name} stickiness to '#{value.to_s}'") + elbv2_client(region).modify_target_group_attributes( { + target_group_arn: arn, + attributes: [ { key: 'stickiness.enabled', + value: ( value == :enabled ? 'true' : 'false' ), } ], + }) + @property_hash[:stickiness] = value + end + def stickiness_duration=(value) + Puppet.debug("Updating target group #{name} stickiness_duration") + elbv2_client(region).modify_target_group_attributes( { + target_group_arn: arn, + attributes: [ { key: 'stickiness.lb_cookie.duration_seconds', + value: value.to_s } ], + }) + @property_hash[:stickiness_duration] = value end def create - Puppet.info("Creating target group #{name} #{resource[:protocol]} #{resource[:port]} in region #{target_region}") + Puppet.debug("Creating target group #{name} #{resource[:protocol]} #{resource[:port]} in region #{target_region}") fail('You must specify the AWS region') unless target_region != :absent fail('You must specify the Target protocol') if resource[:protocol].nil? fail('You must specify the Target port') if resource[:port].nil? vpc_name = resource[:vpc] if vpc_name - Puppet.info("Step3 #{vpc_name}") vpc_response = ec2_client(target_region).describe_vpcs(filters: [ {name: 'tag:Name', values: [vpc_name]} ]) - Puppet.info("Step4") fail("No VPC found called #{vpc_name}") if vpc_response.data.vpcs.count == 0 vpc_id = vpc_response.data.vpcs.first.vpc_id - Puppet.info("Step5 #{vpc_id}") Puppet.warning "Multiple VPCs found called #{vpc_name}, using #{vpc_id}" if vpc_response.data.vpcs.count > 1 @property_hash[:vpc_id] = vpc_id @property_hash[:vpc] = vpc_name @@ -155,10 +231,11 @@ def create tg_arn = tg_response.data.target_groups.first.target_group_arn - Puppet.info("TargetGroup Arn: #{tg_arn}") - attrs = {} - attrs['stickiness.enabled'] = resource[:stickiness] unless resource[:stickiness].nil? - attrs['stickiness.lb_cookie.duration_seconds'] = resource[:stickiness_duration] unless resource[:stickiness_duration].nil? + attrs = [] + attrs << { key: 'stickiness.enabled', + value: resource[:stickiness] } unless resource[:stickiness].nil? + attrs << { key: 'stickiness.lb_cookie.duration_seconds', + value: resource[:stickiness_duration] } unless resource[:stickiness_duration].nil? mtga_response = elbv2_client(target_region).modify_target_group_attributes( { targetgrouparn: tg_arn, @@ -168,7 +245,7 @@ def create end def destroy - Puppet.info("Deleting target group #{name} in region #{target_region} #{resources}") + Puppet.debug("Deleting target group #{name} in region #{target_region}") elbv2 = elbv2_client(target_region) elbv2.delete_target_group(target_group_arn: arn) @property_hash[:ensure] = :absent diff --git a/lib/puppet/type/elbv2_targetgroup.rb b/lib/puppet/type/elbv2_targetgroup.rb index b1647bba..e9600d82 100644 --- a/lib/puppet/type/elbv2_targetgroup.rb +++ b/lib/puppet/type/elbv2_targetgroup.rb @@ -74,6 +74,9 @@ validate do |value| fail 'Invalid health check protocol - must be HTTP or HTTPS' unless value.upcase =~ /^HTTPS?$/ end + munge do |value| + value.upcase + end end newproperty(:health_check_interval) do @@ -134,7 +137,8 @@ end end - newproperty(:stickiness, parent: Puppet::Property::Boolean) do + newproperty(:stickiness) do + newvalues(:enabled, :disabled) desc 'Indicates whether sticky sessions are enabled' end From 8ce1b2fab76ad2dfe91c310d1b27ca35dfd66471 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Tue, 27 Dec 2016 18:00:04 +0000 Subject: [PATCH 06/72] add tag setting/updating --- lib/puppet/provider/elbv2_targetgroup/v2.rb | 86 +++++++++++++-------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/lib/puppet/provider/elbv2_targetgroup/v2.rb b/lib/puppet/provider/elbv2_targetgroup/v2.rb index 075e920c..a1395628 100644 --- a/lib/puppet/provider/elbv2_targetgroup/v2.rb +++ b/lib/puppet/provider/elbv2_targetgroup/v2.rb @@ -35,33 +35,27 @@ def self.prefetch(resources) end def self.tgs(region) - Puppet.debug('Fetching ELBv2 Target Groups (tgs)') -# regions.collect do |region| - region_client = elbv2_client(region) + region_client = elbv2_client(region) - response = region_client.describe_target_groups() - marker = response.next_marker + response = region_client.describe_target_groups() + marker = response.next_marker - response.target_groups.each do |tg| - yield tg - end + response.target_groups.each do |tg| + yield tg + end - while marker - Puppet.debug("Calling for marked TargetGroup description") - response = region_client.describe_target_groups( { - marker: marker - }) - marker = response.next_marker - response.target_group_descriptions.each do |tg| - yield tg - end + while marker + response = region_client.describe_target_groups( { + marker: marker + }) + marker = response.next_marker + response.target_group_descriptions.each do |tg| + yield tg end -# end + end end def self.target_group_to_hash(region, target_group, vpcs) - Puppet.debug("target_group_to_hash for #{target_group.target_group_name}") - attributes = { } response = elbv2_client(region).describe_target_group_attributes(target_group_arn: target_group.target_group_arn) response.attributes.collect do |attribute| @@ -98,7 +92,7 @@ def self.target_group_to_hash(region, target_group, vpcs) health_check_success_codes: target_group.matcher.http_code, health_check_timeout: target_group.health_check_timeout_seconds, deregistration_delay: attributes['deregistration_delay.timeout_seconds'], - stickiness: (attributes['stickiness.enabled'] == true ? :enabled : :disabled), + stickiness: (attributes['stickiness.enabled'] == 'true' ? :enabled : :disabled), stickiness_duration: attributes['stickiness.lb_cookie.duration_seconds'], tags: tags, } @@ -109,7 +103,7 @@ def exists? end def healthy_threshold=(value) - Puppet.debug("Updating target group #{name} healthy_threshold") + Puppet.debug("Updating target group #{name} healthy_threshold to '#{value}'") elbv2_client(region).modify_target_group( { target_group_arn: arn, healthy_threshold_count: value, @@ -117,7 +111,7 @@ def healthy_threshold=(value) end def unhealthy_threshold=(value) - Puppet.debug("Updating target group #{name} unhealthy_threshold") + Puppet.debug("Updating target group #{name} unhealthy_threshold to '#{value}'") elbv2_client(region).modify_target_group( { target_group_arn: arn, unhealthy_threshold_count: value, @@ -125,7 +119,7 @@ def unhealthy_threshold=(value) end def health_check_path=(value) - Puppet.debug("Updating target group #{name} health_check_path") + Puppet.debug("Updating target group #{name} health_check_path to '#{value}'") elbv2_client(region).modify_target_group( { target_group_arn: arn, health_check_path: value, @@ -133,7 +127,7 @@ def health_check_path=(value) end def health_check_port=(value) - Puppet.debug("Updating target group #{name} health_check_port") + Puppet.debug("Updating target group #{name} health_check_port to '#{value}'") elbv2_client(region).modify_target_group( { target_group_arn: arn, health_check_port: value, @@ -141,7 +135,7 @@ def health_check_port=(value) end def health_check_protocol=(value) - Puppet.debug("Updating target group #{name} health_check_protocol") + Puppet.debug("Updating target group #{name} health_check_protocol to '#{value}'") elbv2_client(region).modify_target_group( { target_group_arn: arn, health_check_protocol: value, @@ -149,7 +143,7 @@ def health_check_protocol=(value) end def health_check_interval=(value) - Puppet.debug("Updating target group #{name} health_check_interval") + Puppet.debug("Updating target group #{name} health_check_interval to '#{value}'") elbv2_client(region).modify_target_group( { target_group_arn: arn, health_check_interval_seconds: value, @@ -157,7 +151,7 @@ def health_check_interval=(value) end def health_check_success_codes=(value) - Puppet.debug("Updating target group #{name} #{arn} health_check_success_codes") + Puppet.debug("Updating target group #{name} #{arn} health_check_success_codes to '#{value}'") elbv2_client(region).modify_target_group( { target_group_arn: arn, matcher: { http_code: value }, @@ -165,7 +159,7 @@ def health_check_success_codes=(value) end def health_check_timeout=(value) - Puppet.debug("Updating target group #{name} health_check_timeout") + Puppet.debug("Updating target group #{name} health_check_timeout to '#{value}'") elbv2_client(region).modify_target_group( { target_group_arn: arn, health_check_timeout_seconds: value, @@ -183,7 +177,7 @@ def stickiness=(value) end def stickiness_duration=(value) - Puppet.debug("Updating target group #{name} stickiness_duration") + Puppet.debug("Updating target group #{name} stickiness_duration to '#{value}'") elbv2_client(region).modify_target_group_attributes( { target_group_arn: arn, attributes: [ { key: 'stickiness.lb_cookie.duration_seconds', @@ -192,8 +186,33 @@ def stickiness_duration=(value) @property_hash[:stickiness_duration] = value end + def tags=(value) + Puppet.debug("Updating target group #{name} tags to '#{value}'") + client = elbv2_client(region) + resp = client.describe_tags( resource_arns: [ arn ] ) + is = resp.tag_descriptions.collect do |tds| + tds.tags.collect do |tag| + tag.key + end + end.flatten + should = value.keys + to_del = is - should + Puppet.info("Response: #{to_del}") + + client.remove_tags( resource_arns: [ arn ], + tag_keys: to_del ) + client.add_tags( resource_arns: [ arn ], + tags: value ? value.map{ |k,v| { key: k, value: v, } } : [] ) + + +# client.create_or_update_tags( +# tags: tags ? tags.map { |k,v| { key: k, value: v, } } : [] +# ) + + end + def create - Puppet.debug("Creating target group #{name} #{resource[:protocol]} #{resource[:port]} in region #{target_region}") + Puppet.debug("Creating target group #{name} in region #{target_region} using #{resource[:protocol]}:#{resource[:port]}") fail('You must specify the AWS region') unless target_region != :absent fail('You must specify the Target protocol') if resource[:protocol].nil? fail('You must specify the Target port') if resource[:port].nil? @@ -227,13 +246,12 @@ def create config[:matcher] = { http_code: resource[:health_check_success_codes] } unless resource[:health_check_success_codes].nil? tg_response = elbv2_client(target_region).create_target_group(config) - Puppet.info("Config: #{tg_response.data}") tg_arn = tg_response.data.target_groups.first.target_group_arn attrs = [] attrs << { key: 'stickiness.enabled', - value: resource[:stickiness] } unless resource[:stickiness].nil? + value: ( resource[:stickiness] == :enabled ? 'true' : 'false' ) } unless resource[:stickiness].nil? attrs << { key: 'stickiness.lb_cookie.duration_seconds', value: resource[:stickiness_duration] } unless resource[:stickiness_duration].nil? @@ -242,6 +260,8 @@ def create attributes: attrs, }) unless attrs.empty? + tags = resource[:tags] ? resource[:tags].map { |k,v| {key: k, value: v} } : [] + end def destroy From 6009576426c90486c6c3f53ff8c4a8e12ff42c57 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Wed, 28 Dec 2016 04:37:30 +0000 Subject: [PATCH 07/72] populate targetgroup resource on prefetch, initial get instance for elbv2 loadbalancers --- lib/puppet/provider/elbv2_loadbalancer/v2.rb | 85 ++++++++++++++++++++ lib/puppet/provider/elbv2_targetgroup/v2.rb | 20 ++++- lib/puppet/type/elbv2_loadbalancer.rb | 42 +--------- 3 files changed, 104 insertions(+), 43 deletions(-) diff --git a/lib/puppet/provider/elbv2_loadbalancer/v2.rb b/lib/puppet/provider/elbv2_loadbalancer/v2.rb index e69de29b..3aadbe6a 100644 --- a/lib/puppet/provider/elbv2_loadbalancer/v2.rb +++ b/lib/puppet/provider/elbv2_loadbalancer/v2.rb @@ -0,0 +1,85 @@ +require_relative '../../../puppet_x/puppetlabs/aws.rb' + +Puppet::Type.type(:elbv2_loadbalancer).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do + + confine feature: :aws + + mk_resource_methods + + def self.instances() + Puppet.debug('Fetching ELBv2 Load Balancers (instances)') + regions.collect do |region| + vpc_names = {} + vpc_response = ec2_client(region).describe_vpcs() + vpc_response.data.vpcs.each do |vpc| + vpc_name = name_from_tag(vpc) + vpc_names[vpc.vpc_id] = vpc_name if vpc_name + end + target_groups = [] + elbs(region) do |elb| + load_balancers << new(load_balancer_to_hash(region, elb, vpc_names) ) + end + + load_balancers + end.flatten + end + + def self.prefetch(resources) + instances.each do |prov| + Puppet.debug("Prefetching #{prov.name}") + if resource = resources[prov.name] # rubocop:disable Lint/AssignmentInCondition + if resource[:region] == prov.region + Puppet.debug("Updating resource for #{prov.name}") + resource.provider = prov + end + end + end + end + + def self.elbs(region) + region_client = elbv2_client(region) + + response = region_client.describe_load_balancers() + marker = response.next_marker + + response.load_balancer_descriptions.each do |elb| + yield elb + end + + while marker + response = region_client.describe_load_balancers( { + marker: marker + }) + marker = response.next_marker + response.load_balancer_descriptions.each do |elb| + yield elb + end + end + end + + def self.load_balancer_to_hash(region, elb, vpcs) + attributes = { } + tags = { } + { + name: elb.load_balancer_name, + arn: elb.load_balancer_arn, + region: region, + vpc: vpcs[target_group.vpc_id], + tags: tags, + } + end + + def exists? + @property_hash[:ensure] == :present + end + + def create + Puppet.debug("Creating load balancer #{name} in region #{target_region}") + + end + + def destroy + Puppet.debug("Deleting load balancer #{name} in region #{target_region}") + elbv2 = elbv2_client(target_region) + end +end diff --git a/lib/puppet/provider/elbv2_targetgroup/v2.rb b/lib/puppet/provider/elbv2_targetgroup/v2.rb index a1395628..b20e341a 100644 --- a/lib/puppet/provider/elbv2_targetgroup/v2.rb +++ b/lib/puppet/provider/elbv2_targetgroup/v2.rb @@ -15,7 +15,6 @@ def self.instances() vpc_name = name_from_tag(vpc) vpc_names[vpc.vpc_id] = vpc_name if vpc_name end - Puppet.debug("instances region: #{region}") target_groups = [] tgs(region) do |tg| target_groups << new(target_group_to_hash(region, tg, vpc_names) ) @@ -29,7 +28,24 @@ def self.prefetch(resources) instances.each do |prov| Puppet.debug("Prefetching #{prov.name}") if resource = resources[prov.name] # rubocop:disable Lint/AssignmentInCondition - resource.provider = prov if resource[:region] == prov.region + if resource[:region] == prov.region + Puppet.debug("Updating resource for #{prov.name}") + resource.provider = prov + resource[:port] = prov.port + resource[:protocol] = prov.protocol +# resource[:healthy_threshold] = prov.healthy_threshold +# resource[:unhealthy_threshold] = prov.unhealthy_threshold + resource[:health_check_path] = prov.health_check_path + resource[:health_check_port] = prov.health_check_port + resource[:health_check_protocol] = prov.health_check_protocol +# resource[:health_check_interval] = prov.health_check_interval + resource[:health_check_success_codes] = prov.health_check_success_codes +# resource[:health_check_timeout] = prov.health_check_timeout +# resource[:deregistration_delay] = prov.deregistration_delay + resource[:stickiness] = prov.stickiness +# resource[:stickiness_duration] = prov.stickiness_duration + resource[:tags] = prov.tags + end end end end diff --git a/lib/puppet/type/elbv2_loadbalancer.rb b/lib/puppet/type/elbv2_loadbalancer.rb index 2451f33f..5298c4ee 100644 --- a/lib/puppet/type/elbv2_loadbalancer.rb +++ b/lib/puppet/type/elbv2_loadbalancer.rb @@ -35,25 +35,13 @@ def normalise(listeners) value = [value] unless value.is_a?(Array) fail "you must provide a set of listeners for the load balancer" if value.empty? value.each do |listener| - ['protocol', 'load_balancer_port', 'instance_protocol', 'instance_port'].each do |key| + ['protocol', 'port', 'target_group'].each do |key| fail "listeners must include #{key}" unless listener.keys.include?(key) end end end end - newproperty(:health_check) do - desc 'The health check configuration for the load balancer' - def insync?(is) - provider.class.normalize_values(is) == provider.class.normalize_values(should) - end - validate do |value| - ['target', 'interval', 'timeout', 'unhealthy_threshold', 'healthy_threshold'].each do |key| - fail "health_check must include #{key}" unless value.keys.include?(key) - end - end - end - newproperty(:tags, :parent => PuppetX::Property::AwsTag) do desc 'The tags for the load balancer.' end @@ -78,23 +66,6 @@ def insync?(is) end end - newproperty(:availability_zones, :array_matching => :all) do - desc 'The availability zones in which to launch the load balancer.' - def insync?(is) - is.to_set == should.to_set - end - end - - newproperty(:instances, :array_matching => :all) do - desc 'The instances to associate with the load balancer.' - validate do |value| - fail 'instances should be a String' unless value.is_a?(String) - end - def insync?(is) - is.to_set == should.to_set - end - end - newproperty(:scheme) do desc 'Whether the load balancer is internal or public facing.' defaultto :'internet-facing' @@ -108,17 +79,6 @@ def insync?(is) desc 'The DNS name of the load balancer' end - validate do - subnets = self[:subnets] || [] - zones = self[:availability_zones] || [] - fail "You can specify either subnets or availability_zones for the ELB #{self[:name]}" if !zones.empty? && !subnets.empty? - end - - autorequire(:ec2_instance) do - instances = self[:instances] - instances.is_a?(Array) ? instances : [instances] - end - autorequire(:ec2_securitygroup) do groups = self[:security_groups] groups.is_a?(Array) ? groups : [groups] From 6a8d26eeba6be41e0be04f069e5c8333ef9c73e5 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Thu, 19 Jan 2017 19:22:42 +0000 Subject: [PATCH 08/72] add target groups and certificate info to elbv2 information --- lib/puppet/provider/elbv2_loadbalancer/v2.rb | 129 ++++++++++++++++++- lib/puppet/type/elbv2_loadbalancer.rb | 6 +- 2 files changed, 125 insertions(+), 10 deletions(-) diff --git a/lib/puppet/provider/elbv2_loadbalancer/v2.rb b/lib/puppet/provider/elbv2_loadbalancer/v2.rb index 3aadbe6a..ee67bc7a 100644 --- a/lib/puppet/provider/elbv2_loadbalancer/v2.rb +++ b/lib/puppet/provider/elbv2_loadbalancer/v2.rb @@ -7,7 +7,7 @@ mk_resource_methods def self.instances() - Puppet.debug('Fetching ELBv2 Load Balancers (instances)') + Puppet.debug("Fetching ELBv2 Load Balancers (instances)") regions.collect do |region| vpc_names = {} vpc_response = ec2_client(region).describe_vpcs() @@ -15,9 +15,22 @@ def self.instances() vpc_name = name_from_tag(vpc) vpc_names[vpc.vpc_id] = vpc_name if vpc_name end - target_groups = [] + + tg_names = {} + tg_response = elbv2_client(region).describe_target_groups() + tg_response.data.target_groups.each do |tg| + tg_names[tg.target_group_arn] = tg.target_group_name + end + + cert_names = {} + cert_response = iam_client(region).list_server_certificates() + cert_response.data.server_certificate_metadata_list.each do |cert| + cert_names[cert.arn] = cert.server_certificate_name + end + + load_balancers = [] elbs(region) do |elb| - load_balancers << new(load_balancer_to_hash(region, elb, vpc_names) ) + load_balancers << new(load_balancer_to_hash(region, elb, vpc_names, tg_names, cert_names) ) end load_balancers @@ -42,7 +55,9 @@ def self.elbs(region) response = region_client.describe_load_balancers() marker = response.next_marker - response.load_balancer_descriptions.each do |elb| + Puppet.debug(response) + + response.load_balancers.each do |elb| yield elb end @@ -51,24 +66,107 @@ def self.elbs(region) marker: marker }) marker = response.next_marker - response.load_balancer_descriptions.each do |elb| + response.load_balancers.each do |elb| yield elb end end end - def self.load_balancer_to_hash(region, elb, vpcs) + def self.listeners(region,lbarn) + Puppet.debug("listeners('#{region}','#{lbarn}')") + region_client = elbv2_client(region) + + response = region_client.describe_listeners( { + load_balancer_arn: lbarn, + }) + marker = response.next_marker + + response.listeners.each do |listener| + yield listener + end + + while marker + response = region_client.describe_listeners( { + marker: marker + }) + marker = response.next_marker + response.listeners.each do |listener| + yield listener + end + end + end + + def self.rules(region,lstnrarn) + Puppet.debug("rules('#{region}','#{lstnrarn}')") + region_client = elbv2_client(region) + + response = region_client.describe_rules( { + listener_arn: lstnrarn, + }) + response.rules.each do |rule| + next if rule.priority == 'default' + yield rule + end + end + + def self.load_balancer_to_hash(region, elb, vpcs, tgs, certs) + Puppet.debug("vpc id: #{elb.vpc_id}, Vpcs: #{vpcs}") + + elblisteners = [ ] + listeners(region, elb.load_balancer_arn) do |listener| + elblisteners << listener_to_hash(region, listener, tgs, certs) + end + + Puppet.debug("Listeners: #{elblisteners}") + attributes = { } tags = { } + { + ensure: :present, name: elb.load_balancer_name, arn: elb.load_balancer_arn, region: region, - vpc: vpcs[target_group.vpc_id], + vpc: vpcs[elb.vpc_id], + scheme: elb.scheme, + listeners: elblisteners, tags: tags, } end + def self.listener_to_hash(region, listener, tgs, certs) + Puppet.debug("listener_to_hash: #{listener}") + + rules = [ ] + rules(region,listener.listener_arn) do |rule| + rules << rule_to_hash(rule,tgs) + end + + lstnr = { + protocol: listener.protocol, + port: listener.port, + ssl_policy: listener.ssl_policy, + default_target_group: tgs[ listener.default_actions.first.target_group_arn ], + } + lstnr[:rules] = rules unless rules.empty? + lstnr[:certificate] = certs[listener.certificates.first.certificate_arn] unless listener.certificates.empty? + + lstnr + end + + def self.rule_to_hash(rule,tgs) + Puppet.debug("rule_to_hash: #{rule}") + + rh = { + priority: rule.priority, + target_group: tgs[rule.actions.first.target_group_arn], + } + + rh[:path_match] = rule.conditions.first.values.first unless rule.conditions.empty? + + rh + end + def exists? @property_hash[:ensure] == :present end @@ -76,10 +174,27 @@ def exists? def create Puppet.debug("Creating load balancer #{name} in region #{target_region}") + elbv2 = elbv2_client(target_region) + ec2 = ec2_client(target_region) + ec2_response = ec2.describe_subnets() + + config = { + load_balancer_name: name, + + scheme: scheme.nil? ? scheme : :'internet-facing', + } + end def destroy Puppet.debug("Deleting load balancer #{name} in region #{target_region}") elbv2 = elbv2_client(target_region) + + Puppet.debug("Load Balancer Arn: ${@property_hash[:arn]}") + + elbv2.delete_load_balancer({ + load_balancer_arn: @property_hash[:arn], + }) + @property_hash[:ensure] = :absent end end diff --git a/lib/puppet/type/elbv2_loadbalancer.rb b/lib/puppet/type/elbv2_loadbalancer.rb index 5298c4ee..a642487f 100644 --- a/lib/puppet/type/elbv2_loadbalancer.rb +++ b/lib/puppet/type/elbv2_loadbalancer.rb @@ -42,6 +42,9 @@ def normalise(listeners) end end + newproperty(:arn) + newproperty(:vpc) + newproperty(:tags, :parent => PuppetX::Property::AwsTag) do desc 'The tags for the load balancer.' end @@ -70,9 +73,6 @@ def insync?(is) desc 'Whether the load balancer is internal or public facing.' defaultto :'internet-facing' newvalues(:'internet-facing', :internal) - def insync?(is) - is.to_s == should.to_s - end end newproperty(:dns_name) do From 7ea165288b85e98ad6f0c11af8023a15ac9d95d3 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Tue, 13 Dec 2016 21:50:53 +0000 Subject: [PATCH 09/72] initial work adding elbv2 loadbalancer and targetgroup --- lib/puppet/type/elbv2_loadbalancer.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/puppet/type/elbv2_loadbalancer.rb b/lib/puppet/type/elbv2_loadbalancer.rb index a642487f..346e8b97 100644 --- a/lib/puppet/type/elbv2_loadbalancer.rb +++ b/lib/puppet/type/elbv2_loadbalancer.rb @@ -73,12 +73,26 @@ def insync?(is) desc 'Whether the load balancer is internal or public facing.' defaultto :'internet-facing' newvalues(:'internet-facing', :internal) + def insync?(is) + is.to_s == should.to_s + end end newproperty(:dns_name) do desc 'The DNS name of the load balancer' end + validate do + subnets = self[:subnets] || [] + zones = self[:availability_zones] || [] + fail "You can specify either subnets or availability_zones for the ELB #{self[:name]}" if !zones.empty? && !subnets.empty? + end + + autorequire(:ec2_instance) do + instances = self[:instances] + instances.is_a?(Array) ? instances : [instances] + end + autorequire(:ec2_securitygroup) do groups = self[:security_groups] groups.is_a?(Array) ? groups : [groups] From f8b5392b382e7bfd0caf4274f629eb5028c55a66 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Sat, 24 Dec 2016 19:57:39 +0000 Subject: [PATCH 10/72] destroy now working, updating of target group parameters and attributes mostly working Todo :- stickiness - enabled/disabled not updating --- lib/puppet/provider/elbv2_targetgroup/v2.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/puppet/provider/elbv2_targetgroup/v2.rb b/lib/puppet/provider/elbv2_targetgroup/v2.rb index b20e341a..38b2e7a9 100644 --- a/lib/puppet/provider/elbv2_targetgroup/v2.rb +++ b/lib/puppet/provider/elbv2_targetgroup/v2.rb @@ -225,6 +225,14 @@ def tags=(value) # tags: tags ? tags.map { |k,v| { key: k, value: v, } } : [] # ) + def stickiness_duration=(value) + Puppet.debug("Updating target group #{name} stickiness_duration") + elbv2_client(region).modify_target_group_attributes( { + target_group_arn: arn, + attributes: [ { key: 'stickiness.lb_cookie.duration_seconds', + value: value.to_s } ], + }) + @property_hash[:stickiness_duration] = value end def create From 2874aece1a51def2b0ff3e463bc30953bdfeea46 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Tue, 27 Dec 2016 18:00:04 +0000 Subject: [PATCH 11/72] add tag setting/updating --- lib/puppet/provider/elbv2_targetgroup/v2.rb | 25 +++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/lib/puppet/provider/elbv2_targetgroup/v2.rb b/lib/puppet/provider/elbv2_targetgroup/v2.rb index 38b2e7a9..64d2a69c 100644 --- a/lib/puppet/provider/elbv2_targetgroup/v2.rb +++ b/lib/puppet/provider/elbv2_targetgroup/v2.rb @@ -235,6 +235,31 @@ def stickiness_duration=(value) @property_hash[:stickiness_duration] = value end + def tags=(value) + Puppet.debug("Updating target group #{name} tags to '#{value}'") + client = elbv2_client(region) + resp = client.describe_tags( resource_arns: [ arn ] ) + is = resp.tag_descriptions.collect do |tds| + tds.tags.collect do |tag| + tag.key + end + end.flatten + should = value.keys + to_del = is - should + Puppet.info("Response: #{to_del}") + + client.remove_tags( resource_arns: [ arn ], + tag_keys: to_del ) + client.add_tags( resource_arns: [ arn ], + tags: value ? value.map{ |k,v| { key: k, value: v, } } : [] ) + + +# client.create_or_update_tags( +# tags: tags ? tags.map { |k,v| { key: k, value: v, } } : [] +# ) + + end + def create Puppet.debug("Creating target group #{name} in region #{target_region} using #{resource[:protocol]}:#{resource[:port]}") fail('You must specify the AWS region') unless target_region != :absent From 7ff81ffa8f0c957306dd284fc4bcac9620943c8c Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Wed, 28 Dec 2016 04:37:30 +0000 Subject: [PATCH 12/72] populate targetgroup resource on prefetch, initial get instance for elbv2 loadbalancers --- lib/puppet/type/elbv2_loadbalancer.rb | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/lib/puppet/type/elbv2_loadbalancer.rb b/lib/puppet/type/elbv2_loadbalancer.rb index 346e8b97..37e7625d 100644 --- a/lib/puppet/type/elbv2_loadbalancer.rb +++ b/lib/puppet/type/elbv2_loadbalancer.rb @@ -82,17 +82,6 @@ def insync?(is) desc 'The DNS name of the load balancer' end - validate do - subnets = self[:subnets] || [] - zones = self[:availability_zones] || [] - fail "You can specify either subnets or availability_zones for the ELB #{self[:name]}" if !zones.empty? && !subnets.empty? - end - - autorequire(:ec2_instance) do - instances = self[:instances] - instances.is_a?(Array) ? instances : [instances] - end - autorequire(:ec2_securitygroup) do groups = self[:security_groups] groups.is_a?(Array) ? groups : [groups] From 07511182c943983a052ff7d580d86973fc297be8 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Thu, 19 Jan 2017 19:22:42 +0000 Subject: [PATCH 13/72] add target groups and certificate info to elbv2 information --- lib/puppet/type/elbv2_loadbalancer.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/puppet/type/elbv2_loadbalancer.rb b/lib/puppet/type/elbv2_loadbalancer.rb index 37e7625d..a642487f 100644 --- a/lib/puppet/type/elbv2_loadbalancer.rb +++ b/lib/puppet/type/elbv2_loadbalancer.rb @@ -73,9 +73,6 @@ def insync?(is) desc 'Whether the load balancer is internal or public facing.' defaultto :'internet-facing' newvalues(:'internet-facing', :internal) - def insync?(is) - is.to_s == should.to_s - end end newproperty(:dns_name) do From bd20a973b3809f2d16bcfefdef637e55727b21cb Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Sat, 19 Nov 2016 17:55:55 +0100 Subject: [PATCH 14/72] Update the Gemfile and .travis.yml This should make gem installation across all supported ruby versions work again, and reduce the delta, once we can roll that up into modulesync. This also includes version restrictions for gems droppint 1.9.3 support. --- .travis.yml | 40 +++++++++++++-------- Gemfile | 102 ++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 98 insertions(+), 44 deletions(-) diff --git a/.travis.yml b/.travis.yml index 815dfa9e..00e4dd17 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,17 +1,29 @@ +#This file is generated by ModuleSync, do not edit. --- +sudo: false language: ruby -bundler_args: --without development acceptance cache: bundler -before_install: rm Gemfile.lock || true -sudo: false -rvm: - - 2.1 - - 2.2 - - 1.9.3 -script: bundle exec rake test -env: - - PUPPET_LOCATION="~> 3.6.0" PARSER="future" - - PUPPET_LOCATION="~> 3.7.0" PARSER="future" - - PUPPET_LOCATION="~> 3.6.0" - - PUPPET_LOCATION="~> 3.7.0" - - PUPPET_LOCATION="~> 4.0.0" +script: "bundle exec rake validate lint spec" +#Inserting below due to the following issue: https://github.com/travis-ci/travis-ci/issues/3531#issuecomment-88311203 +before_install: + - gem update bundler +matrix: + fast_finish: true + include: + - rvm: 2.3.1 + bundler_args: --without system_tests + env: PUPPET_GEM_VERSION="~> 4.0" STDLIB_LOG_DEPRECATIONS="false" + - rvm: 2.1.9 + bundler_args: --without system_tests + env: PUPPET_GEM_VERSION="~> 4.0" STDLIB_LOG_DEPRECATIONS="false" + - rvm: 2.1.5 + bundler_args: --without system_tests + env: PUPPET_GEM_VERSION="~> 3.0" FUTURE_PARSER="yes" + - rvm: 2.1.5 + bundler_args: --without system_tests + env: PUPPET_GEM_VERSION="~> 3.0" + - rvm: 1.9.3 + bundler_args: --without system_tests + env: PUPPET_GEM_VERSION="~> 3.0" +notifications: + email: false diff --git a/Gemfile b/Gemfile index 587b1fbc..e17a8b27 100644 --- a/Gemfile +++ b/Gemfile @@ -1,50 +1,92 @@ -source ENV['GEM_SOURCE'] || 'https://rubygems.org' +#This file is generated by ModuleSync, do not edit. -def location_for(place, fake_version = nil) - if place =~ /^(git:[^#]*)#(.*)/ +source ENV['GEM_SOURCE'] || "https://rubygems.org" + +# Determines what type of gem is requested based on place_or_version. +def gem_type(place_or_version) + if place_or_version =~ /^git:/ + :git + elsif place_or_version =~ /^file:/ + :file + else + :gem + end +end + +# Find a location or specific version for a gem. place_or_version can be a +# version, which is most often used. It can also be git, which is specified as +# `git://somewhere.git#branch`. You can also use a file source location, which +# is specified as `file://some/location/on/disk`. +def location_for(place_or_version, fake_version = nil) + if place_or_version =~ /^(git[:@][^#]*)#(.*)/ [fake_version, { :git => $1, :branch => $2, :require => false }].compact - elsif place =~ /^file:\/\/(.*)/ + elsif place_or_version =~ /^file:\/\/(.*)/ ['>= 0', { :path => File.expand_path($1), :require => false }] else - [place, { :require => false }] + [place_or_version, { :require => false }] end end +# Used for gem conditionals +supports_windows = false + gem 'aws-sdk-core', '2.3.22' gem 'retries' -group :test do - gem 'rake' - gem 'puppet', *location_for(ENV['PUPPET_LOCATION'] || ENV['PUPPET_GEM_VERSION']) - gem 'puppetlabs_spec_helper' +group :development do + gem 'puppet-lint', :require => false + gem 'metadata-json-lint', :require => false + gem 'puppet_facts', :require => false + gem 'puppet-blacksmith', '>= 3.4.0', :require => false, :platforms => 'ruby' + gem 'puppetlabs_spec_helper', '>= 1.2.1', :require => false + gem 'rspec-puppet', '>= 2.3.2', :require => false + gem 'rspec-puppet-facts', :require => false + gem 'mocha', '< 1.2.0', :require => false + gem 'simplecov', :require => false + gem 'parallel_tests', '< 2.10.0', :require => false if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0') + gem 'parallel_tests', :require => false if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.0.0') + gem 'rubocop', '0.41.2', :require => false if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0') + gem 'rubocop', :require => false if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.0.0') + gem 'rubocop-rspec', '~> 1.6', :require => false if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.3.0') + gem 'pry', :require => false + gem 'json_pure', '<= 2.0.1', :require => false if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0') + gem 'json', '<= 2.0.0', :require => false if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0') gem 'webmock' + gem 'public_suffix', '< 1.5.0' if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0') gem 'vcr' - gem 'rspec-puppet', :git => 'https://github.com/rodjek/rspec-puppet.git' - gem 'metadata-json-lint' - gem 'json_pure', '~>1.0' if RUBY_VERSION == '1.9.3' -end - -group :development do - gem 'travis' - gem 'travis-lint' - gem 'puppet-blacksmith' - gem 'guard-rake' - gem 'listen', '= 3.0.7' # last version to support ruby 1.9; the proper fix would be to not install the development group in our internal CI - if RUBY_VERSION =~ /^1\./ - gem 'rubocop', '0.41.2' - else - gem 'rubocop' - end - gem 'pry' - gem 'librarian-puppet' end -group :acceptance do +group :system_tests do gem 'mustache', '0.99.8' - gem 'beaker-rspec' - gem 'beaker-puppet_install_helper' + gem 'beaker', *location_for(ENV['BEAKER_VERSION'] || '~> 2.20') if supports_windows + gem 'beaker', *location_for(ENV['BEAKER_VERSION']) if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.3.0') and ! supports_windows + gem 'beaker', *location_for(ENV['BEAKER_VERSION'] || '< 3') if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3.0') and ! supports_windows + gem 'beaker-pe', :require => false if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.3.0') + gem 'beaker-rspec', *location_for(ENV['BEAKER_RSPEC_VERSION'] || '>= 3.4') if ! supports_windows + gem 'beaker-rspec', *location_for(ENV['BEAKER_RSPEC_VERSION'] || '~> 5.1') if supports_windows + gem 'beaker-puppet_install_helper', :require => false + gem 'master_manipulator', :require => false + gem 'beaker-hostgenerator', *location_for(ENV['BEAKER_HOSTGENERATOR_VERSION']) end +gem 'puppet', *location_for(ENV['PUPPET_GEM_VERSION']) + +# Only explicitly specify Facter/Hiera if a version has been specified. +# Otherwise it can lead to strange bundler behavior. If you are seeing weird +# gem resolution behavior, try setting `DEBUG_RESOLVER` environment variable +# to `1` and then run bundle install. +gem 'facter', *location_for(ENV['FACTER_GEM_VERSION']) if ENV['FACTER_GEM_VERSION'] +gem 'hiera', *location_for(ENV['HIERA_GEM_VERSION']) if ENV['HIERA_GEM_VERSION'] + + +# Evaluate Gemfile.local if it exists if File.exists? "#{__FILE__}.local" eval(File.read("#{__FILE__}.local"), binding) end + +# Evaluate ~/.gemfile if it exists +if File.exists?(File.join(Dir.home, '.gemfile')) + eval(File.read(File.join(Dir.home, '.gemfile')), binding) +end + +# vim:ft=ruby From 509aee4b8f4d8e00299bd673cd17ac76052cac3a Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Thu, 1 Dec 2016 18:46:17 +0000 Subject: [PATCH 15/72] Designate former 'tests' files as examples --- {tests => examples/tests}/create.pp | 0 {tests => examples/tests}/destroy.pp | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {tests => examples/tests}/create.pp (100%) rename {tests => examples/tests}/destroy.pp (100%) diff --git a/tests/create.pp b/examples/tests/create.pp similarity index 100% rename from tests/create.pp rename to examples/tests/create.pp diff --git a/tests/destroy.pp b/examples/tests/destroy.pp similarity index 100% rename from tests/destroy.pp rename to examples/tests/destroy.pp From dd93f6a638a1f7e65ce6abde5b5e043997aeebb1 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 28 Nov 2016 10:43:21 -0800 Subject: [PATCH 16/72] Attempt fix hash method call on nil object Without this change, we call '.keys' on a nil object. The 'initialize' method should have set the 'property_flush' to an empty hash, so I'm a little confused about why this is required. --- lib/puppet/provider/rds_instance/v2.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/puppet/provider/rds_instance/v2.rb b/lib/puppet/provider/rds_instance/v2.rb index f40853f5..dd629e76 100644 --- a/lib/puppet/provider/rds_instance/v2.rb +++ b/lib/puppet/provider/rds_instance/v2.rb @@ -134,7 +134,7 @@ def destroy end def flush - if @property_hash[:ensure] != :absent + if @property_hash[:ensure] != :absent and not @property_flush.nil? Puppet.debug("Flushing RDS instance for #{@property_hash[:name]}") if @property_flush.keys.size > 0 From f4dca9851f59bf9d78ce9132602510f94b147f1b Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Thu, 15 Dec 2016 13:42:22 -0800 Subject: [PATCH 17/72] Update the Gemfile for webmock ruby versions Without this change, webmock fails to install correctly due to a version mismatch on ruby. Here we address this by pinning the version of webmock based on the ruby version. --- Gemfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index e17a8b27..01ed145e 100644 --- a/Gemfile +++ b/Gemfile @@ -50,8 +50,9 @@ group :development do gem 'rubocop-rspec', '~> 1.6', :require => false if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.3.0') gem 'pry', :require => false gem 'json_pure', '<= 2.0.1', :require => false if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0') - gem 'json', '<= 2.0.0', :require => false if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0') - gem 'webmock' + gem 'json', '<= 2.0.0', :require => false if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0') + gem 'webmock', :require => false if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.0.0') + gem 'webmock', '~> 1.24', :require => false if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0') gem 'public_suffix', '< 1.5.0' if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0') gem 'vcr' end From d53d51ae4b067595f645faf925015cb2e7c98d4b Mon Sep 17 00:00:00 2001 From: Mike Marseglia Date: Wed, 16 Nov 2016 09:27:35 -0500 Subject: [PATCH 18/72] Updated README.md to reflect that allocated_storage is a required parameter for RDS instances. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 03e2aeba..1a58863e 100644 --- a/README.md +++ b/README.md @@ -1181,7 +1181,7 @@ using the `rds-describe-db-engine-versions` command from the AWS CLI. This parameter is set at creation only; it is not affected by updates. #####`allocated_storage` -The size of the database in gigabytes. Note that minimum size constraints +*Required* The size of the database in gigabytes. Note that minimum size constraints exist, which vary depending on the database engine selected. This parameter is set at creation only; it is not affected by updates. From 6a6fa697f495b3038fb595444adc0de8f53b2ab4 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 19 Dec 2016 09:49:38 -0800 Subject: [PATCH 19/72] Bump the SDK gem version This work updates the SDK to be newer. This will be required for several items going in currently, as well as work that is planned to be submitted around CloudFront soon. --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 01ed145e..75b193aa 100644 --- a/Gemfile +++ b/Gemfile @@ -30,7 +30,7 @@ end # Used for gem conditionals supports_windows = false -gem 'aws-sdk-core', '2.3.22' +gem 'aws-sdk-core', '2.6.38' gem 'retries' group :development do From fba03b220af7733816ea4c593c36f54761bfaa3f Mon Sep 17 00:00:00 2001 From: Eric Putnam Date: Wed, 4 Jan 2017 14:11:14 -0500 Subject: [PATCH 20/72] add xenial to metadata adds Ubuntu 16.04 to supported ubuntu platforms on metadata.json --- metadata.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/metadata.json b/metadata.json index 9c46fe9c..5a62f1a1 100644 --- a/metadata.json +++ b/metadata.json @@ -73,7 +73,8 @@ "operatingsystemrelease": [ "10.04", "12.04", - "14.04" + "14.04", + "16.04" ] }, { From 257c9a8d6fdec63687f11af9987b881980f89fe1 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Tue, 13 Dec 2016 13:32:35 -0800 Subject: [PATCH 21/72] Add support for ELB listener modifications Without this change, the listeners on elb_loadbalancer resources are marked as read-only in the type and are thus not modifiable. This work adds support for modifying listeners and setting the 'policy' for HTTPS listeners to control which cipher suites are available. --- README.md | 6 +- lib/puppet/provider/elb_loadbalancer/v2.rb | 160 +++++++++++++++++++-- lib/puppet/type/elb_loadbalancer.rb | 9 +- 3 files changed, 161 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 1a58863e..ba59ce12 100644 --- a/README.md +++ b/README.md @@ -490,12 +490,14 @@ The AWS generated interfaces hash for the instance. Read-only. *Required* The region in which to launch the load balancer. For valid values, see [AWS Regions](http://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region). #####`listeners` -*Required* The ports and protocols the load balancer listens to. This parameter is set at creation only; it is not affected by updates. Accepts an array of the following values: +*Required* The ports and protocols the load balancer listens to. Accepts an +array of the following values: * protocol * load_balancer_port * instance_protocol * instance_port - * ssl_certificate_id (optional if protocol is HTTPS ) + * ssl_certificate_id (required if protocol is HTTPS) + * policy_names (optional array of policy name strings for HTTPS) #####`health_check` The configuration for an ELB health check used to determine the health of the diff --git a/lib/puppet/provider/elb_loadbalancer/v2.rb b/lib/puppet/provider/elb_loadbalancer/v2.rb index ae5e0f35..1c79d280 100644 --- a/lib/puppet/provider/elb_loadbalancer/v2.rb +++ b/lib/puppet/provider/elb_loadbalancer/v2.rb @@ -59,7 +59,7 @@ def self.elbs end end - read_only(:region, :scheme, :listeners, :tags, :dns_name) + read_only(:region, :scheme, :tags, :dns_name) def self.prefetch(resources) ref_catalog = resources.values.first.respond_to?(:catalog) ? resources.values.first.catalog : nil @@ -98,7 +98,7 @@ def self.load_balancer_to_hash(region, load_balancer, ref_catalog=nil) # ID to Name have not been found in the reference catalog. As such, # here we need to make the call to ec2_client to resolve the instances # that are missing. - Puppet.debug('calling ec2_client for instances') + Puppet.debug('Calling ec2_client for instances') instances = ec2_client(region).describe_instances(instance_ids: instance_ids).collect do |response| response.data.reservations.collect do |reservation| reservation.instances.collect do |instance| @@ -122,6 +122,7 @@ def self.load_balancer_to_hash(region, load_balancer, ref_catalog=nil) 'instance_port' => listener.listener.instance_port, } result['ssl_certificate_id'] = listener.listener.ssl_certificate_id unless listener.listener.ssl_certificate_id.nil? + result['policy_names'] = listener.policy_names unless listener.policy_names.nil? or listener.policy_names.size == 0 result end @@ -158,7 +159,7 @@ def self.load_balancer_to_hash(region, load_balancer, ref_catalog=nil) # We arrive here when the subnet that we are looking to convert from ID # to Name is not found in the catalog. This requires us to make the # call to ec2_client to get the subnet information we need. - Puppet.debug('calling ec2_client for subnets') + Puppet.debug('Calling ec2_client for subnets') subnent_response = ec2_client(region).describe_subnets(subnet_ids: load_balancer.subnets) subnent_response.data.subnets.each do |subnet| subnet_name_tag = subnet.tags.detect { |tag| tag.key == 'Name' } @@ -180,11 +181,11 @@ def self.load_balancer_to_hash(region, load_balancer, ref_catalog=nil) catalog_security_groups = ref_catalog.resources.select do |rec| rec.is_a? Puppet::Type::Ec2_securitygroup and load_balancer.security_groups.include? rec.provider.id end - end - catalog_security_groups.each do |rec| - security_group_names << rec.provider.name - security_groups_to_resolve.delete(rec.provider.id) + catalog_security_groups.each do |rec| + security_group_names << rec.provider.name + security_groups_to_resolve.delete(rec.provider.id) + end end if security_groups_to_resolve.size > 0 @@ -192,7 +193,7 @@ def self.load_balancer_to_hash(region, load_balancer, ref_catalog=nil) # convert from IDs to names have not been found in the catalog, in # which case, we must make the call to AWS to get the security group # information we need to make the translation. - Puppet.debug('calling ec2_client for security_groups') + Puppet.debug('Calling ec2_client for security_groups') group_response = ec2_client(region).describe_security_groups(group_ids: security_groups_to_resolve) group_response.data.security_groups.collect(&:group_name).each do |sg_name| security_group_names << sg_name @@ -257,6 +258,10 @@ def health_check=(value) }) end + def listeners=(value) + Puppet.debug("Requesting listeners #{value.inspect} for ELB #{name} in region #{target_region}") + end + def update Puppet.info("Updating load balancer #{name} in region #{target_region}") instances = resource[:instances] @@ -273,6 +278,11 @@ def update update_subnets(resource[:subnets]) end end + + unless @property_hash[:listeners] == resource[:listeners] + update_listeners + end + end def fail_if_availability_zones_changed @@ -281,6 +291,140 @@ def fail_if_availability_zones_changed end end + def update_listeners + # Listeners are identified uniquely by their 'load_balancer_port' key. As + # such, we can collect a list of ports that should exist, and compare that + # to the ones that already exist to make decisions about which to remove, + # which to add, and which need modification. The modification is a bit of + # a misnomer, since it really ends up being a delete followed by an add. + + is_listener_ports = @property_hash[:listeners].collect {|x| x['load_balancer_port'].to_i } + should_listener_ports = resource[:listeners].collect {|x| x['load_balancer_port'].to_i } + + # Collect a list of ports for listeners that should be deleted + listeners_to_delete = is_listener_ports.collect {|listener_port| + # Get the 'is' listener port and check if it 'should' exist + listener_port unless should_listener_ports.include? listener_port + }.compact + + # Collect a list of ports for listeners that should be created + listeners_to_create = should_listener_ports.collect {|listener_port| + # Get the 'should' listener port and check if already exists in 'is' + listener_port unless is_listener_ports.include? listener_port + }.compact + + resource[:listeners].each do |should_listener| + # If our current should listeners is already known to need creating, then + # we can safely skip comparison + next if listeners_to_create.include? should_listener['load_balancer_port'] + + # Identify and retrieve the existing listener to our current 'should' + # listener by port + is_listener = @property_hash[:listeners].select {|x| + x['load_balancer_port'].to_i == should_listener['load_balancer_port'].to_i + }.first + + # Unless we found a match, there is no comparison needed + next unless is_listener + + # We arrive here if the load_balancer_ports match, but + # @property_hash[:listeners] needs updating. Thus we must compare what + # is to what should be. + + # When comparing listeners, the following are possible keys to look at. + # There is also a key for 'policy_names', but that is updated separated, + # so when identifying equality of what is and what should be, the + # following list of keys is sufficient. + keys_to_compare = [ 'instance_port', 'instance_protocol', + 'load_balancer_port', 'protocol', + 'ssl_certificate_id' ] + + # Build the hashes to compare from what is and what should be, using the + # above keys. + should_hash = {} + is_hash = {} + keys_to_compare.each do |k| + if should_listener[k] + should_hash[k] = should_listener[k] + end + + if is_listener[k] + is_hash[k] = is_listener[k] + end + end + + # Perform the comparison after normalizing the values from each. + if self.class.normalize_values(is_hash) != self.class.normalize_values(should_hash) + # This queues up the modify by adding the load_balancer_port to both + # the add and delete arrays. + + # Add the port for deletion if its not already there + unless listeners_to_delete.include? is_listener['load_balancer_port'].to_i + listeners_to_delete << is_listener['load_balancer_port'].to_i + end + + # Add the port for creation if its not already there + unless listeners_to_create.include? should_listener['load_balancer_port'].to_i + listeners_to_create << should_listener['load_balancer_port'].to_i + end + end + end + + # Perform the delete for listeners that need not exist + if listeners_to_delete.size > 0 + Puppet.debug("deleting listeners #{listeners_to_delete} on ELB #{resource[:name]}") + elb_client.delete_load_balancer_listeners({ + load_balancer_name: resource[:name], + load_balancer_ports: listeners_to_delete, + }) + end + + # Perform the create for listeners that should exist but don't + if listeners_to_create.size > 0 + listeners = resource[:listeners].collect {|listener| + if listeners_to_create.include? listener['load_balancer_port'].to_i + hsh = { + protocol: listener['protocol'], + load_balancer_port: listener['load_balancer_port'], + instance_protocol: listener['instance_protocol'], + instance_port: listener['instance_port'], + } + if listener['ssl_certificate_id'] + hsh['ssl_certificate_id'] = listener['ssl_certificate_id'] + end + + hsh + end + }.compact + + Puppet.debug("Creating listeners #{listeners} on ELB #{resource[:name]}") + elb_client.create_load_balancer_listeners({ + load_balancer_name: resource[:name], + listeners: listeners + }) + end + + resource[:listeners].each do |should_listener| + # If the resource does not specify a policy_name, do nothing + next unless should_listener['policy_names'] + + # Match the should_listener to the is_listener + is_listener = @property_hash[:listeners].select {|x| + x['load_balancer_port'].to_i == should_listener['load_balancer_port'].to_i + }.first + + # Update the working listener policy if requested + if should_listener['policy_names'] and should_listener['policy_names'] != is_listener['policy_names'] + Puppet.debug("Calling elb_client for policy_names update on #{resource[:name]}") + elb_client.set_load_balancer_policies_of_listener({ + load_balancer_name: resource[:name], + load_balancer_port: should_listener['load_balancer_port'], + policy_names: should_listener['policy_names'], + }) + end + end + end + def update_subnets(value) if @property_hash[:subnets].empty? && !value.empty? fail 'Cannot set subnets on a EC2 instance' diff --git a/lib/puppet/type/elb_loadbalancer.rb b/lib/puppet/type/elb_loadbalancer.rb index a9792be9..862d4c71 100644 --- a/lib/puppet/type/elb_loadbalancer.rb +++ b/lib/puppet/type/elb_loadbalancer.rb @@ -24,12 +24,13 @@ newproperty(:listeners, :array_matching => :all) do desc 'The ports and protocols the load balancer listens to.' def insync?(is) - normalise(is).to_set == normalise(should).to_set - end - def normalise(listeners) - listeners.collect do |obj| + one = provider.class.normalize_values(is).collect do |obj| + obj.each { |k,v| obj[k] = v.to_s.downcase } + end + two = provider.class.normalize_values(should).collect do |obj| obj.each { |k,v| obj[k] = v.to_s.downcase } end + one == two end validate do |value| value = [value] unless value.is_a?(Array) From b210472f39b12b7fa6bc154c350596730282753f Mon Sep 17 00:00:00 2001 From: Ben Dalling Date: Thu, 15 Dec 2016 21:04:51 +0000 Subject: [PATCH 22/72] Remove contradictory attribute descriptions. --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index ba59ce12..9830b095 100644 --- a/README.md +++ b/README.md @@ -819,9 +819,6 @@ routes => [ #####`route_table` The route table to attach to the subnet. This parameter is set at creation only; it is not affected by updates. -#####`region` -*Optional* Region in which to launch the route table. For valid values, see [AWS Regions](http://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region). - #####`routes` *Optional* Individual routes for the routing table. Accepts an array of 'destination_cidr_block' and 'gateway' values: From 57fef439afc40f840a542c2bca5eb5fe2941d615 Mon Sep 17 00:00:00 2001 From: Ben Dalling Date: Sat, 17 Sep 2016 06:42:17 +0100 Subject: [PATCH 23/72] Fixed typo for ec2:DeleteDhcpOptions action in the policy. --- examples/iam-profile/README.md | 2 +- examples/iam-profile/profile.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/iam-profile/README.md b/examples/iam-profile/README.md index ad9c699b..8d9a622a 100644 --- a/examples/iam-profile/README.md +++ b/examples/iam-profile/README.md @@ -51,7 +51,7 @@ add to this profile. "ec2:DeleteVpc", "ec2:DescribeDhcpOptions", "ec2:CreateDhcpOptions", - "ec2:DeleteDhcp_options", + "ec2:DeleteDhcpOptions", "ec2:DescribeCustomerGateways", "ec2:CreateCustomerGateway", "ec2:DeleteCustomerGateway", diff --git a/examples/iam-profile/profile.json b/examples/iam-profile/profile.json index fae4c233..a94ea900 100644 --- a/examples/iam-profile/profile.json +++ b/examples/iam-profile/profile.json @@ -26,7 +26,7 @@ "ec2:DeleteVpc", "ec2:DescribeDhcpOptions", "ec2:CreateDhcpOptions", - "ec2:DeleteDhcp_options", + "ec2:DeleteDhcpOptions", "ec2:DescribeCustomerGateways", "ec2:CreateCustomerGateway", "ec2:DeleteCustomerGateway", From 70082e808d31f7ca20f9b8ab6787e02e1efaa8ed Mon Sep 17 00:00:00 2001 From: Ben Dalling Date: Sat, 17 Sep 2016 06:46:28 +0100 Subject: [PATCH 24/72] The ec2:AssociateDhcpOptions action is required in the policy to allow ec2_vpc_dhcp_options to be associated with ec2_vpc. --- examples/iam-profile/README.md | 1 + examples/iam-profile/profile.json | 1 + 2 files changed, 2 insertions(+) diff --git a/examples/iam-profile/README.md b/examples/iam-profile/README.md index 8d9a622a..3abdda09 100644 --- a/examples/iam-profile/README.md +++ b/examples/iam-profile/README.md @@ -49,6 +49,7 @@ add to this profile. "ec2:DescribeVpcs", "ec2:CreateVpc", "ec2:DeleteVpc", + "ec2:AssociateDhcpOptions", "ec2:DescribeDhcpOptions", "ec2:CreateDhcpOptions", "ec2:DeleteDhcpOptions", diff --git a/examples/iam-profile/profile.json b/examples/iam-profile/profile.json index a94ea900..34677d62 100644 --- a/examples/iam-profile/profile.json +++ b/examples/iam-profile/profile.json @@ -24,6 +24,7 @@ "ec2:DescribeVpcs", "ec2:CreateVpc", "ec2:DeleteVpc", + "ec2:AssociateDhcpOptions", "ec2:DescribeDhcpOptions", "ec2:CreateDhcpOptions", "ec2:DeleteDhcpOptions", From f3451bfd068b5f4b7a874e4e22ebbac9a2d98556 Mon Sep 17 00:00:00 2001 From: apopp Date: Tue, 25 Oct 2016 01:00:01 -0400 Subject: [PATCH 25/72] Modifying logic behind dhcp_options netbios validation removing test for enforcing old value adding tests fixing tests fixing test more elegant way of handling the validation using symbol which is more efficient performance wise --- lib/puppet/type/ec2_vpc_dhcp_options.rb | 7 +++++-- spec/unit/type/ec2_vpc_dhcp_options_spec.rb | 9 ++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/puppet/type/ec2_vpc_dhcp_options.rb b/lib/puppet/type/ec2_vpc_dhcp_options.rb index e1305634..9c66e301 100644 --- a/lib/puppet/type/ec2_vpc_dhcp_options.rb +++ b/lib/puppet/type/ec2_vpc_dhcp_options.rb @@ -68,8 +68,7 @@ def insync?(is) end newproperty(:netbios_node_type) do - desc 'The netbios node type, defaults to 2.' - defaultto '2' + desc 'The netbios node type, the recommended value is 2 (Point-to-Point). Required if Netbios name server is used.' munge do |value| value.to_s end @@ -79,4 +78,8 @@ def insync?(is) end end end + + validate do + fail ('You must specify netbios node type, when using netbios name server.Recommended value is 2') if !self[:netbios_name_servers].nil? && self[:netbios_node_type].nil? + end end diff --git a/spec/unit/type/ec2_vpc_dhcp_options_spec.rb b/spec/unit/type/ec2_vpc_dhcp_options_spec.rb index d1588810..932186d6 100644 --- a/spec/unit/type/ec2_vpc_dhcp_options_spec.rb +++ b/spec/unit/type/ec2_vpc_dhcp_options_spec.rb @@ -47,9 +47,12 @@ }.to raise_error(Puppet::ResourceError, /region should not contain spaces/) end - it 'should default node type to 2' do - srv = type_class.new(:name => 'sample') - expect(srv[:netbios_node_type]).to eq('2') + ['8.8.8.8','2.2.2.2'].each do |value| + it 'require netbios node type when netbios name server is used' do + expect{ + type_class.new(:name => 'sample', :netbios_name_servers => value) + }.to raise_error(Puppet::ResourceError, /You must specify netbios node type, when using netbios name server.Recommended value is 2/) + end end it 'compare a list of domain names with an array correctly' do From a3ab111f9cb81ecc40f3fc06a61efc72972a3a30 Mon Sep 17 00:00:00 2001 From: Hunter Haugen Date: Thu, 12 Jan 2017 09:34:18 -0800 Subject: [PATCH 26/72] Update docs for #377 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9830b095..3cb4f9e2 100644 --- a/README.md +++ b/README.md @@ -748,7 +748,7 @@ The type of customer gateway. The only currently supported value --- and the def *Optional* A list of netbios name servers to use for the DHCP options set. This parameter is set at creation only; it is not affected by updates. Accepts an array. #####`netbios_node_type` -*Optional* The netbios node type. This parameter is set at creation only; it is not affected by updates. Valid values are '1', '2', '4', '8'. Defaults to '2'. +*Optional* The netbios node type. This parameter is set at creation only; it is not affected by updates. Valid values are '1', '2', '4', '8'. #### Type: ec2_vpc_internet_gateway From 26e82bd17eb22fcdd76fc7c8ba5d6963f75eb2b8 Mon Sep 17 00:00:00 2001 From: Dave Seff Date: Wed, 19 Oct 2016 11:21:32 +1000 Subject: [PATCH 27/72] Rds snapshot restore --- README.md | 3 +++ lib/puppet/provider/rds_instance/v2.rb | 11 +++++++++-- lib/puppet/type/rds_instance.rb | 7 +++++++ spec/unit/provider/rds_instance/v2_spec.rb | 3 ++- spec/unit/type/rds_instance_spec.rb | 2 ++ 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3cb4f9e2..0e2f5f26 100644 --- a/README.md +++ b/README.md @@ -1239,6 +1239,9 @@ is deleted. Defaults to false. The name of an associated DB parameter group. Should be a string. This parameter is set at creation only; it is not affected by updates. +#####`restore_snapshot +Specify the snapshot name to optionally trigger creating the RDS DB from a snapshot. + #####`final_db_snapshot_identifier` The name of the snapshot created when the instance is terminated. Note that skip_final_snapshot must be set to false. diff --git a/lib/puppet/provider/rds_instance/v2.rb b/lib/puppet/provider/rds_instance/v2.rb index dd629e76..9fedec32 100644 --- a/lib/puppet/provider/rds_instance/v2.rb +++ b/lib/puppet/provider/rds_instance/v2.rb @@ -113,8 +113,15 @@ def create availability_zone: resource[:availability_zone], } - rds_client(resource[:region]).create_db_instance(config) - + if resource[:restore_snapshot] + Puppet.info("Restoring DB instance #{name} from snapshot #{resource[:restore_snapshot]}") + [:engine_version, :backup_retention_period].each { |k| config.delete(k) } + config[:db_snapshot_identifier] = resource[:restore_snapshot] + rds_client(resource[:region]).restore_db_instance_from_db_snapshot(config) + else + Puppet.info("Starting DB instance #{name}") + rds_client(resource[:region]).create_db_instance(config) + end @property_hash[:ensure] = :present end diff --git a/lib/puppet/type/rds_instance.rb b/lib/puppet/type/rds_instance.rb index f5f64df9..6e8ea4b1 100644 --- a/lib/puppet/type/rds_instance.rb +++ b/lib/puppet/type/rds_instance.rb @@ -213,6 +213,13 @@ def insync?(is) end end + newproperty(:restore_snapshot) do + desc 'The database snapshot to restore as this RDS instance.' + validate do |value| + fail 'restore_snapshot should be a String' unless value.is_a?(String) + end + end + autorequire(:rds_db_securitygroup) do groups = self[:db_security_groups] groups.is_a?(Array) ? groups : [groups] diff --git a/spec/unit/provider/rds_instance/v2_spec.rb b/spec/unit/provider/rds_instance/v2_spec.rb index 5a27c6e1..b081b1c2 100644 --- a/spec/unit/provider/rds_instance/v2_spec.rb +++ b/spec/unit/provider/rds_instance/v2_spec.rb @@ -24,6 +24,7 @@ master_username: 'awsusername', master_user_password: 'the-master-password', multi_az: false, + restore_snapshot: 'some-snapshot-name', ) } @@ -35,4 +36,4 @@ expect(provider).to be_an_instance_of Puppet::Type::Rds_instance::ProviderV2 end -end \ No newline at end of file +end diff --git a/spec/unit/type/rds_instance_spec.rb b/spec/unit/type/rds_instance_spec.rb index 2adb4119..dfa1c55c 100644 --- a/spec/unit/type/rds_instance_spec.rb +++ b/spec/unit/type/rds_instance_spec.rb @@ -35,6 +35,7 @@ :db_parameter_group, :backup_retention_period, :db_subnet, + :restore_snapshot, ] end @@ -91,6 +92,7 @@ 'master_user_password', :db_parameter_group, 'final_db_snapshot_identifier', + 'restore_snapshot', ].each do |property| it "should require #{property} to be a string" do expect(type_class).to require_string_for(property) From 38337196e73adf8eb9c88030d3a471fdae5c3b6d Mon Sep 17 00:00:00 2001 From: Reuben Avery Date: Tue, 26 Jul 2016 10:45:37 -0400 Subject: [PATCH 28/72] early iam_role type and provider development Updating readme --- README.md | 51 ++++++++++ fixtures/vcr_cassettes/create-role.yml | 125 +++++++++++++++++++++++++ fixtures/vcr_cassettes/roles-named.yml | 64 +++++++++++++ lib/puppet/provider/iam_role/v2.rb | 57 +++++++++++ lib/puppet/type/iam_role.rb | 44 +++++++++ spec/acceptance/iam_role_spec.rb | 51 ++++++++++ spec/spec_helper_acceptance.rb | 3 + spec/unit/provider/iam_role/v2_spec.rb | 52 ++++++++++ spec/unit/type/iam_role_spec.rb | 50 ++++++++++ 9 files changed, 497 insertions(+) create mode 100644 fixtures/vcr_cassettes/create-role.yml create mode 100644 fixtures/vcr_cassettes/roles-named.yml create mode 100644 lib/puppet/provider/iam_role/v2.rb create mode 100644 lib/puppet/type/iam_role.rb create mode 100644 spec/acceptance/iam_role_spec.rb create mode 100644 spec/unit/provider/iam_role/v2_spec.rb create mode 100644 spec/unit/type/iam_role_spec.rb diff --git a/README.md b/README.md index 0e2f5f26..bc76f75b 100644 --- a/README.md +++ b/README.md @@ -333,6 +333,7 @@ You can use the aws module to audit AWS resources, launch autoscaling groups in * `iam_group`: Manage IAM groups and their membership. * `iam_policy`: Manage an IAM 'managed' policy. * `iam_policy_attachment`: Manage an IAM 'managed' policy attachments. +* `iam_role`: Manage an IAM role. * `iam_user`: Manage IAM users. * `rds_db_parameter_group`: Allows read access to DB Parameter Groups. * `rds_db_securitygroup`: Sets up an RDS DB Security Group. @@ -1096,6 +1097,56 @@ iam_policy_attachment { 'root': #####`roles` *Optional* An array of role names to attach to the policy. **Role names not mentioned in this array will be detached from the policy.** +#### Type: iam_role +The `iam_role` type manages IAM roles. + +``` +iam_role { 'devtesting': + ensure => present, + policy_document => '[ + { + "Effect": "Allow", + "Principal": { + "Service": "ec2.amazonaws.com" + }, + "Action": "sts:AssumeRole" + } + ]', +} +``` + +All parameters are read-only once created. + +#####`ensure` +Specifies the basic state of the resource. Valid values are 'present', 'absent' + +#####`name` +The name of the IAM role + +#####`path` +Role path (optional) + +#####`policy_document` +A string containing the IAM policy in JSON format which controls which entities may assume this role, e.g. the default: + +``` +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": "ec2.amazonaws.com" + }, + "Action": "sts:AssumeRole" + } + ] +} +``` + +#####`arn` +The Amazon Resource Name for this IAM role. + #### Type: iam_user The `iam_user` type manages user accounts in IAM. Only the user's name is required as the title of the resource. diff --git a/fixtures/vcr_cassettes/create-role.yml b/fixtures/vcr_cassettes/create-role.yml new file mode 100644 index 00000000..2373cd18 --- /dev/null +++ b/fixtures/vcr_cassettes/create-role.yml @@ -0,0 +1,125 @@ +--- +http_interactions: +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=ListRoles&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.3.3 ruby/2.1.7 x86_64-darwin14.0 + X-Amz-Date: + - 20160728T202344Z + X-Amz-Content-Sha256: + - 8e689dc6b69b17003f0460011582254d8643f0dfb48ac46e093a24df58170b3f + Authorization: + - AWS4-HMAC-SHA256 Credential=redacted/20160728/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, + Signature=bfaf846ce12189c1b0a1346f056397b72de78058195dfe675220da75fcfa7a3b + Content-Length: + - '35' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 2e5aa7e2-5501-11e6-b3ac-ab2eb361e21c + Content-Type: + - text/xml + Content-Length: + - '816' + Date: + - Thu, 28 Jul 2016 20:23:43 GMT + body: + encoding: UTF-8 + string: | + + + false + + + / + %7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D + AROAJTVOOGRMNHXZHEQKU + devtest + arn:aws:iam::111111111111:role/devtest + 2016-07-28T20:22:30Z + + + + + 2e5aa7e2-5501-11e6-b3ac-ab2eb361e21c + + + http_version: + recorded_at: Thu, 28 Jul 2016 20:23:44 GMT +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=ListRoles&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.3.3 ruby/2.1.7 x86_64-darwin14.0 + X-Amz-Date: + - 20160728T202344Z + X-Amz-Content-Sha256: + - 8e689dc6b69b17003f0460011582254d8643f0dfb48ac46e093a24df58170b3f + Authorization: + - AWS4-HMAC-SHA256 Credential=redacted/20160728/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, + Signature=bfaf846ce12189c1b0a1346f056397b72de78058195dfe675220da75fcfa7a3b + Content-Length: + - '35' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 2e736006-5501-11e6-a9a1-2131b69057ae + Content-Type: + - text/xml + Content-Length: + - '816' + Date: + - Thu, 28 Jul 2016 20:23:43 GMT + body: + encoding: UTF-8 + string: | + + + false + + + / + %7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D + AROAJTVOOGRMNHXZHEQKU + devtest + arn:aws:iam::111111111111:role/devtest + 2016-07-28T20:22:30Z + + + + + 2e736006-5501-11e6-a9a1-2131b69057ae + + + http_version: + recorded_at: Thu, 28 Jul 2016 20:23:44 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/roles-named.yml b/fixtures/vcr_cassettes/roles-named.yml new file mode 100644 index 00000000..55825a78 --- /dev/null +++ b/fixtures/vcr_cassettes/roles-named.yml @@ -0,0 +1,64 @@ +--- +http_interactions: +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=ListRoles&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.3.3 ruby/2.1.7 x86_64-darwin14.0 + X-Amz-Date: + - 20160728T202344Z + X-Amz-Content-Sha256: + - 8e689dc6b69b17003f0460011582254d8643f0dfb48ac46e093a24df58170b3f + Authorization: + - AWS4-HMAC-SHA256 Credential=redacted/20160728/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, + Signature=bfaf846ce12189c1b0a1346f056397b72de78058195dfe675220da75fcfa7a3b + Content-Length: + - '35' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 2e8f4ba7-5501-11e6-945e-5dbedde336ba + Content-Type: + - text/xml + Content-Length: + - '816' + Date: + - Thu, 28 Jul 2016 20:23:44 GMT + body: + encoding: UTF-8 + string: | + + + false + + + / + %7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D + AROAJTVOOGRMNHXZHEQKU + devtest + arn:aws:iam::111111111111:role/devtest + 2016-07-28T20:22:30Z + + + + + 2e8f4ba7-5501-11e6-945e-5dbedde336ba + + + http_version: + recorded_at: Thu, 28 Jul 2016 20:23:44 GMT +recorded_with: VCR 3.0.3 diff --git a/lib/puppet/provider/iam_role/v2.rb b/lib/puppet/provider/iam_role/v2.rb new file mode 100644 index 00000000..f11956ab --- /dev/null +++ b/lib/puppet/provider/iam_role/v2.rb @@ -0,0 +1,57 @@ +require_relative '../../../puppet_x/puppetlabs/aws.rb' + +require 'uri' + +Puppet::Type.type(:iam_role).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do + confine feature: :aws + + mk_resource_methods + + def self.instances + response = iam_client.list_roles() + response.roles.collect do |role| + policy_data = JSON.parse(URI.unescape(role.assume_role_policy_document)) + policy_document = JSON.pretty_generate(policy_data) + + new({ + name: role.role_name, + ensure: :present, + path: role.path, + arn: role.arn, + policy_document: policy_document, + }) + end + end + + def self.prefetch(resources) + instances.each do |prov| + if resource = resources[prov.name] + resource.provider = prov + end + end + end + + def exists? + Puppet.info("Checking if IAM role #{name} exists") + @property_hash[:ensure] == :present + end + + def create + Puppet.info("Creating IAM role #{name}") + + iam_client.create_role({ + role_name: name, + assume_role_policy_document: resource[:policy_document] + }) + + @property_hash[:ensure] = :present + end + + def destroy + Puppet.info("Deleting IAM role #{name}") + + iam_client.delete_role({role_name: name}) + + @property_hash[:ensure] = :absent + end +end diff --git a/lib/puppet/type/iam_role.rb b/lib/puppet/type/iam_role.rb new file mode 100644 index 00000000..ac08cc93 --- /dev/null +++ b/lib/puppet/type/iam_role.rb @@ -0,0 +1,44 @@ +Puppet::Type.newtype(:iam_role) do + @doc = 'Type representing IAM role.' + + ensurable + + newparam(:name, namevar: true) do + desc 'The name of the role to manage.' + validate do |value| + fail Puppet::Error, 'Empty role names are not allowed' if value == '' + end + end + + newproperty(:path) do + desc 'The path to the role.' + defaultto '/' + + validate do |value| + unless value =~ /^[^\0]+$/ + raise ArgumentError , "'%s' is not a valid path" % value + end + end + end + + newproperty(:policy_document) do + desc 'The policy document JSON string' + defaultto '{"Version": "2012-10-17", "Statement": [{"Effect": "Allow", "Principal": {"Service": "ec2.amazonaws.com"}, "Action": "sts:AssumeRole"}]}' + + validate do |value| + fail Puppet::Error, 'Policy documents must be JSON strings' unless value.is_a? String + end + + munge do |value| + begin + data = JSON.parse(value) + JSON.pretty_generate(data) + rescue + fail('Document string is not valid JSON') + end + end + end + + newproperty(:arn) + +end diff --git a/spec/acceptance/iam_role_spec.rb b/spec/acceptance/iam_role_spec.rb new file mode 100644 index 00000000..468041d6 --- /dev/null +++ b/spec/acceptance/iam_role_spec.rb @@ -0,0 +1,51 @@ +require 'spec_helper_acceptance' +require 'securerandom' + +describe 'iam_role' do + before(:all) do + @default_region = 'us-east-1' + @aws = AwsHelper.new(@default_region) + end + + def find_role(name) + roles = @aws.get_iam_roles(name) + expect(roles.count).to eq(1) + roles.first + end + + describe 'manage an iam_role' do + + before (:all) do + @name = "#{SecureRandom.uuid}" + @config = { + :name => @name, + } + end + + it 'with puppet resource' do + options = {:name => @config[:name], :ensure => 'present'} + result = TestExecutor.puppet_resource('iam_role', options, '--modulepath spec/fixtures/modules/') + expect(result.stderr).not_to match(/Error:/) + expect{ find_role(@config[:name]) }.not_to raise_error + end + + it 'should create an IAM role with the correct name' do + role = find_role(@name) + expect(role.role_name).to eq(@name) + end + + it 'should create an IAM role with a valid ARN' do + role = find_role(@name) + expect(role.arn).to match(/^arn\:aws\:iam\:\:\d+\:\S+$/) + end + + it 'should destroy an IAM role' do + options = {:name => @config[:name], :ensure => 'absent'} + result = TestExecutor.puppet_resource('iam_role', options, '--modulepath spec/fixtures/modules/') + expect(result.stderr).not_to match(/Error:/) + expect(@aws.get_iam_roles(@name)).to be_empty + end + + end + +end diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb index 9fe31f7f..934a53d0 100644 --- a/spec/spec_helper_acceptance.rb +++ b/spec/spec_helper_acceptance.rb @@ -278,6 +278,9 @@ def get_iam_users(name) @iam_client.list_users.users.select { |user| user.user_name == name } end + def get_iam_roles(name) + @iam_client.list_roles.roles.select { |role| role.role_name == name } + end end class TestExecutor diff --git a/spec/unit/provider/iam_role/v2_spec.rb b/spec/unit/provider/iam_role/v2_spec.rb new file mode 100644 index 00000000..3d0c93b1 --- /dev/null +++ b/spec/unit/provider/iam_role/v2_spec.rb @@ -0,0 +1,52 @@ +require 'spec_helper' + +provider_class = Puppet::Type.type(:iam_role).provider(:v2) + +describe provider_class do + + before do + ENV['AWS_ACCESS_KEY_ID'] = 'redacted' + ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' + ENV['AWS_REGION'] = 'sa-east-1' + end + + context 'with the minimum params' do + let(:resource) { + Puppet::Type.type(:iam_role).new( + name: 'testrole', + ) + } + + let(:provider) { resource.provider } + + let(:instance) { provider.class.instances.first } + + it 'should be an instance of the ProviderV2' do + expect(provider).to be_an_instance_of Puppet::Type::Iam_role::ProviderV2 + end + + describe 'self.prefetch' do + it 'exists' do + VCR.use_cassette('create-role') do + provider.class.instances + provider.class.prefetch({}) + end + end + end + + describe 'exists?' do + it 'should correctly report non-existent roles' do + VCR.use_cassette('no-role-named') do + expect(provider.exists?).to be_falsy + end + end + + it 'should correctly find existing roles' do + VCR.use_cassette('roles-named') do + expect(instance.exists?).to be_truthy + end + end + end + + end +end diff --git a/spec/unit/type/iam_role_spec.rb b/spec/unit/type/iam_role_spec.rb new file mode 100644 index 00000000..a60ada64 --- /dev/null +++ b/spec/unit/type/iam_role_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' + +type_class = Puppet::Type.type(:iam_role) + +describe type_class do + + before do + ENV['AWS_ACCESS_KEY_ID'] = 'redacted' + ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' + ENV['AWS_REGION'] = 'sa-east-1' + end + + let :params do + [ + :name, + ] + end + + let :properties do + [ + :ensure, + ] + end + + it 'should have expected properties' do + properties.each do |property| + expect(type_class.properties.map(&:name)).to be_include(property) + end + end + + it 'should have expected parameters' do + params.each do |param| + expect(type_class.parameters).to be_include(param) + end + end + + it 'should require a name' do + expect { + type_class.new({}) + }.to raise_error(Puppet::Error, 'Title or name must be provided') + end + + context 'with a valid name' do + it 'should create a valid instance' do + type_class.new({ name: 'name' }) + end + end + +end + From fa8dc4724ffae396d51673c591505661ccd6586c Mon Sep 17 00:00:00 2001 From: Reuben Avery Date: Tue, 2 Aug 2016 14:21:17 -0400 Subject: [PATCH 29/72] early iam instance profile type development --- .../vcr_cassettes/create-instance-profile.yml | 141 ++++++++++++++++++ .../vcr_cassettes/instance-profiles-named.yml | 72 +++++++++ .../provider/iam_instance_profile/v2.rb | 53 +++++++ lib/puppet/type/iam_instance_profile.rb | 27 ++++ .../provider/iam_instance_profile/v2_spec.rb | 52 +++++++ spec/unit/type/iam_instance_profile_spec.rb | 50 +++++++ 6 files changed, 395 insertions(+) create mode 100644 fixtures/vcr_cassettes/create-instance-profile.yml create mode 100644 fixtures/vcr_cassettes/instance-profiles-named.yml create mode 100644 lib/puppet/provider/iam_instance_profile/v2.rb create mode 100644 lib/puppet/type/iam_instance_profile.rb create mode 100644 spec/unit/provider/iam_instance_profile/v2_spec.rb create mode 100644 spec/unit/type/iam_instance_profile_spec.rb diff --git a/fixtures/vcr_cassettes/create-instance-profile.yml b/fixtures/vcr_cassettes/create-instance-profile.yml new file mode 100644 index 00000000..e480f25c --- /dev/null +++ b/fixtures/vcr_cassettes/create-instance-profile.yml @@ -0,0 +1,141 @@ +--- +http_interactions: +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=ListInstanceProfiles&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.3.3 ruby/2.1.7 x86_64-darwin14.0 + X-Amz-Date: + - 20160802T182439Z + X-Amz-Content-Sha256: + - 44d83e3a0f5f6915cab0b95802111050b054a3353097341089af8a6c2ee48399 + Authorization: + - AWS4-HMAC-SHA256 Credential=redacted/20160802/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=222a01c263b05370d9bac5ddcd7ef1b5072e241be12b2726f5ca3e970ee2b5d1 + Content-Length: + - '46' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 5fc48fe5-58de-11e6-b882-5bb35db703fa + Content-Type: + - text/xml + Content-Length: + - '1253' + Date: + - Tue, 02 Aug 2016 18:24:38 GMT + body: + encoding: UTF-8 + string: | + + + false + + + / + + + / + %7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D + AROAJTVOOGRMNHXZHEQKU + devtest + arn:aws:iam::111111111111:role/devtest + 2016-07-28T20:22:30Z + + + devtest + arn:aws:iam::111111111111:instance-profile/devtest + AIPAIQX3NLS3B64FZNPAU + 2016-07-28T20:22:31Z + + + + + 5fc48fe5-58de-11e6-b882-5bb35db703fa + + + http_version: + recorded_at: Tue, 02 Aug 2016 18:24:39 GMT +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=ListInstanceProfiles&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.3.3 ruby/2.1.7 x86_64-darwin14.0 + X-Amz-Date: + - 20160802T182439Z + X-Amz-Content-Sha256: + - 44d83e3a0f5f6915cab0b95802111050b054a3353097341089af8a6c2ee48399 + Authorization: + - AWS4-HMAC-SHA256 Credential=redacted/20160802/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=222a01c263b05370d9bac5ddcd7ef1b5072e241be12b2726f5ca3e970ee2b5d1 + Content-Length: + - '46' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 5fd46e73-58de-11e6-b882-5bb35db703fa + Content-Type: + - text/xml + Content-Length: + - '1253' + Date: + - Tue, 02 Aug 2016 18:24:38 GMT + body: + encoding: UTF-8 + string: | + + + false + + + / + + + / + %7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D + AROAJTVOOGRMNHXZHEQKU + devtest + arn:aws:iam::111111111111:role/devtest + 2016-07-28T20:22:30Z + + + devtest + arn:aws:iam::111111111111:instance-profile/devtest + AIPAIQX3NLS3B64FZNPAU + 2016-07-28T20:22:31Z + + + + + 5fd46e73-58de-11e6-b882-5bb35db703fa + + + http_version: + recorded_at: Tue, 02 Aug 2016 18:24:39 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/instance-profiles-named.yml b/fixtures/vcr_cassettes/instance-profiles-named.yml new file mode 100644 index 00000000..36c4a194 --- /dev/null +++ b/fixtures/vcr_cassettes/instance-profiles-named.yml @@ -0,0 +1,72 @@ +--- +http_interactions: +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=ListInstanceProfiles&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.3.3 ruby/2.1.7 x86_64-darwin14.0 + X-Amz-Date: + - 20160802T182439Z + X-Amz-Content-Sha256: + - 44d83e3a0f5f6915cab0b95802111050b054a3353097341089af8a6c2ee48399 + Authorization: + - AWS4-HMAC-SHA256 Credential=redacted/20160802/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=222a01c263b05370d9bac5ddcd7ef1b5072e241be12b2726f5ca3e970ee2b5d1 + Content-Length: + - '46' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 5fe92ecc-58de-11e6-945e-5dbedde336ba + Content-Type: + - text/xml + Content-Length: + - '1253' + Date: + - Tue, 02 Aug 2016 18:24:38 GMT + body: + encoding: UTF-8 + string: | + + + false + + + / + + + / + %7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D + AROAJTVOOGRMNHXZHEQKU + devtest + arn:aws:iam::111111111111:role/devtest + 2016-07-28T20:22:30Z + + + devtest + arn:aws:iam::111111111111:instance-profile/devtest + AIPAIQX3NLS3B64FZNPAU + 2016-07-28T20:22:31Z + + + + + 5fe92ecc-58de-11e6-945e-5dbedde336ba + + + http_version: + recorded_at: Tue, 02 Aug 2016 18:24:39 GMT +recorded_with: VCR 3.0.3 diff --git a/lib/puppet/provider/iam_instance_profile/v2.rb b/lib/puppet/provider/iam_instance_profile/v2.rb new file mode 100644 index 00000000..1f9b4ac8 --- /dev/null +++ b/lib/puppet/provider/iam_instance_profile/v2.rb @@ -0,0 +1,53 @@ +require_relative '../../../puppet_x/puppetlabs/aws.rb' + +require 'uri' + +Puppet::Type.type(:iam_instance_profile).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do + confine feature: :aws + + mk_resource_methods + + def self.instances + response = iam_client.list_instance_profiles() + response.instance_profiles.collect do |instance_profile| + new({ + name: instance_profile.instance_profile_name, + ensure: :present, + path: instance_profile.path, + arn: instance_profile.arn, + roles: instance_profile.roles, + }) + end + end + + def self.prefetch(resources) + instances.each do |prov| + if resource = resources[prov.name] + resource.provider = prov + end + end + end + + def exists? + Puppet.info("Checking if IAM instance profile #{name} exists") + @property_hash[:ensure] == :present + end + + def create + Puppet.info("Creating IAM instance profile #{name}") + + iam_client.create_instance_profile({ + instance_profile_name: name, + }) + + @property_hash[:ensure] = :present + end + + def destroy + Puppet.info("Deleting IAM instnace profile #{name}") + + iam_client.delete_instance_profile({ instance_profile_name: name }) + + @property_hash[:ensure] = :absent + end +end diff --git a/lib/puppet/type/iam_instance_profile.rb b/lib/puppet/type/iam_instance_profile.rb new file mode 100644 index 00000000..d4db2e7f --- /dev/null +++ b/lib/puppet/type/iam_instance_profile.rb @@ -0,0 +1,27 @@ +Puppet::Type.newtype(:iam_instance_profile) do + @doc = 'Type representing IAM instance profiles.' + + ensurable + + newparam(:name, namevar: true) do + desc 'The name of the instance profile to manage.' + validate do |value| + fail Puppet::Error, 'Empty instnace profile names are not allowed' if value == '' + end + end + + newproperty(:path) do + desc 'The path of the instance profile.' + defaultto '/' + + validate do |value| + unless value =~ /^[^\0]+$/ + raise ArgumentError , "'%s' is not a valid path" % value + end + end + end + + newproperty(:arn) + + newproperty(:roles) +end diff --git a/spec/unit/provider/iam_instance_profile/v2_spec.rb b/spec/unit/provider/iam_instance_profile/v2_spec.rb new file mode 100644 index 00000000..1f7d51a6 --- /dev/null +++ b/spec/unit/provider/iam_instance_profile/v2_spec.rb @@ -0,0 +1,52 @@ +require 'spec_helper' + +provider_class = Puppet::Type.type(:iam_instance_profile).provider(:v2) + +describe provider_class do + + before do + ENV['AWS_ACCESS_KEY_ID'] = 'redacted' + ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' + ENV['AWS_REGION'] = 'sa-east-1' + end + + context 'with the minimum params' do + let(:resource) { + Puppet::Type.type(:iam_instance_profile).new( + name: 'test_instance_profile', + ) + } + + let(:provider) { resource.provider } + + let(:instance) { provider.class.instances.first } + + it 'should be an instance of the ProviderV2' do + expect(provider).to be_an_instance_of Puppet::Type::Iam_instance_profile::ProviderV2 + end + + describe 'self.prefetch' do + it 'exists' do + VCR.use_cassette('create-instance-profile') do + provider.class.instances + provider.class.prefetch({}) + end + end + end + + describe 'exists?' do + it 'should correctly report non-existent instance profiles' do + VCR.use_cassette('no-instance-profiles-named') do + expect(provider.exists?).to be_falsy + end + end + + it 'should correctly find existing instance profiles' do + VCR.use_cassette('instance-profiles-named') do + expect(instance.exists?).to be_truthy + end + end + end + + end +end diff --git a/spec/unit/type/iam_instance_profile_spec.rb b/spec/unit/type/iam_instance_profile_spec.rb new file mode 100644 index 00000000..86beb95d --- /dev/null +++ b/spec/unit/type/iam_instance_profile_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' + +type_class = Puppet::Type.type(:iam_instance_profile) + +describe type_class do + + before do + ENV['AWS_ACCESS_KEY_ID'] = 'redacted' + ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' + ENV['AWS_REGION'] = 'sa-east-1' + end + + let :params do + [ + :name, + ] + end + + let :properties do + [ + :ensure, + ] + end + + it 'should have expected properties' do + properties.each do |property| + expect(type_class.properties.map(&:name)).to be_include(property) + end + end + + it 'should have expected parameters' do + params.each do |param| + expect(type_class.parameters).to be_include(param) + end + end + + it 'should require a name' do + expect { + type_class.new({}) + }.to raise_error(Puppet::Error, 'Title or name must be provided') + end + + context 'with a valid name' do + it 'should create a valid instance' do + type_class.new({ name: 'name' }) + end + end + +end + From b80ca1d4e9d76c7326ac4730c5e60675bb3fc4db Mon Sep 17 00:00:00 2001 From: Reuben Avery Date: Wed, 3 Aug 2016 15:37:03 -0400 Subject: [PATCH 30/72] iam_role policy_document unescaping html escaped by what seems to be puppet compiler --- lib/puppet/type/iam_role.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/puppet/type/iam_role.rb b/lib/puppet/type/iam_role.rb index ac08cc93..57a3c2df 100644 --- a/lib/puppet/type/iam_role.rb +++ b/lib/puppet/type/iam_role.rb @@ -31,10 +31,10 @@ munge do |value| begin - data = JSON.parse(value) + data = JSON.parse(CGI::unescapeHTML(value)) JSON.pretty_generate(data) - rescue - fail('Document string is not valid JSON') + rescue Exception => e + fail("Document string is not valid JSON: #{e}") end end end From a0985f04f2f69d560ad7d1c863f4eeeaaf6d07da Mon Sep 17 00:00:00 2001 From: Reuben Avery Date: Wed, 3 Aug 2016 15:38:43 -0400 Subject: [PATCH 31/72] finishing up iam_instance_profile type --- .../provider/iam_instance_profile/v2.rb | 43 +++++- lib/puppet/provider/iam_role/v2.rb | 36 +++++ lib/puppet/type/iam_instance_profile.rb | 15 +- .../fixtures/iam_instance_profile.pp.tmpl | 9 ++ spec/acceptance/iam_instance_profile_spec.rb | 129 ++++++++++++++++++ spec/spec_helper_acceptance.rb | 13 ++ 6 files changed, 242 insertions(+), 3 deletions(-) create mode 100644 spec/acceptance/fixtures/iam_instance_profile.pp.tmpl create mode 100644 spec/acceptance/iam_instance_profile_spec.rb diff --git a/lib/puppet/provider/iam_instance_profile/v2.rb b/lib/puppet/provider/iam_instance_profile/v2.rb index 1f9b4ac8..ce879631 100644 --- a/lib/puppet/provider/iam_instance_profile/v2.rb +++ b/lib/puppet/provider/iam_instance_profile/v2.rb @@ -7,6 +7,8 @@ mk_resource_methods + read_only(:arn) + def self.instances response = iam_client.list_instance_profiles() response.instance_profiles.collect do |instance_profile| @@ -43,10 +45,47 @@ def create @property_hash[:ensure] = :present end + def roles=(value) + Puppet.info("Updating roles for #{name} instance profile") + + value.to_a.each do |role| + Puppet.info("Adding #{role} to instance profile #{name}") + + iam_client.add_role_to_instance_profile({ + instance_profile_name: name, + role_name: role + }) + end + + missing_roles = resource[:roles].to_a - value.to_a + missing_roles.to_a.each do |role| + Puppet.info("Removing #{role} from instance profile #{name}") + + iam_client.remove_role_from_instance_profile({ + instance_profile_name: name, + role_name: role + }) + end + end + def destroy - Puppet.info("Deleting IAM instnace profile #{name}") + Puppet.info("Deleting IAM instance profile #{name}") + + @property_hash[:roles].to_a.each do |role| + Puppet.info("Removing #{role.role_name} from instance profile #{name}") + + begin + iam_client.remove_role_from_instance_profile({ + instance_profile_name: name, + role_name: role.role_name + }) + rescue Exception => e + Puppet.warning("Cannot remove: #{e}") + end + + end - iam_client.delete_instance_profile({ instance_profile_name: name }) + iam_client.delete_instance_profile({instance_profile_name: name}) @property_hash[:ensure] = :absent end diff --git a/lib/puppet/provider/iam_role/v2.rb b/lib/puppet/provider/iam_role/v2.rb index f11956ab..2403885c 100644 --- a/lib/puppet/provider/iam_role/v2.rb +++ b/lib/puppet/provider/iam_role/v2.rb @@ -47,9 +47,45 @@ def create @property_hash[:ensure] = :present end + def get_iam_instance_profiles_for_role(role) + response = iam_client.list_instance_profiles_for_role({ + role_name: role + }) + response.data.instance_profiles + end + + def get_iam_attached_policies_for_role(role) + response = iam_client.list_attached_role_policies({ + role_name: role + }) + response.data.attached_policies + end + def destroy Puppet.info("Deleting IAM role #{name}") + profiles = get_iam_instance_profiles_for_role(name) + + profiles.each do |profile| + Puppet.info("Removing #{name} from instance profile #{profile.instance_profile_name}") + + iam_client.remove_role_from_instance_profile({ + instance_profile_name: profile.instance_profile_name, + role_name: name + }) + end + + policies = get_iam_attached_policies_for_role(name) + + policies.each do |policy| + Puppet.info("Detaching #{policy.policy_arn} from role #{name}") + + iam_client.detach_role_policy({ + role_name: name, + policy_arn: policy.policy_arn + }) + end + iam_client.delete_role({role_name: name}) @property_hash[:ensure] = :absent diff --git a/lib/puppet/type/iam_instance_profile.rb b/lib/puppet/type/iam_instance_profile.rb index d4db2e7f..a1974b3f 100644 --- a/lib/puppet/type/iam_instance_profile.rb +++ b/lib/puppet/type/iam_instance_profile.rb @@ -23,5 +23,18 @@ newproperty(:arn) - newproperty(:roles) + newproperty(:roles, :array_matching => :all) do + desc 'The roles to associate the instance profile.' + def insync?(is) + is.to_set == should.to_set + end + validate do |value| + fail 'roles should be a String' unless value.is_a?(String) + end + end + + autorequire(:iam_role) do + roles = self[:roles] + roles.is_a?(Array) ? roles : [roles] + end end diff --git a/spec/acceptance/fixtures/iam_instance_profile.pp.tmpl b/spec/acceptance/fixtures/iam_instance_profile.pp.tmpl new file mode 100644 index 00000000..7f79e913 --- /dev/null +++ b/spec/acceptance/fixtures/iam_instance_profile.pp.tmpl @@ -0,0 +1,9 @@ +iam_role { '{{role_name}}': + ensure => {{ensure}}, + policy_document => '{{role_policy_document}}', +} + +iam_instance_profile { '{{profile_name}}': + ensure => {{ensure}}, + roles => [ '{{role_name}}' ], +} diff --git a/spec/acceptance/iam_instance_profile_spec.rb b/spec/acceptance/iam_instance_profile_spec.rb new file mode 100644 index 00000000..293910a0 --- /dev/null +++ b/spec/acceptance/iam_instance_profile_spec.rb @@ -0,0 +1,129 @@ +require 'spec_helper_acceptance' +require 'securerandom' + +describe 'iam_instance_profile' do + before(:all) do + @default_region = 'us-east-1' + @aws = AwsHelper.new(@default_region) + @template = 'iam_instance_profile.pp.tmpl' + end + + def get_role(name) + roles = @aws.get_iam_roles(name) + expect(roles.count).to eq(1) + roles.first + end + + def get_instance_profile(name) + instance_profiles = @aws.get_iam_instance_profiles(name) + expect(instance_profiles.count).to eq(1) + instance_profiles.first + end + + describe 'managing as puppet resource' do + before :all do + @name = "#{SecureRandom.uuid}" + + @config = { + :role_name => @name, + :profile_name => @name, + :ensure => 'present', + } + end + + it "should create properly with only defaults" do + profile_options = { :name => @config[:profile_name], :ensure => @config[:ensure] } + result = TestExecutor.puppet_resource('iam_instance_profile', profile_options, '--modulepath spec/fixtures/modules/') + expect(result.stderr).not_to match(/Error:/) + end + + it "should have the specified name" do + profile = get_instance_profile(@config[:profile_name]) + expect(profile.instance_profile_name).to eq(@config[:profile_name]) + end + + it "should have a valid ARN" do + profile = get_instance_profile(@config[:profile_name]) + expect(profile.arn).to match(/^arn\:aws\:iam\:\:\d+\:\S+$/) + end + + it "should accept a role assignment after the fact" do + role_options = { :name => @config[:role_name], :ensure => @config[:ensure] } + result = TestExecutor.puppet_resource('iam_role', role_options, '--modulepath spec/fixtures/modules/ --trace') + expect(result.stderr).not_to match(/Error:/) + + profile_options = { :name => @config[:profile_name], :ensure => @config[:ensure], :roles => @config[:role_name] } + result = TestExecutor.puppet_resource('iam_instance_profile', profile_options, '--modulepath spec/fixtures/modules/ --trace') + expect(result.stderr).not_to match(/Error:/) + end + + it "should accept policy attachment" do + policy_options = { :name => 'IAMFullAccess', :roles => @config[:role_name] } + result = TestExecutor.puppet_resource('iam_policy_attachment', policy_options, '--modulepath spec/fixtures/modules/ --trace') + expect(result.stderr).not_to match(/Error:/) + end + + it "should destroy and cleanup properly" do + new_config = @config.update({:ensure => 'absent'}) + + role_options = { :name => new_config[:role_name], :ensure => new_config[:ensure] } + result = TestExecutor.puppet_resource('iam_role', role_options, '--modulepath spec/fixtures/modules/ --trace') + expect(result.stderr).not_to match(/Error:/) + + profile_options = { :name => new_config[:profile_name], :ensure => new_config[:ensure] } + result = TestExecutor.puppet_resource('iam_instance_profile', profile_options, '--modulepath spec/fixtures/modules/ --trace') + expect(result.stderr).not_to match(/Error:/) + end + + end + + describe 'managing via puppet manifest apply' do + + before (:all) do + @name = "#{SecureRandom.uuid}" + @role_policy_json = <<-'JSON' + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": "ec2.amazonaws.com" + }, + "Action": "sts:AssumeRole" + } + ] + } + JSON + + @config = { + :role_name => @name, + :profile_name => @name, + :role_policy_document => @role_policy_json.strip.gsub(/\r\n?/, " "), + :ensure => 'present', + } + end + + it "should compile and apply" do + result = PuppetManifest.new(@template, @config).apply + expect(result.stderr).not_to match(/Error:/) + end + + it "with the specified name" do + profile = get_instance_profile(@config[:profile_name]) + expect(profile.instance_profile_name).to eq(@config[:profile_name]) + end + + it "should have valid ARN" do + profile = get_instance_profile(@config[:profile_name]) + expect(profile.arn).to match(/^arn\:aws\:iam\:\:\d+\:\S+$/) + end + + it "should cleanup properly" do + new_config = @config.update({:ensure => 'absent'}) + result = PuppetManifest.new(@template, new_config).apply + expect(result.stderr).not_to match(/Error:/) + end + end + +end diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb index 934a53d0..b644c103 100644 --- a/spec/spec_helper_acceptance.rb +++ b/spec/spec_helper_acceptance.rb @@ -281,6 +281,19 @@ def get_iam_users(name) def get_iam_roles(name) @iam_client.list_roles.roles.select { |role| role.role_name == name } end + + def get_iam_instance_profiles(name) + @iam_client.list_instance_profiles.instance_profiles.select { |instance_profile| + instance_profile.instance_profile_name == name + } + end + + def get_iam_instance_profiles_for_role(name) + response = @iam_client.list_instance_profiles_for_role( + role_name: [name] + ) + response.data.instance_profiles + end end class TestExecutor From 046b298fd0cfe0213f1c72ae19751085ebbdd76f Mon Sep 17 00:00:00 2001 From: Reuben Avery Date: Fri, 5 Aug 2016 10:47:44 -0400 Subject: [PATCH 32/72] Updating README for iam_instance_profile --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index bc76f75b..50a9f5b8 100644 --- a/README.md +++ b/README.md @@ -331,6 +331,7 @@ You can use the aws module to audit AWS resources, launch autoscaling groups in * `ecs_service`: Manage an Ec2 Container Service service. * `ecs_task_definition`: Manage an Ec2 Container Service task definition. * `iam_group`: Manage IAM groups and their membership. +* `iam_instance_profile`: Manage IAM instance profiles. * `iam_policy`: Manage an IAM 'managed' policy. * `iam_policy_attachment`: Manage an IAM 'managed' policy attachments. * `iam_role`: Manage an IAM role. @@ -1037,6 +1038,24 @@ iam_group { 'root': #####`members` *Required* An array of user names to include in the group. Users not specified in this array will be removed. +#### Type: iam_instance_profile + +```Puppet +iam_instance_profile { 'my_iam_role': + ensure => present, + roles => [ 'my_iam_role' ], +} +``` + +#####`ensure` +Specifies the basic state of the resource. Valid values are 'present', 'absent'. + +#####`name` +*Required* The name of the IAM instance profile. + +#####`roles` +*Optional* The IAM role(s) to associate this instance profile with. Accepts an array for multiple roles. + #### Type: iam_policy [IAM From e70cb6b6715f98cd48f8c342e8826bdb3cfb7c58 Mon Sep 17 00:00:00 2001 From: Reuben Avery Date: Fri, 5 Aug 2016 14:28:23 -0400 Subject: [PATCH 33/72] iam_role and iam_instance_profile: Changing secondary operation messages from Puppet.info to Puppet.debug --- lib/puppet/provider/iam_instance_profile/v2.rb | 10 +++++----- lib/puppet/provider/iam_role/v2.rb | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/puppet/provider/iam_instance_profile/v2.rb b/lib/puppet/provider/iam_instance_profile/v2.rb index ce879631..9a40ea18 100644 --- a/lib/puppet/provider/iam_instance_profile/v2.rb +++ b/lib/puppet/provider/iam_instance_profile/v2.rb @@ -31,7 +31,7 @@ def self.prefetch(resources) end def exists? - Puppet.info("Checking if IAM instance profile #{name} exists") + Puppet.debug("Checking if IAM instance profile #{name} exists") @property_hash[:ensure] == :present end @@ -46,10 +46,10 @@ def create end def roles=(value) - Puppet.info("Updating roles for #{name} instance profile") + Puppet.debug("Updating roles for #{name} instance profile") value.to_a.each do |role| - Puppet.info("Adding #{role} to instance profile #{name}") + Puppet.debug("Adding #{role} to instance profile #{name}") iam_client.add_role_to_instance_profile({ instance_profile_name: name, @@ -59,7 +59,7 @@ def roles=(value) missing_roles = resource[:roles].to_a - value.to_a missing_roles.to_a.each do |role| - Puppet.info("Removing #{role} from instance profile #{name}") + Puppet.debug("Removing #{role} from instance profile #{name}") iam_client.remove_role_from_instance_profile({ instance_profile_name: name, @@ -72,7 +72,7 @@ def destroy Puppet.info("Deleting IAM instance profile #{name}") @property_hash[:roles].to_a.each do |role| - Puppet.info("Removing #{role.role_name} from instance profile #{name}") + Puppet.debug("Removing #{role.role_name} from instance profile #{name}") begin iam_client.remove_role_from_instance_profile({ diff --git a/lib/puppet/provider/iam_role/v2.rb b/lib/puppet/provider/iam_role/v2.rb index 2403885c..77c5159e 100644 --- a/lib/puppet/provider/iam_role/v2.rb +++ b/lib/puppet/provider/iam_role/v2.rb @@ -67,7 +67,7 @@ def destroy profiles = get_iam_instance_profiles_for_role(name) profiles.each do |profile| - Puppet.info("Removing #{name} from instance profile #{profile.instance_profile_name}") + Puppet.debug("Removing #{name} from instance profile #{profile.instance_profile_name}") iam_client.remove_role_from_instance_profile({ instance_profile_name: profile.instance_profile_name, @@ -78,7 +78,7 @@ def destroy policies = get_iam_attached_policies_for_role(name) policies.each do |policy| - Puppet.info("Detaching #{policy.policy_arn} from role #{name}") + Puppet.debug("Detaching #{policy.policy_arn} from role #{name}") iam_client.detach_role_policy({ role_name: name, From cc836cdd46ef30393e45836d35c93bc4b69aedec Mon Sep 17 00:00:00 2001 From: Reuben Avery Date: Tue, 9 Aug 2016 18:05:02 -0400 Subject: [PATCH 34/72] Adding support for path prefixes to iam_role and iam_instance_profile --- lib/puppet/provider/iam_instance_profile/v2.rb | 1 + lib/puppet/provider/iam_role/v2.rb | 1 + .../fixtures/iam_instance_profile.pp.tmpl | 2 ++ spec/acceptance/iam_instance_profile_spec.rb | 15 ++++++++++----- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/puppet/provider/iam_instance_profile/v2.rb b/lib/puppet/provider/iam_instance_profile/v2.rb index 9a40ea18..563f7d8f 100644 --- a/lib/puppet/provider/iam_instance_profile/v2.rb +++ b/lib/puppet/provider/iam_instance_profile/v2.rb @@ -40,6 +40,7 @@ def create iam_client.create_instance_profile({ instance_profile_name: name, + path: resource[:path], }) @property_hash[:ensure] = :present diff --git a/lib/puppet/provider/iam_role/v2.rb b/lib/puppet/provider/iam_role/v2.rb index 77c5159e..f18bae91 100644 --- a/lib/puppet/provider/iam_role/v2.rb +++ b/lib/puppet/provider/iam_role/v2.rb @@ -41,6 +41,7 @@ def create iam_client.create_role({ role_name: name, + path: resource[:path], assume_role_policy_document: resource[:policy_document] }) diff --git a/spec/acceptance/fixtures/iam_instance_profile.pp.tmpl b/spec/acceptance/fixtures/iam_instance_profile.pp.tmpl index 7f79e913..f83b5dde 100644 --- a/spec/acceptance/fixtures/iam_instance_profile.pp.tmpl +++ b/spec/acceptance/fixtures/iam_instance_profile.pp.tmpl @@ -1,9 +1,11 @@ iam_role { '{{role_name}}': ensure => {{ensure}}, + path => '{{path}}', policy_document => '{{role_policy_document}}', } iam_instance_profile { '{{profile_name}}': ensure => {{ensure}}, + path => '{{path}}', roles => [ '{{role_name}}' ], } diff --git a/spec/acceptance/iam_instance_profile_spec.rb b/spec/acceptance/iam_instance_profile_spec.rb index 293910a0..7d96093e 100644 --- a/spec/acceptance/iam_instance_profile_spec.rb +++ b/spec/acceptance/iam_instance_profile_spec.rb @@ -27,12 +27,13 @@ def get_instance_profile(name) @config = { :role_name => @name, :profile_name => @name, + :path_prefix => "/#{SecureRandom.hex(8)}/", :ensure => 'present', } end it "should create properly with only defaults" do - profile_options = { :name => @config[:profile_name], :ensure => @config[:ensure] } + profile_options = { :name => @config[:profile_name], :path => @config[:path_prefix], :ensure => @config[:ensure] } result = TestExecutor.puppet_resource('iam_instance_profile', profile_options, '--modulepath spec/fixtures/modules/') expect(result.stderr).not_to match(/Error:/) end @@ -45,14 +46,15 @@ def get_instance_profile(name) it "should have a valid ARN" do profile = get_instance_profile(@config[:profile_name]) expect(profile.arn).to match(/^arn\:aws\:iam\:\:\d+\:\S+$/) + expect(profile.arn).to include("#{@config[:path]}#{@config[:profile_name]}") end it "should accept a role assignment after the fact" do - role_options = { :name => @config[:role_name], :ensure => @config[:ensure] } + role_options = { :name => @config[:role_name], :path => @config[:path_prefix], :ensure => @config[:ensure] } result = TestExecutor.puppet_resource('iam_role', role_options, '--modulepath spec/fixtures/modules/ --trace') expect(result.stderr).not_to match(/Error:/) - profile_options = { :name => @config[:profile_name], :ensure => @config[:ensure], :roles => @config[:role_name] } + profile_options = { :name => @config[:profile_name], :path => @config[:path_prefix], :ensure => @config[:ensure], :roles => @config[:role_name] } result = TestExecutor.puppet_resource('iam_instance_profile', profile_options, '--modulepath spec/fixtures/modules/ --trace') expect(result.stderr).not_to match(/Error:/) end @@ -66,11 +68,11 @@ def get_instance_profile(name) it "should destroy and cleanup properly" do new_config = @config.update({:ensure => 'absent'}) - role_options = { :name => new_config[:role_name], :ensure => new_config[:ensure] } + role_options = { :name => new_config[:role_name], :path => @config[:path_prefix], :ensure => new_config[:ensure] } result = TestExecutor.puppet_resource('iam_role', role_options, '--modulepath spec/fixtures/modules/ --trace') expect(result.stderr).not_to match(/Error:/) - profile_options = { :name => new_config[:profile_name], :ensure => new_config[:ensure] } + profile_options = { :name => new_config[:profile_name], :path => @config[:path_prefix], :ensure => new_config[:ensure] } result = TestExecutor.puppet_resource('iam_instance_profile', profile_options, '--modulepath spec/fixtures/modules/ --trace') expect(result.stderr).not_to match(/Error:/) end @@ -81,6 +83,7 @@ def get_instance_profile(name) before (:all) do @name = "#{SecureRandom.uuid}" + @path_prefix = "/#{SecureRandom.hex(8)}/" @role_policy_json = <<-'JSON' { "Version": "2012-10-17", @@ -99,6 +102,7 @@ def get_instance_profile(name) @config = { :role_name => @name, :profile_name => @name, + :path => @path_prefix, :role_policy_document => @role_policy_json.strip.gsub(/\r\n?/, " "), :ensure => 'present', } @@ -117,6 +121,7 @@ def get_instance_profile(name) it "should have valid ARN" do profile = get_instance_profile(@config[:profile_name]) expect(profile.arn).to match(/^arn\:aws\:iam\:\:\d+\:\S+$/) + expect(profile.arn).to include("#{@config[:path]}#{@config[:profile_name]}") end it "should cleanup properly" do From 93e976c03c4b4dd107e36f63d5fba59606b4ea54 Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Mon, 14 Nov 2016 13:31:00 +0000 Subject: [PATCH 35/72] Add functionality to support elbv2 load balancers - Add fix for using ec2_launchconfiguration with existing configs but no block_device_mappings (defaults to []) - add termination_policies and target_group support - update README.md --- README.md | 6 +++ .../provider/ec2_autoscalinggroup/v2.rb | 44 +++++++++++++++++++ lib/puppet/type/ec2_autoscalinggroup.rb | 18 ++++++++ lib/puppet_x/puppetlabs/aws.rb | 8 ++++ 4 files changed, 76 insertions(+) diff --git a/README.md b/README.md index 50a9f5b8..594aec55 100644 --- a/README.md +++ b/README.md @@ -601,9 +601,15 @@ back- end instances. Accepts a hash with the following keys: ##### `load_balancers` *Optional* A list of load balancer names that should be attached to this autoscaling group. +##### `target_groups` +*Optional* A list of ELBv2 Target Group names that should be attached to this autoscaling group. + ##### `subnets` *Optional* The subnets to associate with the autoscaling group. +##### `termination_policies` +*Optional* A list of termination policies to use when scaling in instances. For valid termination policies, see [Controlling Which Instances Auto Scaling Terminates During Scale In](http://docs.aws.amazon.com/autoscaling/latest/userguide/as-instance-termination.html). + #####`tags` *Optional* The tags to assign to the autoscaling group. Accepts a 'key => value' hash of tags. The tags are not propagated to launched instances. diff --git a/lib/puppet/provider/ec2_autoscalinggroup/v2.rb b/lib/puppet/provider/ec2_autoscalinggroup/v2.rb index 093b5953..d0a413ca 100644 --- a/lib/puppet/provider/ec2_autoscalinggroup/v2.rb +++ b/lib/puppet/provider/ec2_autoscalinggroup/v2.rb @@ -59,6 +59,8 @@ def self.group_to_hash(region, group) health_check_grace_period: group.health_check_grace_period, new_instances_protected_from_scale_in: group.new_instances_protected_from_scale_in, load_balancers: fetch_load_balancers(autoscaling_client(region), group.auto_scaling_group_name), + target_groups: fetch_target_groups(region, group.auto_scaling_group_name), + termination_policies: group.termination_policies, instance_count: group.instances.count, ensure: :present, subnets: subnet_names, @@ -72,6 +74,17 @@ def self.fetch_load_balancers(client, name) response.load_balancers.collect { |lb| lb.load_balancer_name } end + def self.fetch_target_groups(region, name) + response = autoscaling_client(region).describe_load_balancer_target_groups(auto_scaling_group_name: name) + response.load_balancer_target_groups.collect { |tg| fetch_target_group_name(region, tg.load_balancer_target_group_arn) }.flatten + end + + def self.fetch_target_group_name(region, value) + arn = value.is_a?(Array) ? value : [value] + response = elbv2_client(region).describe_target_groups(target_group_arns: arn) + response.target_groups.collect { |tg| tg.target_group_name } + end + def exists? Puppet.debug("Checking if auto scaling group #{name} exists in region #{target_region}") @property_hash[:ensure] == :present @@ -177,6 +190,14 @@ def subnets=(value) ) end + def termination_policies=(value) + policies = value.is_a?(Array) ? value : [value] + autoscaling_client(target_region).update_auto_scaling_group( + auto_scaling_group_name: name, + termination_policies: policies, + ) + end + def availability_zones=(value) zones = value.is_a?(Array) ? value : [value] autoscaling_client(target_region).update_auto_scaling_group( @@ -185,6 +206,29 @@ def availability_zones=(value) ) end + def target_groups=(value) + should_names = value.is_a?(Array) ? value : [value] + + response = elbv2_client(target_region).describe_target_groups(names: should_names) + should = (response.target_groups.collect { |tg| tg.target_group_arn }).to_set + + response = elbv2_client(target_region).describe_target_groups(names: target_groups) + is = (response.target_groups.collect { |tg| tg.target_group_arn }).to_set + + to_delete = is - should + to_add = should - is + + autoscaling_client(target_region).attach_load_balancer_target_groups( + auto_scaling_group_name: name, + target_group_arns: to_add, + ) + autoscaling_client(target_region).detach_load_balancer_target_groups( + auto_scaling_group_name: name, + target_group_arns: to_delete, + ) + + end + def load_balancers=(value) should = (value.is_a?(Array) ? value : [value]).to_set is = fetch_load_balancers(autoscaling_client(target_region), name).to_set diff --git a/lib/puppet/type/ec2_autoscalinggroup.rb b/lib/puppet/type/ec2_autoscalinggroup.rb index 44b73ce0..45cb1298 100644 --- a/lib/puppet/type/ec2_autoscalinggroup.rb +++ b/lib/puppet/type/ec2_autoscalinggroup.rb @@ -135,6 +135,24 @@ def insync?(is) end end + newproperty(:target_groups, :array_matching => :all) do + desc 'The target groups attached to this group.' + validate do |value| + fail 'target_groups cannot be blank' if value == '' + fail 'target_groups should be a String' unless value.is_a?(String) + end + def insync?(is) + is.to_set == should.to_set + end + end + + newproperty(:termination_policies, :array_matching => :all) do + desc 'The termination policies attached to this group.' + def insync?(is) + is.to_set == should.to_set + end + end + newproperty(:subnets, :array_matching => :all) do desc 'The subnets to associate the autoscaling group.' validate do |value| diff --git a/lib/puppet_x/puppetlabs/aws.rb b/lib/puppet_x/puppetlabs/aws.rb index 5b7fd9c9..184631d0 100644 --- a/lib/puppet_x/puppetlabs/aws.rb +++ b/lib/puppet_x/puppetlabs/aws.rb @@ -162,6 +162,14 @@ def elb_client(region = default_region) self.class.elb_client(region) end + def self.elbv2_client(region = default_region) + ::Aws::ElasticLoadBalancingV2::Client.new(client_config(region)) + end + + def elbv2_client(region = default_region) + self.class.elbv2_client(region) + end + def self.autoscaling_client(region = default_region) ::Aws::AutoScaling::Client.new(client_config(region)) end From f425ce6253712541410a6443c189e24aa9cd32da Mon Sep 17 00:00:00 2001 From: Hunter Haugen Date: Thu, 12 Jan 2017 09:46:35 -0800 Subject: [PATCH 36/72] (maint) Comment out iam acceptance tests Our internal AWS testing credentials do not have the ability to manage iam credentials, but we don't want to delete the tests. --- spec/acceptance/iam_instance_profile_spec.rb | 268 +++++++++---------- spec/acceptance/iam_role_spec.rb | 102 +++---- spec/acceptance/iam_user_spec.rb | 112 ++++---- 3 files changed, 241 insertions(+), 241 deletions(-) diff --git a/spec/acceptance/iam_instance_profile_spec.rb b/spec/acceptance/iam_instance_profile_spec.rb index 7d96093e..487677a7 100644 --- a/spec/acceptance/iam_instance_profile_spec.rb +++ b/spec/acceptance/iam_instance_profile_spec.rb @@ -1,134 +1,134 @@ -require 'spec_helper_acceptance' -require 'securerandom' - -describe 'iam_instance_profile' do - before(:all) do - @default_region = 'us-east-1' - @aws = AwsHelper.new(@default_region) - @template = 'iam_instance_profile.pp.tmpl' - end - - def get_role(name) - roles = @aws.get_iam_roles(name) - expect(roles.count).to eq(1) - roles.first - end - - def get_instance_profile(name) - instance_profiles = @aws.get_iam_instance_profiles(name) - expect(instance_profiles.count).to eq(1) - instance_profiles.first - end - - describe 'managing as puppet resource' do - before :all do - @name = "#{SecureRandom.uuid}" - - @config = { - :role_name => @name, - :profile_name => @name, - :path_prefix => "/#{SecureRandom.hex(8)}/", - :ensure => 'present', - } - end - - it "should create properly with only defaults" do - profile_options = { :name => @config[:profile_name], :path => @config[:path_prefix], :ensure => @config[:ensure] } - result = TestExecutor.puppet_resource('iam_instance_profile', profile_options, '--modulepath spec/fixtures/modules/') - expect(result.stderr).not_to match(/Error:/) - end - - it "should have the specified name" do - profile = get_instance_profile(@config[:profile_name]) - expect(profile.instance_profile_name).to eq(@config[:profile_name]) - end - - it "should have a valid ARN" do - profile = get_instance_profile(@config[:profile_name]) - expect(profile.arn).to match(/^arn\:aws\:iam\:\:\d+\:\S+$/) - expect(profile.arn).to include("#{@config[:path]}#{@config[:profile_name]}") - end - - it "should accept a role assignment after the fact" do - role_options = { :name => @config[:role_name], :path => @config[:path_prefix], :ensure => @config[:ensure] } - result = TestExecutor.puppet_resource('iam_role', role_options, '--modulepath spec/fixtures/modules/ --trace') - expect(result.stderr).not_to match(/Error:/) - - profile_options = { :name => @config[:profile_name], :path => @config[:path_prefix], :ensure => @config[:ensure], :roles => @config[:role_name] } - result = TestExecutor.puppet_resource('iam_instance_profile', profile_options, '--modulepath spec/fixtures/modules/ --trace') - expect(result.stderr).not_to match(/Error:/) - end - - it "should accept policy attachment" do - policy_options = { :name => 'IAMFullAccess', :roles => @config[:role_name] } - result = TestExecutor.puppet_resource('iam_policy_attachment', policy_options, '--modulepath spec/fixtures/modules/ --trace') - expect(result.stderr).not_to match(/Error:/) - end - - it "should destroy and cleanup properly" do - new_config = @config.update({:ensure => 'absent'}) - - role_options = { :name => new_config[:role_name], :path => @config[:path_prefix], :ensure => new_config[:ensure] } - result = TestExecutor.puppet_resource('iam_role', role_options, '--modulepath spec/fixtures/modules/ --trace') - expect(result.stderr).not_to match(/Error:/) - - profile_options = { :name => new_config[:profile_name], :path => @config[:path_prefix], :ensure => new_config[:ensure] } - result = TestExecutor.puppet_resource('iam_instance_profile', profile_options, '--modulepath spec/fixtures/modules/ --trace') - expect(result.stderr).not_to match(/Error:/) - end - - end - - describe 'managing via puppet manifest apply' do - - before (:all) do - @name = "#{SecureRandom.uuid}" - @path_prefix = "/#{SecureRandom.hex(8)}/" - @role_policy_json = <<-'JSON' - { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Principal": { - "Service": "ec2.amazonaws.com" - }, - "Action": "sts:AssumeRole" - } - ] - } - JSON - - @config = { - :role_name => @name, - :profile_name => @name, - :path => @path_prefix, - :role_policy_document => @role_policy_json.strip.gsub(/\r\n?/, " "), - :ensure => 'present', - } - end - - it "should compile and apply" do - result = PuppetManifest.new(@template, @config).apply - expect(result.stderr).not_to match(/Error:/) - end - - it "with the specified name" do - profile = get_instance_profile(@config[:profile_name]) - expect(profile.instance_profile_name).to eq(@config[:profile_name]) - end - - it "should have valid ARN" do - profile = get_instance_profile(@config[:profile_name]) - expect(profile.arn).to match(/^arn\:aws\:iam\:\:\d+\:\S+$/) - expect(profile.arn).to include("#{@config[:path]}#{@config[:profile_name]}") - end - - it "should cleanup properly" do - new_config = @config.update({:ensure => 'absent'}) - result = PuppetManifest.new(@template, new_config).apply - expect(result.stderr).not_to match(/Error:/) - end - end - -end +#require 'spec_helper_acceptance' +#require 'securerandom' +# +#describe 'iam_instance_profile' do +# before(:all) do +# @default_region = 'us-east-1' +# @aws = AwsHelper.new(@default_region) +# @template = 'iam_instance_profile.pp.tmpl' +# end +# +# def get_role(name) +# roles = @aws.get_iam_roles(name) +# expect(roles.count).to eq(1) +# roles.first +# end +# +# def get_instance_profile(name) +# instance_profiles = @aws.get_iam_instance_profiles(name) +# expect(instance_profiles.count).to eq(1) +# instance_profiles.first +# end +# +# describe 'managing as puppet resource' do +# before :all do +# @name = "#{SecureRandom.uuid}" +# +# @config = { +# :role_name => @name, +# :profile_name => @name, +# :path_prefix => "/#{SecureRandom.hex(8)}/", +# :ensure => 'present', +# } +# end +# +# it "should create properly with only defaults" do +# profile_options = { :name => @config[:profile_name], :path => @config[:path_prefix], :ensure => @config[:ensure] } +# result = TestExecutor.puppet_resource('iam_instance_profile', profile_options, '--modulepath spec/fixtures/modules/') +# expect(result.stderr).not_to match(/Error:/) +# end +# +# it "should have the specified name" do +# profile = get_instance_profile(@config[:profile_name]) +# expect(profile.instance_profile_name).to eq(@config[:profile_name]) +# end +# +# it "should have a valid ARN" do +# profile = get_instance_profile(@config[:profile_name]) +# expect(profile.arn).to match(/^arn\:aws\:iam\:\:\d+\:\S+$/) +# expect(profile.arn).to include("#{@config[:path]}#{@config[:profile_name]}") +# end +# +# it "should accept a role assignment after the fact" do +# role_options = { :name => @config[:role_name], :path => @config[:path_prefix], :ensure => @config[:ensure] } +# result = TestExecutor.puppet_resource('iam_role', role_options, '--modulepath spec/fixtures/modules/ --trace') +# expect(result.stderr).not_to match(/Error:/) +# +# profile_options = { :name => @config[:profile_name], :path => @config[:path_prefix], :ensure => @config[:ensure], :roles => @config[:role_name] } +# result = TestExecutor.puppet_resource('iam_instance_profile', profile_options, '--modulepath spec/fixtures/modules/ --trace') +# expect(result.stderr).not_to match(/Error:/) +# end +# +# it "should accept policy attachment" do +# policy_options = { :name => 'IAMFullAccess', :roles => @config[:role_name] } +# result = TestExecutor.puppet_resource('iam_policy_attachment', policy_options, '--modulepath spec/fixtures/modules/ --trace') +# expect(result.stderr).not_to match(/Error:/) +# end +# +# it "should destroy and cleanup properly" do +# new_config = @config.update({:ensure => 'absent'}) +# +# role_options = { :name => new_config[:role_name], :path => @config[:path_prefix], :ensure => new_config[:ensure] } +# result = TestExecutor.puppet_resource('iam_role', role_options, '--modulepath spec/fixtures/modules/ --trace') +# expect(result.stderr).not_to match(/Error:/) +# +# profile_options = { :name => new_config[:profile_name], :path => @config[:path_prefix], :ensure => new_config[:ensure] } +# result = TestExecutor.puppet_resource('iam_instance_profile', profile_options, '--modulepath spec/fixtures/modules/ --trace') +# expect(result.stderr).not_to match(/Error:/) +# end +# +# end +# +# describe 'managing via puppet manifest apply' do +# +# before (:all) do +# @name = "#{SecureRandom.uuid}" +# @path_prefix = "/#{SecureRandom.hex(8)}/" +# @role_policy_json = <<-'JSON' +# { +# "Version": "2012-10-17", +# "Statement": [ +# { +# "Effect": "Allow", +# "Principal": { +# "Service": "ec2.amazonaws.com" +# }, +# "Action": "sts:AssumeRole" +# } +# ] +# } +# JSON +# +# @config = { +# :role_name => @name, +# :profile_name => @name, +# :path => @path_prefix, +# :role_policy_document => @role_policy_json.strip.gsub(/\r\n?/, " "), +# :ensure => 'present', +# } +# end +# +# it "should compile and apply" do +# result = PuppetManifest.new(@template, @config).apply +# expect(result.stderr).not_to match(/Error:/) +# end +# +# it "with the specified name" do +# profile = get_instance_profile(@config[:profile_name]) +# expect(profile.instance_profile_name).to eq(@config[:profile_name]) +# end +# +# it "should have valid ARN" do +# profile = get_instance_profile(@config[:profile_name]) +# expect(profile.arn).to match(/^arn\:aws\:iam\:\:\d+\:\S+$/) +# expect(profile.arn).to include("#{@config[:path]}#{@config[:profile_name]}") +# end +# +# it "should cleanup properly" do +# new_config = @config.update({:ensure => 'absent'}) +# result = PuppetManifest.new(@template, new_config).apply +# expect(result.stderr).not_to match(/Error:/) +# end +# end +# +#end diff --git a/spec/acceptance/iam_role_spec.rb b/spec/acceptance/iam_role_spec.rb index 468041d6..593e39aa 100644 --- a/spec/acceptance/iam_role_spec.rb +++ b/spec/acceptance/iam_role_spec.rb @@ -1,51 +1,51 @@ -require 'spec_helper_acceptance' -require 'securerandom' - -describe 'iam_role' do - before(:all) do - @default_region = 'us-east-1' - @aws = AwsHelper.new(@default_region) - end - - def find_role(name) - roles = @aws.get_iam_roles(name) - expect(roles.count).to eq(1) - roles.first - end - - describe 'manage an iam_role' do - - before (:all) do - @name = "#{SecureRandom.uuid}" - @config = { - :name => @name, - } - end - - it 'with puppet resource' do - options = {:name => @config[:name], :ensure => 'present'} - result = TestExecutor.puppet_resource('iam_role', options, '--modulepath spec/fixtures/modules/') - expect(result.stderr).not_to match(/Error:/) - expect{ find_role(@config[:name]) }.not_to raise_error - end - - it 'should create an IAM role with the correct name' do - role = find_role(@name) - expect(role.role_name).to eq(@name) - end - - it 'should create an IAM role with a valid ARN' do - role = find_role(@name) - expect(role.arn).to match(/^arn\:aws\:iam\:\:\d+\:\S+$/) - end - - it 'should destroy an IAM role' do - options = {:name => @config[:name], :ensure => 'absent'} - result = TestExecutor.puppet_resource('iam_role', options, '--modulepath spec/fixtures/modules/') - expect(result.stderr).not_to match(/Error:/) - expect(@aws.get_iam_roles(@name)).to be_empty - end - - end - -end +#require 'spec_helper_acceptance' +#require 'securerandom' +# +#describe 'iam_role' do +# before(:all) do +# @default_region = 'us-east-1' +# @aws = AwsHelper.new(@default_region) +# end +# +# def find_role(name) +# roles = @aws.get_iam_roles(name) +# expect(roles.count).to eq(1) +# roles.first +# end +# +# describe 'manage an iam_role' do +# +# before (:all) do +# @name = "#{SecureRandom.uuid}" +# @config = { +# :name => @name, +# } +# end +# +# it 'with puppet resource' do +# options = {:name => @config[:name], :ensure => 'present'} +# result = TestExecutor.puppet_resource('iam_role', options, '--modulepath spec/fixtures/modules/') +# expect(result.stderr).not_to match(/Error:/) +# expect{ find_role(@config[:name]) }.not_to raise_error +# end +# +# it 'should create an IAM role with the correct name' do +# role = find_role(@name) +# expect(role.role_name).to eq(@name) +# end +# +# it 'should create an IAM role with a valid ARN' do +# role = find_role(@name) +# expect(role.arn).to match(/^arn\:aws\:iam\:\:\d+\:\S+$/) +# end +# +# it 'should destroy an IAM role' do +# options = {:name => @config[:name], :ensure => 'absent'} +# result = TestExecutor.puppet_resource('iam_role', options, '--modulepath spec/fixtures/modules/') +# expect(result.stderr).not_to match(/Error:/) +# expect(@aws.get_iam_roles(@name)).to be_empty +# end +# +# end +# +#end diff --git a/spec/acceptance/iam_user_spec.rb b/spec/acceptance/iam_user_spec.rb index c86df7c4..bfa77163 100644 --- a/spec/acceptance/iam_user_spec.rb +++ b/spec/acceptance/iam_user_spec.rb @@ -1,56 +1,56 @@ -require 'spec_helper_acceptance' -require 'securerandom' - -describe 'iam_user' do - before(:all) do - @default_region = 'sa-east-1' - @aws = AwsHelper.new(@default_region) - end - - def find_user(name) - users = @aws.find_iam_users(name) - expect(users.count).to eq(1) - users.first - end - - describe 'manage an iam_user' do - - before (:all) do - @name = "#{SecureRandom.uuid}.com." - @config = { - :name => @name, - } - @template = 'iam_user.pp.tmpl' - @user = find_user(@name) - end - - it 'with puppet resource' do - options = {:name => @config[:name], :ensure => 'present'} - result = TestExecutor.puppet_resource('iam_user', options, '--modulepath spec/fixtures/modules/') - expect(result.stderr).not_to match(/Error:/) - expect{ find_user(@config[:name]) }.not_to raise_error - end - - it 'should run idempotently' do - result = PuppetManifest.new(@template, @config).apply - expect(result.exit_code).to eq(0) - end - - it 'should create an IAM user with the correct name' do - expect(user.user_name).to eq(@name) - end - - it 'should destroy an IAM user' do - options = {:name => @config[:name], :ensure => 'absent'} - TestExecutor.puppet_resource('iam_user', options, '--modulepath spec/fixtures/modules/') - expect(@aws.get_iam_users(@name)).to be_empty - end - - it 'should run idempotently after destroy' do - result = PuppetManifest.new(@template, @config).apply - expect(result.exit_code).to eq(0) - end - - end - -end +#require 'spec_helper_acceptance' +#require 'securerandom' +# +#describe 'iam_user' do +# before(:all) do +# @default_region = 'sa-east-1' +# @aws = AwsHelper.new(@default_region) +# end +# +# def find_user(name) +# users = @aws.find_iam_users(name) +# expect(users.count).to eq(1) +# users.first +# end +# +# describe 'manage an iam_user' do +# +# before (:all) do +# @name = "#{SecureRandom.uuid}.com." +# @config = { +# :name => @name, +# } +# @template = 'iam_user.pp.tmpl' +# @user = find_user(@name) +# end +# +# it 'with puppet resource' do +# options = {:name => @config[:name], :ensure => 'present'} +# result = TestExecutor.puppet_resource('iam_user', options, '--modulepath spec/fixtures/modules/') +# expect(result.stderr).not_to match(/Error:/) +# expect{ find_user(@config[:name]) }.not_to raise_error +# end +# +# it 'should run idempotently' do +# result = PuppetManifest.new(@template, @config).apply +# expect(result.exit_code).to eq(0) +# end +# +# it 'should create an IAM user with the correct name' do +# expect(user.user_name).to eq(@name) +# end +# +# it 'should destroy an IAM user' do +# options = {:name => @config[:name], :ensure => 'absent'} +# TestExecutor.puppet_resource('iam_user', options, '--modulepath spec/fixtures/modules/') +# expect(@aws.get_iam_users(@name)).to be_empty +# end +# +# it 'should run idempotently after destroy' do +# result = PuppetManifest.new(@template, @config).apply +# expect(result.exit_code).to eq(0) +# end +# +# end +# +#end From ec8760ed7c4bc97d3442bf721906e1717281536e Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Fri, 20 Jan 2017 14:13:16 -0800 Subject: [PATCH 37/72] Add refresh for Ecs_service resources Without this change, the ECS service is unable to track changes to the task. This leaves the code in a state where the task definition is updated, but the service is not refreshed to be running on that code. Here we implement the ability for the Ecs_service resources to subscribe to Ecs_task_definition resources. --- lib/puppet/provider/ecs_service/v2.rb | 11 +++++++++++ lib/puppet/type/ecs_service.rb | 6 +++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/puppet/provider/ecs_service/v2.rb b/lib/puppet/provider/ecs_service/v2.rb index 5cea2935..500e4773 100644 --- a/lib/puppet/provider/ecs_service/v2.rb +++ b/lib/puppet/provider/ecs_service/v2.rb @@ -166,6 +166,17 @@ def destroy @property_hash[:ensure] = :absent end + def update + service_def = { + service: resource[:name], + cluster: resource[:cluster], + task_definition: resource[:task_definition], + } + Puppet.debug("Updating ECS service #{resource[:name]} to latest task definition") + + ecs_client.update_service(service_def) + end + def flush if @property_hash[:ensure] != :absent Puppet.debug("Flushing ECS service for #{@property_hash[:name]}") diff --git a/lib/puppet/type/ecs_service.rb b/lib/puppet/type/ecs_service.rb index 28a47178..62fad067 100644 --- a/lib/puppet/type/ecs_service.rb +++ b/lib/puppet/type/ecs_service.rb @@ -56,6 +56,7 @@ def insync?(is) newproperty(:task_definition) do isrequired end + newproperty(:deployment_configuration) do desc 'The deployment configuration of the service. @@ -84,5 +85,8 @@ def insync?(is) isrequired defaultto "default" end -end + def refresh + provider.update + end +end From c43aa84cbd79d34f74d7855509f806c122fdac66 Mon Sep 17 00:00:00 2001 From: Brian Engler Date: Tue, 13 Oct 2015 00:33:12 -0400 Subject: [PATCH 38/72] Add delete_on_termination and volume_type settings for the block_devices parameter --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 594aec55..dd3be005 100644 --- a/README.md +++ b/README.md @@ -408,13 +408,15 @@ The name of the key pair associated with this instance. This must be an existing *Optional* Whether the instance stops or terminates when you initiate shutdown from the instance. This parameter is set at creation only; it is not affected by updates. Valid values are 'stop', 'terminate'. Defaults to 'stop'. #####`block_devices` -*Optional* A list of block devices to associate with the instance. This parameter is set at creation only; it is not affected by updates. Accepts an array of hashes with the device name and either the volume size or snapshot id specified: +*Optional* A list of block devices to associate with the instance. This parameter is set at creation only; it is not affected by updates. Accepts an array of hashes with the device name, volume size, delete on termination flag, and volume type specified: ~~~ block_devices => [ { - device_name => '/dev/sda1', - volume_size => 8, + device_name => '/dev/sda1', + volume_size => 8, + delete_on_termination => 'true', + volume_type' => 'gp2', } ] ~~~ From 788743cba1538560d36892de20d38e06bf1a2647 Mon Sep 17 00:00:00 2001 From: Gareth Rushgrove Date: Tue, 24 Mar 2015 09:46:20 +0000 Subject: [PATCH 39/72] Avoid ambiguity when using the AWS_REGION environment var If using the AWS_REGION environment variable and a manifest where the region property of one or more resources doesn't match you can see unspecified behaviour. See https://github.com/puppetlabs/puppetlabs-aws/pull/117 for discussions. This PR extracted from the above simply stops that from happening. If the env is present and doesn't match All of the region properties then we fail. This maintains the utility of the env var as an optimisation but stops us shooting ourselves in the foot. --- lib/puppet/type/cloudwatch_alarm.rb | 9 +++------ lib/puppet/type/ec2_autoscalinggroup.rb | 7 +------ lib/puppet/type/ec2_elastic_ip.rb | 8 +++----- lib/puppet/type/ec2_launchconfiguration.rb | 9 +++------ lib/puppet/type/ec2_scalingpolicy.rb | 9 +++------ lib/puppet/type/ec2_securitygroup.rb | 9 +++------ lib/puppet/type/ec2_vpc.rb | 9 +++------ lib/puppet/type/ec2_vpc_customer_gateway.rb | 9 +++------ lib/puppet/type/ec2_vpc_dhcp_options.rb | 5 +++-- lib/puppet/type/ec2_vpc_internet_gateway.rb | 9 +++------ lib/puppet/type/ec2_vpc_routetable.rb | 9 +++------ lib/puppet/type/ec2_vpc_subnet.rb | 9 +++------ lib/puppet/type/ec2_vpc_vpn.rb | 9 +++------ lib/puppet/type/ec2_vpc_vpn_gateway.rb | 9 +++------ lib/puppet/type/elb_loadbalancer.rb | 9 +++------ lib/puppet_x/puppetlabs/property/region.rb | 15 +++++++++++++++ spec/unit/type/ec2_elastic_ip_spec.rb | 6 +++--- 17 files changed, 61 insertions(+), 88 deletions(-) create mode 100644 lib/puppet_x/puppetlabs/property/region.rb diff --git a/lib/puppet/type/cloudwatch_alarm.rb b/lib/puppet/type/cloudwatch_alarm.rb index ee358e2c..9c00fafa 100644 --- a/lib/puppet/type/cloudwatch_alarm.rb +++ b/lib/puppet/type/cloudwatch_alarm.rb @@ -1,3 +1,5 @@ +require_relative '../../puppet_x/puppetlabs/property/region' + Puppet::Type.newtype(:cloudwatch_alarm) do @doc = 'Type representing an AWS CloudWatch Alarm.' @@ -73,13 +75,8 @@ end end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The region in which to launch the instances.' - validate do |value| - fail 'region should not contain spaces' if value =~ /\s/ - fail 'region should not be blank' if value == '' - fail 'region should be a String' unless value.is_a?(String) - end end newproperty(:dimensions, :array_matching => :all) do diff --git a/lib/puppet/type/ec2_autoscalinggroup.rb b/lib/puppet/type/ec2_autoscalinggroup.rb index 45cb1298..74deb951 100644 --- a/lib/puppet/type/ec2_autoscalinggroup.rb +++ b/lib/puppet/type/ec2_autoscalinggroup.rb @@ -87,13 +87,8 @@ desc 'Indicates whether newly launched instances are protected from termination by Auto Scaling when scaling in.' end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The region in which to launch the instances.' - validate do |value| - fail 'region should not contain spaces' if value =~ /\s/ - fail 'region should not be blank' if value == '' - fail 'region should be a String' unless value.is_a?(String) - end end newproperty(:launch_configuration) do diff --git a/lib/puppet/type/ec2_elastic_ip.rb b/lib/puppet/type/ec2_elastic_ip.rb index 15c022d5..29aed019 100644 --- a/lib/puppet/type/ec2_elastic_ip.rb +++ b/lib/puppet/type/ec2_elastic_ip.rb @@ -1,3 +1,5 @@ +require_relative '../../puppet_x/puppetlabs/property/region' + Puppet::Type.newtype(:ec2_elastic_ip) do @doc = "Type representing an Elastic IP and it's association." @@ -19,12 +21,8 @@ end end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The name of the region in which the Elastic IP is found.' - validate do |value| - fail 'region should be a String' unless value.is_a?(String) - fail 'You must provide a region for Elastic IPs.' if value.nil? || value.empty? - end end newproperty(:instance) do diff --git a/lib/puppet/type/ec2_launchconfiguration.rb b/lib/puppet/type/ec2_launchconfiguration.rb index 9dfee1e7..839a0f6b 100644 --- a/lib/puppet/type/ec2_launchconfiguration.rb +++ b/lib/puppet/type/ec2_launchconfiguration.rb @@ -1,3 +1,5 @@ +require_relative '../../puppet_x/puppetlabs/property/region' + Puppet::Type.newtype(:ec2_launchconfiguration) do @doc = 'Type representing an EC2 launch configuration.' @@ -33,13 +35,8 @@ def insync?(is) end end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The region in which to launch the instances.' - validate do |value| - fail 'region should not contain spaces' if value =~ /\s/ - fail 'region should not be blank' if value == '' - fail 'region should be a String' unless value.is_a?(String) - end end newproperty(:instance_type) do diff --git a/lib/puppet/type/ec2_scalingpolicy.rb b/lib/puppet/type/ec2_scalingpolicy.rb index 99698cb9..922c22ca 100644 --- a/lib/puppet/type/ec2_scalingpolicy.rb +++ b/lib/puppet/type/ec2_scalingpolicy.rb @@ -1,3 +1,5 @@ +require_relative '../../puppet_x/puppetlabs/property/region' + Puppet::Type.newtype(:ec2_scalingpolicy) do @doc = 'Type representing an EC2 scaling policy.' @@ -21,13 +23,8 @@ end end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The region in which to launch the policy.' - validate do |value| - fail 'region should not contain spaces' if value =~ /\s/ - fail 'region should not be blank' if value == '' - fail 'region should be a String' unless value.is_a?(String) - end end newproperty(:adjustment_type) do diff --git a/lib/puppet/type/ec2_securitygroup.rb b/lib/puppet/type/ec2_securitygroup.rb index 838b39f9..5587c462 100644 --- a/lib/puppet/type/ec2_securitygroup.rb +++ b/lib/puppet/type/ec2_securitygroup.rb @@ -1,4 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/tag' +require_relative '../../puppet_x/puppetlabs/property/region' require_relative '../../puppet_x/puppetlabs/aws_ingress_rules_parser' Puppet::Type.newtype(:ec2_securitygroup) do @@ -14,12 +15,8 @@ end end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'the region in which to launch the security group' - validate do |value| - fail 'region should not contain spaces' if value =~ /\s/ - fail 'region should be a String' unless value.is_a?(String) - end end newproperty(:ingress, :array_matching => :all) do diff --git a/lib/puppet/type/ec2_vpc.rb b/lib/puppet/type/ec2_vpc.rb index 81e09189..f8c1f14a 100644 --- a/lib/puppet/type/ec2_vpc.rb +++ b/lib/puppet/type/ec2_vpc.rb @@ -1,4 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/tag' +require_relative '../../puppet_x/puppetlabs/property/region' Puppet::Type.newtype(:ec2_vpc) do @doc = 'A type representing an AWS VPC.' @@ -13,12 +14,8 @@ end end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The region in which to launch the VPC.' - validate do |value| - fail 'region should not contain spaces' if value =~ /\s/ - fail 'region should be a String' unless value.is_a?(String) - end end newproperty(:cidr_block) do diff --git a/lib/puppet/type/ec2_vpc_customer_gateway.rb b/lib/puppet/type/ec2_vpc_customer_gateway.rb index f5badd64..42aeaf8a 100644 --- a/lib/puppet/type/ec2_vpc_customer_gateway.rb +++ b/lib/puppet/type/ec2_vpc_customer_gateway.rb @@ -1,4 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/tag' +require_relative '../../puppet_x/puppetlabs/property/region' Puppet::Type.newtype(:ec2_vpc_customer_gateway) do @doc = 'Type representing an AWS VPC customer gateways.' @@ -31,12 +32,8 @@ desc 'The tags for the customer gateway.' end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The region in which to launch the customer gateway.' - validate do |value| - fail 'region should not contain spaces' if value =~ /\s/ - fail 'region should be a String' unless value.is_a?(String) - end end newproperty(:type) do diff --git a/lib/puppet/type/ec2_vpc_dhcp_options.rb b/lib/puppet/type/ec2_vpc_dhcp_options.rb index 9c66e301..f4ace4fe 100644 --- a/lib/puppet/type/ec2_vpc_dhcp_options.rb +++ b/lib/puppet/type/ec2_vpc_dhcp_options.rb @@ -1,4 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/tag' +require_relative '../../puppet_x/puppetlabs/property/region' Puppet::Type.newtype(:ec2_vpc_dhcp_options) do @doc = 'Type representing a DHCP option set for AWS VPC.' @@ -17,7 +18,7 @@ desc 'Tags for the DHCP option set.' end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The region in which to assign the DHCP option set.' validate do |value| fail 'region should not contain spaces' if value =~ /\s/ diff --git a/lib/puppet/type/ec2_vpc_internet_gateway.rb b/lib/puppet/type/ec2_vpc_internet_gateway.rb index 1607b57f..423d31a4 100644 --- a/lib/puppet/type/ec2_vpc_internet_gateway.rb +++ b/lib/puppet/type/ec2_vpc_internet_gateway.rb @@ -1,4 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/tag' +require_relative '../../puppet_x/puppetlabs/property/region' Puppet::Type.newtype(:ec2_vpc_internet_gateway) do @doc = 'Type representing an EC2 VPC Internet Gateway.' @@ -17,12 +18,8 @@ desc 'Tags to assign to the internet gateway.' end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The region in which to launch the internet gateway.' - validate do |value| - fail 'region should not contain spaces' if value =~ /\s/ - fail 'region should be a String' unless value.is_a?(String) - end end newproperty(:vpc) do diff --git a/lib/puppet/type/ec2_vpc_routetable.rb b/lib/puppet/type/ec2_vpc_routetable.rb index c37f0684..c576613c 100644 --- a/lib/puppet/type/ec2_vpc_routetable.rb +++ b/lib/puppet/type/ec2_vpc_routetable.rb @@ -1,4 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/tag' +require_relative '../../puppet_x/puppetlabs/property/region' Puppet::Type.newtype(:ec2_vpc_routetable) do @doc = 'Type representing a VPC route table.' @@ -20,12 +21,8 @@ end end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'Region in which to launch the route table.' - validate do |value| - fail 'region should not contain spaces' if value =~ /\s/ - fail 'region should be a String' unless value.is_a?(String) - end end newproperty(:routes, :array_matching => :all) do diff --git a/lib/puppet/type/ec2_vpc_subnet.rb b/lib/puppet/type/ec2_vpc_subnet.rb index c126badf..f2d1acf8 100644 --- a/lib/puppet/type/ec2_vpc_subnet.rb +++ b/lib/puppet/type/ec2_vpc_subnet.rb @@ -1,4 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/tag' +require_relative '../../puppet_x/puppetlabs/property/region' Puppet::Type.newtype(:ec2_vpc_subnet) do @doc = 'Type representing a VPC Subnet.' @@ -20,12 +21,8 @@ end end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The region in which to launch the subnet.' - validate do |value| - fail 'region should not contain spaces' if value =~ /\s/ - fail 'region should be a String' unless value.is_a?(String) - end end newproperty(:cidr_block) do diff --git a/lib/puppet/type/ec2_vpc_vpn.rb b/lib/puppet/type/ec2_vpc_vpn.rb index fbdb5a47..10806a81 100644 --- a/lib/puppet/type/ec2_vpc_vpn.rb +++ b/lib/puppet/type/ec2_vpc_vpn.rb @@ -1,4 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/tag' +require_relative '../../puppet_x/puppetlabs/property/region' Puppet::Type.newtype(:ec2_vpc_vpn) do @doc = 'Type representing an AWS Virtual Private Networks.' @@ -53,12 +54,8 @@ def insync?(is) end end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The region in which to launch the VPN.' - validate do |value| - fail 'region should not contain spaces' if value =~ /\s/ - fail 'region should be a String' unless value.is_a?(String) - end end newproperty(:tags, :parent => PuppetX::Property::AwsTag) do diff --git a/lib/puppet/type/ec2_vpc_vpn_gateway.rb b/lib/puppet/type/ec2_vpc_vpn_gateway.rb index d0276125..22e56eaf 100644 --- a/lib/puppet/type/ec2_vpc_vpn_gateway.rb +++ b/lib/puppet/type/ec2_vpc_vpn_gateway.rb @@ -1,4 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/tag' +require_relative '../../puppet_x/puppetlabs/property/region' Puppet::Type.newtype(:ec2_vpc_vpn_gateway) do @doc = 'A type representing a VPN gateway.' @@ -24,12 +25,8 @@ end end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The region in which to launch the VPN gateway.' - validate do |value| - fail 'region should not contain spaces' if value =~ /\s/ - fail 'region should be a String' unless value.is_a?(String) - end end newparam(:availability_zone) do diff --git a/lib/puppet/type/elb_loadbalancer.rb b/lib/puppet/type/elb_loadbalancer.rb index 862d4c71..000a1822 100644 --- a/lib/puppet/type/elb_loadbalancer.rb +++ b/lib/puppet/type/elb_loadbalancer.rb @@ -1,4 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/tag' +require_relative '../../puppet_x/puppetlabs/property/region' Puppet::Type.newtype(:elb_loadbalancer) do @doc = 'Type representing an ELB load balancer.' @@ -13,12 +14,8 @@ end end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The region in which to launch the load balancer.' - validate do |value| - fail 'region must not contain spaces' if value =~ /\s/ - fail 'region should be a String' unless value.is_a?(String) - end end newproperty(:listeners, :array_matching => :all) do diff --git a/lib/puppet_x/puppetlabs/property/region.rb b/lib/puppet_x/puppetlabs/property/region.rb new file mode 100644 index 00000000..efe89476 --- /dev/null +++ b/lib/puppet_x/puppetlabs/property/region.rb @@ -0,0 +1,15 @@ +module PuppetX + module Property + class AwsRegion < Puppet::Property + validate do |value| + name = resource[:name] + fail 'region should not contain spaces' if value =~ /\s/ + fail 'region should not be blank' if value == '' + fail 'region should be a String' unless value.is_a?(String) + if !ENV['AWS_REGION'].nil? && ENV['AWS_REGION'] != value + fail "if using AWS_REGION environment variable it must match the specified region value for #{name}" + end + end + end + end +end diff --git a/spec/unit/type/ec2_elastic_ip_spec.rb b/spec/unit/type/ec2_elastic_ip_spec.rb index 803abdf1..6faa3332 100644 --- a/spec/unit/type/ec2_elastic_ip_spec.rb +++ b/spec/unit/type/ec2_elastic_ip_spec.rb @@ -45,12 +45,12 @@ it 'should require a region to be specified' do expect { type_class.new({ name: '10.0.0.1', region: '' }) - }.to raise_error(Puppet::Error, /You must provide a region for Elastic IPs/) + }.to raise_error(Puppet::Error, /region should not be blank/) end it 'should require an instance to be specified' do expect { - type_class.new({ name: '10.0.0.1', region: 'us-east-1', instance: '' }) + type_class.new({ name: '10.0.0.1', region: 'sa-east-1', instance: '' }) }.to raise_error(Puppet::Error, /You must provide an instance for the Elastic IP association/) end @@ -76,7 +76,7 @@ context 'with valid properties' do it 'should create a valid elastic ip ' do - type_class.new({ name: '10.0.0.1', region: 'us-east-1', instance: 'web-1' }) + type_class.new({ name: '10.0.0.1', region: 'sa-east-1', instance: 'web-1' }) end end From df71b579144e2e5ac46f186b357da46163b757f0 Mon Sep 17 00:00:00 2001 From: Andy Henroid Date: Fri, 20 Jan 2017 11:42:29 -0800 Subject: [PATCH 40/72] (CLOUD-184, CLOUD-205) Avoid ambiguity when using the AWS_REGION environment var --- lib/puppet/type/cloudwatch_alarm.rb | 2 +- lib/puppet/type/ec2_autoscalinggroup.rb | 1 + lib/puppet/type/ec2_elastic_ip.rb | 2 +- lib/puppet/type/ec2_instance.rb | 7 ++-- lib/puppet/type/ec2_launchconfiguration.rb | 2 +- lib/puppet/type/ec2_scalingpolicy.rb | 2 +- lib/puppet/type/ec2_securitygroup.rb | 4 +-- lib/puppet/type/ec2_vpc.rb | 4 +-- lib/puppet/type/ec2_vpc_customer_gateway.rb | 4 +-- lib/puppet/type/ec2_vpc_dhcp_options.rb | 8 ++--- lib/puppet/type/ec2_vpc_internet_gateway.rb | 4 +-- lib/puppet/type/ec2_vpc_routetable.rb | 4 +-- lib/puppet/type/ec2_vpc_subnet.rb | 4 +-- lib/puppet/type/ec2_vpc_vpn.rb | 4 +-- lib/puppet/type/ec2_vpc_vpn_gateway.rb | 4 +-- lib/puppet/type/elb_loadbalancer.rb | 4 +-- lib/puppet/type/rds_db_parameter_group.rb | 8 ++--- lib/puppet/type/rds_db_securitygroup.rb | 8 ++--- lib/puppet/type/rds_instance.rb | 8 ++--- lib/puppet/type/sqs_queue.rb | 9 ++--- lib/puppet_x/puppetlabs/property/region.rb | 5 ++- spec/unit/provider/rds_instance/v2_spec.rb | 2 +- spec/unit/type/ec2_elastic_ip_spec.rb | 2 +- spec/unit/type/ec2_securitygroup_spec.rb | 2 +- .../type/ec2_vpc_customer_gateway_spec.rb | 2 +- spec/unit/type/ec2_vpc_dhcp_options_spec.rb | 2 +- .../type/ec2_vpc_internet_gateway_spec.rb | 2 +- spec/unit/type/ec2_vpc_routetable_spec.rb | 2 +- spec/unit/type/ec2_vpc_spec.rb | 2 +- spec/unit/type/ec2_vpc_subnet_spec.rb | 2 +- spec/unit/type/ec2_vpc_vpn_gateway_spec.rb | 2 +- spec/unit/type/ec2_vpc_vpn_spec.rb | 2 +- spec/unit/type/rds_db_parameter_group_spec.rb | 2 +- spec/unit/type/rds_db_securitygroup_spec.rb | 2 +- spec/unit/type/rds_instance_spec.rb | 2 +- spec/unit/type/sqs_queue_spec.rb | 33 +++++++++---------- 36 files changed, 70 insertions(+), 89 deletions(-) diff --git a/lib/puppet/type/cloudwatch_alarm.rb b/lib/puppet/type/cloudwatch_alarm.rb index 9c00fafa..c236ebc1 100644 --- a/lib/puppet/type/cloudwatch_alarm.rb +++ b/lib/puppet/type/cloudwatch_alarm.rb @@ -1,4 +1,4 @@ -require_relative '../../puppet_x/puppetlabs/property/region' +require_relative '../../puppet_x/puppetlabs/property/region.rb' Puppet::Type.newtype(:cloudwatch_alarm) do @doc = 'Type representing an AWS CloudWatch Alarm.' diff --git a/lib/puppet/type/ec2_autoscalinggroup.rb b/lib/puppet/type/ec2_autoscalinggroup.rb index 74deb951..8856a756 100644 --- a/lib/puppet/type/ec2_autoscalinggroup.rb +++ b/lib/puppet/type/ec2_autoscalinggroup.rb @@ -1,4 +1,5 @@ require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/region.rb' require 'puppet/property/boolean' Puppet::Type.newtype(:ec2_autoscalinggroup) do diff --git a/lib/puppet/type/ec2_elastic_ip.rb b/lib/puppet/type/ec2_elastic_ip.rb index 29aed019..d45a5d53 100644 --- a/lib/puppet/type/ec2_elastic_ip.rb +++ b/lib/puppet/type/ec2_elastic_ip.rb @@ -1,4 +1,4 @@ -require_relative '../../puppet_x/puppetlabs/property/region' +require_relative '../../puppet_x/puppetlabs/property/region.rb' Puppet::Type.newtype(:ec2_elastic_ip) do @doc = "Type representing an Elastic IP and it's association." diff --git a/lib/puppet/type/ec2_instance.rb b/lib/puppet/type/ec2_instance.rb index 96125b78..95008287 100644 --- a/lib/puppet/type/ec2_instance.rb +++ b/lib/puppet/type/ec2_instance.rb @@ -1,4 +1,5 @@ require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/region.rb' Puppet::Type.newtype(:ec2_instance) do @doc = 'Type representing an EC2 instance.' @@ -93,12 +94,8 @@ def insync?(is) end end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The region in which to launch the instance.' - validate do |value| - fail 'region should not contain spaces' if value =~ /\s/ - fail 'region should be a String' unless value.is_a?(String) - end end newproperty(:image_id) do diff --git a/lib/puppet/type/ec2_launchconfiguration.rb b/lib/puppet/type/ec2_launchconfiguration.rb index 839a0f6b..a490d10f 100644 --- a/lib/puppet/type/ec2_launchconfiguration.rb +++ b/lib/puppet/type/ec2_launchconfiguration.rb @@ -1,4 +1,4 @@ -require_relative '../../puppet_x/puppetlabs/property/region' +require_relative '../../puppet_x/puppetlabs/property/region.rb' Puppet::Type.newtype(:ec2_launchconfiguration) do @doc = 'Type representing an EC2 launch configuration.' diff --git a/lib/puppet/type/ec2_scalingpolicy.rb b/lib/puppet/type/ec2_scalingpolicy.rb index 922c22ca..32511be3 100644 --- a/lib/puppet/type/ec2_scalingpolicy.rb +++ b/lib/puppet/type/ec2_scalingpolicy.rb @@ -1,4 +1,4 @@ -require_relative '../../puppet_x/puppetlabs/property/region' +require_relative '../../puppet_x/puppetlabs/property/region.rb' Puppet::Type.newtype(:ec2_scalingpolicy) do @doc = 'Type representing an EC2 scaling policy.' diff --git a/lib/puppet/type/ec2_securitygroup.rb b/lib/puppet/type/ec2_securitygroup.rb index 5587c462..1ef502fd 100644 --- a/lib/puppet/type/ec2_securitygroup.rb +++ b/lib/puppet/type/ec2_securitygroup.rb @@ -1,5 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag' -require_relative '../../puppet_x/puppetlabs/property/region' +require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/region.rb' require_relative '../../puppet_x/puppetlabs/aws_ingress_rules_parser' Puppet::Type.newtype(:ec2_securitygroup) do diff --git a/lib/puppet/type/ec2_vpc.rb b/lib/puppet/type/ec2_vpc.rb index f8c1f14a..7221969f 100644 --- a/lib/puppet/type/ec2_vpc.rb +++ b/lib/puppet/type/ec2_vpc.rb @@ -1,5 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag' -require_relative '../../puppet_x/puppetlabs/property/region' +require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/region.rb' Puppet::Type.newtype(:ec2_vpc) do @doc = 'A type representing an AWS VPC.' diff --git a/lib/puppet/type/ec2_vpc_customer_gateway.rb b/lib/puppet/type/ec2_vpc_customer_gateway.rb index 42aeaf8a..f9721056 100644 --- a/lib/puppet/type/ec2_vpc_customer_gateway.rb +++ b/lib/puppet/type/ec2_vpc_customer_gateway.rb @@ -1,5 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag' -require_relative '../../puppet_x/puppetlabs/property/region' +require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/region.rb' Puppet::Type.newtype(:ec2_vpc_customer_gateway) do @doc = 'Type representing an AWS VPC customer gateways.' diff --git a/lib/puppet/type/ec2_vpc_dhcp_options.rb b/lib/puppet/type/ec2_vpc_dhcp_options.rb index f4ace4fe..ee3fb3e0 100644 --- a/lib/puppet/type/ec2_vpc_dhcp_options.rb +++ b/lib/puppet/type/ec2_vpc_dhcp_options.rb @@ -1,5 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag' -require_relative '../../puppet_x/puppetlabs/property/region' +require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/region.rb' Puppet::Type.newtype(:ec2_vpc_dhcp_options) do @doc = 'Type representing a DHCP option set for AWS VPC.' @@ -20,10 +20,6 @@ newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The region in which to assign the DHCP option set.' - validate do |value| - fail 'region should not contain spaces' if value =~ /\s/ - fail 'region should be a String' unless value.is_a?(String) - end end newproperty(:domain_name, :array_matching => :all) do diff --git a/lib/puppet/type/ec2_vpc_internet_gateway.rb b/lib/puppet/type/ec2_vpc_internet_gateway.rb index 423d31a4..7ef6fb67 100644 --- a/lib/puppet/type/ec2_vpc_internet_gateway.rb +++ b/lib/puppet/type/ec2_vpc_internet_gateway.rb @@ -1,5 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag' -require_relative '../../puppet_x/puppetlabs/property/region' +require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/region.rb' Puppet::Type.newtype(:ec2_vpc_internet_gateway) do @doc = 'Type representing an EC2 VPC Internet Gateway.' diff --git a/lib/puppet/type/ec2_vpc_routetable.rb b/lib/puppet/type/ec2_vpc_routetable.rb index c576613c..4fdeb4f0 100644 --- a/lib/puppet/type/ec2_vpc_routetable.rb +++ b/lib/puppet/type/ec2_vpc_routetable.rb @@ -1,5 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag' -require_relative '../../puppet_x/puppetlabs/property/region' +require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/region.rb' Puppet::Type.newtype(:ec2_vpc_routetable) do @doc = 'Type representing a VPC route table.' diff --git a/lib/puppet/type/ec2_vpc_subnet.rb b/lib/puppet/type/ec2_vpc_subnet.rb index f2d1acf8..86c8f73f 100644 --- a/lib/puppet/type/ec2_vpc_subnet.rb +++ b/lib/puppet/type/ec2_vpc_subnet.rb @@ -1,5 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag' -require_relative '../../puppet_x/puppetlabs/property/region' +require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/region.rb' Puppet::Type.newtype(:ec2_vpc_subnet) do @doc = 'Type representing a VPC Subnet.' diff --git a/lib/puppet/type/ec2_vpc_vpn.rb b/lib/puppet/type/ec2_vpc_vpn.rb index 10806a81..c4822a24 100644 --- a/lib/puppet/type/ec2_vpc_vpn.rb +++ b/lib/puppet/type/ec2_vpc_vpn.rb @@ -1,5 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag' -require_relative '../../puppet_x/puppetlabs/property/region' +require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/region.rb' Puppet::Type.newtype(:ec2_vpc_vpn) do @doc = 'Type representing an AWS Virtual Private Networks.' diff --git a/lib/puppet/type/ec2_vpc_vpn_gateway.rb b/lib/puppet/type/ec2_vpc_vpn_gateway.rb index 22e56eaf..d9ef918a 100644 --- a/lib/puppet/type/ec2_vpc_vpn_gateway.rb +++ b/lib/puppet/type/ec2_vpc_vpn_gateway.rb @@ -1,5 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag' -require_relative '../../puppet_x/puppetlabs/property/region' +require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/region.rb' Puppet::Type.newtype(:ec2_vpc_vpn_gateway) do @doc = 'A type representing a VPN gateway.' diff --git a/lib/puppet/type/elb_loadbalancer.rb b/lib/puppet/type/elb_loadbalancer.rb index 000a1822..970aa249 100644 --- a/lib/puppet/type/elb_loadbalancer.rb +++ b/lib/puppet/type/elb_loadbalancer.rb @@ -1,5 +1,5 @@ -require_relative '../../puppet_x/puppetlabs/property/tag' -require_relative '../../puppet_x/puppetlabs/property/region' +require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/region.rb' Puppet::Type.newtype(:elb_loadbalancer) do @doc = 'Type representing an ELB load balancer.' diff --git a/lib/puppet/type/rds_db_parameter_group.rb b/lib/puppet/type/rds_db_parameter_group.rb index dd013a5c..a286c099 100644 --- a/lib/puppet/type/rds_db_parameter_group.rb +++ b/lib/puppet/type/rds_db_parameter_group.rb @@ -1,3 +1,5 @@ +require_relative '../../puppet_x/puppetlabs/property/region.rb' + Puppet::Type.newtype(:rds_db_parameter_group) do @doc = 'Type representing an RDS DB Parameter group.' @@ -22,12 +24,8 @@ end end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The region in which to create the db_parameter_group.' - validate do |value| - fail 'region should be a String' unless value.is_a?(String) - fail 'region should not contain spaces' if value =~ /\s/ - end end end diff --git a/lib/puppet/type/rds_db_securitygroup.rb b/lib/puppet/type/rds_db_securitygroup.rb index 42bc4831..703c202a 100644 --- a/lib/puppet/type/rds_db_securitygroup.rb +++ b/lib/puppet/type/rds_db_securitygroup.rb @@ -1,3 +1,5 @@ +require_relative '../../puppet_x/puppetlabs/property/region.rb' + Puppet::Type.newtype(:rds_db_securitygroup) do @doc = 'Type representing an RDS instance.' @@ -32,12 +34,8 @@ end end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The region in which to create the db_securitygroup.' - validate do |value| - fail 'region should be a String' unless value.is_a?(String) - fail 'region should not contain spaces' if value =~ /\s/ - end end newproperty(:ip_ranges, :array_matching => :all) do diff --git a/lib/puppet/type/rds_instance.rb b/lib/puppet/type/rds_instance.rb index 6e8ea4b1..6c65e196 100644 --- a/lib/puppet/type/rds_instance.rb +++ b/lib/puppet/type/rds_instance.rb @@ -1,3 +1,5 @@ +require_relative '../../puppet_x/puppetlabs/property/region.rb' + Puppet::Type.newtype(:rds_instance) do @doc = 'Type representing an RDS instance.' @@ -49,12 +51,8 @@ Not applicable. Must be null.' end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The region in which to launch the instance.' - validate do |value| - fail 'region should be a String' unless value.is_a?(String) - fail 'region should not contain spaces' if value =~ /\s/ - end end newproperty(:db_instance_class) do diff --git a/lib/puppet/type/sqs_queue.rb b/lib/puppet/type/sqs_queue.rb index dc72d9b3..2f4fa054 100644 --- a/lib/puppet/type/sqs_queue.rb +++ b/lib/puppet/type/sqs_queue.rb @@ -1,3 +1,5 @@ +require_relative '../../puppet_x/puppetlabs/property/region.rb' + Puppet::Type.newtype(:sqs_queue) do @doc = "Type representing a SQS Queue" ensurable @@ -43,13 +45,8 @@ munge(&:to_s) end - newproperty(:region) do + newproperty(:region, :parent => PuppetX::Property::AwsRegion) do desc 'The name of the region in which the SQS queue is located' - validate do |value| - fail 'region should be a String' unless value.is_a?(String) - fail 'You must provide a non-blank region name for SQS Queues' if value.nil? || value.empty? - fail 'The name of a region should contain only alphanumeric characters or dashes' unless value =~ /^([a-zA-Z]+-+)+\d$/ - end end newproperty(:visibility_timeout) do diff --git a/lib/puppet_x/puppetlabs/property/region.rb b/lib/puppet_x/puppetlabs/property/region.rb index efe89476..2f24c7b5 100644 --- a/lib/puppet_x/puppetlabs/property/region.rb +++ b/lib/puppet_x/puppetlabs/property/region.rb @@ -3,10 +3,9 @@ module Property class AwsRegion < Puppet::Property validate do |value| name = resource[:name] - fail 'region should not contain spaces' if value =~ /\s/ - fail 'region should not be blank' if value == '' fail 'region should be a String' unless value.is_a?(String) - if !ENV['AWS_REGION'].nil? && ENV['AWS_REGION'] != value + fail 'region should be a valid AWS region' unless value =~ /^([a-z]{2}-[a-z]{4,}-\d)$/ + if ENV['AWS_REGION'] && ENV['AWS_REGION'] != value fail "if using AWS_REGION environment variable it must match the specified region value for #{name}" end end diff --git a/spec/unit/provider/rds_instance/v2_spec.rb b/spec/unit/provider/rds_instance/v2_spec.rb index b081b1c2..c98537d7 100644 --- a/spec/unit/provider/rds_instance/v2_spec.rb +++ b/spec/unit/provider/rds_instance/v2_spec.rb @@ -12,7 +12,7 @@ Puppet::Type.type(:rds_instance).new( ensure: 'present', name: 'awesome-db-5', - region: 'us-west-1', + region: 'sa-east-1', db_name: 'mysqldbname3', engine: 'mysql', engine_version: '5.6.19a', diff --git a/spec/unit/type/ec2_elastic_ip_spec.rb b/spec/unit/type/ec2_elastic_ip_spec.rb index 6faa3332..9f2ef803 100644 --- a/spec/unit/type/ec2_elastic_ip_spec.rb +++ b/spec/unit/type/ec2_elastic_ip_spec.rb @@ -45,7 +45,7 @@ it 'should require a region to be specified' do expect { type_class.new({ name: '10.0.0.1', region: '' }) - }.to raise_error(Puppet::Error, /region should not be blank/) + }.to raise_error(Puppet::Error, /region should be a valid AWS region/) end it 'should require an instance to be specified' do diff --git a/spec/unit/type/ec2_securitygroup_spec.rb b/spec/unit/type/ec2_securitygroup_spec.rb index c15ce5ce..7e9717ca 100644 --- a/spec/unit/type/ec2_securitygroup_spec.rb +++ b/spec/unit/type/ec2_securitygroup_spec.rb @@ -42,7 +42,7 @@ it 'should require region to not contain spaces' do expect { type_class.new({name: 'name', region: 'invalid region'}) - }.to raise_error(Puppet::Error, /region should not contain spaces/) + }.to raise_error(Puppet::Error, /region should be a valid AWS region/) end [ diff --git a/spec/unit/type/ec2_vpc_customer_gateway_spec.rb b/spec/unit/type/ec2_vpc_customer_gateway_spec.rb index 149f873d..690a36dc 100644 --- a/spec/unit/type/ec2_vpc_customer_gateway_spec.rb +++ b/spec/unit/type/ec2_vpc_customer_gateway_spec.rb @@ -42,7 +42,7 @@ it 'region should not contain spaces' do expect { type_class.new(:name => 'sample', :region => 'sa east 1') - }.to raise_error(Puppet::ResourceError, /region should not contain spaces/) + }.to raise_error(Puppet::ResourceError, /region should be a valid AWS region/) end it 'the ASN should be a number' do diff --git a/spec/unit/type/ec2_vpc_dhcp_options_spec.rb b/spec/unit/type/ec2_vpc_dhcp_options_spec.rb index 932186d6..d8929c31 100644 --- a/spec/unit/type/ec2_vpc_dhcp_options_spec.rb +++ b/spec/unit/type/ec2_vpc_dhcp_options_spec.rb @@ -44,7 +44,7 @@ it 'region should not contain spaces' do expect { type_class.new(:name => 'sample', :region => 'sa east 1') - }.to raise_error(Puppet::ResourceError, /region should not contain spaces/) + }.to raise_error(Puppet::ResourceError, /region should be a valid AWS region/) end ['8.8.8.8','2.2.2.2'].each do |value| diff --git a/spec/unit/type/ec2_vpc_internet_gateway_spec.rb b/spec/unit/type/ec2_vpc_internet_gateway_spec.rb index 74c4fcfc..53300e21 100644 --- a/spec/unit/type/ec2_vpc_internet_gateway_spec.rb +++ b/spec/unit/type/ec2_vpc_internet_gateway_spec.rb @@ -39,7 +39,7 @@ it 'region should not contain spaces' do expect { type_class.new(:name => 'sample', :region => 'sa east 1') - }.to raise_error(Puppet::ResourceError, /region should not contain spaces/) + }.to raise_error(Puppet::ResourceError, /region should be a valid AWS region/) end [ diff --git a/spec/unit/type/ec2_vpc_routetable_spec.rb b/spec/unit/type/ec2_vpc_routetable_spec.rb index d0ecd0ca..6bc82ab0 100644 --- a/spec/unit/type/ec2_vpc_routetable_spec.rb +++ b/spec/unit/type/ec2_vpc_routetable_spec.rb @@ -40,7 +40,7 @@ it 'region should not contain spaces' do expect { type_class.new(:name => 'sample', :region => 'sa east 1') - }.to raise_error(Puppet::ResourceError, /region should not contain spaces/) + }.to raise_error(Puppet::ResourceError, /region should be a valid AWS region/) end it 'routes should contain a cidr' do diff --git a/spec/unit/type/ec2_vpc_spec.rb b/spec/unit/type/ec2_vpc_spec.rb index 0907486b..bbd55054 100644 --- a/spec/unit/type/ec2_vpc_spec.rb +++ b/spec/unit/type/ec2_vpc_spec.rb @@ -57,7 +57,7 @@ it 'region should not contain spaces' do expect { type_class.new(:name => 'sample', :region => 'sa east 1') - }.to raise_error(Puppet::ResourceError, /region should not contain spaces/) + }.to raise_error(Puppet::ResourceError, /region should be a valid AWS region/) end it 'should order tags on output' do diff --git a/spec/unit/type/ec2_vpc_subnet_spec.rb b/spec/unit/type/ec2_vpc_subnet_spec.rb index f935273e..80a6e88e 100644 --- a/spec/unit/type/ec2_vpc_subnet_spec.rb +++ b/spec/unit/type/ec2_vpc_subnet_spec.rb @@ -42,7 +42,7 @@ it 'region should not contain spaces' do expect { type_class.new(:name => 'sample', :region => 'sa east 1') - }.to raise_error(Puppet::ResourceError, /region should not contain spaces/) + }.to raise_error(Puppet::ResourceError, /region should be a valid AWS region/) end [ diff --git a/spec/unit/type/ec2_vpc_vpn_gateway_spec.rb b/spec/unit/type/ec2_vpc_vpn_gateway_spec.rb index 73e41619..1945671f 100644 --- a/spec/unit/type/ec2_vpc_vpn_gateway_spec.rb +++ b/spec/unit/type/ec2_vpc_vpn_gateway_spec.rb @@ -42,7 +42,7 @@ it 'region should not contain spaces' do expect { type_class.new(:name => 'sample', :region => 'sa east 1') - }.to raise_error(Puppet::ResourceError, /region should not contain spaces/) + }.to raise_error(Puppet::ResourceError, /region should be a valid AWS region/) end it 'should default type to ipsec.1' do diff --git a/spec/unit/type/ec2_vpc_vpn_spec.rb b/spec/unit/type/ec2_vpc_vpn_spec.rb index 7bfc95c1..55c85558 100644 --- a/spec/unit/type/ec2_vpc_vpn_spec.rb +++ b/spec/unit/type/ec2_vpc_vpn_spec.rb @@ -65,7 +65,7 @@ it 'region should not contain spaces' do expect { type_class.new(:name => 'sample', :region => 'sa east 1') - }.to raise_error(Puppet::ResourceError, /region should not contain spaces/) + }.to raise_error(Puppet::ResourceError, /region should be a valid AWS region/) end [ diff --git a/spec/unit/type/rds_db_parameter_group_spec.rb b/spec/unit/type/rds_db_parameter_group_spec.rb index 2bc2d1c2..bbe60496 100644 --- a/spec/unit/type/rds_db_parameter_group_spec.rb +++ b/spec/unit/type/rds_db_parameter_group_spec.rb @@ -39,7 +39,7 @@ it 'should require a valid looking region' do expect { type_class.new({:name => 'sample', :region => 'definitely invalid'}) - }.to raise_error(Puppet::Error, /region should not contain spaces/) + }.to raise_error(Puppet::Error, /region should be a valid AWS region/) end [ diff --git a/spec/unit/type/rds_db_securitygroup_spec.rb b/spec/unit/type/rds_db_securitygroup_spec.rb index ba3d8e3a..a8cd8ef1 100644 --- a/spec/unit/type/rds_db_securitygroup_spec.rb +++ b/spec/unit/type/rds_db_securitygroup_spec.rb @@ -47,7 +47,7 @@ it 'should require a valid looking region' do expect { type_class.new({:name => 'sample', :region => 'definitely invalid'}) - }.to raise_error(Puppet::Error, /region should not contain spaces/) + }.to raise_error(Puppet::Error, /region should be a valid AWS region/) end [ diff --git a/spec/unit/type/rds_instance_spec.rb b/spec/unit/type/rds_instance_spec.rb index dfa1c55c..e8425c09 100644 --- a/spec/unit/type/rds_instance_spec.rb +++ b/spec/unit/type/rds_instance_spec.rb @@ -60,7 +60,7 @@ it 'region should not contain spaces' do expect { type_class.new(:name => 'sample', :region => 'sa east 1') - }.to raise_error(Puppet::ResourceError, /region should not contain spaces/) + }.to raise_error(Puppet::ResourceError, /region should be a valid AWS region/) end it 'IOPS must be an integer' do diff --git a/spec/unit/type/sqs_queue_spec.rb b/spec/unit/type/sqs_queue_spec.rb index ab631385..6a886317 100644 --- a/spec/unit/type/sqs_queue_spec.rb +++ b/spec/unit/type/sqs_queue_spec.rb @@ -29,46 +29,46 @@ end it 'should create a valid instance' do - type_class.new({name: 'name', region: 'us-east-1'}) + type_class.new({name: 'name', region: 'sa-east-1'}) end it 'should set delay seconds should get set with a valid value' do - queue = type_class.new({name: 'queue', region: 'us-east-1', delay_seconds: 450}) + queue = type_class.new({name: 'queue', region: 'sa-east-1', delay_seconds: 450}) expect(queue[:delay_seconds]).to eq("450") end it 'delay seconds should default to 0' do - queue = type_class.new({name: 'queue', region: 'us-east-1'}) + queue = type_class.new({name: 'queue', region: 'sa-east-1'}) expect(queue[:delay_seconds]).to eq("0") end it 'visibility_timeout should default to 30' do - queue = type_class.new({name: 'queue', region: 'us-east-1'}) + queue = type_class.new({name: 'queue', region: 'sa-east-1'}) expect(queue[:visibility_timeout]).to eq('30') end it 'should set visibility_timeout with a valid value' do - queue = type_class.new({name: 'queue', region: 'us-east-1', visibility_timeout: 123}) + queue = type_class.new({name: 'queue', region: 'sa-east-1', visibility_timeout: 123}) expect(queue[:visibility_timeout]).to eq("123") end it 'should set message_retention_period should get set with a valid value' do - queue = type_class.new({name: 'queue', region: 'us-east-1', message_retention_period: 360}) + queue = type_class.new({name: 'queue', region: 'sa-east-1', message_retention_period: 360}) expect(queue[:message_retention_period]).to eq("360") end it 'should set message_retention_period to default to 345600' do - queue = type_class.new({name: 'queue', region: 'us-east-1'}) + queue = type_class.new({name: 'queue', region: 'sa-east-1'}) expect(queue[:message_retention_period]).to eq("345600") end it 'should set maximum_message_size should get set with a valid value' do - queue = type_class.new({name: 'queue', region: 'us-east-1', maximum_message_size: 2048}) + queue = type_class.new({name: 'queue', region: 'sa-east-1', maximum_message_size: 2048}) expect(queue[:maximum_message_size]).to eq("2048") end it 'should set maximum_message_size to default to 262144' do - queue = type_class.new({name: 'queue', region: 'us-east-1'}) + queue = type_class.new({name: 'queue', region: 'sa-east-1'}) expect(queue[:maximum_message_size]).to eq("262144") end @@ -81,26 +81,23 @@ context 'erroring values' do it 'should error with incorrect range value for delay seconds' do expect do - type_class.new({name: 'queue', region: 'us-east-1', delay_seconds: 1024}) + type_class.new({name: 'queue', region: 'sa-east-1', delay_seconds: 1024}) end.to raise_error(Puppet::Error, /delay_seconds must be an integer between 0 and 900/) end it 'should require something that looks like a region' do expect do - type_class.new ({name: 'somename', :region => 'us_east_1'}) - end.to raise_error(Puppet::Error, /The name of a region should contain only alphanumeric characters or dashes/) + type_class.new ({name: 'somename', :region => 'sa-east-1 '}) + end.to raise_error(Puppet::Error, /region should be a valid AWS region/) expect do - type_class.new ({name: 'somename', :region => '123'}) - end.to raise_error(Puppet::Error, /The name of a region should contain only alphanumeric characters or dashes/) - expect do - type_class.new ({name: 'somename', :region => 'europe'}) - end.to raise_error(Puppet::Error, /The name of a region should contain only alphanumeric characters or dashes/) + type_class.new ({name: 'somename', :region => 1}) + end.to raise_error(Puppet::Error, /region should be a String/) end it 'should require a non-blank region' do expect do type_class.new ({name: 'somename', region: ''}) - end.to raise_error(Puppet::Error, /You must provide a non-blank region name for SQS Queues/) + end.to raise_error(Puppet::Error, /region should be a valid AWS region/) end it 'should require a name' do expect do From 4b54530e0c2bf9c822099dd5561a9e19a24d5d69 Mon Sep 17 00:00:00 2001 From: Ian Shearin Date: Fri, 16 Dec 2016 13:54:28 -0800 Subject: [PATCH 41/72] Add initial support for CloudFront This adds support for creating, destroying, and enumerating CloudFront web distributions. Basic parameters and custom origins may be set up. Modification, several parameters, and S3 origins are left for future work. --- README.md | 39 +++ .../provider/cloudfront_distribution/v2.rb | 245 ++++++++++++++++++ lib/puppet/type/cloudfront_distribution.rb | 102 ++++++++ lib/puppet_x/puppetlabs/aws.rb | 8 + 4 files changed, 394 insertions(+) create mode 100644 lib/puppet/provider/cloudfront_distribution/v2.rb create mode 100644 lib/puppet/type/cloudfront_distribution.rb diff --git a/README.md b/README.md index dd3be005..873fa31b 100644 --- a/README.md +++ b/README.md @@ -311,6 +311,7 @@ You can use the aws module to audit AWS resources, launch autoscaling groups in ### Types +* `cloudfront_distribution`: Sets up a CloudFront distribution. * `ec2_instance`: Sets up an EC2 instance. * `ec2_securitygroup`: Sets up an EC2 security group. * `elb_loadbalancer`: Sets up an ELB load balancer. @@ -354,6 +355,44 @@ You can use the aws module to audit AWS resources, launch autoscaling groups in ###Parameters +#### Type: cloudfront_distribution + +##### `ensure` +Specifies the basic state of the resource. Valid values are 'present', 'absent'. + +##### `arn` +The AWS-generated ARN of the distribution. Read only. + +##### `id` +The AWS-generated ID of the distribution. Read only. + +##### `status` +The AWS-reported status of the distribution. Read only. + +##### `comment` +*Optional* The comment on the distribution. + +##### `enabled` +*Optional* Whether the distribution is enabled. + +##### `price_class` +*Optional* The price class of the distribution. Takes one of 'all' (default), '100', '200'. + +##### `origins` +*Required* An array of at least one origin. Each origin is a hash with the following keys: + +* `type` — *Required* The origin type. One of 'custom', 'S3' (not yet supported). +* `id` — *Required* The origin ID. Must be unique within the distribution. Used to identify the origin for caching rules. +* `domain_name` — *Required* The origin domain name. +* `path` — *Optional* The origin path. Defaults to no path. +* `http_port` — *Required for custom origins* The port the origin is listening on for HTTP connections. +* `https_port` — *Required for custom origins* The port the origin is listening on for HTTPS connections. +* `protocol_policy` — *Required for custom origins* Which protocols the origin accepts. One of 'http-only', 'https-only', 'match-viewer'. +* `protocols` — *Required for custom origins* An array of SSL and TLS versions the origin accepts. At least one of 'SSLv3', 'TLSv1', 'TLSv1.1', 'TLSv1.2'. + +##### `tags` +*Optional* The tags for the distribution. Accepts a 'key => value' hash of tags. Excludes 'Name' tag. + ####Type: ec2_instance #####`ensure` diff --git a/lib/puppet/provider/cloudfront_distribution/v2.rb b/lib/puppet/provider/cloudfront_distribution/v2.rb new file mode 100644 index 00000000..233cf923 --- /dev/null +++ b/lib/puppet/provider/cloudfront_distribution/v2.rb @@ -0,0 +1,245 @@ +require_relative '../../../puppet_x/puppetlabs/aws.rb' + +Puppet::Type.type(:cloudfront_distribution).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do + confine feature: :aws + + mk_resource_methods + + read_only(:arn, :id, :status) + + def self.instances + dists = [] + list_opts = {max_items: 100} + + # Loop over paginated API responses. + loop do + dists_resp = cloudfront_client.list_distributions(list_opts).distribution_list + + # Loop over each distribution in one API response. + dists_resp.items.each do |dist| + tags = cloudfront_client.list_tags_for_resource({resource: dist.arn}).tags.items + + hash = self.distribution_to_hash(dist, tags) + dists << new(hash) if hash[:name] + end + + break unless dists_resp.is_truncated + list_opts[:marker] = dists_resp.next_marker + end + + dists.compact + end + + def self.prefetch(resources) + instances.each do |prov| + if resource = resources[prov.name] + resource.provider = prov + end + end + end + + def self.distribution_to_hash(dist, tags) + { + name: self.name_from_cloudfront_tags(tags), + ensure: :present, + arn: dist.arn, + id: dist.id, + status: dist.status, + comment: dist.comment, + enabled: dist.enabled, + price_class: dist.price_class.sub(/^PriceClass_/, '').downcase, + origins: dist.origins.items.collect { |hash| self.origin_to_hash(hash) }, + tags: self.tags_to_hash(tags), + } + end + + def self.origin_to_hash(origin) + type = if origin['custom_origin_config'] then + 'custom' + elsif origin['s3_origin_config'] then + 's3' + else + fail 'Unknown origin type returned from AWS API' + end + + hash = { + 'id' => origin[:id], + 'type' => type, + 'domain_name' => origin[:domain_name], + 'path' => origin[:origin_path], + } + + case type + when 'custom' + hash['http_port'] = origin['custom_origin_config']['http_port'] + hash['https_port'] = origin['custom_origin_config']['https_port'] + hash['protocol_policy'] = origin['custom_origin_config']['origin_protocol_policy'] + hash['protocols'] = origin['custom_origin_config']['origin_ssl_protocols']['items'] + when 's3' + Puppet.warning('CloudFront S3 origins are not supported.') + end + + hash + end + + # CloudFront tags are a unique data type. + def self.name_from_cloudfront_tags(tags) + name_tag = tags.find { |tag| tag.key.downcase == 'name' } + name_tag ? name_tag.value : nil + end + + def self.tags_to_hash(tags) + tags_hash = {} + tags.each do |tag| + tags_hash[tag.key] = tag.value unless tag.key.downcase == 'name' + end + + tags_hash + end + + def exists? + @property_hash[:ensure] == :present + end + + def create + create_resp = cloudfront_client.create_distribution_with_tags({ + distribution_config_with_tags: { + distribution_config: hash_to_distribution_config(resource), + tags: { + items: tags_for_resource + }, + }, + }) + + @property_hash[:ensure] = :present + @property_hash[:arn] = create_resp.distribution.arn + @property_hash[:id] = create_resp.distribution.id + @property_hash[:status] = create_resp.distribution.status + @property_hash[:just_created] = true + end + + def hash_to_distribution_config(hash) + dist_origins = hash['origins'].collect { |origin| hash_to_origin(origin) } + + { + enabled: hash['enabled'], + caller_reference: hash['name'], + comment: (hash['comment'] or ''), + price_class: ("PriceClass_#{hash['price_class'].capitalize}"), + origins: { + quantity: dist_origins.length, + items: dist_origins, + }, + # All values below are hard-coded defaults for now. + default_cache_behavior: { + target_origin_id: dist_origins[0][:id], + min_ttl: 1, + viewer_protocol_policy: 'allow-all', + allowed_methods: { + quantity: 2, + items: ['GET', 'HEAD'], + cached_methods: { + quantity: 2, + items: ['GET', 'HEAD'], + }, + }, + forwarded_values: { + query_string: false, + cookies: { + forward: 'none', + whitelisted_names: { + quantity: 0, + }, + }, + headers: { + quantity: 0, + }, + query_string_cache_keys: { + quantity: 0, + }, + }, + lambda_function_associations: { + quantity: 0, + }, + trusted_signers: { + enabled: false, + quantity: 0, + }, + }, + } + end + + def hash_to_origin(hash) + { + id: hash['id'], + domain_name: hash['domain_name'], + custom_origin_config: { + http_port: hash['http_port'], + https_port: hash['https_port'], + origin_protocol_policy: hash['protocol_policy'], + origin_ssl_protocols: { + quantity: hash['protocols'].length, + items: hash['protocols'], + }, + }, + } + end + + def destroy + # Disabling the distribution returns a new etag. Otherwise, get the current one. + if enabled then etag = disable end + etag = etag ? etag : cloudfront_client.get_distribution({id: @property_hash[:id]}).etag + + begin + cloudfront_client.delete_distribution({ + id: @property_hash[:id], + if_match: etag, + }) + + @property_hash[:ensure] = :absent + rescue Aws::CloudFront::Errors::DistributionNotDisabled + Puppet.warning("The CloudFront distribution #{@property_hash[:name]} is not finished being disabled and cannot be deleted yet.") + end + end + + def enabled? + @property_hash[:enabled] == true + end + + def enable + enable_or_disable(:enable) + end + + def disable + enable_or_disable(:disable) + end + + def enable_or_disable(which) + to_enable = case which + when :enable; true + when :disable; false + else + fail "'#{which}' is neither :enable nor :disable" + end + + dist_resp = cloudfront_client.get_distribution({id: @property_hash[:id]}) + dist_resp.distribution.distribution_config.enabled = to_enable + dist_disabled_resp = cloudfront_client.update_distribution({ + id: @property_hash[:id], + if_match: dist_resp.etag, + distribution_config: dist_resp.distribution.distribution_config, + }) + + @property_hash[:enabled] = to_enable + + dist_disabled_resp.etag + end + + def flush + if @property_hash[:ensure] != :present then return end + if @property_hash[:just_created] then return end + + Puppet.warning('Altering a CloudFront distribution is not supported yet.') + end + +end diff --git a/lib/puppet/type/cloudfront_distribution.rb b/lib/puppet/type/cloudfront_distribution.rb new file mode 100644 index 00000000..45caabbd --- /dev/null +++ b/lib/puppet/type/cloudfront_distribution.rb @@ -0,0 +1,102 @@ +require_relative '../../puppet_x/puppetlabs/property/tag.rb' + +Puppet::Type.newtype(:cloudfront_distribution) do + @doc = 'Type representing a CloudFront distribution.' + + ensurable + + newparam(:name, namevar: true) do + desc 'The name of the distribution to manage.' + validate do |value| + fail Puppet::Error, 'Empty distribution names are not allowed' if value == '' + end + end + + newproperty(:arn) do + desc 'Read-only unique AWS resource name assigned to the distribution' + end + + newproperty(:id) do + desc 'Read-only unique distribution ID' + end + + newproperty(:status) do + desc 'Read-only status of the distribution' + end + + newproperty(:comment) do + desc 'Comment for the distribution' + end + + newproperty(:enabled, :boolean => true) do + desc 'If the distribution is enabled' + defaultto true + end + + newproperty(:price_class) do + desc 'Price class of the distribution' + defaultto 'all' + validate do |value| + fail "Invalid price class '#{value}'" unless ['all', '100', '200'].include? value + end + end + + newproperty(:origins, :array_matching => :all) do + desc 'Array of origins for the distribution' + validate do |value| + fail 'Origin requires an ID' unless value['id'] + fail 'Origin requires a domain name' unless value['domain_name'] + + case value['type'].downcase + when nil, 'custom' + if value['http_port'] then + fail 'Invalid HTTP port number' unless value['http_port'].to_i > 0 + end + if value['https_port'] then + fail 'Invalid HTTPS port number' unless value['https_port'].to_i > 0 + end + if value['protocol_policy'] then + fail 'Invalid protocol policy' unless value['protocol_policy'].all? do |policy| + ['match-viewer', 'http-only', 'https-only'].include? policy.downcase + end + end + if value['protocols'] then + fail 'Invalid protocol set' unless value['protocols'].all? do |proto| + ['SSLv3', 'TLSv1', 'TLSv1.1', 'TLSv1.2'].include? proto + end + end + when 's3' + fail 'S3 origins are not supported' + else + fail "Unknown origin type: #{value['type']}" + end + end + + munge do |value| + clean = { + # Default origin type to custom + 'type' => value['type'] ? value['type'].downcase : 'custom', + # Default to no path + 'path' => value['path'] ? value['path'] : '', + # Make ports ints and default to 80 and 443 + 'http_port' => value['http_port'] ? value['http_port'] : '80', + 'https_port' => value['https_port'] ? value['https_port'] : '443', + # Default protocol policy to match viewer + 'protocol_policy' => value['protocol_policy'] ? value['protocol_policy'].downcase : 'match-viewer', + # Default protocols to any TLS + 'protocols' => value['protocols'] ? value['protocols'] : ['TLSv1', 'TLSv1.1', 'TLSv1.2'], + } + + value.merge clean + end + + def insync?(is) + provider.class.normalize_values(is) == provider.class.normalize_values(should) + end + end + + newproperty(:tags, :parent => PuppetX::Property::AwsTag) do + desc 'The tags for the distribution' + end + +end diff --git a/lib/puppet_x/puppetlabs/aws.rb b/lib/puppet_x/puppetlabs/aws.rb index 184631d0..dbbd13e5 100644 --- a/lib/puppet_x/puppetlabs/aws.rb +++ b/lib/puppet_x/puppetlabs/aws.rb @@ -234,6 +234,14 @@ def ecs_client(region = default_region) self.class.ecs_client(region) end + def self.cloudfront_client(region = default_region) + ::Aws::CloudFront::Client.new(client_config(region)) + end + + def cloudfront_client(region = default_region) + self.class.cloudfront_client(region) + end + def tags_for_resource tags = resource[:tags] ? resource[:tags].map { |k,v| {key: k, value: v} } : [] tags << {key: 'Name', value: name} From e9b20e527d303f0ce76010a08332aca90b44f16d Mon Sep 17 00:00:00 2001 From: Ian Shearin Date: Mon, 23 Jan 2017 15:00:48 -0800 Subject: [PATCH 42/72] Allow security groups mutual peering Without this change, two security groups cannot peer with each other. The first security group will be created, but will fail to add rules since the second security group does not exist yet. Further security groups will not be created due to the first security group failing and being a dependency. This skips rules that refer to security groups that do not exist. --- lib/puppet/provider/ec2_securitygroup/v2.rb | 35 ++++++++++++--------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/lib/puppet/provider/ec2_securitygroup/v2.rb b/lib/puppet/provider/ec2_securitygroup/v2.rb index 5fc76ed7..2492d737 100644 --- a/lib/puppet/provider/ec2_securitygroup/v2.rb +++ b/lib/puppet/provider/ec2_securitygroup/v2.rb @@ -164,22 +164,25 @@ def prepare_ingress_for_api(rule) group_response = ec2.describe_security_groups(filters: filters) match_count = group_response.data.security_groups.count - msg = "No groups found called #{source_group_name}" - msg = msg + " in #{@property_hash[:vpc]}" - fail(msg) if match_count == 0 - source_group_id = group_response.data.security_groups.first.group_id - Puppet.warning "#{match_count} groups found called #{source_group_name}, using #{source_group_id}" if match_count > 1 - - permission[:user_id_group_pairs] = [{ - group_id: source_group_id - }] + if match_count == 0 + Puppet.warning("No groups found called #{source_group_name} in #{@property_hash[:vpc]}; skipping rule") + else + source_group_id = group_response.data.security_groups.first.group_id + Puppet.warning "#{match_count} groups found called #{source_group_name}, using #{source_group_id}" if match_count > 1 + + permission[:user_id_group_pairs] = [{ + group_id: source_group_id + }] + end elsif rule.key? 'cidr' permission[:ip_ranges] = [{cidr_ip: rule['cidr']}] end - rule_hash[:ip_permissions] << permission + + # Skip the permission if it has no peer. + rule_hash[:ip_permissions] << permission unless (permission.keys & [:user_id_group_pairs, :ip_ranges]).empty? end - rule_hash + rule_hash[:ip_permissions].any? ? rule_hash : nil end def authorize_ingress(new_rules, existing_rules=[]) @@ -190,12 +193,14 @@ def authorize_ingress(new_rules, existing_rules=[]) to_create = parser.rules_to_create(existing_rules) to_delete = parser.rules_to_delete(existing_rules) - to_delete.reject(&:nil?).each do |rule| - ec2.revoke_security_group_ingress(prepare_ingress_for_api(rule)) + to_delete.compact.each do |rule| + prepared_rule = prepare_ingress_for_api(rule) and + ec2.revoke_security_group_ingress(prepared_rule) end - to_create.each do |rule| - ec2.authorize_security_group_ingress(prepare_ingress_for_api(rule)) + to_create.compact.each do |rule| + prepared_rule = prepare_ingress_for_api(rule) and + ec2.authorize_security_group_ingress(prepared_rule) end end From ec3192f5e1d8037b65bd57c865ee2a21b49313b7 Mon Sep 17 00:00:00 2001 From: Dave Seff Date: Thu, 18 Feb 2016 09:57:31 +1000 Subject: [PATCH 43/72] Support for managing EC2 Volumes --- README.md | 30 ++++++ lib/puppet/provider/ec2_volume/v2.rb | 119 +++++++++++++++++++++++ lib/puppet/type/ec2_volume.rb | 102 +++++++++++++++++++ spec/unit/provider/ec2_volume/v2_spec.rb | 29 ++++++ spec/unit/type/ec2_volume_spec.rb | 68 +++++++++++++ 5 files changed, 348 insertions(+) create mode 100644 lib/puppet/provider/ec2_volume/v2.rb create mode 100644 lib/puppet/type/ec2_volume.rb create mode 100644 spec/unit/provider/ec2_volume/v2_spec.rb create mode 100644 spec/unit/type/ec2_volume_spec.rb diff --git a/README.md b/README.md index 873fa31b..285e6ac9 100644 --- a/README.md +++ b/README.md @@ -314,6 +314,7 @@ You can use the aws module to audit AWS resources, launch autoscaling groups in * `cloudfront_distribution`: Sets up a CloudFront distribution. * `ec2_instance`: Sets up an EC2 instance. * `ec2_securitygroup`: Sets up an EC2 security group. +* `ec2_volume`: Sets up an EC2 EBS volume. * `elb_loadbalancer`: Sets up an ELB load balancer. * `cloudwatch_alarm`: Sets up a Cloudwatch Alarm. * `ec2_autoscalinggroup`: Sets up an EC2 auto scaling group. @@ -569,6 +570,35 @@ back- end instances. Accepts a hash with the following keys: #####`scheme` *Optional* Whether the load balancer is internal or public facing. This parameter is set at creation only; it is not affected by updates. Valid values are 'internal', 'internet-facing'. Default value is 'internet-facing' and makes the load balancer publicly available. +#### Type: ec2_volume + +##### `name` +*Required* The name of the volume + +##### `region` +*Required* The region in which to create the volume. For valid values, see [AWS Regions](http://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region). + +##### `size` +*Conditional* The size of the EBS volume in GB. if restoring from snapshot this parameter is not required. + +##### `iops` +*Optional* Only valid for Provisioned IOPS SSD volumes. The number of I/O operations per second (IOPS) to provision for the volume, with a maximum ratio of 50 IOPS/GiB. + +##### `availability_zone` +*Required* The availability zones in which to create the volume. Accepts an array of availability zone codes. For valid availability zone codes, see [AWS Regions and Availability Zones](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html). + +##### `volume_type` +*Required* The volume type. This can be gp2 for General Purpose SSD, io1 for Provisioned IOPS SSD, st1 for Throughput Optimized HDD, sc1 for Cold HDD, or standard for Magnetic volumes. + +##### `encrypted` +*Optional* Specifies whether the volume should be encrypted. Encrypted Amazon EBS volumes may only be attached to instances that support Amazon EBS encryption. Volumes that are created from encrypted snapshots are automatically encrypted. There is no way to create an encrypted volume from an unencrypted snapshot or vice versa. + +##### `kms_key_id` +*Optional* The full ARN of the AWS Key Management Service (AWS KMS) customer master key (CMK) to use when creating the encrypted volume. This parameter is only required if you want to use a non-default CMK; if this parameter is not specified, the default CMK for EBS is used. + +##### `snapshot_id` +*Optional* The snapshot from which to create the volume. + #### Type: cloudwatch_alarm ##### `name` diff --git a/lib/puppet/provider/ec2_volume/v2.rb b/lib/puppet/provider/ec2_volume/v2.rb new file mode 100644 index 00000000..30e83221 --- /dev/null +++ b/lib/puppet/provider/ec2_volume/v2.rb @@ -0,0 +1,119 @@ +require_relative '../../../puppet_x/puppetlabs/aws' + +Puppet::Type.type(:ec2_volume).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do + confine feature: :aws + + mk_resource_methods + + def self.instances + regions.collect do |region| + ec2 = ec2_client(region) + begin + volumes = [] + volume_response = ec2.describe_volumes() + volume_response.data.volumes.collect do |volume| + hash = volume_to_hash(region, volume) + volumes << new(hash) if has_name?(hash) + end + volumes + rescue Timeout::Error, StandardError => e + raise PuppetX::Puppetlabs::FetchingAWSDataError.new(region, self.resource_type.name.to_s, e.message) + end + end.flatten + end + + def self.prefetch(resources) + instances.each do |prov| + if resource = resources[prov.name] # rubocop:disable Lint/AssignmentInCondition + resource.provider = prov if resource[:region] == prov.region + end + end + end + + def self.volume_to_hash(region, volume) + name = name_from_tag(volume) + attachments = volume.attachments.collect do |att| + { + instance_id: att.instance_id, + device: att.device, + } + end + config = { + name: name, + volume_id: volume.volume_id, + size: volume.size, + iops: volume.iops, + volume_type: volume.volume_type, + availability_zone: volume.availability_zone, + snapshot_id: volume.snapshot_id, + ensure: :present, + region: region, + } + config[:attach] = attachments unless attachments.empty? + config + end + + def exists? + Puppet.info("Checking if EC2 volume #{name} exists in region #{target_region}") + @property_hash[:ensure] == :present + end + + def create_from_snapshot(config) + snapshot = resource[:snapshot_id] ? resource[:snapshot_id] : false + config['snapshot_id'] = snapshot if snapshot + config + end + + def ec2 + ec2 = ec2_client(target_region) + ec2 + end + + def attach_instance(volume_id) + config = {} + config[:instance_id] = resource[:attach]["instance_id"] + config[:volume_id] = volume_id + config[:device] = resource[:attach]["device"] + Puppet.info("Attaching Volume #{volume_id} to ec2 instance #{config[:instance_id]}") + ec2.wait_until(:volume_available, volume_ids: [volume_id]) + ec2.attach_volume(config) + end + + def create + Puppet.info("Creating Volume #{name} in region #{target_region}") + config = { + size: resource[:size], + availability_zone: resource[:availability_zone], + volume_type: resource[:volume_type], + iops: resource[:iops], + encrypted: resource[:encrypted], + kms_key_id: resource[:kms_key_id], + } + + config = create_from_snapshot(config) + response = ec2.create_volume(config) + + ec2.create_tags( + resources: [response.volume_id], + tags: tags_for_resource + ) if resource[:tags] + + attach_instance(response.volume_id) if resource[:attach] + + @property_hash[:id] = response.volume_id + @property_hash[:ensure] = :present + end + + def destroy + Puppet.info("Deleting Volume #{name} in region #{target_region}") + # Detach if in use first + config = { + volume_id: volume_id, + force: true + } + ec2.detach_volume(config) unless @property_hash[:attach] == nil + ec2.wait_until(:volume_available, volume_ids: [volume_id]) + ec2.delete_volume(volume_id: volume_id) + @property_hash[:ensure] = :absent + end +end diff --git a/lib/puppet/type/ec2_volume.rb b/lib/puppet/type/ec2_volume.rb new file mode 100644 index 00000000..1a6ea1c8 --- /dev/null +++ b/lib/puppet/type/ec2_volume.rb @@ -0,0 +1,102 @@ +require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require 'puppet/property/boolean' + +Puppet::Type.newtype(:ec2_volume) do + @doc = 'type representing an EC2 Block Device' + + ensurable + + newparam(:name, namevar: true) do + desc 'the name of the security group' + validate do |value| + fail 'Volume must have a name' if value == '' + fail 'name should be a String' unless value.is_a?(String) + end + end + + newproperty(:region) do + desc 'the region in which to launch the volume' + validate do |value| + fail 'region should not contain spaces' if value =~ /\s/ + fail 'region should be a String' unless value.is_a?(String) + end + end + + newproperty(:tags, :parent => PuppetX::Property::AwsTag) do + desc 'the tags for the volume' + end + + newproperty(:description) do + desc 'a short description of the volume' + validate do |value| + fail 'description cannot be blank' if value == '' + fail 'description should be a String' unless value.is_a?(String) + end + end + + newproperty(:availability_zone) do + desc 'The availability zone in which to place the instance.' + validate do |value| + fail 'availability_zone should not contain spaces' if value =~ /\s/ + fail 'availability_zone should not be blank' if value == '' + fail 'availability_zone should be a String' unless value.is_a?(String) + end + end + + newproperty(:size) do + desc 'The size in GB of the volume.' + validate do |value| + fail 'Size should be a integer' unless value =~ /^\d+$/ + end + end + + newproperty(:volume_id) do + desc 'aws id of volume' + validate do |value| + fail "Volume Type should be a String: #{value}" unless value.is_a?(String) + end + end + + newproperty(:volume_type) do + desc 'standard, io1, gp2' + validate do |value| + fail "Volume Type should be a String: #{value}" unless value.is_a?(String) + end + end + + newproperty(:snapshot_id) do + desc 'The snapshot that this volume should be created from' + validate do |value| + fail 'snapshot_id should be an string' unless value.is_a?(String) + end + end + + newproperty(:attach) do + desc 'The ec2 instance that this volume should attach to' + validate do |value| + attachments = value.is_a?(Array) ? value : [value] + attachments.each do |params| + fail "must supply instance id" unless value.keys.include?('instance_id') + fail "must supply device name" unless value.keys.include?('device') + end + end + end + + newproperty(:iops) do + desc 'Provisioned iops for volume' + validate do |value| + fail 'iops should be an integer' unless value =~ /^\d+$/ + end + end + + newproperty(:kms_key_id) do + desc 'The full ARN of the AWS Key Management Service (AWS KMS) customer master key (CMK) to use when creating the encrypted volume.' + validate do |value| + fail 'kms_key_id should be an string' unless value.is_a?(String) + end + end + + newproperty(:encrypted, parent: Puppet::Property::Boolean) do + desc 'Indicates whether newly created volume should be encrypted.' + end +end diff --git a/spec/unit/provider/ec2_volume/v2_spec.rb b/spec/unit/provider/ec2_volume/v2_spec.rb new file mode 100644 index 00000000..cfebd760 --- /dev/null +++ b/spec/unit/provider/ec2_volume/v2_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +provider_class = Puppet::Type.type(:ec2_volume).provider(:v2) + +ENV['AWS_ACCESS_KEY_ID'] = 'redacted' +ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' +ENV['AWS_REGION'] = 'sa-east-1' + +describe provider_class do + + let(:resource) { + Puppet::Type.type(:ec2_volume).new( + name: 'test-volume', + region: 'sa-east-1', + size: '10', + volume_type: 'gp2', + iops: '300', + availability_zone: 'sa-east-1a', + ) + } + + let(:provider) { resource.provider } + + let(:instance) { provider.class.instances.first } + + it 'should be an instance of the ProviderV2' do + expect(provider).to be_an_instance_of Puppet::Type::Ec2_volume::ProviderV2 + end +end diff --git a/spec/unit/type/ec2_volume_spec.rb b/spec/unit/type/ec2_volume_spec.rb new file mode 100644 index 00000000..721da01f --- /dev/null +++ b/spec/unit/type/ec2_volume_spec.rb @@ -0,0 +1,68 @@ +require 'spec_helper' + +type_class = Puppet::Type.type(:ec2_volume) + +describe type_class do + + let :params do + [ + :name, + ] + end + + let :properties do + [ + :ensure, + :availability_zone, + :size, + :volume_type, + :iops, + :attach, + :region, + :tags, + ] + end + + it 'should have expected properties' do + properties.each do |property| + expect(type_class.properties.map(&:name)).to be_include(property) + end + end + + it 'should have expected parameters' do + params.each do |param| + expect(type_class.parameters).to be_include(param) + end + end + + it 'should require a name' do + expect { + type_class.new({}) + }.to raise_error(Puppet::Error, 'Title or name must be provided') + end + + it 'should require region to not contain spaces' do + expect { + type_class.new({name: 'name', region: 'invalid region'}) + }.to raise_error(Puppet::Error, /region should not contain spaces/) + end + + [ + 'name', + 'availability_zone', + 'region', + ].each do |property| + it "should require #{property} to be a string" do + expect(type_class).to require_string_for(property) + end + end + + it "should require tags to be a hash" do + expect(type_class).to require_hash_for('tags') + end + + it 'should order tags on output' do + expect(type_class).to order_tags_on_output + end + +end From 0664a53d3806adb83dcd6293a218eab12ec32b0b Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Tue, 10 Jan 2017 12:46:26 -0800 Subject: [PATCH 44/72] Begin filtering sensitive data during VCR recording Without this change, module testers are left to their own methods to ensure that they are not leaking any sensitive material when contributing to this module. This is not good, as a) we want more tests and b) we would like not to expose data from contributor environments when submitting changes. Here we take a stab addressing this concern by configuring VCR to filter out the AWS_ACCESS_KEY_ID. This alone is not enough to be complete, but it begins the road of making testing simpler on the part of those who wish to contribute to the module. Now we can amend the documentation to include information about exporting the necessary environment variables, not providers specs don't have to modified last minute to avoid committing credentials. --- CONTRIBUTING.md | 68 +++++++++++-------- spec/spec_helper.rb | 31 +++++++++ .../unit/provider/cloudwatch_alarm/v2_spec.rb | 3 - spec/unit/provider/ec2_elastic_ip/v2_spec.rb | 3 - spec/unit/provider/ec2_instance/v2_spec.rb | 3 - .../unit/provider/ec2_launchconfig/v2_spec.rb | 3 - .../provider/ec2_scalingpolicy/v2_spec.rb | 3 - .../provider/ec2_securitygroup/v2_spec.rb | 3 - spec/unit/provider/ecs_service/v2_spec.rb | 7 -- .../provider/ecs_task_definition/v2_spec.rb | 6 -- .../unit/provider/elb_loadbalancer/v2_spec.rb | 3 - spec/unit/provider/iam_user/v2_spec.rb | 3 - .../provider/rds_db_securitygroup/v2_spec.rb | 3 - spec/unit/provider/rds_instance/v2_spec.rb | 3 - spec/unit/provider/route53_record/v2_spec.rb | 3 - spec/unit/provider/route53_zone/v2_spec.rb | 3 - spec/unit/provider/s3_bucket/v2_spec.rb | 6 -- spec/unit/provider/sqs_queue/v2_spec.rb | 3 - 18 files changed, 69 insertions(+), 88 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d545cbd9..ba5383b0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -198,13 +198,25 @@ Unit Testing with VCR --------------------- VCR is a utility for testing which is used to capture the requests and -responses to the AWS APIs. The results of a transaction are stored in a YAML -file that can then be loaded later and used to validate data structures etc -without requiring access to AWS. This comes in handy when unit testing using -Rspec. - -Consider the following test for a new provider. - +responses to and from the AWS APIs. The results of a transaction are stored in +a YAML file that can then be loaded later and used to validate data structures +etc without requiring access to AWS. This comes in handy when unit testing +using Rspec, as the calls can be made once, and the communication can be stored +for future testing. + +Consider the following test for a new provider. In order to create new fixture +files, or to replace existing fixtures, you must have the following environment +variables set. + + AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY + AWS_REGION + +This will allow the spec tests to call out to AWS on your behalf and store the +responses. A minimal amount of automatic filtering is done to ensure that the +stored YAML files do not contain sensitive information, like the account +number, or your access credential ID. This filtering is done in the +`spec_helper`. ```Ruby require 'spec_helper' @@ -213,12 +225,6 @@ provider_class = Puppet::Type.type(:snazzy_new_type).provider(:v2) describe provider_class do - before do - ENV['AWS_ACCESS_KEY_ID'] = 'something goes here' - ENV['AWS_SECRET_ACCESS_KEY'] = 'something else goes here' - ENV['AWS_REGION'] = 'us-west-2' - end - let(:provider) { resource.provider } ``` @@ -274,32 +280,34 @@ You may notice that some tests make use of multiple cassettes. One might test the environment for creating a resource. One might test the environment for tearing down a resource. This is all an exercise left to the developer. +Its worth noting, that perioically it may be advisiable to remove the exissting +fixutre files and run the specs locally to allow new fixutres to be captured +using VCR. This might become more important if larg refactors are being done +on an existing provider, or new calls need ot be made for extended +functionality. + ### Tidying up! IMPORTANT Its important to tidy up on spec tests before committing. Its easy to do, so just remember to tidy up. You don't want to commit your credentials to GitHub, as I have done this morning. -Firstly, replace the credentials in the `before` block within any spec files -that you have written. - -Secondly, replace the credential reference in the resulting cassette yaml -files. I use something like the following. - -``` -sed -i '' -e 's/ABCEFGOOOOOOOOOOOOOOR/AAAAAAAAAAAAAAAAAAAAA/g' -e 's/123456789101/111111111111/g' fixtures/vcr_cassettes/*.yml -``` +It is no longer necessary to write your credentials anywhere in the spec test +files. Exporting the variables is all that is required now, so that the +version-tracked files never contain credential inforamtion, and there is not a +concern of accidentally committing keys, as many of us have done. -The above 'sed' replaces my account id of '123456789101' with a string of -matching length which is not my account id. Also above, we replace the access -credential of 'ABCEFGOOOOOOOOOOOOOOR' with a string of matching length. I -don't believe keeping the length of the strings is required, but I do it -anyway. +As mentioned above, some of the responses may contain sensitive information, +and a small amount of automatic filtering is done in `spec_helper.rb` to +ensure that accout and credential information is not stored in the YAML. -If you do both of the above, then you should not have account information, -identity information, or credential information in either the `_sepc.rb` test -files, or the VCR cassette files. +What you consider sensitive may depend on your organization. +It is advisable to create a seperate AWS accout for testing, as some of the +specs will store information like a list of users or groups for the given +account. For example, when working on the IAM providers, I would not want a +list of users for my organization to be stored in YAML, but for a development +account, this is more accaptable. This is up to you. If you have commit access to the repository =========================================== diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0c9ad5ff..71dc5f8c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,9 +5,40 @@ WebMock.disable_net_connect! +unless ENV['AWS_ACCESS_KEY_ID'] + ENV['AWS_ACCESS_KEY_ID'] = 'redacted' +end + +unless ENV['AWS_SECRET_ACCESS_KEY'] + ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' +end + +unless ENV['AWS_REGION'] + ENV['AWS_REGION'] = 'sa-east-1' +end + VCR.configure do |c| c.cassette_library_dir = 'fixtures/vcr_cassettes' c.hook_into :webmock + c.filter_sensitive_data('111111111111') { ENV['AWS_ACCESS_KEY_ID'] } + + # Filter the account number from arn references + c.filter_sensitive_data('123456789012') {|i| + # arn:aws:component:region:account:otherstuff + if matches = /arn:aws:\w+:([\-\w]+)?:(\d{12}):/.match(i.response.body) + matches[2] + end + } + + # Filter account from ELB Data + c.filter_sensitive_data('123456789012') {|i| + if matches = /(\d{12})<\/OwnerAlias>/.match(i.response.body) + matches[1] + elsif matches = /(\d{12})<\/ownerId>/.match(i.response.body) + matches[1] + end + } + end if ENV['PARSER'] == 'future' diff --git a/spec/unit/provider/cloudwatch_alarm/v2_spec.rb b/spec/unit/provider/cloudwatch_alarm/v2_spec.rb index 634ec061..c812ed4d 100644 --- a/spec/unit/provider/cloudwatch_alarm/v2_spec.rb +++ b/spec/unit/provider/cloudwatch_alarm/v2_spec.rb @@ -2,9 +2,6 @@ provider_class = Puppet::Type.type(:cloudwatch_alarm).provider(:v2) -ENV['AWS_ACCESS_KEY_ID'] = 'redacted' -ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' -ENV['AWS_REGION'] = 'sa-east-1' describe provider_class do diff --git a/spec/unit/provider/ec2_elastic_ip/v2_spec.rb b/spec/unit/provider/ec2_elastic_ip/v2_spec.rb index 36688fb5..952eb531 100644 --- a/spec/unit/provider/ec2_elastic_ip/v2_spec.rb +++ b/spec/unit/provider/ec2_elastic_ip/v2_spec.rb @@ -2,9 +2,6 @@ provider_class = Puppet::Type.type(:ec2_elastic_ip).provider(:v2) -ENV['AWS_ACCESS_KEY_ID'] = 'redacted' -ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' -ENV['AWS_REGION'] = 'sa-east-1' describe provider_class do diff --git a/spec/unit/provider/ec2_instance/v2_spec.rb b/spec/unit/provider/ec2_instance/v2_spec.rb index 1225e5e8..bbe65b6c 100644 --- a/spec/unit/provider/ec2_instance/v2_spec.rb +++ b/spec/unit/provider/ec2_instance/v2_spec.rb @@ -2,9 +2,6 @@ provider_class = Puppet::Type.type(:ec2_instance).provider(:v2) -ENV['AWS_ACCESS_KEY_ID'] = 'redacted' -ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' -ENV['AWS_REGION'] = 'sa-east-1' describe provider_class do diff --git a/spec/unit/provider/ec2_launchconfig/v2_spec.rb b/spec/unit/provider/ec2_launchconfig/v2_spec.rb index 62e81345..6a53a255 100644 --- a/spec/unit/provider/ec2_launchconfig/v2_spec.rb +++ b/spec/unit/provider/ec2_launchconfig/v2_spec.rb @@ -2,9 +2,6 @@ provider_class = Puppet::Type.type(:ec2_launchconfiguration).provider(:v2) -ENV['AWS_ACCESS_KEY_ID'] = 'redacted' -ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' -ENV['AWS_REGION'] = 'sa-east-1' describe provider_class do diff --git a/spec/unit/provider/ec2_scalingpolicy/v2_spec.rb b/spec/unit/provider/ec2_scalingpolicy/v2_spec.rb index 470f8142..e1279c4c 100644 --- a/spec/unit/provider/ec2_scalingpolicy/v2_spec.rb +++ b/spec/unit/provider/ec2_scalingpolicy/v2_spec.rb @@ -2,9 +2,6 @@ provider_class = Puppet::Type.type(:ec2_scalingpolicy).provider(:v2) -ENV['AWS_ACCESS_KEY_ID'] = 'redacted' -ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' -ENV['AWS_REGION'] = 'sa-east-1' describe provider_class do diff --git a/spec/unit/provider/ec2_securitygroup/v2_spec.rb b/spec/unit/provider/ec2_securitygroup/v2_spec.rb index 5636a0da..4ed47aa0 100644 --- a/spec/unit/provider/ec2_securitygroup/v2_spec.rb +++ b/spec/unit/provider/ec2_securitygroup/v2_spec.rb @@ -2,9 +2,6 @@ provider_class = Puppet::Type.type(:ec2_securitygroup).provider(:v2) -ENV['AWS_ACCESS_KEY_ID'] = 'redacted' -ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' -ENV['AWS_REGION'] = 'sa-east-1' describe provider_class do diff --git a/spec/unit/provider/ecs_service/v2_spec.rb b/spec/unit/provider/ecs_service/v2_spec.rb index aab30292..217d9561 100644 --- a/spec/unit/provider/ecs_service/v2_spec.rb +++ b/spec/unit/provider/ecs_service/v2_spec.rb @@ -2,15 +2,8 @@ provider_class = Puppet::Type.type(:ecs_service).provider(:v2) - describe provider_class do - before do - ENV['AWS_ACCESS_KEY_ID'] = 'redacted' - ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' - ENV['AWS_REGION'] = 'us-west-2' - end - let(:resource) { Puppet::Type.type(:ecs_service).new( name: 'myshinyservice', diff --git a/spec/unit/provider/ecs_task_definition/v2_spec.rb b/spec/unit/provider/ecs_task_definition/v2_spec.rb index 8da47f7d..cec9ee6e 100644 --- a/spec/unit/provider/ecs_task_definition/v2_spec.rb +++ b/spec/unit/provider/ecs_task_definition/v2_spec.rb @@ -5,12 +5,6 @@ describe provider_class do - before do - ENV['AWS_ACCESS_KEY_ID'] = 'redacted' - ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' - ENV['AWS_REGION'] = 'us-west-2' - end - let(:resource) { Puppet::Type.type(:ecs_task_definition).new( name: 'omgolly123', diff --git a/spec/unit/provider/elb_loadbalancer/v2_spec.rb b/spec/unit/provider/elb_loadbalancer/v2_spec.rb index 2b02f6c4..eaabf057 100644 --- a/spec/unit/provider/elb_loadbalancer/v2_spec.rb +++ b/spec/unit/provider/elb_loadbalancer/v2_spec.rb @@ -2,9 +2,6 @@ provider_class = Puppet::Type.type(:elb_loadbalancer).provider(:v2) -ENV['AWS_ACCESS_KEY_ID'] = 'redacted' -ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' -ENV['AWS_REGION'] = 'sa-east-1' describe provider_class do diff --git a/spec/unit/provider/iam_user/v2_spec.rb b/spec/unit/provider/iam_user/v2_spec.rb index c7b316af..8adc4ca4 100644 --- a/spec/unit/provider/iam_user/v2_spec.rb +++ b/spec/unit/provider/iam_user/v2_spec.rb @@ -2,9 +2,6 @@ provider_class = Puppet::Type.type(:iam_user).provider(:v2) -ENV['AWS_ACCESS_KEY_ID'] = 'redacted' -ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' -ENV['AWS_REGION'] = 'sa-east-1' describe provider_class do diff --git a/spec/unit/provider/rds_db_securitygroup/v2_spec.rb b/spec/unit/provider/rds_db_securitygroup/v2_spec.rb index 5e72fa30..ffd7a230 100644 --- a/spec/unit/provider/rds_db_securitygroup/v2_spec.rb +++ b/spec/unit/provider/rds_db_securitygroup/v2_spec.rb @@ -2,9 +2,6 @@ provider_class = Puppet::Type.type(:rds_db_securitygroup).provider(:v2) -ENV['AWS_ACCESS_KEY_ID'] = 'redacted' -ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' -ENV['AWS_REGION'] = 'sa-east-1' describe provider_class do diff --git a/spec/unit/provider/rds_instance/v2_spec.rb b/spec/unit/provider/rds_instance/v2_spec.rb index c98537d7..f271a1cd 100644 --- a/spec/unit/provider/rds_instance/v2_spec.rb +++ b/spec/unit/provider/rds_instance/v2_spec.rb @@ -2,9 +2,6 @@ provider_class = Puppet::Type.type(:rds_instance).provider(:v2) -ENV['AWS_ACCESS_KEY_ID'] = 'redacted' -ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' -ENV['AWS_REGION'] = 'sa-east-1' describe provider_class do diff --git a/spec/unit/provider/route53_record/v2_spec.rb b/spec/unit/provider/route53_record/v2_spec.rb index 596a36ff..c8ad685d 100644 --- a/spec/unit/provider/route53_record/v2_spec.rb +++ b/spec/unit/provider/route53_record/v2_spec.rb @@ -2,9 +2,6 @@ provider_class = Puppet::Type.type(:route53_a_record).provider(:v2) -ENV['AWS_ACCESS_KEY_ID'] = 'redacted' -ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' -ENV['AWS_REGION'] = 'sa-east-1' describe provider_class do diff --git a/spec/unit/provider/route53_zone/v2_spec.rb b/spec/unit/provider/route53_zone/v2_spec.rb index d2025efc..2c5580ec 100644 --- a/spec/unit/provider/route53_zone/v2_spec.rb +++ b/spec/unit/provider/route53_zone/v2_spec.rb @@ -2,9 +2,6 @@ provider_class = Puppet::Type.type(:route53_zone).provider(:v2) -ENV['AWS_ACCESS_KEY_ID'] = 'redacted' -ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' -ENV['AWS_REGION'] = 'sa-east-1' describe provider_class do diff --git a/spec/unit/provider/s3_bucket/v2_spec.rb b/spec/unit/provider/s3_bucket/v2_spec.rb index 8502289e..e56466c5 100644 --- a/spec/unit/provider/s3_bucket/v2_spec.rb +++ b/spec/unit/provider/s3_bucket/v2_spec.rb @@ -5,12 +5,6 @@ describe provider_class do - before do - ENV['AWS_ACCESS_KEY_ID'] = 'redacted' - ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' - ENV['AWS_REGION'] = 'us-west-2' - end - context 'with the minimum params' do let(:resource) { Puppet::Type.type(:s3_bucket).new( diff --git a/spec/unit/provider/sqs_queue/v2_spec.rb b/spec/unit/provider/sqs_queue/v2_spec.rb index ceb5bb5a..dfbf2284 100644 --- a/spec/unit/provider/sqs_queue/v2_spec.rb +++ b/spec/unit/provider/sqs_queue/v2_spec.rb @@ -4,9 +4,6 @@ provider_class = Puppet::Type.type(:sqs_queue).provider(:v2) -ENV['AWS_ACCESS_KEY_ID'] = 'redacted' -ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' -ENV['AWS_REGION'] = 'sa-east-1' describe provider_class do context 'with params' do From 9bf5d2ecba50168872f6fa0d3a0e697c3007c0d3 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 11 Jan 2017 11:05:42 -0800 Subject: [PATCH 45/72] Update tests for filtering changes This work is part of updating the way spec tests are handled by VCR. Here we update the fixtures, and make a few test improvements that were brought about by the improved spec handling. --- CONTRIBUTING.md | 6 +- fixtures/vcr_cassettes/create-ecs_service.yml | 52 + .../create-ecs_task_definition.yml | 52 + fixtures/vcr_cassettes/create-elb-test.yml | 315 ++-- fixtures/vcr_cassettes/create-iam_group.yml | 59 + fixtures/vcr_cassettes/create-iam_user.yml | 59 + .../vcr_cassettes/create-instance-profile.yml | 72 +- fixtures/vcr_cassettes/create-role.yml | 58 +- fixtures/vcr_cassettes/create-user.yml | 125 -- .../vcr_cassettes/destroy-ecs_service.yml | 52 + .../destroy-ecs_task_definition.yml | 248 ++++ fixtures/vcr_cassettes/destroy-elb-test.yml | 97 +- fixtures/vcr_cassettes/destroy-iam_group.yml | 225 +++ fixtures/vcr_cassettes/destroy-iam_user.yml | 284 ++++ fixtures/vcr_cassettes/ecs-service-setup.yml | 507 ------- fixtures/vcr_cassettes/ecs-setup.yml | 297 ---- fixtures/vcr_cassettes/ecs_service-setup.yml | 444 ++++++ .../ecs_task_definition-setup.yml | 395 +++++ fixtures/vcr_cassettes/elb-named-test.yml | 642 ++++----- fixtures/vcr_cassettes/elb-setup.yml | 1274 ++++++++--------- fixtures/vcr_cassettes/iam_group-setup.yml | 385 +++++ fixtures/vcr_cassettes/iam_user-setup.yml | 153 ++ .../vcr_cassettes/instance-profiles-named.yml | 36 +- fixtures/vcr_cassettes/no-elb-named-test.yml | 101 +- fixtures/vcr_cassettes/roles-named.yml | 29 +- fixtures/vcr_cassettes/s3-bucket.yml | 92 +- fixtures/vcr_cassettes/users-named.yml | 64 - lib/puppet/provider/ecs_service/v2.rb | 4 +- lib/puppet/provider/ecs_task_definition/v2.rb | 3 +- lib/puppet/provider/elb_loadbalancer/v2.rb | 8 +- lib/puppet/provider/iam_group/v2.rb | 16 +- spec/unit/provider/ecs_service/v2_spec.rb | 33 +- .../provider/ecs_task_definition/v2_spec.rb | 81 +- .../unit/provider/elb_loadbalancer/v2_spec.rb | 24 +- spec/unit/provider/iam_group/v2_spec.rb | 59 + .../provider/iam_instance_profile/v2_spec.rb | 6 - spec/unit/provider/iam_role/v2_spec.rb | 6 - spec/unit/provider/iam_user/v2_spec.rb | 22 +- spec/unit/type/iam_instance_profile_spec.rb | 6 - spec/unit/type/iam_role_spec.rb | 6 - 40 files changed, 3885 insertions(+), 2512 deletions(-) create mode 100644 fixtures/vcr_cassettes/create-ecs_service.yml create mode 100644 fixtures/vcr_cassettes/create-ecs_task_definition.yml create mode 100644 fixtures/vcr_cassettes/create-iam_group.yml create mode 100644 fixtures/vcr_cassettes/create-iam_user.yml delete mode 100644 fixtures/vcr_cassettes/create-user.yml create mode 100644 fixtures/vcr_cassettes/destroy-ecs_service.yml create mode 100644 fixtures/vcr_cassettes/destroy-ecs_task_definition.yml create mode 100644 fixtures/vcr_cassettes/destroy-iam_group.yml create mode 100644 fixtures/vcr_cassettes/destroy-iam_user.yml delete mode 100644 fixtures/vcr_cassettes/ecs-service-setup.yml delete mode 100644 fixtures/vcr_cassettes/ecs-setup.yml create mode 100644 fixtures/vcr_cassettes/ecs_service-setup.yml create mode 100644 fixtures/vcr_cassettes/ecs_task_definition-setup.yml create mode 100644 fixtures/vcr_cassettes/iam_group-setup.yml create mode 100644 fixtures/vcr_cassettes/iam_user-setup.yml delete mode 100644 fixtures/vcr_cassettes/users-named.yml create mode 100644 spec/unit/provider/iam_group/v2_spec.rb diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ba5383b0..d4f94af2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -288,9 +288,9 @@ functionality. ### Tidying up! IMPORTANT -Its important to tidy up on spec tests before committing. Its easy to do, so -just remember to tidy up. You don't want to commit your credentials to GitHub, -as I have done this morning. +Its important to tidy up on spec tests before committing. This is easy to do, +so just remember to tidy up. You don't want to commit your credentials to +GitHub, as I have done this morning. It is no longer necessary to write your credentials anywhere in the spec test files. Exporting the variables is all that is required now, so that the diff --git a/fixtures/vcr_cassettes/create-ecs_service.yml b/fixtures/vcr_cassettes/create-ecs_service.yml new file mode 100644 index 00000000..86895b61 --- /dev/null +++ b/fixtures/vcr_cassettes/create-ecs_service.yml @@ -0,0 +1,52 @@ +--- +http_interactions: +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"serviceName":"testservice","desiredCount":0,"taskDefinition":"testtask","cluster":"test"}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.CreateService + X-Amz-Date: + - 20170111T222401Z + X-Amz-Content-Sha256: + - 3b876237a5fbef0a66e55a768e21e062696348d7004323e70c6a611a4c30686e + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=165676ac0310b87b5651cf96967719a47784948c338ba40b13340f2a6b54473e + Content-Length: + - '91' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 22:24:01 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '1017' + Connection: + - keep-alive + X-Amzn-Requestid: + - a75d4382-d84c-11e6-9fc4-c582c9263b89 + body: + encoding: UTF-8 + string: '{"service":{"clusterArn":"arn:aws:ecs:us-west-2:123456789012:cluster/test","createdAt":1.484173441895E9,"deploymentConfiguration":{"maximumPercent":200,"minimumHealthyPercent":100},"deployments":[{"createdAt":1.484173441895E9,"desiredCount":0,"id":"ecs-svc/9223370552681333906","pendingCount":0,"runningCount":0,"status":"PRIMARY","taskDefinition":"arn:aws:ecs:us-west-2:123456789012:task-definition/testtask:6","updatedAt":1.484173441895E9},{"createdAt":1.484173289602E9,"desiredCount":0,"id":"ecs-svc/9223370552681486168","pendingCount":0,"runningCount":0,"status":"ACTIVE","taskDefinition":"arn:aws:ecs:us-west-2:123456789012:task-definition/testtask:6","updatedAt":1.484173289602E9}],"desiredCount":0,"events":[],"loadBalancers":[],"pendingCount":0,"placementConstraints":[],"placementStrategy":[],"runningCount":0,"serviceArn":"arn:aws:ecs:us-west-2:123456789012:service/testservice","serviceName":"testservice","status":"ACTIVE","taskDefinition":"arn:aws:ecs:us-west-2:123456789012:task-definition/testtask:6"}}' + http_version: + recorded_at: Wed, 11 Jan 2017 22:24:01 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/create-ecs_task_definition.yml b/fixtures/vcr_cassettes/create-ecs_task_definition.yml new file mode 100644 index 00000000..ab4b64ce --- /dev/null +++ b/fixtures/vcr_cassettes/create-ecs_task_definition.yml @@ -0,0 +1,52 @@ +--- +http_interactions: +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"family":"testtask","containerDefinitions":[{"cpu":1024,"environment":[{"name":"one","value":"one"},{"name":"two","value":"2"}],"essential":true,"image":"debian:jessie17","memory":512,"name":"zleslietesting","portMappings":[{"containerPort":8081,"hostPort":8082,"protocol":"tcp"}]},{"cpu":1024,"environment":[{"name":"one","value":"one"},{"name":"two","value":"2"}],"essential":true,"image":"debian:jessie17","memory":512,"name":"zleslietesting2","portMappings":[{"containerPort":8082,"hostPort":8083,"protocol":"tcp"}]}]}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.RegisterTaskDefinition + X-Amz-Date: + - 20170111T232134Z + X-Amz-Content-Sha256: + - 3aa835a0677bba08d97536cb29603c21e7c8ea311783248b37496009a2b0d912 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=29c2cc3010a2916514d8a1fcc8e00cc0fda5690caa0ab4d447f6b177ab5e7a19 + Content-Length: + - '523' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 23:21:34 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '764' + Connection: + - keep-alive + X-Amzn-Requestid: + - b15440a7-d854-11e6-9bee-fdb066638639 + body: + encoding: UTF-8 + string: '{"taskDefinition":{"containerDefinitions":[{"cpu":1024,"environment":[{"name":"two","value":"2"},{"name":"one","value":"one"}],"essential":true,"image":"debian:jessie17","memory":512,"mountPoints":[],"name":"zleslietesting","portMappings":[{"containerPort":8081,"hostPort":8082,"protocol":"tcp"}],"volumesFrom":[]},{"cpu":1024,"environment":[{"name":"two","value":"2"},{"name":"one","value":"one"}],"essential":true,"image":"debian:jessie17","memory":512,"mountPoints":[],"name":"zleslietesting2","portMappings":[{"containerPort":8082,"hostPort":8083,"protocol":"tcp"}],"volumesFrom":[]}],"family":"testtask","placementConstraints":[],"revision":7,"status":"ACTIVE","taskDefinitionArn":"arn:aws:ecs:us-west-2:123456789012:task-definition/testtask:7","volumes":[]}}' + http_version: + recorded_at: Wed, 11 Jan 2017 23:21:34 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/create-elb-test.yml b/fixtures/vcr_cassettes/create-elb-test.yml index 94b1add6..955ec850 100644 --- a/fixtures/vcr_cassettes/create-elb-test.yml +++ b/fixtures/vcr_cassettes/create-elb-test.yml @@ -1,213 +1,102 @@ ---- - http_interactions: - - request: - method: post - uri: "https://elasticloadbalancing.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=CreateLoadBalancer&AvailabilityZones.member.1=sa-east-1a&Listeners.member.1.InstancePort=80&Listeners.member.1.InstanceProtocol=tcp&Listeners.member.1.LoadBalancerPort=80&Listeners.member.1.Protocol=tcp&LoadBalancerName=lb-1&SecurityGroups=&Version=2012-06-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.1 ruby/2.1.1 x86_64-darwin13.0" - X-Amz-Date: - - "20141003T115712Z" - Host: - - elasticloadbalancing.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - "157d28a0a1b02c3c4f0b2e4aaa534ee868b49c902628c268a84b55877d355462" - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20141003/sa-east-1/elasticloadbalancing/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=redacted" - Content-Length: - - "266" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - "69bda78d-4af4-11e4-8264-99e567340869" - Content-Type: - - text/xml - Content-Length: - - "357" - Date: - - "Fri, 03 Oct 2014 11:57:12 GMT" - body: - encoding: UTF-8 - string: "\n \n lb-1-580078311.sa-east-1.elb.amazonaws.com\n \n \n 69bda78d-4af4-11e4-8264-99e567340869\n \n\n" - http_version: - recorded_at: "Fri, 03 Oct 2014 11:57:13 GMT" - - request: - method: post - uri: "https://ec2.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "AWSAccessKeyId=redacted&Action=DescribeInstances&Filter.1.Name=tag%3AName&Filter.1.Value.1=web-1&Filter.2.Name=instance-state-name&Filter.2.Value.1=pending&Filter.2.Value.2=running&Signature=redacted&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2014-10-03T11%3A57%3A13Z&Version=2014-06-15" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.1 ruby/2.1.1 x86_64-darwin13.0" - Content-Length: - - "355" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Content-Type: - - "text/xml;charset=UTF-8" - Transfer-Encoding: - - chunked - Vary: - - Accept-Encoding - Date: - - "Fri, 03 Oct 2014 11:57:14 GMT" - Server: - - AmazonEC2 - body: - encoding: UTF-8 - string: |- - - - 581fe662-cf91-4b52-8eda-d2354ac9fb38 - - - r-8f11ba9a - 482693910459 - - - sg-d5d0f4c8 - web-sg - - - - - i-1774f402 - ami-41e85d5c - - 16 - running - - ip-10-252-14-59.sa-east-1.compute.internal - ec2-54-207-152-222.sa-east-1.compute.amazonaws.com - - 0 - - t1.micro - 2014-10-01T12:06:56.000Z - - sa-east-1a - - default - - aki-5553f448 - - disabled - - 10.252.14.59 - 54.207.152.222 - - - sg-d5d0f4c8 - web-sg - - - x86_64 - ebs - /dev/sda1 - - - /dev/sda1 - - vol-d32d86de - attached - 2014-10-01T12:07:01.000Z - true - - - - paravirtual - - - - project - cloud - - - department - engineering - - - created_by - garethr - - - Name - web-1 - - - xen - - false - - - - - - http_version: - recorded_at: "Fri, 03 Oct 2014 11:57:14 GMT" - - request: - method: post - uri: "https://elasticloadbalancing.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=RegisterInstancesWithLoadBalancer&Instances.member.1.InstanceId=i-1774f402&LoadBalancerName=lb-1&Version=2012-06-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.1 ruby/2.1.1 x86_64-darwin13.0" - X-Amz-Date: - - "20141003T115714Z" - Host: - - elasticloadbalancing.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - "9c627aff393df8a6c30c4e71c66385861cb3ec4c50659c3bd7d653f4e786e353" - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20141003/sa-east-1/elasticloadbalancing/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=redacted" - Content-Length: - - "122" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - "6b283446-4af4-11e4-a56e-315151d8de86" - Content-Type: - - text/xml - Content-Length: - - "459" - Date: - - "Fri, 03 Oct 2014 11:57:15 GMT" - body: - encoding: UTF-8 - string: "\n \n \n \n i-1774f402\n \n \n \n \n 6b283446-4af4-11e4-a56e-315151d8de86\n \n\n" - http_version: - recorded_at: "Fri, 03 Oct 2014 11:57:15 GMT" - recorded_with: "VCR 2.9.3" +--- +http_interactions: +- request: + method: post + uri: https://elasticloadbalancing.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=CreateLoadBalancer&AvailabilityZones.member.1=sa-east-1a&Listeners.member.1.InstancePort=80&Listeners.member.1.LoadBalancerPort=80&Listeners.member.1.Protocol=TCP&LoadBalancerName=lb-1&Scheme=internet-facing&SecurityGroups=&Subnets=&Tags.member.1.Key=Name&Tags.member.1.Value=lb-1&Version=2012-06-01 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170112T183657Z + X-Amz-Content-Sha256: + - f0f21a0b0eea82f184d91ce551406194c9a85495a1afb46b0bf20a0eeeabeced + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=88cc8056f70853377592d483b70c63864b99053b39db9b3ed9236a961a7cfade + Content-Length: + - '306' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 1943162d-d8f6-11e6-a828-4f226993f0a0 + Content-Type: + - text/xml + Content-Length: + - '357' + Date: + - Thu, 12 Jan 2017 18:36:58 GMT + body: + encoding: UTF-8 + string: | + + + lb-1-836530285.sa-east-1.elb.amazonaws.com + + + 1943162d-d8f6-11e6-a828-4f226993f0a0 + + + http_version: + recorded_at: Thu, 12 Jan 2017 18:36:59 GMT +- request: + method: post + uri: https://ec2.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeInstances&Filter.1.Name=tag%3AName&Filter.1.Value.1=web-1&Filter.2.Name=instance-state-name&Filter.2.Value.1=pending&Filter.2.Value.2=running&Version=2016-11-15 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170112T183659Z + X-Amz-Content-Sha256: + - c56603cbdf45c89429925da0c8e72355856b953cba3fe6d7726125c3c3c7b073 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/ec2/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=af05f831cbf8dbb3c5af46412651fcf37880a4a26c05f2bc9b761c48695be20d + Content-Length: + - '175' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - text/xml;charset=UTF-8 + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + Date: + - Thu, 12 Jan 2017 18:36:59 GMT + Server: + - AmazonEC2 + body: + encoding: UTF-8 + string: |- + + + fd7c968d-19c5-45f2-b233-bbec5a41c986 + + + http_version: + recorded_at: Thu, 12 Jan 2017 18:37:00 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/create-iam_group.yml b/fixtures/vcr_cassettes/create-iam_group.yml new file mode 100644 index 00000000..b35155a3 --- /dev/null +++ b/fixtures/vcr_cassettes/create-iam_group.yml @@ -0,0 +1,59 @@ +--- +http_interactions: +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=CreateGroup&GroupName=tgroup&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172010Z + X-Amz-Content-Sha256: + - 97315f7d6b878790d6aeb8f04a806f120ec57d8baa84f4a398028e34530a6e72 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=461a1299024b2173ba80385a19e7090f94b96ea714c5068c2b7b0bde1ffe00ba + Content-Length: + - '54' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 34dc773a-d822-11e6-bd77-5d62273fd38b + Content-Type: + - text/xml + Content-Length: + - '488' + Date: + - Wed, 11 Jan 2017 17:20:10 GMT + body: + encoding: UTF-8 + string: | + + + + / + tgroup + arn:aws:iam::123456789012:group/tgroup + AGPAID3BRVWPWS7SXRYHC + 2017-01-11T17:20:10.888Z + + + + 34dc773a-d822-11e6-bd77-5d62273fd38b + + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:10 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/create-iam_user.yml b/fixtures/vcr_cassettes/create-iam_user.yml new file mode 100644 index 00000000..a087a157 --- /dev/null +++ b/fixtures/vcr_cassettes/create-iam_user.yml @@ -0,0 +1,59 @@ +--- +http_interactions: +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=CreateUser&UserName=tuser&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172014Z + X-Amz-Content-Sha256: + - 89c195b7f373d1fbed01b2e87d2ecd8622f4215ce20449b6dbeef2dc82e2a5ea + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=1e1b398886049727f64114ad877e05fce3ecdab9a072101afd1072a5f8a586c2 + Content-Length: + - '51' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 37745f8b-d822-11e6-9deb-11451b078a2d + Content-Type: + - text/xml + Content-Length: + - '475' + Date: + - Wed, 11 Jan 2017 17:20:14 GMT + body: + encoding: UTF-8 + string: | + + + + / + tuser + arn:aws:iam::123456789012:user/tuser + AIDAIXE6MBUG4WUE4SEIO + 2017-01-11T17:20:15.237Z + + + + 37745f8b-d822-11e6-9deb-11451b078a2d + + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:15 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/create-instance-profile.yml b/fixtures/vcr_cassettes/create-instance-profile.yml index e480f25c..3aaed599 100644 --- a/fixtures/vcr_cassettes/create-instance-profile.yml +++ b/fixtures/vcr_cassettes/create-instance-profile.yml @@ -12,14 +12,14 @@ http_interactions: Accept-Encoding: - '' User-Agent: - - aws-sdk-ruby2/2.3.3 ruby/2.1.7 x86_64-darwin14.0 + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 X-Amz-Date: - - 20160802T182439Z + - 20170119T191203Z X-Amz-Content-Sha256: - 44d83e3a0f5f6915cab0b95802111050b054a3353097341089af8a6c2ee48399 Authorization: - - AWS4-HMAC-SHA256 Credential=redacted/20160802/us-east-1/iam/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=222a01c263b05370d9bac5ddcd7ef1b5072e241be12b2726f5ca3e970ee2b5d1 + - AWS4-HMAC-SHA256 Credential=111111111111/20170119/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=6987c0cf4634b76054fe7fde4b1203162fe8c7a0e2645bbbb81bf0bd50aa0f4b Content-Length: - '46' Accept: @@ -30,13 +30,13 @@ http_interactions: message: OK headers: X-Amzn-Requestid: - - 5fc48fe5-58de-11e6-b882-5bb35db703fa + - 29428e40-de7b-11e6-b26b-f729fc68ac82 Content-Type: - text/xml Content-Length: - - '1253' + - '1306' Date: - - Tue, 02 Aug 2016 18:24:38 GMT + - Thu, 19 Jan 2017 19:12:03 GMT body: encoding: UTF-8 string: | @@ -46,29 +46,29 @@ http_interactions: / + ecsInstanceRole / - %7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D - AROAJTVOOGRMNHXZHEQKU - devtest - arn:aws:iam::111111111111:role/devtest - 2016-07-28T20:22:30Z + %7B%22Version%22%3A%222008-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D + AROAJTEW6IGCXX4HNR5T2 + ecsInstanceRole + arn:aws:iam::123456789012:role/ecsInstanceRole + 2017-01-11T21:32:55Z - devtest - arn:aws:iam::111111111111:instance-profile/devtest - AIPAIQX3NLS3B64FZNPAU - 2016-07-28T20:22:31Z + arn:aws:iam::123456789012:instance-profile/ecsInstanceRole + AIPAJFXZIVRDCVKHVT75G + 2017-01-11T21:32:55Z - 5fc48fe5-58de-11e6-b882-5bb35db703fa + 29428e40-de7b-11e6-b26b-f729fc68ac82 http_version: - recorded_at: Tue, 02 Aug 2016 18:24:39 GMT + recorded_at: Thu, 19 Jan 2017 19:12:03 GMT - request: method: post uri: https://iam.amazonaws.com/ @@ -81,14 +81,14 @@ http_interactions: Accept-Encoding: - '' User-Agent: - - aws-sdk-ruby2/2.3.3 ruby/2.1.7 x86_64-darwin14.0 + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 X-Amz-Date: - - 20160802T182439Z + - 20170119T191203Z X-Amz-Content-Sha256: - 44d83e3a0f5f6915cab0b95802111050b054a3353097341089af8a6c2ee48399 Authorization: - - AWS4-HMAC-SHA256 Credential=redacted/20160802/us-east-1/iam/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=222a01c263b05370d9bac5ddcd7ef1b5072e241be12b2726f5ca3e970ee2b5d1 + - AWS4-HMAC-SHA256 Credential=111111111111/20170119/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=6987c0cf4634b76054fe7fde4b1203162fe8c7a0e2645bbbb81bf0bd50aa0f4b Content-Length: - '46' Accept: @@ -99,13 +99,13 @@ http_interactions: message: OK headers: X-Amzn-Requestid: - - 5fd46e73-58de-11e6-b882-5bb35db703fa + - 29766f47-de7b-11e6-9cb5-6fc5af467f59 Content-Type: - text/xml Content-Length: - - '1253' + - '1306' Date: - - Tue, 02 Aug 2016 18:24:38 GMT + - Thu, 19 Jan 2017 19:12:03 GMT body: encoding: UTF-8 string: | @@ -115,27 +115,27 @@ http_interactions: / + ecsInstanceRole / - %7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D - AROAJTVOOGRMNHXZHEQKU - devtest - arn:aws:iam::111111111111:role/devtest - 2016-07-28T20:22:30Z + %7B%22Version%22%3A%222008-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D + AROAJTEW6IGCXX4HNR5T2 + ecsInstanceRole + arn:aws:iam::123456789012:role/ecsInstanceRole + 2017-01-11T21:32:55Z - devtest - arn:aws:iam::111111111111:instance-profile/devtest - AIPAIQX3NLS3B64FZNPAU - 2016-07-28T20:22:31Z + arn:aws:iam::123456789012:instance-profile/ecsInstanceRole + AIPAJFXZIVRDCVKHVT75G + 2017-01-11T21:32:55Z - 5fd46e73-58de-11e6-b882-5bb35db703fa + 29766f47-de7b-11e6-9cb5-6fc5af467f59 http_version: - recorded_at: Tue, 02 Aug 2016 18:24:39 GMT + recorded_at: Thu, 19 Jan 2017 19:12:04 GMT recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/create-role.yml b/fixtures/vcr_cassettes/create-role.yml index 2373cd18..94f2b5e3 100644 --- a/fixtures/vcr_cassettes/create-role.yml +++ b/fixtures/vcr_cassettes/create-role.yml @@ -12,15 +12,14 @@ http_interactions: Accept-Encoding: - '' User-Agent: - - aws-sdk-ruby2/2.3.3 ruby/2.1.7 x86_64-darwin14.0 + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 X-Amz-Date: - - 20160728T202344Z + - 20170119T190642Z X-Amz-Content-Sha256: - 8e689dc6b69b17003f0460011582254d8643f0dfb48ac46e093a24df58170b3f Authorization: - - AWS4-HMAC-SHA256 Credential=redacted/20160728/us-east-1/iam/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, - Signature=bfaf846ce12189c1b0a1346f056397b72de78058195dfe675220da75fcfa7a3b + - AWS4-HMAC-SHA256 Credential=111111111111/20170119/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=f172283564fbd0dce039e6bb7b86f52d178d0f3eed91ef539c27bb2859c93026 Content-Length: - '35' Accept: @@ -31,13 +30,13 @@ http_interactions: message: OK headers: X-Amzn-Requestid: - - 2e5aa7e2-5501-11e6-b3ac-ab2eb361e21c + - 6a32f6d4-de7a-11e6-98c2-d336c3453283 Content-Type: - text/xml Content-Length: - - '816' + - '853' Date: - - Thu, 28 Jul 2016 20:23:43 GMT + - Thu, 19 Jan 2017 19:06:42 GMT body: encoding: UTF-8 string: | @@ -47,20 +46,20 @@ http_interactions: / - %7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D - AROAJTVOOGRMNHXZHEQKU - devtest - arn:aws:iam::111111111111:role/devtest - 2016-07-28T20:22:30Z + %7B%22Version%22%3A%222008-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D + AROAJTEW6IGCXX4HNR5T2 + ecsInstanceRole + arn:aws:iam::123456789012:role/ecsInstanceRole + 2017-01-11T21:32:55Z - 2e5aa7e2-5501-11e6-b3ac-ab2eb361e21c + 6a32f6d4-de7a-11e6-98c2-d336c3453283 http_version: - recorded_at: Thu, 28 Jul 2016 20:23:44 GMT + recorded_at: Thu, 19 Jan 2017 19:06:43 GMT - request: method: post uri: https://iam.amazonaws.com/ @@ -73,15 +72,14 @@ http_interactions: Accept-Encoding: - '' User-Agent: - - aws-sdk-ruby2/2.3.3 ruby/2.1.7 x86_64-darwin14.0 + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 X-Amz-Date: - - 20160728T202344Z + - 20170119T190643Z X-Amz-Content-Sha256: - 8e689dc6b69b17003f0460011582254d8643f0dfb48ac46e093a24df58170b3f Authorization: - - AWS4-HMAC-SHA256 Credential=redacted/20160728/us-east-1/iam/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, - Signature=bfaf846ce12189c1b0a1346f056397b72de78058195dfe675220da75fcfa7a3b + - AWS4-HMAC-SHA256 Credential=111111111111/20170119/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=eb671afb53c5ecb8336a3fa22e7e05e7b2604c0af0782eb298a29e310b6c2344 Content-Length: - '35' Accept: @@ -92,13 +90,13 @@ http_interactions: message: OK headers: X-Amzn-Requestid: - - 2e736006-5501-11e6-a9a1-2131b69057ae + - 6a6355b9-de7a-11e6-b721-7d7493774d49 Content-Type: - text/xml Content-Length: - - '816' + - '853' Date: - - Thu, 28 Jul 2016 20:23:43 GMT + - Thu, 19 Jan 2017 19:06:42 GMT body: encoding: UTF-8 string: | @@ -108,18 +106,18 @@ http_interactions: / - %7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D - AROAJTVOOGRMNHXZHEQKU - devtest - arn:aws:iam::111111111111:role/devtest - 2016-07-28T20:22:30Z + %7B%22Version%22%3A%222008-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D + AROAJTEW6IGCXX4HNR5T2 + ecsInstanceRole + arn:aws:iam::123456789012:role/ecsInstanceRole + 2017-01-11T21:32:55Z - 2e736006-5501-11e6-a9a1-2131b69057ae + 6a6355b9-de7a-11e6-b721-7d7493774d49 http_version: - recorded_at: Thu, 28 Jul 2016 20:23:44 GMT + recorded_at: Thu, 19 Jan 2017 19:06:43 GMT recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/create-user.yml b/fixtures/vcr_cassettes/create-user.yml deleted file mode 100644 index 18331081..00000000 --- a/fixtures/vcr_cassettes/create-user.yml +++ /dev/null @@ -1,125 +0,0 @@ ---- -http_interactions: -- request: - method: post - uri: https://iam.amazonaws.com/ - body: - encoding: UTF-8 - string: Action=ListUsers&Version=2010-05-08 - headers: - Content-Type: - - application/x-www-form-urlencoded; charset=utf-8 - Accept-Encoding: - - '' - User-Agent: - - aws-sdk-ruby2/2.0.5 ruby/2.2.3 x86_64-darwin15 - X-Amz-Date: - - 20160523T191019Z - X-Amz-Content-Sha256: - - b6359072c78d70ebee1e81adcbab4f01bf2c23245fa365ef83fe8f1f955085e2 - Authorization: - - AWS4-HMAC-SHA256 Credential=redacterd/20160523/us-east-1/iam/aws4_request, - SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, - Signature=14925d85ab7c5f62eee479280483f756a67361483edd024b1a7808555c6c4c08 - Content-Length: - - '35' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - fdd8ed5a-2119-11e6-a1a2-718946016691 - Content-Type: - - text/xml - Content-Length: - - '617' - Date: - - Mon, 23 May 2016 19:10:19 GMT - body: - encoding: UTF-8 - string: | - - - false - - - / - 2016-05-20T20:59:26Z - zleslie - arn:aws:iam::111111111111:user/zleslie - AAAAAAAAAAAAAAAAAAAAA - 2016-05-20T20:58:02Z - - - - - fdd8ed5a-2119-11e6-a1a2-718946016691 - - - http_version: - recorded_at: Mon, 23 May 2016 19:10:19 GMT -- request: - method: post - uri: https://iam.amazonaws.com/ - body: - encoding: UTF-8 - string: Action=ListUsers&Version=2010-05-08 - headers: - Content-Type: - - application/x-www-form-urlencoded; charset=utf-8 - Accept-Encoding: - - '' - User-Agent: - - aws-sdk-ruby2/2.0.5 ruby/2.2.3 x86_64-darwin15 - X-Amz-Date: - - 20160523T191019Z - X-Amz-Content-Sha256: - - b6359072c78d70ebee1e81adcbab4f01bf2c23245fa365ef83fe8f1f955085e2 - Authorization: - - AWS4-HMAC-SHA256 Credential=redacterd/20160523/us-east-1/iam/aws4_request, - SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, - Signature=14925d85ab7c5f62eee479280483f756a67361483edd024b1a7808555c6c4c08 - Content-Length: - - '35' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - fe0d9296-2119-11e6-96d0-5da17d99c5f9 - Content-Type: - - text/xml - Content-Length: - - '617' - Date: - - Mon, 23 May 2016 19:10:19 GMT - body: - encoding: UTF-8 - string: | - - - false - - - / - 2016-05-20T20:59:26Z - zleslie - arn:aws:iam::111111111111:user/zleslie - AAAAAAAAAAAAAAAAAAAAA - 2016-05-20T20:58:02Z - - - - - fe0d9296-2119-11e6-96d0-5da17d99c5f9 - - - http_version: - recorded_at: Mon, 23 May 2016 19:10:20 GMT -recorded_with: VCR 3.0.1 diff --git a/fixtures/vcr_cassettes/destroy-ecs_service.yml b/fixtures/vcr_cassettes/destroy-ecs_service.yml new file mode 100644 index 00000000..b84f2284 --- /dev/null +++ b/fixtures/vcr_cassettes/destroy-ecs_service.yml @@ -0,0 +1,52 @@ +--- +http_interactions: +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"service":"testservice","cluster":"test"}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.DeleteService + X-Amz-Date: + - 20170111T222403Z + X-Amz-Content-Sha256: + - f1c61043a1dea46cf96c7345abe115c06fe034113cf07334197a1421c0c6d2a2 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=90f901145083f98f21884842ce9ce7154fbb5b369a683f388ffdcbfed414b95e + Content-Length: + - '42' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 22:24:03 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '774' + Connection: + - keep-alive + X-Amzn-Requestid: + - a83fdaf6-d84c-11e6-9f70-5f80690e25cf + body: + encoding: UTF-8 + string: '{"service":{"clusterArn":"arn:aws:ecs:us-west-2:123456789012:cluster/test","createdAt":1.484173441895E9,"deploymentConfiguration":{"maximumPercent":200,"minimumHealthyPercent":100},"deployments":[{"createdAt":1.484173441895E9,"desiredCount":0,"id":"ecs-svc/9223370552681333906","pendingCount":0,"runningCount":0,"status":"PRIMARY","taskDefinition":"arn:aws:ecs:us-west-2:123456789012:task-definition/testtask:6","updatedAt":1.484173441895E9}],"desiredCount":0,"events":[],"loadBalancers":[],"pendingCount":0,"placementConstraints":[],"placementStrategy":[],"runningCount":0,"serviceArn":"arn:aws:ecs:us-west-2:123456789012:service/testservice","serviceName":"testservice","status":"DRAINING","taskDefinition":"arn:aws:ecs:us-west-2:123456789012:task-definition/testtask:6"}}' + http_version: + recorded_at: Wed, 11 Jan 2017 22:24:03 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/destroy-ecs_task_definition.yml b/fixtures/vcr_cassettes/destroy-ecs_task_definition.yml new file mode 100644 index 00000000..cda93fbc --- /dev/null +++ b/fixtures/vcr_cassettes/destroy-ecs_task_definition.yml @@ -0,0 +1,248 @@ +--- +http_interactions: +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"status":"ACTIVE"}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.ListTaskDefinitionFamilies + X-Amz-Date: + - 20170112T185158Z + X-Amz-Content-Sha256: + - 264e28f424ac2f00738ee11c418ac9a1666d7f44940f512ab9a9e105711a2f39 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=2c695e71a7cd0dd7c45f81ef40b7639b922807b6963e10350a02df301c43ffd3 + Content-Length: + - '19' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Thu, 12 Jan 2017 18:51:58 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '54' + Connection: + - keep-alive + X-Amzn-Requestid: + - 31ebe194-d8f8-11e6-b00d-cb0e37bed37c + body: + encoding: UTF-8 + string: '{"families":["netflix-ice","netflix-ice2","testtask"]}' + http_version: + recorded_at: Thu, 12 Jan 2017 18:51:58 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"taskDefinition":"netflix-ice"}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.DescribeTaskDefinition + X-Amz-Date: + - 20170112T185158Z + X-Amz-Content-Sha256: + - 75840101855fab3849b65b3c028f259060cd7e7d9616c8a57ba19fda19df23ae + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=98f59dac299fa7554bd06bbf21916f4f79bb31100c4c0be5a5d9865f3c758d9d + Content-Length: + - '32' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Thu, 12 Jan 2017 18:51:58 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '473' + Connection: + - keep-alive + X-Amzn-Requestid: + - 3212a338-d8f8-11e6-857b-29512a0ad198 + body: + encoding: UTF-8 + string: '{"taskDefinition":{"containerDefinitions":[{"cpu":1024,"environment":[{"name":"two","value":"2"},{"name":"one","value":"one"}],"essential":true,"image":"debian:jessie17","memory":512,"mountPoints":[],"name":"zleslietesting","portMappings":[{"containerPort":8081,"hostPort":8082,"protocol":"tcp"}],"volumesFrom":[]}],"family":"netflix-ice","revision":52,"status":"ACTIVE","taskDefinitionArn":"arn:aws:ecs:us-west-2:123456789012:task-definition/netflix-ice:52","volumes":[]}}' + http_version: + recorded_at: Thu, 12 Jan 2017 18:51:58 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"taskDefinition":"netflix-ice2"}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.DescribeTaskDefinition + X-Amz-Date: + - 20170112T185158Z + X-Amz-Content-Sha256: + - 7d85761083e15ebb6d4a5acd43a04c5df9b4ac443705060eac6a533421584ce1 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=098437597f9ac0ab8361f5808ec4e7cb0a948409456fd9db6e1a4d1962e781d2 + Content-Length: + - '33' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Thu, 12 Jan 2017 18:51:58 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '473' + Connection: + - keep-alive + X-Amzn-Requestid: + - 323064b0-d8f8-11e6-b00d-cb0e37bed37c + body: + encoding: UTF-8 + string: '{"taskDefinition":{"containerDefinitions":[{"cpu":1023,"environment":[{"name":"two","value":"2"},{"name":"one","value":"one"}],"essential":true,"image":"debian:jessie19","memory":512,"mountPoints":[],"name":"zleslietesting","portMappings":[{"containerPort":8081,"hostPort":8082,"protocol":"tcp"}],"volumesFrom":[]}],"family":"netflix-ice2","revision":2,"status":"ACTIVE","taskDefinitionArn":"arn:aws:ecs:us-west-2:123456789012:task-definition/netflix-ice2:2","volumes":[]}}' + http_version: + recorded_at: Thu, 12 Jan 2017 18:51:58 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"taskDefinition":"testtask"}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.DescribeTaskDefinition + X-Amz-Date: + - 20170112T185158Z + X-Amz-Content-Sha256: + - a4f77f09f82abaab5e573332bb562eb361aed53e1acb9bdc1da98fdad621e6a2 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=865aa8fffe81a48c0f0924fcaa8152804936fd9f1a1b0bfbceed0f9d5d7e0a0f + Content-Length: + - '29' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Thu, 12 Jan 2017 18:51:58 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '764' + Connection: + - keep-alive + X-Amzn-Requestid: + - 324ec27f-d8f8-11e6-af44-1b255b73231d + body: + encoding: UTF-8 + string: '{"taskDefinition":{"containerDefinitions":[{"cpu":1024,"environment":[{"name":"two","value":"2"},{"name":"one","value":"one"}],"essential":true,"image":"debian:jessie17","memory":512,"mountPoints":[],"name":"zleslietesting","portMappings":[{"containerPort":8081,"hostPort":8082,"protocol":"tcp"}],"volumesFrom":[]},{"cpu":1024,"environment":[{"name":"two","value":"2"},{"name":"one","value":"one"}],"essential":true,"image":"debian:jessie17","memory":512,"mountPoints":[],"name":"zleslietesting2","portMappings":[{"containerPort":8082,"hostPort":8083,"protocol":"tcp"}],"volumesFrom":[]}],"family":"testtask","placementConstraints":[],"revision":7,"status":"ACTIVE","taskDefinitionArn":"arn:aws:ecs:us-west-2:123456789012:task-definition/testtask:7","volumes":[]}}' + http_version: + recorded_at: Thu, 12 Jan 2017 18:51:58 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"taskDefinition":"arn:aws:ecs:us-west-2:123456789012:task-definition/testtask:7"}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.DeregisterTaskDefinition + X-Amz-Date: + - 20170112T185158Z + X-Amz-Content-Sha256: + - 263eb70f04aed99dc657e959dfb7ae8ccb789fe86332d230f9a9866f63940682 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=6988f1d9e170c9d592f0a5e4b0cb1ee936ef9836875cf1b5462dd745f94589e5 + Content-Length: + - '82' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Thu, 12 Jan 2017 18:51:59 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '766' + Connection: + - keep-alive + X-Amzn-Requestid: + - 3272ec03-d8f8-11e6-9980-ed6b686084cc + body: + encoding: UTF-8 + string: '{"taskDefinition":{"containerDefinitions":[{"cpu":1024,"environment":[{"name":"two","value":"2"},{"name":"one","value":"one"}],"essential":true,"image":"debian:jessie17","memory":512,"mountPoints":[],"name":"zleslietesting","portMappings":[{"containerPort":8081,"hostPort":8082,"protocol":"tcp"}],"volumesFrom":[]},{"cpu":1024,"environment":[{"name":"two","value":"2"},{"name":"one","value":"one"}],"essential":true,"image":"debian:jessie17","memory":512,"mountPoints":[],"name":"zleslietesting2","portMappings":[{"containerPort":8082,"hostPort":8083,"protocol":"tcp"}],"volumesFrom":[]}],"family":"testtask","placementConstraints":[],"revision":7,"status":"INACTIVE","taskDefinitionArn":"arn:aws:ecs:us-west-2:123456789012:task-definition/testtask:7","volumes":[]}}' + http_version: + recorded_at: Thu, 12 Jan 2017 18:51:59 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/destroy-elb-test.yml b/fixtures/vcr_cassettes/destroy-elb-test.yml index 55d78a46..334a7e03 100644 --- a/fixtures/vcr_cassettes/destroy-elb-test.yml +++ b/fixtures/vcr_cassettes/destroy-elb-test.yml @@ -1,46 +1,51 @@ ---- - http_interactions: - - request: - method: post - uri: "https://elasticloadbalancing.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DeleteLoadBalancer&LoadBalancerName=lb-1&Version=2012-06-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.1 ruby/2.1.1 x86_64-darwin13.0" - X-Amz-Date: - - "20141003T115254Z" - Host: - - elasticloadbalancing.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - b2d7e898602a78800eef4240a0beedc4091cbc0d42a162fa31fb1b2a296b25cd - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20141003/sa-east-1/elasticloadbalancing/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=redacted" - Content-Length: - - "66" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - cff4c24a-4af3-11e4-b2a1-31f021862379 - Content-Type: - - text/xml - Content-Length: - - "262" - Date: - - "Fri, 03 Oct 2014 11:52:54 GMT" - body: - encoding: UTF-8 - string: "\n \n \n cff4c24a-4af3-11e4-b2a1-31f021862379\n \n\n" - http_version: - recorded_at: "Fri, 03 Oct 2014 11:52:55 GMT" - recorded_with: "VCR 2.9.3" +--- +http_interactions: +- request: + method: post + uri: https://elasticloadbalancing.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DeleteLoadBalancer&LoadBalancerName=lb-1&Version=2012-06-01 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170112T183721Z + X-Amz-Content-Sha256: + - b2d7e898602a78800eef4240a0beedc4091cbc0d42a162fa31fb1b2a296b25cd + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=928ca13d4a33ad60cbde0acb753f626b6e613ba6bea44455aa85c60fab35fc34 + Content-Length: + - '66' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 279d3fac-d8f6-11e6-b029-fb770eddb995 + Content-Type: + - text/xml + Content-Length: + - '262' + Date: + - Thu, 12 Jan 2017 18:37:22 GMT + body: + encoding: UTF-8 + string: | + + + + 279d3fac-d8f6-11e6-b029-fb770eddb995 + + + http_version: + recorded_at: Thu, 12 Jan 2017 18:37:22 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/destroy-iam_group.yml b/fixtures/vcr_cassettes/destroy-iam_group.yml new file mode 100644 index 00000000..c4627c03 --- /dev/null +++ b/fixtures/vcr_cassettes/destroy-iam_group.yml @@ -0,0 +1,225 @@ +--- +http_interactions: +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=ListGroups&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172010Z + X-Amz-Content-Sha256: + - 5f776d91509b9c99b8cb5eb5d6d4a787a33ae41c8cd6e7b69effca69080e1e1f + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=e478778bd42b10d59a4bedb02e8616eddc49673bac64e6978f4a299e946bac58 + Content-Length: + - '36' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 350e0ebd-d822-11e6-bd77-5d62273fd38b + Content-Type: + - text/xml + Content-Length: + - '1060' + Date: + - Wed, 11 Jan 2017 17:20:10 GMT + body: + encoding: UTF-8 + string: | + + + false + + + / + notops + arn:aws:iam::123456789012:group/notops + AGPAJBN5CML7FQ5J7JD26 + 2016-08-23T19:23:16Z + + + / + ops + arn:aws:iam::123456789012:group/ops + AGPAIQCI4K2HPEBNN6QQM + 2016-06-16T18:23:08Z + + + / + tgroup + arn:aws:iam::123456789012:group/tgroup + AGPAID3BRVWPWS7SXRYHC + 2017-01-11T17:20:10Z + + + + + 350e0ebd-d822-11e6-bd77-5d62273fd38b + + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:11 GMT +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=ListGroupPolicies&GroupName=tgroup&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172011Z + X-Amz-Content-Sha256: + - 3b1ad7eb460cab3b197e1e426b9e23698616b2f97209ed5e649f59327deb6642 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=87e167878095a80f9918a1fbf13e46049a67b51e6c6985518242648a91ad2933 + Content-Length: + - '60' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 3552430e-d822-11e6-9deb-11451b078a2d + Content-Type: + - text/xml + Content-Length: + - '327' + Date: + - Wed, 11 Jan 2017 17:20:11 GMT + body: + encoding: UTF-8 + string: | + + + false + + + + 3552430e-d822-11e6-9deb-11451b078a2d + + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:11 GMT +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=ListAttachedGroupPolicies&GroupName=tgroup&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172011Z + X-Amz-Content-Sha256: + - f5206b2c3a76d51ef5980965af46fd9484df7250ddf1d4a1872f49484455726b + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=91e68b3ae6cdd9a7bc235d8e33905633fde00bdab11bc5fece7969dc3eaaf35d + Content-Length: + - '68' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 35e0eef5-d822-11e6-bd77-5d62273fd38b + Content-Type: + - text/xml + Content-Length: + - '364' + Date: + - Wed, 11 Jan 2017 17:20:11 GMT + body: + encoding: UTF-8 + string: | + + + false + + + + 35e0eef5-d822-11e6-bd77-5d62273fd38b + + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:12 GMT +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DeleteGroup&GroupName=tgroup&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172012Z + X-Amz-Content-Sha256: + - 288338ec2165b0579b11b01751e470bcf2a85c4e1807f8ff9b96f90a1905fa8b + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=fb31fef652acec286585e0e6ee709aef22ce033acb1ac025d27683d83787f5d3 + Content-Length: + - '54' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 362068a9-d822-11e6-ab10-214f93a0c1e1 + Content-Type: + - text/xml + Content-Length: + - '202' + Date: + - Wed, 11 Jan 2017 17:20:12 GMT + body: + encoding: UTF-8 + string: | + + + 362068a9-d822-11e6-ab10-214f93a0c1e1 + + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:13 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/destroy-iam_user.yml b/fixtures/vcr_cassettes/destroy-iam_user.yml new file mode 100644 index 00000000..1a7a3e2f --- /dev/null +++ b/fixtures/vcr_cassettes/destroy-iam_user.yml @@ -0,0 +1,284 @@ +--- +http_interactions: +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=ListUsers&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172015Z + X-Amz-Content-Sha256: + - b6359072c78d70ebee1e81adcbab4f01bf2c23245fa365ef83fe8f1f955085e2 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=c17e4c6b0bc3c1ae53efaf8e9bb2e04166708ff1208594c9e9a3b5512fc86ba3 + Content-Length: + - '35' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 37b18fe1-d822-11e6-bd77-5d62273fd38b + Content-Type: + - text/xml + Content-Length: + - '1433' + Date: + - Wed, 11 Jan 2017 17:20:14 GMT + body: + encoding: UTF-8 + string: | + + + false + + + / + 2017-01-11T16:16:54Z + ishearin + arn:aws:iam::123456789012:user/ishearin + AIDAJD5YADU67WPGYXKYK + 2016-06-16T20:28:41Z + + + / + tuser + arn:aws:iam::123456789012:user/tuser + AIDAIXE6MBUG4WUE4SEIO + 2017-01-11T17:20:15Z + + + / + 2017-01-10T19:07:58Z + zleslie + arn:aws:iam::123456789012:user/zleslie + AIDAJEOSIABK4O2G5JGRQ + 2016-05-20T20:58:02Z + + + / + zleslie2 + arn:aws:iam::123456789012:user/zleslie2 + AIDAJXLSYDKUU7Q6G7F5S + 2016-06-16T20:28:40Z + + + + + 37b18fe1-d822-11e6-bd77-5d62273fd38b + + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:15 GMT +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DeleteLoginProfile&UserName=tuser&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172015Z + X-Amz-Content-Sha256: + - 7bb5ee2a5db4bcad69d516dc8fd77feb7568b4acf5eb75a6459dc8f93c9bf819 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=cd0e3ceb50233a068f4e54e1adb287bc7f5af8fa72e39e44119540973eb9de1f + Content-Length: + - '59' + Accept: + - "*/*" + response: + status: + code: 404 + message: Not Found + headers: + X-Amzn-Requestid: + - 37f04720-d822-11e6-ab10-214f93a0c1e1 + Content-Type: + - text/xml + Content-Length: + - '284' + Date: + - Wed, 11 Jan 2017 17:20:15 GMT + body: + encoding: UTF-8 + string: | + + + Sender + NoSuchEntity + Cannot find Login Profile for User tuser + + 37f04720-d822-11e6-ab10-214f93a0c1e1 + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:16 GMT +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=ListAccessKeys&UserName=tuser&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172016Z + X-Amz-Content-Sha256: + - bdf6470fdf394978b19c4feeb008899b67a2cd1f5e34cc7ef176d94eaf9afbff + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=14e16b9f65e6495ebaa9f285c8c4ba271d8cedd92466162f3355d27e27a0f708 + Content-Length: + - '55' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 3831e3db-d822-11e6-9a43-1f83f6da3a89 + Content-Type: + - text/xml + Content-Length: + - '321' + Date: + - Wed, 11 Jan 2017 17:20:15 GMT + body: + encoding: UTF-8 + string: | + + + false + + + + 3831e3db-d822-11e6-9a43-1f83f6da3a89 + + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:16 GMT +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=ListMFADevices&UserName=tuser&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172016Z + X-Amz-Content-Sha256: + - 93547d81f5357984d5b979254906bef9a200b615d941af3a37faf8e36b5b6d6b + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=935f211dc3ca7988ee6770cfd1489f3d70ca6afa29264dedeea13e752b7202f3 + Content-Length: + - '55' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 3861cdb9-d822-11e6-9a43-1f83f6da3a89 + Content-Type: + - text/xml + Content-Length: + - '314' + Date: + - Wed, 11 Jan 2017 17:20:16 GMT + body: + encoding: UTF-8 + string: | + + + false + + + + 3861cdb9-d822-11e6-9a43-1f83f6da3a89 + + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:16 GMT +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DeleteUser&UserName=tuser&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172016Z + X-Amz-Content-Sha256: + - 6d1f867eea3f5cc37413b6abd9b5b857235a79368268c69b723438e39c32219a + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=0372b6a930889513435d8b91386fb8c54b7dc978254da739503e9c63d8d8ae26 + Content-Length: + - '51' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 38a3b869-d822-11e6-ab10-214f93a0c1e1 + Content-Type: + - text/xml + Content-Length: + - '200' + Date: + - Wed, 11 Jan 2017 17:20:17 GMT + body: + encoding: UTF-8 + string: | + + + 38a3b869-d822-11e6-ab10-214f93a0c1e1 + + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:17 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/ecs-service-setup.yml b/fixtures/vcr_cassettes/ecs-service-setup.yml deleted file mode 100644 index d1afd853..00000000 --- a/fixtures/vcr_cassettes/ecs-service-setup.yml +++ /dev/null @@ -1,507 +0,0 @@ ---- -http_interactions: -- request: - method: post - uri: https://ecs.us-west-2.amazonaws.com/ - body: - encoding: UTF-8 - string: "{}" - headers: - Content-Type: - - application/x-amz-json-1.1 - Accept-Encoding: - - '' - User-Agent: - - aws-sdk-ruby2/2.3.22 ruby/2.1.2 x86_64-darwin15.0 - X-Amz-Target: - - AmazonEC2ContainerServiceV20141113.ListClusters - X-Amz-Date: - - 20160801T223714Z - X-Amz-Content-Sha256: - - 44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a - Authorization: - - AWS4-HMAC-SHA256 Credential=redacterd/20160801/us-west-2/ecs/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, - Signature=703de8a29d4515513c54ddced9fe6c9df7b259b0ac55e25959993b72124a5969 - Content-Length: - - '2' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Server: - - Server - Date: - - Mon, 01 Aug 2016 22:37:14 GMT - Content-Type: - - application/x-amz-json-1.1 - Content-Length: - - '70' - Connection: - - keep-alive - X-Amzn-Requestid: - - 7ea9f860-5838-11e6-b123-0d6ff5d80840 - body: - encoding: UTF-8 - string: '{"clusterArns":["arn:aws:ecs:us-west-2:111111111111:cluster/zleslie"]}' - http_version: - recorded_at: Mon, 01 Aug 2016 22:37:14 GMT -- request: - method: post - uri: https://ecs.us-west-2.amazonaws.com/ - body: - encoding: UTF-8 - string: '{"cluster":"arn:aws:ecs:us-west-2:111111111111:cluster/zleslie"}' - headers: - Content-Type: - - application/x-amz-json-1.1 - Accept-Encoding: - - '' - User-Agent: - - aws-sdk-ruby2/2.3.22 ruby/2.1.2 x86_64-darwin15.0 - X-Amz-Target: - - AmazonEC2ContainerServiceV20141113.ListServices - X-Amz-Date: - - 20160801T223714Z - X-Amz-Content-Sha256: - - 537b417af8208177ebdbb47afcfa6462c3b19bc144ea126047855a6c4821ff3b - Authorization: - - AWS4-HMAC-SHA256 Credential=redacterd/20160801/us-west-2/ecs/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, - Signature=cd9f15da552331aa29f4b8bd67d5380f28854451cacfa83d791ba27c48ff6043 - Content-Length: - - '64' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Server: - - Server - Date: - - Mon, 01 Aug 2016 22:37:14 GMT - Content-Type: - - application/x-amz-json-1.1 - Content-Length: - - '74' - Connection: - - keep-alive - X-Amzn-Requestid: - - 7ec08e49-5838-11e6-977d-5f5e74dc3386 - body: - encoding: UTF-8 - string: '{"serviceArns":["arn:aws:ecs:us-west-2:111111111111:service/netflix-ice"]}' - http_version: - recorded_at: Mon, 01 Aug 2016 22:37:14 GMT -- request: - method: post - uri: https://ecs.us-west-2.amazonaws.com/ - body: - encoding: UTF-8 - string: '{"cluster":"arn:aws:ecs:us-west-2:111111111111:cluster/zleslie","services":["arn:aws:ecs:us-west-2:111111111111:service/netflix-ice"]}' - headers: - Content-Type: - - application/x-amz-json-1.1 - Accept-Encoding: - - '' - User-Agent: - - aws-sdk-ruby2/2.3.22 ruby/2.1.2 x86_64-darwin15.0 - X-Amz-Target: - - AmazonEC2ContainerServiceV20141113.DescribeServices - X-Amz-Date: - - 20160801T223714Z - X-Amz-Content-Sha256: - - c44e35d7bb974d8a0a562b33d09e355e6b6964a1e35bd4850163aaa80c29ca30 - Authorization: - - AWS4-HMAC-SHA256 Credential=redacterd/20160801/us-west-2/ecs/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, - Signature=66300138122f70c298e4556a59a2c5f1fcba8e60f4cc9ca39b0af66489c0bac1 - Content-Length: - - '134' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Server: - - Server - Date: - - Mon, 01 Aug 2016 22:37:15 GMT - Content-Type: - - application/x-amz-json-1.1 - Content-Length: - - '3621' - Connection: - - keep-alive - X-Amzn-Requestid: - - 7ed30432-5838-11e6-b123-0d6ff5d80840 - body: - encoding: UTF-8 - string: '{"failures":[],"services":[{"clusterArn":"arn:aws:ecs:us-west-2:111111111111:cluster/zleslie","createdAt":1.469637628671E9,"deploymentConfiguration":{"maximumPercent":200,"minimumHealthyPercent":100},"deployments":[{"createdAt":1.469637628671E9,"desiredCount":0,"id":"ecs-svc/9223370567217147128","pendingCount":0,"runningCount":0,"status":"PRIMARY","taskDefinition":"arn:aws:ecs:us-west-2:111111111111:task-definition/netflix-ice:30","updatedAt":1.469637628671E9}],"desiredCount":0,"events":[{"createdAt":1.470069887643E9,"id":"afeb8fc9-7dff-425d-9723-9dc6392702b3","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.470048261521E9,"id":"ba93794a-ddee-47a8-87b0-c5282b1c3f03","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.470026639099E9,"id":"cec1c78f-301e-4593-b7fd-79b9f907052f","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.470005024165E9,"id":"41769e97-fb45-4600-abb7-55615e22aa42","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.4699834144E9,"id":"e936db17-e05c-404e-ba5e-e07843a82721","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469961814258E9,"id":"7e228a56-1d76-4a38-88e1-a9fdf0f9e2cb","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469940196823E9,"id":"cab8a403-d9d9-4e07-ac68-8501a79780b7","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469918588348E9,"id":"e4c9afcf-b48a-4566-b2a9-b1790d506f02","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.46989697723E9,"id":"4b19f863-35fb-4eba-9617-d75e49f78110","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469875345099E9,"id":"b8969e63-6080-4bfc-8f02-89dc42b994da","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469853726707E9,"id":"38972468-9477-488d-b9c3-3d9c709b5bbe","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.46983212157E9,"id":"432dcfb0-6fa0-4613-807c-cd3d7a93f37b","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469810506433E9,"id":"be544d09-91ff-4512-884f-455874e48fbf","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469788905003E9,"id":"1ab21f17-cb26-47d8-864d-b4780eb5bfec","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469767301462E9,"id":"941ff5b8-ef46-48a0-8bba-d7bda2509bc2","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469745681305E9,"id":"53e4e256-17cb-44bb-9e64-e0b185a9735f","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469724067804E9,"id":"e917a1dd-6ae1-4649-9efa-6ed42902568f","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.46970246178E9,"id":"c71e7b0d-787f-4a23-bc4f-70fe99869c51","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469680861439E9,"id":"04f4f14b-a0d8-4e69-bc0e-22c36fce15a3","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.46965924988E9,"id":"2d35c0c3-ccfb-4f1e-84ec-9f7959cbac74","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469637631371E9,"id":"1fd1dbf9-a4ad-46c4-8905-9ae893ce3747","message":"(service - netflix-ice) has reached a steady state."}],"loadBalancers":[],"pendingCount":0,"runningCount":0,"serviceArn":"arn:aws:ecs:us-west-2:111111111111:service/netflix-ice","serviceName":"netflix-ice","status":"ACTIVE","taskDefinition":"arn:aws:ecs:us-west-2:111111111111:task-definition/netflix-ice:30"}]}' - http_version: - recorded_at: Mon, 01 Aug 2016 22:37:15 GMT -- request: - method: post - uri: https://ecs.us-west-2.amazonaws.com/ - body: - encoding: UTF-8 - string: "{}" - headers: - Content-Type: - - application/x-amz-json-1.1 - Accept-Encoding: - - '' - User-Agent: - - aws-sdk-ruby2/2.3.22 ruby/2.1.2 x86_64-darwin15.0 - X-Amz-Target: - - AmazonEC2ContainerServiceV20141113.ListClusters - X-Amz-Date: - - 20160801T223715Z - X-Amz-Content-Sha256: - - 44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a - Authorization: - - AWS4-HMAC-SHA256 Credential=redacterd/20160801/us-west-2/ecs/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, - Signature=510f2f9029b31cff1b4d4d295d1668718d3b70f0e0ef37fad3982c3b58141a08 - Content-Length: - - '2' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Server: - - Server - Date: - - Mon, 01 Aug 2016 22:37:15 GMT - Content-Type: - - application/x-amz-json-1.1 - Content-Length: - - '70' - Connection: - - keep-alive - X-Amzn-Requestid: - - 7ee4b7e4-5838-11e6-b537-c5d54ab9cbd5 - body: - encoding: UTF-8 - string: '{"clusterArns":["arn:aws:ecs:us-west-2:111111111111:cluster/zleslie"]}' - http_version: - recorded_at: Mon, 01 Aug 2016 22:37:15 GMT -- request: - method: post - uri: https://ecs.us-west-2.amazonaws.com/ - body: - encoding: UTF-8 - string: '{"cluster":"arn:aws:ecs:us-west-2:111111111111:cluster/zleslie"}' - headers: - Content-Type: - - application/x-amz-json-1.1 - Accept-Encoding: - - '' - User-Agent: - - aws-sdk-ruby2/2.3.22 ruby/2.1.2 x86_64-darwin15.0 - X-Amz-Target: - - AmazonEC2ContainerServiceV20141113.ListServices - X-Amz-Date: - - 20160801T223715Z - X-Amz-Content-Sha256: - - 537b417af8208177ebdbb47afcfa6462c3b19bc144ea126047855a6c4821ff3b - Authorization: - - AWS4-HMAC-SHA256 Credential=redacterd/20160801/us-west-2/ecs/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, - Signature=bba70547a97ca7f3d90548f1c3ea4512c482ee3f9b5783834561c7696a539448 - Content-Length: - - '64' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Server: - - Server - Date: - - Mon, 01 Aug 2016 22:37:15 GMT - Content-Type: - - application/x-amz-json-1.1 - Content-Length: - - '74' - Connection: - - keep-alive - X-Amzn-Requestid: - - 7ef5cf1c-5838-11e6-977d-5f5e74dc3386 - body: - encoding: UTF-8 - string: '{"serviceArns":["arn:aws:ecs:us-west-2:111111111111:service/netflix-ice"]}' - http_version: - recorded_at: Mon, 01 Aug 2016 22:37:15 GMT -- request: - method: post - uri: https://ecs.us-west-2.amazonaws.com/ - body: - encoding: UTF-8 - string: '{"cluster":"arn:aws:ecs:us-west-2:111111111111:cluster/zleslie","services":["arn:aws:ecs:us-west-2:111111111111:service/netflix-ice"]}' - headers: - Content-Type: - - application/x-amz-json-1.1 - Accept-Encoding: - - '' - User-Agent: - - aws-sdk-ruby2/2.3.22 ruby/2.1.2 x86_64-darwin15.0 - X-Amz-Target: - - AmazonEC2ContainerServiceV20141113.DescribeServices - X-Amz-Date: - - 20160801T223715Z - X-Amz-Content-Sha256: - - c44e35d7bb974d8a0a562b33d09e355e6b6964a1e35bd4850163aaa80c29ca30 - Authorization: - - AWS4-HMAC-SHA256 Credential=redacterd/20160801/us-west-2/ecs/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, - Signature=39873d9d27e03f50602d6de50c32d03daf4598a715ca12e68dc896340032a97a - Content-Length: - - '134' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Server: - - Server - Date: - - Mon, 01 Aug 2016 22:37:15 GMT - Content-Type: - - application/x-amz-json-1.1 - Content-Length: - - '3621' - Connection: - - keep-alive - X-Amzn-Requestid: - - 7f06e5ea-5838-11e6-b537-c5d54ab9cbd5 - body: - encoding: UTF-8 - string: '{"failures":[],"services":[{"clusterArn":"arn:aws:ecs:us-west-2:111111111111:cluster/zleslie","createdAt":1.469637628671E9,"deploymentConfiguration":{"maximumPercent":200,"minimumHealthyPercent":100},"deployments":[{"createdAt":1.469637628671E9,"desiredCount":0,"id":"ecs-svc/9223370567217147128","pendingCount":0,"runningCount":0,"status":"PRIMARY","taskDefinition":"arn:aws:ecs:us-west-2:111111111111:task-definition/netflix-ice:30","updatedAt":1.469637628671E9}],"desiredCount":0,"events":[{"createdAt":1.470069887643E9,"id":"afeb8fc9-7dff-425d-9723-9dc6392702b3","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.470048261521E9,"id":"ba93794a-ddee-47a8-87b0-c5282b1c3f03","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.470026639099E9,"id":"cec1c78f-301e-4593-b7fd-79b9f907052f","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.470005024165E9,"id":"41769e97-fb45-4600-abb7-55615e22aa42","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.4699834144E9,"id":"e936db17-e05c-404e-ba5e-e07843a82721","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469961814258E9,"id":"7e228a56-1d76-4a38-88e1-a9fdf0f9e2cb","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469940196823E9,"id":"cab8a403-d9d9-4e07-ac68-8501a79780b7","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469918588348E9,"id":"e4c9afcf-b48a-4566-b2a9-b1790d506f02","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.46989697723E9,"id":"4b19f863-35fb-4eba-9617-d75e49f78110","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469875345099E9,"id":"b8969e63-6080-4bfc-8f02-89dc42b994da","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469853726707E9,"id":"38972468-9477-488d-b9c3-3d9c709b5bbe","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.46983212157E9,"id":"432dcfb0-6fa0-4613-807c-cd3d7a93f37b","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469810506433E9,"id":"be544d09-91ff-4512-884f-455874e48fbf","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469788905003E9,"id":"1ab21f17-cb26-47d8-864d-b4780eb5bfec","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469767301462E9,"id":"941ff5b8-ef46-48a0-8bba-d7bda2509bc2","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469745681305E9,"id":"53e4e256-17cb-44bb-9e64-e0b185a9735f","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469724067804E9,"id":"e917a1dd-6ae1-4649-9efa-6ed42902568f","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.46970246178E9,"id":"c71e7b0d-787f-4a23-bc4f-70fe99869c51","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469680861439E9,"id":"04f4f14b-a0d8-4e69-bc0e-22c36fce15a3","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.46965924988E9,"id":"2d35c0c3-ccfb-4f1e-84ec-9f7959cbac74","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469637631371E9,"id":"1fd1dbf9-a4ad-46c4-8905-9ae893ce3747","message":"(service - netflix-ice) has reached a steady state."}],"loadBalancers":[],"pendingCount":0,"runningCount":0,"serviceArn":"arn:aws:ecs:us-west-2:111111111111:service/netflix-ice","serviceName":"netflix-ice","status":"ACTIVE","taskDefinition":"arn:aws:ecs:us-west-2:111111111111:task-definition/netflix-ice:30"}]}' - http_version: - recorded_at: Mon, 01 Aug 2016 22:37:15 GMT -- request: - method: post - uri: https://ecs.us-west-2.amazonaws.com/ - body: - encoding: UTF-8 - string: "{}" - headers: - Content-Type: - - application/x-amz-json-1.1 - Accept-Encoding: - - '' - User-Agent: - - aws-sdk-ruby2/2.3.22 ruby/2.1.2 x86_64-darwin15.0 - X-Amz-Target: - - AmazonEC2ContainerServiceV20141113.ListClusters - X-Amz-Date: - - 20160801T223715Z - X-Amz-Content-Sha256: - - 44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a - Authorization: - - AWS4-HMAC-SHA256 Credential=redacterd/20160801/us-west-2/ecs/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, - Signature=510f2f9029b31cff1b4d4d295d1668718d3b70f0e0ef37fad3982c3b58141a08 - Content-Length: - - '2' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Server: - - Server - Date: - - Mon, 01 Aug 2016 22:37:15 GMT - Content-Type: - - application/x-amz-json-1.1 - Content-Length: - - '70' - Connection: - - keep-alive - X-Amzn-Requestid: - - 7f1898b0-5838-11e6-8f3f-af71e704ebce - body: - encoding: UTF-8 - string: '{"clusterArns":["arn:aws:ecs:us-west-2:111111111111:cluster/zleslie"]}' - http_version: - recorded_at: Mon, 01 Aug 2016 22:37:15 GMT -- request: - method: post - uri: https://ecs.us-west-2.amazonaws.com/ - body: - encoding: UTF-8 - string: '{"cluster":"arn:aws:ecs:us-west-2:111111111111:cluster/zleslie"}' - headers: - Content-Type: - - application/x-amz-json-1.1 - Accept-Encoding: - - '' - User-Agent: - - aws-sdk-ruby2/2.3.22 ruby/2.1.2 x86_64-darwin15.0 - X-Amz-Target: - - AmazonEC2ContainerServiceV20141113.ListServices - X-Amz-Date: - - 20160801T223715Z - X-Amz-Content-Sha256: - - 537b417af8208177ebdbb47afcfa6462c3b19bc144ea126047855a6c4821ff3b - Authorization: - - AWS4-HMAC-SHA256 Credential=redacterd/20160801/us-west-2/ecs/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, - Signature=bba70547a97ca7f3d90548f1c3ea4512c482ee3f9b5783834561c7696a539448 - Content-Length: - - '64' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Server: - - Server - Date: - - Mon, 01 Aug 2016 22:37:15 GMT - Content-Type: - - application/x-amz-json-1.1 - Content-Length: - - '74' - Connection: - - keep-alive - X-Amzn-Requestid: - - 7f2c4805-5838-11e6-a2f8-5b25449583a6 - body: - encoding: UTF-8 - string: '{"serviceArns":["arn:aws:ecs:us-west-2:111111111111:service/netflix-ice"]}' - http_version: - recorded_at: Mon, 01 Aug 2016 22:37:15 GMT -- request: - method: post - uri: https://ecs.us-west-2.amazonaws.com/ - body: - encoding: UTF-8 - string: '{"cluster":"arn:aws:ecs:us-west-2:111111111111:cluster/zleslie","services":["arn:aws:ecs:us-west-2:111111111111:service/netflix-ice"]}' - headers: - Content-Type: - - application/x-amz-json-1.1 - Accept-Encoding: - - '' - User-Agent: - - aws-sdk-ruby2/2.3.22 ruby/2.1.2 x86_64-darwin15.0 - X-Amz-Target: - - AmazonEC2ContainerServiceV20141113.DescribeServices - X-Amz-Date: - - 20160801T223715Z - X-Amz-Content-Sha256: - - c44e35d7bb974d8a0a562b33d09e355e6b6964a1e35bd4850163aaa80c29ca30 - Authorization: - - AWS4-HMAC-SHA256 Credential=redacterd/20160801/us-west-2/ecs/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, - Signature=39873d9d27e03f50602d6de50c32d03daf4598a715ca12e68dc896340032a97a - Content-Length: - - '134' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Server: - - Server - Date: - - Mon, 01 Aug 2016 22:37:15 GMT - Content-Type: - - application/x-amz-json-1.1 - Content-Length: - - '3621' - Connection: - - keep-alive - X-Amzn-Requestid: - - 7f3dd3f7-5838-11e6-b123-0d6ff5d80840 - body: - encoding: UTF-8 - string: '{"failures":[],"services":[{"clusterArn":"arn:aws:ecs:us-west-2:111111111111:cluster/zleslie","createdAt":1.469637628671E9,"deploymentConfiguration":{"maximumPercent":200,"minimumHealthyPercent":100},"deployments":[{"createdAt":1.469637628671E9,"desiredCount":0,"id":"ecs-svc/9223370567217147128","pendingCount":0,"runningCount":0,"status":"PRIMARY","taskDefinition":"arn:aws:ecs:us-west-2:111111111111:task-definition/netflix-ice:30","updatedAt":1.469637628671E9}],"desiredCount":0,"events":[{"createdAt":1.470069887643E9,"id":"afeb8fc9-7dff-425d-9723-9dc6392702b3","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.470048261521E9,"id":"ba93794a-ddee-47a8-87b0-c5282b1c3f03","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.470026639099E9,"id":"cec1c78f-301e-4593-b7fd-79b9f907052f","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.470005024165E9,"id":"41769e97-fb45-4600-abb7-55615e22aa42","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.4699834144E9,"id":"e936db17-e05c-404e-ba5e-e07843a82721","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469961814258E9,"id":"7e228a56-1d76-4a38-88e1-a9fdf0f9e2cb","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469940196823E9,"id":"cab8a403-d9d9-4e07-ac68-8501a79780b7","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469918588348E9,"id":"e4c9afcf-b48a-4566-b2a9-b1790d506f02","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.46989697723E9,"id":"4b19f863-35fb-4eba-9617-d75e49f78110","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469875345099E9,"id":"b8969e63-6080-4bfc-8f02-89dc42b994da","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469853726707E9,"id":"38972468-9477-488d-b9c3-3d9c709b5bbe","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.46983212157E9,"id":"432dcfb0-6fa0-4613-807c-cd3d7a93f37b","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469810506433E9,"id":"be544d09-91ff-4512-884f-455874e48fbf","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469788905003E9,"id":"1ab21f17-cb26-47d8-864d-b4780eb5bfec","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469767301462E9,"id":"941ff5b8-ef46-48a0-8bba-d7bda2509bc2","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469745681305E9,"id":"53e4e256-17cb-44bb-9e64-e0b185a9735f","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469724067804E9,"id":"e917a1dd-6ae1-4649-9efa-6ed42902568f","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.46970246178E9,"id":"c71e7b0d-787f-4a23-bc4f-70fe99869c51","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469680861439E9,"id":"04f4f14b-a0d8-4e69-bc0e-22c36fce15a3","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.46965924988E9,"id":"2d35c0c3-ccfb-4f1e-84ec-9f7959cbac74","message":"(service - netflix-ice) has reached a steady state."},{"createdAt":1.469637631371E9,"id":"1fd1dbf9-a4ad-46c4-8905-9ae893ce3747","message":"(service - netflix-ice) has reached a steady state."}],"loadBalancers":[],"pendingCount":0,"runningCount":0,"serviceArn":"arn:aws:ecs:us-west-2:111111111111:service/netflix-ice","serviceName":"netflix-ice","status":"ACTIVE","taskDefinition":"arn:aws:ecs:us-west-2:111111111111:task-definition/netflix-ice:30"}]}' - http_version: - recorded_at: Mon, 01 Aug 2016 22:37:15 GMT -recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/ecs-setup.yml b/fixtures/vcr_cassettes/ecs-setup.yml deleted file mode 100644 index 3528f6a7..00000000 --- a/fixtures/vcr_cassettes/ecs-setup.yml +++ /dev/null @@ -1,297 +0,0 @@ ---- -http_interactions: -- request: - method: post - uri: https://ecs.us-west-2.amazonaws.com/ - body: - encoding: UTF-8 - string: '{"status":"ACTIVE"}' - headers: - Content-Type: - - application/x-amz-json-1.1 - Accept-Encoding: - - '' - User-Agent: - - aws-sdk-ruby2/2.3.7 ruby/2.1.2 x86_64-darwin15.0 - X-Amz-Target: - - AmazonEC2ContainerServiceV20141113.ListTaskDefinitionFamilies - X-Amz-Date: - - 20160727T001519Z - X-Amz-Content-Sha256: - - 264e28f424ac2f00738ee11c418ac9a1666d7f44940f512ab9a9e105711a2f39 - Authorization: - - AWS4-HMAC-SHA256 Credential=AAAAAAAAAAAAAAAAAAAAA/20160727/us-west-2/ecs/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, - Signature=85f9ae5ef4c74cd242ea6675bf96d6174f2c39bf15830ef7e1976270f6fa86b1 - Content-Length: - - '19' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Server: - - Server - Date: - - Wed, 27 Jul 2016 00:15:20 GMT - Content-Type: - - application/x-amz-json-1.1 - Content-Length: - - '28' - Connection: - - keep-alive - X-Amzn-Requestid: - - 34157938-538f-11e6-b537-c5d54ab9cbd5 - body: - encoding: UTF-8 - string: '{"families":["netflix-ice"]}' - http_version: - recorded_at: Wed, 27 Jul 2016 00:15:20 GMT -- request: - method: post - uri: https://ecs.us-west-2.amazonaws.com/ - body: - encoding: UTF-8 - string: '{"taskDefinition":"netflix-ice"}' - headers: - Content-Type: - - application/x-amz-json-1.1 - Accept-Encoding: - - '' - User-Agent: - - aws-sdk-ruby2/2.3.7 ruby/2.1.2 x86_64-darwin15.0 - X-Amz-Target: - - AmazonEC2ContainerServiceV20141113.DescribeTaskDefinition - X-Amz-Date: - - 20160727T001520Z - X-Amz-Content-Sha256: - - 75840101855fab3849b65b3c028f259060cd7e7d9616c8a57ba19fda19df23ae - Authorization: - - AWS4-HMAC-SHA256 Credential=AAAAAAAAAAAAAAAAAAAAA/20160727/us-west-2/ecs/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, - Signature=2368db17b3f3886fcb0532b47c2d0d2e262b34d8a55bd66ce6df0c7676ba0a87 - Content-Length: - - '32' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Server: - - Server - Date: - - Wed, 27 Jul 2016 00:15:20 GMT - Content-Type: - - application/x-amz-json-1.1 - Content-Length: - - '672' - Connection: - - keep-alive - X-Amzn-Requestid: - - 34272c92-538f-11e6-8f3f-af71e704ebce - body: - encoding: UTF-8 - string: '{"taskDefinition":{"containerDefinitions":[{"cpu":1,"environment":[],"essential":false,"image":"debian:jessie","memory":256,"mountPoints":[],"name":"two","portMappings":[],"volumesFrom":[]},{"cpu":1021,"environment":[{"name":"two","value":"2"},{"name":"one","value":"1"}],"essential":true,"image":"debian:jessie","memory":512,"mountPoints":[],"name":"zleslietesting","portMappings":[{"containerPort":8080,"hostPort":8080,"protocol":"tcp"},{"containerPort":8081,"hostPort":8082,"protocol":"tcp"}],"volumesFrom":[]}],"family":"netflix-ice","revision":29,"status":"ACTIVE","taskDefinitionArn":"arn:aws:ecs:us-west-2:111111111111:task-definition/netflix-ice:29","volumes":[]}}' - http_version: - recorded_at: Wed, 27 Jul 2016 00:15:20 GMT -- request: - method: post - uri: https://ecs.us-west-2.amazonaws.com/ - body: - encoding: UTF-8 - string: '{"status":"ACTIVE"}' - headers: - Content-Type: - - application/x-amz-json-1.1 - Accept-Encoding: - - '' - User-Agent: - - aws-sdk-ruby2/2.3.7 ruby/2.1.2 x86_64-darwin15.0 - X-Amz-Target: - - AmazonEC2ContainerServiceV20141113.ListTaskDefinitionFamilies - X-Amz-Date: - - 20160727T001520Z - X-Amz-Content-Sha256: - - 264e28f424ac2f00738ee11c418ac9a1666d7f44940f512ab9a9e105711a2f39 - Authorization: - - AWS4-HMAC-SHA256 Credential=AAAAAAAAAAAAAAAAAAAAA/20160727/us-west-2/ecs/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, - Signature=e7ec24e02c893eed5760da01ae46452eb16f3ad10c5e029f225ea9f2f6c50b41 - Content-Length: - - '19' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Server: - - Server - Date: - - Wed, 27 Jul 2016 00:15:20 GMT - Content-Type: - - application/x-amz-json-1.1 - Content-Length: - - '28' - Connection: - - keep-alive - X-Amzn-Requestid: - - 343efa3e-538f-11e6-b537-c5d54ab9cbd5 - body: - encoding: UTF-8 - string: '{"families":["netflix-ice"]}' - http_version: - recorded_at: Wed, 27 Jul 2016 00:15:20 GMT -- request: - method: post - uri: https://ecs.us-west-2.amazonaws.com/ - body: - encoding: UTF-8 - string: '{"taskDefinition":"netflix-ice"}' - headers: - Content-Type: - - application/x-amz-json-1.1 - Accept-Encoding: - - '' - User-Agent: - - aws-sdk-ruby2/2.3.7 ruby/2.1.2 x86_64-darwin15.0 - X-Amz-Target: - - AmazonEC2ContainerServiceV20141113.DescribeTaskDefinition - X-Amz-Date: - - 20160727T001520Z - X-Amz-Content-Sha256: - - 75840101855fab3849b65b3c028f259060cd7e7d9616c8a57ba19fda19df23ae - Authorization: - - AWS4-HMAC-SHA256 Credential=AAAAAAAAAAAAAAAAAAAAA/20160727/us-west-2/ecs/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, - Signature=2368db17b3f3886fcb0532b47c2d0d2e262b34d8a55bd66ce6df0c7676ba0a87 - Content-Length: - - '32' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Server: - - Server - Date: - - Wed, 27 Jul 2016 00:15:20 GMT - Content-Type: - - application/x-amz-json-1.1 - Content-Length: - - '672' - Connection: - - keep-alive - X-Amzn-Requestid: - - 346c24ac-538f-11e6-b123-0d6ff5d80840 - body: - encoding: UTF-8 - string: '{"taskDefinition":{"containerDefinitions":[{"cpu":1,"environment":[],"essential":false,"image":"debian:jessie","memory":256,"mountPoints":[],"name":"two","portMappings":[],"volumesFrom":[]},{"cpu":1021,"environment":[{"name":"two","value":"2"},{"name":"one","value":"1"}],"essential":true,"image":"debian:jessie","memory":512,"mountPoints":[],"name":"zleslietesting","portMappings":[{"containerPort":8080,"hostPort":8080,"protocol":"tcp"},{"containerPort":8081,"hostPort":8082,"protocol":"tcp"}],"volumesFrom":[]}],"family":"netflix-ice","revision":29,"status":"ACTIVE","taskDefinitionArn":"arn:aws:ecs:us-west-2:111111111111:task-definition/netflix-ice:29","volumes":[]}}' - http_version: - recorded_at: Wed, 27 Jul 2016 00:15:20 GMT -- request: - method: post - uri: https://ecs.us-west-2.amazonaws.com/ - body: - encoding: UTF-8 - string: '{"status":"ACTIVE"}' - headers: - Content-Type: - - application/x-amz-json-1.1 - Accept-Encoding: - - '' - User-Agent: - - aws-sdk-ruby2/2.3.7 ruby/2.1.2 x86_64-darwin15.0 - X-Amz-Target: - - AmazonEC2ContainerServiceV20141113.ListTaskDefinitionFamilies - X-Amz-Date: - - 20160727T001520Z - X-Amz-Content-Sha256: - - 264e28f424ac2f00738ee11c418ac9a1666d7f44940f512ab9a9e105711a2f39 - Authorization: - - AWS4-HMAC-SHA256 Credential=AAAAAAAAAAAAAAAAAAAAA/20160727/us-west-2/ecs/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, - Signature=e7ec24e02c893eed5760da01ae46452eb16f3ad10c5e029f225ea9f2f6c50b41 - Content-Length: - - '19' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Server: - - Server - Date: - - Wed, 27 Jul 2016 00:15:20 GMT - Content-Type: - - application/x-amz-json-1.1 - Content-Length: - - '28' - Connection: - - keep-alive - X-Amzn-Requestid: - - 347f10a5-538f-11e6-8f3f-af71e704ebce - body: - encoding: UTF-8 - string: '{"families":["netflix-ice"]}' - http_version: - recorded_at: Wed, 27 Jul 2016 00:15:20 GMT -- request: - method: post - uri: https://ecs.us-west-2.amazonaws.com/ - body: - encoding: UTF-8 - string: '{"taskDefinition":"netflix-ice"}' - headers: - Content-Type: - - application/x-amz-json-1.1 - Accept-Encoding: - - '' - User-Agent: - - aws-sdk-ruby2/2.3.7 ruby/2.1.2 x86_64-darwin15.0 - X-Amz-Target: - - AmazonEC2ContainerServiceV20141113.DescribeTaskDefinition - X-Amz-Date: - - 20160727T001520Z - X-Amz-Content-Sha256: - - 75840101855fab3849b65b3c028f259060cd7e7d9616c8a57ba19fda19df23ae - Authorization: - - AWS4-HMAC-SHA256 Credential=AAAAAAAAAAAAAAAAAAAAA/20160727/us-west-2/ecs/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, - Signature=2368db17b3f3886fcb0532b47c2d0d2e262b34d8a55bd66ce6df0c7676ba0a87 - Content-Length: - - '32' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Server: - - Server - Date: - - Wed, 27 Jul 2016 00:15:20 GMT - Content-Type: - - application/x-amz-json-1.1 - Content-Length: - - '672' - Connection: - - keep-alive - X-Amzn-Requestid: - - 348fb255-538f-11e6-b537-c5d54ab9cbd5 - body: - encoding: UTF-8 - string: '{"taskDefinition":{"containerDefinitions":[{"cpu":1,"environment":[],"essential":false,"image":"debian:jessie","memory":256,"mountPoints":[],"name":"two","portMappings":[],"volumesFrom":[]},{"cpu":1021,"environment":[{"name":"two","value":"2"},{"name":"one","value":"1"}],"essential":true,"image":"debian:jessie","memory":512,"mountPoints":[],"name":"zleslietesting","portMappings":[{"containerPort":8080,"hostPort":8080,"protocol":"tcp"},{"containerPort":8081,"hostPort":8082,"protocol":"tcp"}],"volumesFrom":[]}],"family":"netflix-ice","revision":29,"status":"ACTIVE","taskDefinitionArn":"arn:aws:ecs:us-west-2:111111111111:task-definition/netflix-ice:29","volumes":[]}}' - http_version: - recorded_at: Wed, 27 Jul 2016 00:15:20 GMT -recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/ecs_service-setup.yml b/fixtures/vcr_cassettes/ecs_service-setup.yml new file mode 100644 index 00000000..f2ebd23f --- /dev/null +++ b/fixtures/vcr_cassettes/ecs_service-setup.yml @@ -0,0 +1,444 @@ +--- +http_interactions: +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: "{}" + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.ListClusters + X-Amz-Date: + - 20170111T222401Z + X-Amz-Content-Sha256: + - 44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=c7dbfdad453435523bb11b704263bc2fac941b807232162a73e0a362782ec22b + Content-Length: + - '2' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 22:24:02 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '67' + Connection: + - keep-alive + X-Amzn-Requestid: + - a77e120d-d84c-11e6-97a5-e15b5541a538 + body: + encoding: UTF-8 + string: '{"clusterArns":["arn:aws:ecs:us-west-2:123456789012:cluster/test"]}' + http_version: + recorded_at: Wed, 11 Jan 2017 22:24:02 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"cluster":"arn:aws:ecs:us-west-2:123456789012:cluster/test"}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.ListServices + X-Amz-Date: + - 20170111T222402Z + X-Amz-Content-Sha256: + - b256c3f786d634c26b55172b3da5fef1a67e4f714e0bfeb4c618015ccb5e7dee + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=24b7183b277a7891642e26768eefd9f54af0d74894edb330d39ececaa9f49324 + Content-Length: + - '61' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 22:24:02 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '74' + Connection: + - keep-alive + X-Amzn-Requestid: + - a7932105-d84c-11e6-9f70-5f80690e25cf + body: + encoding: UTF-8 + string: '{"serviceArns":["arn:aws:ecs:us-west-2:123456789012:service/testservice"]}' + http_version: + recorded_at: Wed, 11 Jan 2017 22:24:02 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"cluster":"arn:aws:ecs:us-west-2:123456789012:cluster/test","services":["arn:aws:ecs:us-west-2:123456789012:service/testservice"]}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.DescribeServices + X-Amz-Date: + - 20170111T222402Z + X-Amz-Content-Sha256: + - 33f0f8c43969497fdcfd2f32708d282d88cee303f24dc0c0f0050fb0d2da27b7 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=b97cb3ac79fd7cf929112c69ae5e63af34ba71a4c60be91697ead8c82c7e2e2d + Content-Length: + - '131' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 22:24:02 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '789' + Connection: + - keep-alive + X-Amzn-Requestid: + - a7a7e165-d84c-11e6-ade8-4b8f80170e6e + body: + encoding: UTF-8 + string: '{"failures":[],"services":[{"clusterArn":"arn:aws:ecs:us-west-2:123456789012:cluster/test","createdAt":1.484173441895E9,"deploymentConfiguration":{"maximumPercent":200,"minimumHealthyPercent":100},"deployments":[{"createdAt":1.484173441895E9,"desiredCount":0,"id":"ecs-svc/9223370552681333906","pendingCount":0,"runningCount":0,"status":"PRIMARY","taskDefinition":"arn:aws:ecs:us-west-2:123456789012:task-definition/testtask:6","updatedAt":1.484173441895E9}],"desiredCount":0,"events":[],"loadBalancers":[],"pendingCount":0,"placementConstraints":[],"placementStrategy":[],"runningCount":0,"serviceArn":"arn:aws:ecs:us-west-2:123456789012:service/testservice","serviceName":"testservice","status":"ACTIVE","taskDefinition":"arn:aws:ecs:us-west-2:123456789012:task-definition/testtask:6"}]}' + http_version: + recorded_at: Wed, 11 Jan 2017 22:24:02 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: "{}" + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.ListClusters + X-Amz-Date: + - 20170111T222402Z + X-Amz-Content-Sha256: + - 44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=73322636a1e31276a1907064dba59c6a99201a6893126ffeabd8ee7ccaa96db7 + Content-Length: + - '2' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 22:24:02 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '67' + Connection: + - keep-alive + X-Amzn-Requestid: + - a7bd6536-d84c-11e6-90fb-cb6c24bb816a + body: + encoding: UTF-8 + string: '{"clusterArns":["arn:aws:ecs:us-west-2:123456789012:cluster/test"]}' + http_version: + recorded_at: Wed, 11 Jan 2017 22:24:02 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"cluster":"arn:aws:ecs:us-west-2:123456789012:cluster/test"}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.ListServices + X-Amz-Date: + - 20170111T222402Z + X-Amz-Content-Sha256: + - b256c3f786d634c26b55172b3da5fef1a67e4f714e0bfeb4c618015ccb5e7dee + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=24b7183b277a7891642e26768eefd9f54af0d74894edb330d39ececaa9f49324 + Content-Length: + - '61' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 22:24:02 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '74' + Connection: + - keep-alive + X-Amzn-Requestid: + - a7d1feaa-d84c-11e6-ade8-4b8f80170e6e + body: + encoding: UTF-8 + string: '{"serviceArns":["arn:aws:ecs:us-west-2:123456789012:service/testservice"]}' + http_version: + recorded_at: Wed, 11 Jan 2017 22:24:02 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"cluster":"arn:aws:ecs:us-west-2:123456789012:cluster/test","services":["arn:aws:ecs:us-west-2:123456789012:service/testservice"]}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.DescribeServices + X-Amz-Date: + - 20170111T222402Z + X-Amz-Content-Sha256: + - 33f0f8c43969497fdcfd2f32708d282d88cee303f24dc0c0f0050fb0d2da27b7 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=b97cb3ac79fd7cf929112c69ae5e63af34ba71a4c60be91697ead8c82c7e2e2d + Content-Length: + - '131' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 22:24:02 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '789' + Connection: + - keep-alive + X-Amzn-Requestid: + - a7e6e63e-d84c-11e6-ade8-4b8f80170e6e + body: + encoding: UTF-8 + string: '{"failures":[],"services":[{"clusterArn":"arn:aws:ecs:us-west-2:123456789012:cluster/test","createdAt":1.484173441895E9,"deploymentConfiguration":{"maximumPercent":200,"minimumHealthyPercent":100},"deployments":[{"createdAt":1.484173441895E9,"desiredCount":0,"id":"ecs-svc/9223370552681333906","pendingCount":0,"runningCount":0,"status":"PRIMARY","taskDefinition":"arn:aws:ecs:us-west-2:123456789012:task-definition/testtask:6","updatedAt":1.484173441895E9}],"desiredCount":0,"events":[],"loadBalancers":[],"pendingCount":0,"placementConstraints":[],"placementStrategy":[],"runningCount":0,"serviceArn":"arn:aws:ecs:us-west-2:123456789012:service/testservice","serviceName":"testservice","status":"ACTIVE","taskDefinition":"arn:aws:ecs:us-west-2:123456789012:task-definition/testtask:6"}]}' + http_version: + recorded_at: Wed, 11 Jan 2017 22:24:02 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: "{}" + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.ListClusters + X-Amz-Date: + - 20170111T222402Z + X-Amz-Content-Sha256: + - 44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=73322636a1e31276a1907064dba59c6a99201a6893126ffeabd8ee7ccaa96db7 + Content-Length: + - '2' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 22:24:02 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '67' + Connection: + - keep-alive + X-Amzn-Requestid: + - a7fd53a5-d84c-11e6-9f70-5f80690e25cf + body: + encoding: UTF-8 + string: '{"clusterArns":["arn:aws:ecs:us-west-2:123456789012:cluster/test"]}' + http_version: + recorded_at: Wed, 11 Jan 2017 22:24:02 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"cluster":"arn:aws:ecs:us-west-2:123456789012:cluster/test"}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.ListServices + X-Amz-Date: + - 20170111T222402Z + X-Amz-Content-Sha256: + - b256c3f786d634c26b55172b3da5fef1a67e4f714e0bfeb4c618015ccb5e7dee + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=24b7183b277a7891642e26768eefd9f54af0d74894edb330d39ececaa9f49324 + Content-Length: + - '61' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 22:24:03 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '74' + Connection: + - keep-alive + X-Amzn-Requestid: + - a80f2e68-d84c-11e6-bc57-0d9a6fd42937 + body: + encoding: UTF-8 + string: '{"serviceArns":["arn:aws:ecs:us-west-2:123456789012:service/testservice"]}' + http_version: + recorded_at: Wed, 11 Jan 2017 22:24:03 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"cluster":"arn:aws:ecs:us-west-2:123456789012:cluster/test","services":["arn:aws:ecs:us-west-2:123456789012:service/testservice"]}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.DescribeServices + X-Amz-Date: + - 20170111T222403Z + X-Amz-Content-Sha256: + - 33f0f8c43969497fdcfd2f32708d282d88cee303f24dc0c0f0050fb0d2da27b7 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=bc2cc7a814890eaace14276ffca46a97385b26ddf3d41161318b86170ed3d4d5 + Content-Length: + - '131' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 22:24:03 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '789' + Connection: + - keep-alive + X-Amzn-Requestid: + - a825c40b-d84c-11e6-ade8-4b8f80170e6e + body: + encoding: UTF-8 + string: '{"failures":[],"services":[{"clusterArn":"arn:aws:ecs:us-west-2:123456789012:cluster/test","createdAt":1.484173441895E9,"deploymentConfiguration":{"maximumPercent":200,"minimumHealthyPercent":100},"deployments":[{"createdAt":1.484173441895E9,"desiredCount":0,"id":"ecs-svc/9223370552681333906","pendingCount":0,"runningCount":0,"status":"PRIMARY","taskDefinition":"arn:aws:ecs:us-west-2:123456789012:task-definition/testtask:6","updatedAt":1.484173441895E9}],"desiredCount":0,"events":[],"loadBalancers":[],"pendingCount":0,"placementConstraints":[],"placementStrategy":[],"runningCount":0,"serviceArn":"arn:aws:ecs:us-west-2:123456789012:service/testservice","serviceName":"testservice","status":"ACTIVE","taskDefinition":"arn:aws:ecs:us-west-2:123456789012:task-definition/testtask:6"}]}' + http_version: + recorded_at: Wed, 11 Jan 2017 22:24:03 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/ecs_task_definition-setup.yml b/fixtures/vcr_cassettes/ecs_task_definition-setup.yml new file mode 100644 index 00000000..fa4d6ac0 --- /dev/null +++ b/fixtures/vcr_cassettes/ecs_task_definition-setup.yml @@ -0,0 +1,395 @@ +--- +http_interactions: +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"status":"ACTIVE"}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.ListTaskDefinitionFamilies + X-Amz-Date: + - 20170111T232132Z + X-Amz-Content-Sha256: + - 264e28f424ac2f00738ee11c418ac9a1666d7f44940f512ab9a9e105711a2f39 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=e6fc3f2ca3d12cf9affa6da64fcc74a9cb3d2f11750a89ac4c58820a1bc62a3d + Content-Length: + - '19' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 23:21:33 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '54' + Connection: + - keep-alive + X-Amzn-Requestid: + - b06f5f7c-d854-11e6-b3b3-f758afa069bf + body: + encoding: UTF-8 + string: '{"families":["netflix-ice","netflix-ice2","testtask"]}' + http_version: + recorded_at: Wed, 11 Jan 2017 23:21:33 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"taskDefinition":"netflix-ice"}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.DescribeTaskDefinition + X-Amz-Date: + - 20170111T232133Z + X-Amz-Content-Sha256: + - 75840101855fab3849b65b3c028f259060cd7e7d9616c8a57ba19fda19df23ae + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=8aa83515074c7e6c4463958892642088563f972021d6c40194e76100834fbf8c + Content-Length: + - '32' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 23:21:33 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '473' + Connection: + - keep-alive + X-Amzn-Requestid: + - b085f3c1-d854-11e6-b3b3-f758afa069bf + body: + encoding: UTF-8 + string: '{"taskDefinition":{"containerDefinitions":[{"cpu":1024,"environment":[{"name":"two","value":"2"},{"name":"one","value":"one"}],"essential":true,"image":"debian:jessie17","memory":512,"mountPoints":[],"name":"zleslietesting","portMappings":[{"containerPort":8081,"hostPort":8082,"protocol":"tcp"}],"volumesFrom":[]}],"family":"netflix-ice","revision":52,"status":"ACTIVE","taskDefinitionArn":"arn:aws:ecs:us-west-2:123456789012:task-definition/netflix-ice:52","volumes":[]}}' + http_version: + recorded_at: Wed, 11 Jan 2017 23:21:33 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"taskDefinition":"netflix-ice2"}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.DescribeTaskDefinition + X-Amz-Date: + - 20170111T232133Z + X-Amz-Content-Sha256: + - 7d85761083e15ebb6d4a5acd43a04c5df9b4ac443705060eac6a533421584ce1 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=821478d7343fb4ac882e12883a94b3371e6345f5262d3f7f397b069d52f745db + Content-Length: + - '33' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 23:21:33 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '473' + Connection: + - keep-alive + X-Amzn-Requestid: + - b099f1c9-d854-11e6-ba13-fd5817d08f74 + body: + encoding: UTF-8 + string: '{"taskDefinition":{"containerDefinitions":[{"cpu":1023,"environment":[{"name":"two","value":"2"},{"name":"one","value":"one"}],"essential":true,"image":"debian:jessie19","memory":512,"mountPoints":[],"name":"zleslietesting","portMappings":[{"containerPort":8081,"hostPort":8082,"protocol":"tcp"}],"volumesFrom":[]}],"family":"netflix-ice2","revision":2,"status":"ACTIVE","taskDefinitionArn":"arn:aws:ecs:us-west-2:123456789012:task-definition/netflix-ice2:2","volumes":[]}}' + http_version: + recorded_at: Wed, 11 Jan 2017 23:21:33 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"taskDefinition":"testtask"}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.DescribeTaskDefinition + X-Amz-Date: + - 20170111T232133Z + X-Amz-Content-Sha256: + - a4f77f09f82abaab5e573332bb562eb361aed53e1acb9bdc1da98fdad621e6a2 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=9d0ff1181197353d8b44eef36c23916e91037a21ea549c5df2ada57fc43e5c43 + Content-Length: + - '29' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 23:21:33 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '764' + Connection: + - keep-alive + X-Amzn-Requestid: + - b0b011f0-d854-11e6-801c-6f2c8cddb4be + body: + encoding: UTF-8 + string: '{"taskDefinition":{"containerDefinitions":[{"cpu":1024,"environment":[{"name":"two","value":"2"},{"name":"one","value":"one"}],"essential":true,"image":"debian:jessie17","memory":512,"mountPoints":[],"name":"zleslietesting","portMappings":[{"containerPort":8081,"hostPort":8082,"protocol":"tcp"}],"volumesFrom":[]},{"cpu":1024,"environment":[{"name":"two","value":"2"},{"name":"one","value":"one"}],"essential":true,"image":"debian:jessie17","memory":512,"mountPoints":[],"name":"zleslietesting2","portMappings":[{"containerPort":8082,"hostPort":8083,"protocol":"tcp"}],"volumesFrom":[]}],"family":"testtask","placementConstraints":[],"revision":6,"status":"ACTIVE","taskDefinitionArn":"arn:aws:ecs:us-west-2:123456789012:task-definition/testtask:6","volumes":[]}}' + http_version: + recorded_at: Wed, 11 Jan 2017 23:21:33 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"status":"ACTIVE"}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.ListTaskDefinitionFamilies + X-Amz-Date: + - 20170111T232133Z + X-Amz-Content-Sha256: + - 264e28f424ac2f00738ee11c418ac9a1666d7f44940f512ab9a9e105711a2f39 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=e47d8accf0b0ac59f4806111f38df95c89eb44dc143d166fd390d7a90734304e + Content-Length: + - '19' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 23:21:33 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '54' + Connection: + - keep-alive + X-Amzn-Requestid: + - b0c63125-d854-11e6-bdc8-1dddb95ed95d + body: + encoding: UTF-8 + string: '{"families":["netflix-ice","netflix-ice2","testtask"]}' + http_version: + recorded_at: Wed, 11 Jan 2017 23:21:33 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"taskDefinition":"netflix-ice"}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.DescribeTaskDefinition + X-Amz-Date: + - 20170111T232133Z + X-Amz-Content-Sha256: + - 75840101855fab3849b65b3c028f259060cd7e7d9616c8a57ba19fda19df23ae + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=8aa83515074c7e6c4463958892642088563f972021d6c40194e76100834fbf8c + Content-Length: + - '32' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 23:21:33 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '473' + Connection: + - keep-alive + X-Amzn-Requestid: + - b0dc78d7-d854-11e6-b6b1-5304638d0773 + body: + encoding: UTF-8 + string: '{"taskDefinition":{"containerDefinitions":[{"cpu":1024,"environment":[{"name":"two","value":"2"},{"name":"one","value":"one"}],"essential":true,"image":"debian:jessie17","memory":512,"mountPoints":[],"name":"zleslietesting","portMappings":[{"containerPort":8081,"hostPort":8082,"protocol":"tcp"}],"volumesFrom":[]}],"family":"netflix-ice","revision":52,"status":"ACTIVE","taskDefinitionArn":"arn:aws:ecs:us-west-2:123456789012:task-definition/netflix-ice:52","volumes":[]}}' + http_version: + recorded_at: Wed, 11 Jan 2017 23:21:33 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"taskDefinition":"netflix-ice2"}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.DescribeTaskDefinition + X-Amz-Date: + - 20170111T232133Z + X-Amz-Content-Sha256: + - 7d85761083e15ebb6d4a5acd43a04c5df9b4ac443705060eac6a533421584ce1 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=821478d7343fb4ac882e12883a94b3371e6345f5262d3f7f397b069d52f745db + Content-Length: + - '33' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 23:21:34 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '473' + Connection: + - keep-alive + X-Amzn-Requestid: + - b10cd7ec-d854-11e6-ba13-fd5817d08f74 + body: + encoding: UTF-8 + string: '{"taskDefinition":{"containerDefinitions":[{"cpu":1023,"environment":[{"name":"two","value":"2"},{"name":"one","value":"one"}],"essential":true,"image":"debian:jessie19","memory":512,"mountPoints":[],"name":"zleslietesting","portMappings":[{"containerPort":8081,"hostPort":8082,"protocol":"tcp"}],"volumesFrom":[]}],"family":"netflix-ice2","revision":2,"status":"ACTIVE","taskDefinitionArn":"arn:aws:ecs:us-west-2:123456789012:task-definition/netflix-ice2:2","volumes":[]}}' + http_version: + recorded_at: Wed, 11 Jan 2017 23:21:34 GMT +- request: + method: post + uri: https://ecs.us-west-2.amazonaws.com/ + body: + encoding: UTF-8 + string: '{"taskDefinition":"testtask"}' + headers: + Content-Type: + - application/x-amz-json-1.1 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Target: + - AmazonEC2ContainerServiceV20141113.DescribeTaskDefinition + X-Amz-Date: + - 20170111T232134Z + X-Amz-Content-Sha256: + - a4f77f09f82abaab5e573332bb562eb361aed53e1acb9bdc1da98fdad621e6a2 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-west-2/ecs/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, + Signature=5eb77096c050f67ce515fea9141ae88ae84ff0a62aff4130a27cb1da075e79e4 + Content-Length: + - '29' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - Server + Date: + - Wed, 11 Jan 2017 23:21:34 GMT + Content-Type: + - application/x-amz-json-1.1 + Content-Length: + - '764' + Connection: + - keep-alive + X-Amzn-Requestid: + - b121be9a-d854-11e6-801c-6f2c8cddb4be + body: + encoding: UTF-8 + string: '{"taskDefinition":{"containerDefinitions":[{"cpu":1024,"environment":[{"name":"two","value":"2"},{"name":"one","value":"one"}],"essential":true,"image":"debian:jessie17","memory":512,"mountPoints":[],"name":"zleslietesting","portMappings":[{"containerPort":8081,"hostPort":8082,"protocol":"tcp"}],"volumesFrom":[]},{"cpu":1024,"environment":[{"name":"two","value":"2"},{"name":"one","value":"one"}],"essential":true,"image":"debian:jessie17","memory":512,"mountPoints":[],"name":"zleslietesting2","portMappings":[{"containerPort":8082,"hostPort":8083,"protocol":"tcp"}],"volumesFrom":[]}],"family":"testtask","placementConstraints":[],"revision":6,"status":"ACTIVE","taskDefinitionArn":"arn:aws:ecs:us-west-2:123456789012:task-definition/testtask:6","volumes":[]}}' + http_version: + recorded_at: Wed, 11 Jan 2017 23:21:34 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/elb-named-test.yml b/fixtures/vcr_cassettes/elb-named-test.yml index 89ec0530..a360a9e5 100644 --- a/fixtures/vcr_cassettes/elb-named-test.yml +++ b/fixtures/vcr_cassettes/elb-named-test.yml @@ -1,332 +1,310 @@ ---- - http_interactions: - - request: - method: post - uri: "https://elasticloadbalancing.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeLoadBalancers&Version=2012-06-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131206Z" - Host: - - elasticloadbalancing.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - "236069f72bf74f0c7ddff0a34b0defa8a21d1d6a897e588764e1b2ff6319f94a" - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/elasticloadbalancing/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=4c018c71334fdb88837e509396dbe0ef1be90a923ddac266fd22fce1a9814713" - Content-Length: - - "47" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - e820084b-b838-11e4-a812-754bf84275e1 - Content-Type: - - text/xml - Content-Length: - - "5690" - Vary: - - Accept-Encoding - Date: - - "Thu, 19 Feb 2015 13:12:08 GMT" - body: - encoding: UTF-8 - string: "\n \n \n \n \n garethrProed3b61536416444c8b742\n 2015-02-19T11:44:43.210Z\n \n 30\n TCP:80\n 10\n 5\n 2\n \n \n \n \n \n TCP\n 80\n TCP\n 80\n \n \n \n \n \n i-e06944f5\n \n \n \n \n \n \n \n \n sa-east-1a\n sa-east-1b\n \n Z2ES78Y61JGQKS\n garethrProed3b61536416444c8b742-886078075.sa-east-1.elb.amazonaws.com\n internet-facing\n \n amazon-elb\n amazon-elb-sg\n \n garethrProed3b61536416444c8b742-886078075.sa-east-1.elb.amazonaws.com\n \n \n \n \n \n garethrPro09dbc77f59cd476a82a44\n 2015-02-19T11:47:35.120Z\n \n 30\n TCP:80\n 10\n 5\n 2\n \n \n \n \n \n TCP\n 80\n TCP\n 80\n \n \n \n \n \n i-2c684539\n \n \n \n \n \n \n \n \n sa-east-1a\n sa-east-1b\n \n Z2ES78Y61JGQKS\n garethrPro09dbc77f59cd476a82a44-667909254.sa-east-1.elb.amazonaws.com\n internet-facing\n \n amazon-elb\n amazon-elb-sg\n \n garethrPro09dbc77f59cd476a82a44-667909254.sa-east-1.elb.amazonaws.com\n \n \n \n \n \n garethrProb4c4e3bed64f4af7909b1\n 2015-02-19T11:48:11.620Z\n \n 30\n TCP:80\n 10\n 5\n 2\n \n \n \n \n \n TCP\n 80\n TCP\n 80\n \n \n \n \n \n i-53684546\n \n \n \n \n \n \n \n \n sa-east-1a\n sa-east-1b\n \n Z2ES78Y61JGQKS\n garethrProb4c4e3bed64f4af7909b1-1293617159.sa-east-1.elb.amazonaws.com\n internet-facing\n \n amazon-elb\n amazon-elb-sg\n \n garethrProb4c4e3bed64f4af7909b1-1293617159.sa-east-1.elb.amazonaws.com\n \n \n \n \n \n \n e820084b-b838-11e4-a812-754bf84275e1\n \n\n" - http_version: - recorded_at: "Thu, 19 Feb 2015 13:12:08 GMT" - - request: - method: post - uri: "https://ec2.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeInstances&InstanceId.1=i-e06944f5&Version=2014-09-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131208Z" - Host: - - ec2.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - "9475874c018c2c03c4a93de1947197037608ff464c6bd1a44e059d5f664f8964" - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/ec2/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=5e8d5434bc31aa6af0c78aab473f581324b77eed840b8ba88b3e103567d2a2b1" - Content-Length: - - "67" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Content-Type: - - "text/xml;charset=UTF-8" - Transfer-Encoding: - - chunked - Vary: - - Accept-Encoding - Date: - - "Thu, 19 Feb 2015 13:12:09 GMT" - Cneonction: - - close - Server: - - AmazonEC2 - body: - encoding: UTF-8 - string: |- - - - 7a5c5359-3bfc-4952-a485-99fb4134d421 - - - - http_version: - recorded_at: "Thu, 19 Feb 2015 13:12:09 GMT" - - request: - method: post - uri: "https://elasticloadbalancing.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeTags&LoadBalancerNames.member.1=garethrProed3b61536416444c8b742&Version=2012-06-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131209Z" - Host: - - elasticloadbalancing.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - "4f92033359cb32556b7e192a5e17070c1be1d17d0ce9485b4770551f4781de74" - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/elasticloadbalancing/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=ab735996612eb0b5ffd51258d970a056e936df822782c9521292a48a1df70d8e" - Content-Length: - - "97" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - ea6b30ac-b838-11e4-8230-09161d0c23f4 - Content-Type: - - text/xml - Content-Length: - - "1007" - Date: - - "Thu, 19 Feb 2015 13:12:11 GMT" - body: - encoding: UTF-8 - string: "\n \n \n \n \n \n aws-acceptance\n created_by\n \n \n garethrProed3b61536416444c8b742\n Name\n \n \n cloud\n project\n \n \n engineering\n department\n \n \n polo\n marco\n \n \n garethrProed3b61536416444c8b742\n \n \n \n \n ea6b30ac-b838-11e4-8230-09161d0c23f4\n \n\n" - http_version: - recorded_at: "Thu, 19 Feb 2015 13:12:12 GMT" - - request: - method: post - uri: "https://ec2.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeInstances&InstanceId.1=i-2c684539&Version=2014-09-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131212Z" - Host: - - ec2.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - "5ef3e4edda454587cdf5a141350023404341b8452538a311a4f929e6dc56707f" - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/ec2/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=d3624740b27b42689f20e961bcd8225827a9e25ccf9a782eabf130e39eb920c1" - Content-Length: - - "67" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Content-Type: - - "text/xml;charset=UTF-8" - Transfer-Encoding: - - chunked - Vary: - - Accept-Encoding - Date: - - "Thu, 19 Feb 2015 13:12:13 GMT" - Server: - - AmazonEC2 - body: - encoding: UTF-8 - string: |- - - - 5e0393a0-6116-4c21-881a-6c1393209591 - - - - http_version: - recorded_at: "Thu, 19 Feb 2015 13:12:14 GMT" - - request: - method: post - uri: "https://elasticloadbalancing.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeTags&LoadBalancerNames.member.1=garethrPro09dbc77f59cd476a82a44&Version=2012-06-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131214Z" - Host: - - elasticloadbalancing.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - b16991e74dd9da116372d8bce1a3c700be58482c772d933f528aa53d0b8e562f - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/elasticloadbalancing/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=c5b24e6d7443f9b98019314eda811bf3c8a6d5c0fc53b970f3169d92ab2e7127" - Content-Length: - - "97" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - ece9282d-b838-11e4-a812-754bf84275e1 - Content-Type: - - text/xml - Content-Length: - - "1007" - Date: - - "Thu, 19 Feb 2015 13:12:16 GMT" - body: - encoding: UTF-8 - string: "\n \n \n \n \n \n aws-acceptance\n created_by\n \n \n garethrPro09dbc77f59cd476a82a44\n Name\n \n \n cloud\n project\n \n \n engineering\n department\n \n \n polo\n marco\n \n \n garethrPro09dbc77f59cd476a82a44\n \n \n \n \n ece9282d-b838-11e4-a812-754bf84275e1\n \n\n" - http_version: - recorded_at: "Thu, 19 Feb 2015 13:12:16 GMT" - - request: - method: post - uri: "https://ec2.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeInstances&InstanceId.1=i-53684546&Version=2014-09-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131216Z" - Host: - - ec2.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - "7bf65415c8e3eeeede1f1b2cecc497b02fd1ad49fc3242250c1f338d511aea12" - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/ec2/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=fef0daaf7cf2ed3bc62162fa306c4695a297efae3d14f544c2c909a4ef958660" - Content-Length: - - "67" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Content-Type: - - "text/xml;charset=UTF-8" - Transfer-Encoding: - - chunked - Vary: - - Accept-Encoding - Date: - - "Thu, 19 Feb 2015 13:12:17 GMT" - Server: - - AmazonEC2 - body: - encoding: UTF-8 - string: |- - - - 81b25460-c925-472f-bc05-82b13d3e7d98 - - - - http_version: - recorded_at: "Thu, 19 Feb 2015 13:12:18 GMT" - - request: - method: post - uri: "https://elasticloadbalancing.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeTags&LoadBalancerNames.member.1=garethrProb4c4e3bed64f4af7909b1&Version=2012-06-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131218Z" - Host: - - elasticloadbalancing.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - f28e20c0f1b2b406fbcbfefdb0b8def2add22310f4b8c1a849eff4f875cdf685 - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/elasticloadbalancing/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=7811a8acea0e862aed76e3343879861972303bad2a41063c857e1991a9992aeb" - Content-Length: - - "97" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - ef253591-b838-11e4-bcb5-3bc0afa91bd3 - Content-Type: - - text/xml - Content-Length: - - "1007" - Date: - - "Thu, 19 Feb 2015 13:12:19 GMT" - body: - encoding: UTF-8 - string: "\n \n \n \n \n \n aws-acceptance\n created_by\n \n \n garethrProb4c4e3bed64f4af7909b1\n Name\n \n \n cloud\n project\n \n \n engineering\n department\n \n \n polo\n marco\n \n \n garethrProb4c4e3bed64f4af7909b1\n \n \n \n \n ef253591-b838-11e4-bcb5-3bc0afa91bd3\n \n\n" - http_version: - recorded_at: "Thu, 19 Feb 2015 13:12:19 GMT" - recorded_with: "VCR 2.9.3" +--- +http_interactions: +- request: + method: post + uri: https://elasticloadbalancing.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeLoadBalancers&Version=2012-06-01 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170112T183706Z + X-Amz-Content-Sha256: + - 236069f72bf74f0c7ddff0a34b0defa8a21d1d6a897e588764e1b2ff6319f94a + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=135abb66f84eaf73903fa7170f2ea7c05e21cbc77d4b7d8caac90d5b0190570b + Content-Length: + - '47' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 1f087142-d8f6-11e6-93b1-21728663efa0 + Content-Type: + - text/xml + Content-Length: + - '2112' + Vary: + - Accept-Encoding + Date: + - Thu, 12 Jan 2017 18:37:07 GMT + body: + encoding: UTF-8 + string: | + + + + + vpc-8f0019ea + Z2P70J7HTTTPLU + internet-facing + + + + + + + + sa-east-1a + + lb-1-836530285.sa-east-1.elb.amazonaws.com + + + 123456789012 + default_elb_623306e1-2dd9-3d43-b10d-da5d3df14af2 + + lb-1 + + + + 80 + TCP + TCP + 80 + + + + + + 2 + 30 + 10 + 5 + TCP:80 + + 2017-01-12T18:36:58.480Z + + subnet-0af6436e + + + sg-0ce2ad68 + + lb-1-836530285.sa-east-1.elb.amazonaws.com + + + + + 1f087142-d8f6-11e6-93b1-21728663efa0 + + + http_version: + recorded_at: Thu, 12 Jan 2017 18:37:07 GMT +- request: + method: post + uri: https://elasticloadbalancing.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeTags&LoadBalancerNames.member.1=lb-1&Version=2012-06-01 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170112T183707Z + X-Amz-Content-Sha256: + - 667b7cad12519b7eb3be43722330c19a8cc170d896753a4bebaab30d44d93801 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=3d9d70ab1b6c8f50df0642ddbb2430288ff1b90fcbbbb255d75f7c762e94ee1e + Content-Length: + - '70' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 1f72f2e6-d8f6-11e6-93b1-21728663efa0 + Content-Type: + - text/xml + Content-Length: + - '523' + Date: + - Thu, 12 Jan 2017 18:37:08 GMT + body: + encoding: UTF-8 + string: | + + + + + lb-1 + + + lb-1 + Name + + + + + + + 1f72f2e6-d8f6-11e6-93b1-21728663efa0 + + + http_version: + recorded_at: Thu, 12 Jan 2017 18:37:08 GMT +- request: + method: post + uri: https://ec2.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeSubnets&SubnetId.1=subnet-0af6436e&Version=2016-11-15 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170112T183708Z + X-Amz-Content-Sha256: + - 2b7e0c9eaa89b98b70b3784bc41b7b21bda0b808db0c80cc18e8000626e0d142 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/ec2/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=0c291922245c8db7c61a0e574c00e35b2a4a16cbade02b7acedb7ff2c4a4419b + Content-Length: + - '68' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - text/xml;charset=UTF-8 + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + Date: + - Thu, 12 Jan 2017 18:37:08 GMT + Server: + - AmazonEC2 + body: + encoding: UTF-8 + string: |- + + + 32de270a-3821-46c0-bb37-a98daac0b384 + + + subnet-0af6436e + available + vpc-8f0019ea + 172.31.0.0/20 + + 4090 + sa-east-1a + true + true + false + + + + http_version: + recorded_at: Thu, 12 Jan 2017 18:37:09 GMT +- request: + method: post + uri: https://ec2.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeSecurityGroups&GroupId.1=sg-0ce2ad68&Version=2016-11-15 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170112T183709Z + X-Amz-Content-Sha256: + - a598e638d441e5df353a1e19707221b07f439cbff6de6518dd3fe84683252b33 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/ec2/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=918879d2bd376649ad6bee7da9fc9672cf5df2a9a361be219ad0ed2873b130e4 + Content-Length: + - '70' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - text/xml;charset=UTF-8 + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + Date: + - Thu, 12 Jan 2017 18:37:09 GMT + Server: + - AmazonEC2 + body: + encoding: UTF-8 + string: |- + + + f9200506-64f3-406f-bfd9-ab684db1a27f + + + 123456789012 + sg-0ce2ad68 + default_elb_623306e1-2dd9-3d43-b10d-da5d3df14af2 + ELB created security group used when no security group is specified during ELB creation - modifications could impact traffic to future ELBs + vpc-8f0019ea + + + tcp + 80 + 80 + + + + 0.0.0.0/0 + + + + + + + + + -1 + + + + 0.0.0.0/0 + + + + + + + + + + http_version: + recorded_at: Thu, 12 Jan 2017 18:37:10 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/elb-setup.yml b/fixtures/vcr_cassettes/elb-setup.yml index 6017cde7..ba8f9600 100644 --- a/fixtures/vcr_cassettes/elb-setup.yml +++ b/fixtures/vcr_cassettes/elb-setup.yml @@ -1,657 +1,617 @@ ---- - http_interactions: - - request: - method: post - uri: "https://elasticloadbalancing.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeLoadBalancers&Version=2012-06-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131106Z" - Host: - - elasticloadbalancing.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - "236069f72bf74f0c7ddff0a34b0defa8a21d1d6a897e588764e1b2ff6319f94a" - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/elasticloadbalancing/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=3ae8399c9b92c0ecfc4ade9baaccb2386c9a741086236acfb259c071b6d5db58" - Content-Length: - - "47" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - c44bd17e-b838-11e4-a4e4-c5c904610edd - Content-Type: - - text/xml - Content-Length: - - "5690" - Vary: - - Accept-Encoding - Date: - - "Thu, 19 Feb 2015 13:11:08 GMT" - body: - encoding: UTF-8 - string: "\n \n \n \n \n 2015-02-19T11:44:43.210Z\n garethrProed3b61536416444c8b742\n \n 30\n TCP:80\n 10\n 5\n 2\n \n \n \n \n \n TCP\n 80\n TCP\n 80\n \n \n \n \n \n i-e06944f5\n \n \n \n \n \n \n \n \n sa-east-1a\n sa-east-1b\n \n Z2ES78Y61JGQKS\n garethrProed3b61536416444c8b742-886078075.sa-east-1.elb.amazonaws.com\n internet-facing\n \n amazon-elb\n amazon-elb-sg\n \n garethrProed3b61536416444c8b742-886078075.sa-east-1.elb.amazonaws.com\n \n \n \n \n \n 2015-02-19T11:47:35.120Z\n garethrPro09dbc77f59cd476a82a44\n \n 30\n TCP:80\n 10\n 5\n 2\n \n \n \n \n \n TCP\n 80\n TCP\n 80\n \n \n \n \n \n i-2c684539\n \n \n \n \n \n \n \n \n sa-east-1a\n sa-east-1b\n \n Z2ES78Y61JGQKS\n garethrPro09dbc77f59cd476a82a44-667909254.sa-east-1.elb.amazonaws.com\n internet-facing\n \n amazon-elb\n amazon-elb-sg\n \n garethrPro09dbc77f59cd476a82a44-667909254.sa-east-1.elb.amazonaws.com\n \n \n \n \n \n 2015-02-19T11:48:11.620Z\n garethrProb4c4e3bed64f4af7909b1\n \n 30\n TCP:80\n 10\n 5\n 2\n \n \n \n \n \n TCP\n 80\n TCP\n 80\n \n \n \n \n \n i-53684546\n \n \n \n \n \n \n \n \n sa-east-1a\n sa-east-1b\n \n Z2ES78Y61JGQKS\n garethrProb4c4e3bed64f4af7909b1-1293617159.sa-east-1.elb.amazonaws.com\n internet-facing\n \n amazon-elb\n amazon-elb-sg\n \n garethrProb4c4e3bed64f4af7909b1-1293617159.sa-east-1.elb.amazonaws.com\n \n \n \n \n \n \n c44bd17e-b838-11e4-a4e4-c5c904610edd\n \n\n" - http_version: - recorded_at: "Thu, 19 Feb 2015 13:11:08 GMT" - - request: - method: post - uri: "https://ec2.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeInstances&InstanceId.1=i-e06944f5&Version=2014-09-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131108Z" - Host: - - ec2.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - "9475874c018c2c03c4a93de1947197037608ff464c6bd1a44e059d5f664f8964" - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/ec2/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=4461206a0e651e13c1504e0c7cbede3b760af496b639dedca547c20a2d8b30fe" - Content-Length: - - "67" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Content-Type: - - "text/xml;charset=UTF-8" - Transfer-Encoding: - - chunked - Vary: - - Accept-Encoding - Date: - - "Thu, 19 Feb 2015 13:11:09 GMT" - Server: - - AmazonEC2 - body: - encoding: UTF-8 - string: |- - - - 5c5da034-5c36-4e64-8eb2-b204ba686665 - - - - http_version: - recorded_at: "Thu, 19 Feb 2015 13:11:10 GMT" - - request: - method: post - uri: "https://elasticloadbalancing.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeTags&LoadBalancerNames.member.1=garethrProed3b61536416444c8b742&Version=2012-06-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131110Z" - Host: - - elasticloadbalancing.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - "4f92033359cb32556b7e192a5e17070c1be1d17d0ce9485b4770551f4781de74" - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/elasticloadbalancing/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=55e3318ccf2075eb512d401adcf3eee28544345c73a0a634ce8a5ef813ba0b33" - Content-Length: - - "97" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - c68ee41d-b838-11e4-ae53-9357167949db - Content-Type: - - text/xml - Content-Length: - - "1007" - Date: - - "Thu, 19 Feb 2015 13:11:11 GMT" - body: - encoding: UTF-8 - string: "\n \n \n \n \n \n aws-acceptance\n created_by\n \n \n garethrProed3b61536416444c8b742\n Name\n \n \n cloud\n project\n \n \n engineering\n department\n \n \n polo\n marco\n \n \n garethrProed3b61536416444c8b742\n \n \n \n \n c68ee41d-b838-11e4-ae53-9357167949db\n \n\n" - http_version: - recorded_at: "Thu, 19 Feb 2015 13:11:11 GMT" - - request: - method: post - uri: "https://ec2.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeInstances&InstanceId.1=i-2c684539&Version=2014-09-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131111Z" - Host: - - ec2.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - "5ef3e4edda454587cdf5a141350023404341b8452538a311a4f929e6dc56707f" - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/ec2/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=2d49b7c8d8c02a724ae0e04fa67c71dcf55ee25e8d0ba7168fa086d9d14e52b6" - Content-Length: - - "67" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Content-Type: - - "text/xml;charset=UTF-8" - Transfer-Encoding: - - chunked - Vary: - - Accept-Encoding - Date: - - "Thu, 19 Feb 2015 13:11:12 GMT" - Server: - - AmazonEC2 - body: - encoding: UTF-8 - string: |- - - - 68e20cb2-4c63-4f1c-89e2-860584f23e34 - - - - http_version: - recorded_at: "Thu, 19 Feb 2015 13:11:13 GMT" - - request: - method: post - uri: "https://elasticloadbalancing.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeTags&LoadBalancerNames.member.1=garethrPro09dbc77f59cd476a82a44&Version=2012-06-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131113Z" - Host: - - elasticloadbalancing.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - b16991e74dd9da116372d8bce1a3c700be58482c772d933f528aa53d0b8e562f - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/elasticloadbalancing/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=e88c961258244063d65dad33ee15938ae448a237b018c36b8760e5fad2e42ffd" - Content-Length: - - "97" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - c8c09122-b838-11e4-8230-09161d0c23f4 - Content-Type: - - text/xml - Content-Length: - - "1007" - Date: - - "Thu, 19 Feb 2015 13:11:15 GMT" - body: - encoding: UTF-8 - string: "\n \n \n \n \n \n aws-acceptance\n created_by\n \n \n garethrPro09dbc77f59cd476a82a44\n Name\n \n \n cloud\n project\n \n \n engineering\n department\n \n \n polo\n marco\n \n \n garethrPro09dbc77f59cd476a82a44\n \n \n \n \n c8c09122-b838-11e4-8230-09161d0c23f4\n \n\n" - http_version: - recorded_at: "Thu, 19 Feb 2015 13:11:15 GMT" - - request: - method: post - uri: "https://ec2.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeInstances&InstanceId.1=i-53684546&Version=2014-09-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131115Z" - Host: - - ec2.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - "7bf65415c8e3eeeede1f1b2cecc497b02fd1ad49fc3242250c1f338d511aea12" - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/ec2/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=ef3d44bf1707b26fad0d4ad4d60cc3807c0537a87b1d11036b4b593c9f843e6f" - Content-Length: - - "67" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Content-Type: - - "text/xml;charset=UTF-8" - Transfer-Encoding: - - chunked - Vary: - - Accept-Encoding - Date: - - "Thu, 19 Feb 2015 13:11:17 GMT" - Server: - - AmazonEC2 - body: - encoding: UTF-8 - string: |- - - - c2941df4-963c-42a4-85e2-f11389ed0bdf - - - - http_version: - recorded_at: "Thu, 19 Feb 2015 13:11:17 GMT" - - request: - method: post - uri: "https://elasticloadbalancing.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeTags&LoadBalancerNames.member.1=garethrProb4c4e3bed64f4af7909b1&Version=2012-06-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131117Z" - Host: - - elasticloadbalancing.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - f28e20c0f1b2b406fbcbfefdb0b8def2add22310f4b8c1a849eff4f875cdf685 - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/elasticloadbalancing/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=c8129f1efdccc72d46fd479220b2dcd9f4d7544fa4a496c550e684a8fb3ea7a3" - Content-Length: - - "97" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - caf376de-b838-11e4-a812-754bf84275e1 - Content-Type: - - text/xml - Content-Length: - - "1007" - Date: - - "Thu, 19 Feb 2015 13:11:19 GMT" - body: - encoding: UTF-8 - string: "\n \n \n \n \n \n aws-acceptance\n created_by\n \n \n garethrProb4c4e3bed64f4af7909b1\n Name\n \n \n cloud\n project\n \n \n engineering\n department\n \n \n polo\n marco\n \n \n garethrProb4c4e3bed64f4af7909b1\n \n \n \n \n caf376de-b838-11e4-a812-754bf84275e1\n \n\n" - http_version: - recorded_at: "Thu, 19 Feb 2015 13:11:19 GMT" - - request: - method: post - uri: "https://elasticloadbalancing.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeLoadBalancers&Version=2012-06-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131119Z" - Host: - - elasticloadbalancing.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - "236069f72bf74f0c7ddff0a34b0defa8a21d1d6a897e588764e1b2ff6319f94a" - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/elasticloadbalancing/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=0b55172df3252537bd69f5d63797fc593655b646ac8035dea131a42b281fc564" - Content-Length: - - "47" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - cbb0371a-b838-11e4-92e4-296787047b29 - Content-Type: - - text/xml - Content-Length: - - "5690" - Vary: - - Accept-Encoding - Date: - - "Thu, 19 Feb 2015 13:11:19 GMT" - body: - encoding: UTF-8 - string: "\n \n \n \n \n garethrProed3b61536416444c8b742\n 2015-02-19T11:44:43.210Z\n \n 30\n TCP:80\n 10\n 5\n 2\n \n \n \n \n \n TCP\n 80\n TCP\n 80\n \n \n \n \n \n i-e06944f5\n \n \n \n \n \n \n \n \n sa-east-1a\n sa-east-1b\n \n Z2ES78Y61JGQKS\n garethrProed3b61536416444c8b742-886078075.sa-east-1.elb.amazonaws.com\n internet-facing\n \n amazon-elb\n amazon-elb-sg\n \n garethrProed3b61536416444c8b742-886078075.sa-east-1.elb.amazonaws.com\n \n \n \n \n \n garethrPro09dbc77f59cd476a82a44\n 2015-02-19T11:47:35.120Z\n \n 30\n TCP:80\n 10\n 5\n 2\n \n \n \n \n \n TCP\n 80\n TCP\n 80\n \n \n \n \n \n i-2c684539\n \n \n \n \n \n \n \n \n sa-east-1a\n sa-east-1b\n \n Z2ES78Y61JGQKS\n garethrPro09dbc77f59cd476a82a44-667909254.sa-east-1.elb.amazonaws.com\n internet-facing\n \n amazon-elb\n amazon-elb-sg\n \n garethrPro09dbc77f59cd476a82a44-667909254.sa-east-1.elb.amazonaws.com\n \n \n \n \n \n garethrProb4c4e3bed64f4af7909b1\n 2015-02-19T11:48:11.620Z\n \n 30\n TCP:80\n 10\n 5\n 2\n \n \n \n \n \n TCP\n 80\n TCP\n 80\n \n \n \n \n \n i-53684546\n \n \n \n \n \n \n \n \n sa-east-1a\n sa-east-1b\n \n Z2ES78Y61JGQKS\n garethrProb4c4e3bed64f4af7909b1-1293617159.sa-east-1.elb.amazonaws.com\n internet-facing\n \n amazon-elb\n amazon-elb-sg\n \n garethrProb4c4e3bed64f4af7909b1-1293617159.sa-east-1.elb.amazonaws.com\n \n \n \n \n \n \n cbb0371a-b838-11e4-92e4-296787047b29\n \n\n" - http_version: - recorded_at: "Thu, 19 Feb 2015 13:11:20 GMT" - - request: - method: post - uri: "https://ec2.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeInstances&InstanceId.1=i-e06944f5&Version=2014-09-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131120Z" - Host: - - ec2.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - "9475874c018c2c03c4a93de1947197037608ff464c6bd1a44e059d5f664f8964" - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/ec2/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=255285b79416329735e0fdc9c5b2c43e5c9d028f740c3cd7e25d34909954bb53" - Content-Length: - - "67" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Content-Type: - - "text/xml;charset=UTF-8" - Transfer-Encoding: - - chunked - Vary: - - Accept-Encoding - Date: - - "Thu, 19 Feb 2015 13:11:22 GMT" - Server: - - AmazonEC2 - body: - encoding: UTF-8 - string: |- - - - ca06a7d6-ea03-4be5-896b-03e5ee63bf6b - - - - http_version: - recorded_at: "Thu, 19 Feb 2015 13:11:22 GMT" - - request: - method: post - uri: "https://elasticloadbalancing.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeTags&LoadBalancerNames.member.1=garethrProed3b61536416444c8b742&Version=2012-06-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131122Z" - Host: - - elasticloadbalancing.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - "4f92033359cb32556b7e192a5e17070c1be1d17d0ce9485b4770551f4781de74" - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/elasticloadbalancing/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=bbc3f7a19361f41ff7a7d4833bb0617946223dfea15466223407d0e5098bb6cb" - Content-Length: - - "97" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - cde147fa-b838-11e4-ae53-9357167949db - Content-Type: - - text/xml - Content-Length: - - "1007" - Date: - - "Thu, 19 Feb 2015 13:11:24 GMT" - body: - encoding: UTF-8 - string: "\n \n \n \n \n \n aws-acceptance\n created_by\n \n \n garethrProed3b61536416444c8b742\n Name\n \n \n cloud\n project\n \n \n engineering\n department\n \n \n polo\n marco\n \n \n garethrProed3b61536416444c8b742\n \n \n \n \n cde147fa-b838-11e4-ae53-9357167949db\n \n\n" - http_version: - recorded_at: "Thu, 19 Feb 2015 13:11:24 GMT" - - request: - method: post - uri: "https://ec2.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeInstances&InstanceId.1=i-2c684539&Version=2014-09-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131124Z" - Host: - - ec2.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - "5ef3e4edda454587cdf5a141350023404341b8452538a311a4f929e6dc56707f" - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/ec2/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=2d4deea3085d1aa6238ff95555488d56fbffce0a80bbc2e94ea819c2afd8100b" - Content-Length: - - "67" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Content-Type: - - "text/xml;charset=UTF-8" - Transfer-Encoding: - - chunked - Vary: - - Accept-Encoding - Date: - - "Thu, 19 Feb 2015 13:11:25 GMT" - Server: - - AmazonEC2 - body: - encoding: UTF-8 - string: |- - - - 8b1d15e1-a7ac-4576-8cab-2de50c7861b1 - - - - http_version: - recorded_at: "Thu, 19 Feb 2015 13:11:26 GMT" - - request: - method: post - uri: "https://elasticloadbalancing.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeTags&LoadBalancerNames.member.1=garethrPro09dbc77f59cd476a82a44&Version=2012-06-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131126Z" - Host: - - elasticloadbalancing.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - b16991e74dd9da116372d8bce1a3c700be58482c772d933f528aa53d0b8e562f - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/elasticloadbalancing/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=f9c070de9f176d36b5e5aaca0420fedc34b20a335f549011150815b583b81fac" - Content-Length: - - "97" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - d023219a-b838-11e4-8230-09161d0c23f4 - Content-Type: - - text/xml - Content-Length: - - "1007" - Date: - - "Thu, 19 Feb 2015 13:11:27 GMT" - body: - encoding: UTF-8 - string: "\n \n \n \n \n \n aws-acceptance\n created_by\n \n \n garethrPro09dbc77f59cd476a82a44\n Name\n \n \n cloud\n project\n \n \n engineering\n department\n \n \n polo\n marco\n \n \n garethrPro09dbc77f59cd476a82a44\n \n \n \n \n d023219a-b838-11e4-8230-09161d0c23f4\n \n\n" - http_version: - recorded_at: "Thu, 19 Feb 2015 13:11:27 GMT" - - request: - method: post - uri: "https://ec2.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeInstances&InstanceId.1=i-53684546&Version=2014-09-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131127Z" - Host: - - ec2.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - "7bf65415c8e3eeeede1f1b2cecc497b02fd1ad49fc3242250c1f338d511aea12" - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/ec2/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=230a3ca370771c0d4f4ef9bcde1d9d8ce8205afdfc84db3008e6b1b68c55b9fa" - Content-Length: - - "67" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Content-Type: - - "text/xml;charset=UTF-8" - Transfer-Encoding: - - chunked - Vary: - - Accept-Encoding - Date: - - "Thu, 19 Feb 2015 13:11:29 GMT" - Server: - - AmazonEC2 - body: - encoding: UTF-8 - string: |- - - - 6d8d05b4-82ad-4c66-8b72-49b0df357945 - - - - http_version: - recorded_at: "Thu, 19 Feb 2015 13:11:29 GMT" - - request: - method: post - uri: "https://elasticloadbalancing.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeTags&LoadBalancerNames.member.1=garethrProb4c4e3bed64f4af7909b1&Version=2012-06-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.5 ruby/2.0.0 universal.x86_64-darwin14" - X-Amz-Date: - - "20150219T131129Z" - Host: - - elasticloadbalancing.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - f28e20c0f1b2b406fbcbfefdb0b8def2add22310f4b8c1a849eff4f875cdf685 - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20150219/sa-east-1/elasticloadbalancing/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=d3ac6afb8eb3c82a9a457d02570dd36e655a2ecfd3f12d51bdc01230fff857f0" - Content-Length: - - "97" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - d2665b3a-b838-11e4-a6c9-51a68f787dc1 - Content-Type: - - text/xml - Content-Length: - - "1007" - Date: - - "Thu, 19 Feb 2015 13:11:30 GMT" - body: - encoding: UTF-8 - string: "\n \n \n \n \n \n aws-acceptance\n created_by\n \n \n garethrProb4c4e3bed64f4af7909b1\n Name\n \n \n cloud\n project\n \n \n engineering\n department\n \n \n polo\n marco\n \n \n garethrProb4c4e3bed64f4af7909b1\n \n \n \n \n d2665b3a-b838-11e4-a6c9-51a68f787dc1\n \n\n" - http_version: - recorded_at: "Thu, 19 Feb 2015 13:11:31 GMT" - recorded_with: "VCR 2.9.3" +--- +http_interactions: +- request: + method: post + uri: https://elasticloadbalancing.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeLoadBalancers&Version=2012-06-01 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170112T182834Z + X-Amz-Content-Sha256: + - 236069f72bf74f0c7ddff0a34b0defa8a21d1d6a897e588764e1b2ff6319f94a + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=cd5375485cacdad502c9ae2366f5ab5d8c24fa7e0ab0d9d82de0b2593023392a + Content-Length: + - '47' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - edeeaa5f-d8f4-11e6-8071-ed1c1bc4d23b + Content-Type: + - text/xml + Content-Length: + - '2114' + Vary: + - Accept-Encoding + Date: + - Thu, 12 Jan 2017 18:28:35 GMT + body: + encoding: UTF-8 + string: | + + + + + vpc-8f0019ea + Z2P70J7HTTTPLU + internet-facing + + + + + + + + sa-east-1a + + lb-1-2069710765.sa-east-1.elb.amazonaws.com + + + 123456789012 + default_elb_623306e1-2dd9-3d43-b10d-da5d3df14af2 + + lb-1 + + + + 80 + TCP + TCP + 80 + + + + + + 2 + 30 + 10 + 5 + TCP:80 + + 2017-01-12T00:45:12.090Z + + subnet-0af6436e + + + sg-0ce2ad68 + + lb-1-2069710765.sa-east-1.elb.amazonaws.com + + + + + edeeaa5f-d8f4-11e6-8071-ed1c1bc4d23b + + + http_version: + recorded_at: Thu, 12 Jan 2017 18:28:35 GMT +- request: + method: post + uri: https://elasticloadbalancing.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeTags&LoadBalancerNames.member.1=lb-1&Version=2012-06-01 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170112T182835Z + X-Amz-Content-Sha256: + - 667b7cad12519b7eb3be43722330c19a8cc170d896753a4bebaab30d44d93801 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=9786866fbbd3905a7610162cc22f4f200243be639288787e29df0cfe0bfb3371 + Content-Length: + - '70' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - ee5de6f5-d8f4-11e6-8071-ed1c1bc4d23b + Content-Type: + - text/xml + Content-Length: + - '523' + Date: + - Thu, 12 Jan 2017 18:28:36 GMT + body: + encoding: UTF-8 + string: | + + + + + lb-1 + + + lb-1 + Name + + + + + + + ee5de6f5-d8f4-11e6-8071-ed1c1bc4d23b + + + http_version: + recorded_at: Thu, 12 Jan 2017 18:28:36 GMT +- request: + method: post + uri: https://ec2.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeSubnets&SubnetId.1=subnet-0af6436e&Version=2016-11-15 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170112T182836Z + X-Amz-Content-Sha256: + - 2b7e0c9eaa89b98b70b3784bc41b7b21bda0b808db0c80cc18e8000626e0d142 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/ec2/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=597b70d356d258276a5e9d5214f77e81ab2376d51892b0fdc7930fea168a7a6c + Content-Length: + - '68' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - text/xml;charset=UTF-8 + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + Date: + - Thu, 12 Jan 2017 18:28:36 GMT + Server: + - AmazonEC2 + body: + encoding: UTF-8 + string: |- + + + d0781251-01c0-4784-8d9b-6dfb90e57402 + + + subnet-0af6436e + available + vpc-8f0019ea + 172.31.0.0/20 + + 4090 + sa-east-1a + true + true + false + + + + http_version: + recorded_at: Thu, 12 Jan 2017 18:28:37 GMT +- request: + method: post + uri: https://ec2.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeSecurityGroups&GroupId.1=sg-0ce2ad68&Version=2016-11-15 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170112T182837Z + X-Amz-Content-Sha256: + - a598e638d441e5df353a1e19707221b07f439cbff6de6518dd3fe84683252b33 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/ec2/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=9d89aca07377efc85e5636a8c947e91483ae5f2a9f3da3eb10b3d002331ca60f + Content-Length: + - '70' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - text/xml;charset=UTF-8 + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + Date: + - Thu, 12 Jan 2017 18:28:37 GMT + Server: + - AmazonEC2 + body: + encoding: UTF-8 + string: |- + + + 89d25a6e-5625-41b6-9729-a78f88744467 + + + 123456789012 + sg-0ce2ad68 + default_elb_623306e1-2dd9-3d43-b10d-da5d3df14af2 + ELB created security group used when no security group is specified during ELB creation - modifications could impact traffic to future ELBs + vpc-8f0019ea + + + tcp + 80 + 80 + + + + 0.0.0.0/0 + + + + + + + + + -1 + + + + 0.0.0.0/0 + + + + + + + + + + http_version: + recorded_at: Thu, 12 Jan 2017 18:28:38 GMT +- request: + method: post + uri: https://elasticloadbalancing.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeLoadBalancers&Version=2012-06-01 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170112T182838Z + X-Amz-Content-Sha256: + - 236069f72bf74f0c7ddff0a34b0defa8a21d1d6a897e588764e1b2ff6319f94a + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=f8aac95716d9586cb19f5bfe7aab83598987f08947d0a347768111cedcaea0c9 + Content-Length: + - '47' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - f03b0bb0-d8f4-11e6-9df5-d35ef90998c0 + Content-Type: + - text/xml + Content-Length: + - '2114' + Vary: + - Accept-Encoding + Date: + - Thu, 12 Jan 2017 18:28:39 GMT + body: + encoding: UTF-8 + string: | + + + + + vpc-8f0019ea + Z2P70J7HTTTPLU + internet-facing + + + + + + + + sa-east-1a + + lb-1-2069710765.sa-east-1.elb.amazonaws.com + + + 123456789012 + default_elb_623306e1-2dd9-3d43-b10d-da5d3df14af2 + + lb-1 + + + + 80 + TCP + TCP + 80 + + + + + + 2 + 30 + 10 + 5 + TCP:80 + + 2017-01-12T00:45:12.090Z + + subnet-0af6436e + + + sg-0ce2ad68 + + lb-1-2069710765.sa-east-1.elb.amazonaws.com + + + + + f03b0bb0-d8f4-11e6-9df5-d35ef90998c0 + + + http_version: + recorded_at: Thu, 12 Jan 2017 18:28:39 GMT +- request: + method: post + uri: https://elasticloadbalancing.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeTags&LoadBalancerNames.member.1=lb-1&Version=2012-06-01 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170112T182839Z + X-Amz-Content-Sha256: + - 667b7cad12519b7eb3be43722330c19a8cc170d896753a4bebaab30d44d93801 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=4a48edc7288574b4793a3175ba76a08a588af17e5cbccb788ad0787b73fad839 + Content-Length: + - '70' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - f0bb5f0e-d8f4-11e6-8cdc-6d7bc5c85bf0 + Content-Type: + - text/xml + Content-Length: + - '523' + Date: + - Thu, 12 Jan 2017 18:28:40 GMT + body: + encoding: UTF-8 + string: | + + + + + lb-1 + + + lb-1 + Name + + + + + + + f0bb5f0e-d8f4-11e6-8cdc-6d7bc5c85bf0 + + + http_version: + recorded_at: Thu, 12 Jan 2017 18:28:40 GMT +- request: + method: post + uri: https://ec2.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeSubnets&SubnetId.1=subnet-0af6436e&Version=2016-11-15 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170112T182840Z + X-Amz-Content-Sha256: + - 2b7e0c9eaa89b98b70b3784bc41b7b21bda0b808db0c80cc18e8000626e0d142 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/ec2/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=d221089d6ad7c06807358e27045e141c0b32e7444fe3ffbcd512483d13964a78 + Content-Length: + - '68' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - text/xml;charset=UTF-8 + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + Date: + - Thu, 12 Jan 2017 18:28:40 GMT + Server: + - AmazonEC2 + body: + encoding: UTF-8 + string: |- + + + 3db10a9c-dd9d-4b58-bf49-e73e0a09aa62 + + + subnet-0af6436e + available + vpc-8f0019ea + 172.31.0.0/20 + + 4090 + sa-east-1a + true + true + false + + + + http_version: + recorded_at: Thu, 12 Jan 2017 18:28:41 GMT +- request: + method: post + uri: https://ec2.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeSecurityGroups&GroupId.1=sg-0ce2ad68&Version=2016-11-15 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170112T182841Z + X-Amz-Content-Sha256: + - a598e638d441e5df353a1e19707221b07f439cbff6de6518dd3fe84683252b33 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/ec2/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=1be7530995221ea6fd714c2dd45f1316deb002d0f907d139e4a2711ba1bb9423 + Content-Length: + - '70' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - text/xml;charset=UTF-8 + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + Date: + - Thu, 12 Jan 2017 18:28:41 GMT + Server: + - AmazonEC2 + body: + encoding: UTF-8 + string: |- + + + 2ae96884-f1d5-4953-afbd-cce1ae29d9f1 + + + 123456789012 + sg-0ce2ad68 + default_elb_623306e1-2dd9-3d43-b10d-da5d3df14af2 + ELB created security group used when no security group is specified during ELB creation - modifications could impact traffic to future ELBs + vpc-8f0019ea + + + tcp + 80 + 80 + + + + 0.0.0.0/0 + + + + + + + + + -1 + + + + 0.0.0.0/0 + + + + + + + + + + http_version: + recorded_at: Thu, 12 Jan 2017 18:28:42 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/iam_group-setup.yml b/fixtures/vcr_cassettes/iam_group-setup.yml new file mode 100644 index 00000000..c3a88b0c --- /dev/null +++ b/fixtures/vcr_cassettes/iam_group-setup.yml @@ -0,0 +1,385 @@ +--- +http_interactions: +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=ListGroups&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172007Z + X-Amz-Content-Sha256: + - 5f776d91509b9c99b8cb5eb5d6d4a787a33ae41c8cd6e7b69effca69080e1e1f + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=d4329173997e2d0aee1dc70df5e5a310ac480d7a4b97981df28d64e1deb56105 + Content-Length: + - '36' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 334d4b83-d822-11e6-ab10-214f93a0c1e1 + Content-Type: + - text/xml + Content-Length: + - '807' + Date: + - Wed, 11 Jan 2017 17:20:08 GMT + body: + encoding: UTF-8 + string: | + + + false + + + / + notops + arn:aws:iam::123456789012:group/notops + AGPAJBN5CML7FQ5J7JD26 + 2016-08-23T19:23:16Z + + + / + ops + arn:aws:iam::123456789012:group/ops + AGPAIQCI4K2HPEBNN6QQM + 2016-06-16T18:23:08Z + + + + + 334d4b83-d822-11e6-ab10-214f93a0c1e1 + + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:08 GMT +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=GetGroup&GroupName=notops&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172008Z + X-Amz-Content-Sha256: + - cf68c015f2417aea8bd48137c559a758527a2a67deb4dbe8ba6210da16b707be + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=2466706c76044a9db064ac819072378137859b1e4f8514c3dde669a9422dfc09 + Content-Length: + - '51' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 3399bdad-d822-11e6-bd77-5d62273fd38b + Content-Type: + - text/xml + Content-Length: + - '522' + Date: + - Wed, 11 Jan 2017 17:20:08 GMT + body: + encoding: UTF-8 + string: | + + + false + + + / + notops + arn:aws:iam::123456789012:group/notops + AGPAJBN5CML7FQ5J7JD26 + 2016-08-23T19:23:16Z + + + + 3399bdad-d822-11e6-bd77-5d62273fd38b + + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:08 GMT +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=GetGroup&GroupName=ops&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172008Z + X-Amz-Content-Sha256: + - db0f03bb6c536b0da1477fdd4e528f491b1c6ed8ca6ca34908ecf34329b9e685 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=0e64fa2ac31d780e5b16356698079f0a02a5fe69c3568581ccfda2db8c537b14 + Content-Length: + - '48' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 33dba8df-d822-11e6-8b9d-ff7b08faab19 + Content-Type: + - text/xml + Content-Length: + - '846' + Date: + - Wed, 11 Jan 2017 17:20:08 GMT + body: + encoding: UTF-8 + string: | + + + false + + + / + 2017-01-11T16:16:54Z + ishearin + arn:aws:iam::123456789012:user/ishearin + AIDAJD5YADU67WPGYXKYK + 2016-06-16T20:28:41Z + + + + / + ops + arn:aws:iam::123456789012:group/ops + AGPAIQCI4K2HPEBNN6QQM + 2016-06-16T18:23:08Z + + + + 33dba8df-d822-11e6-8b9d-ff7b08faab19 + + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:09 GMT +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=ListGroups&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172009Z + X-Amz-Content-Sha256: + - 5f776d91509b9c99b8cb5eb5d6d4a787a33ae41c8cd6e7b69effca69080e1e1f + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=8eeb9f4d1171c4ddb3728af4fd3e835f419e734b4b250c48f54ff8b8813c64f1 + Content-Length: + - '36' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 341bbf93-d822-11e6-ab10-214f93a0c1e1 + Content-Type: + - text/xml + Content-Length: + - '807' + Date: + - Wed, 11 Jan 2017 17:20:09 GMT + body: + encoding: UTF-8 + string: | + + + false + + + / + notops + arn:aws:iam::123456789012:group/notops + AGPAJBN5CML7FQ5J7JD26 + 2016-08-23T19:23:16Z + + + / + ops + arn:aws:iam::123456789012:group/ops + AGPAIQCI4K2HPEBNN6QQM + 2016-06-16T18:23:08Z + + + + + 341bbf93-d822-11e6-ab10-214f93a0c1e1 + + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:09 GMT +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=GetGroup&GroupName=notops&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172009Z + X-Amz-Content-Sha256: + - cf68c015f2417aea8bd48137c559a758527a2a67deb4dbe8ba6210da16b707be + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=a1659d294b493cd39e24acfc1d3f42dddaf1a9562db5484d663fdc85b153bde2 + Content-Length: + - '51' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 345b60ab-d822-11e6-940d-b79303d6a8dd + Content-Type: + - text/xml + Content-Length: + - '522' + Date: + - Wed, 11 Jan 2017 17:20:09 GMT + body: + encoding: UTF-8 + string: | + + + false + + + / + notops + arn:aws:iam::123456789012:group/notops + AGPAJBN5CML7FQ5J7JD26 + 2016-08-23T19:23:16Z + + + + 345b60ab-d822-11e6-940d-b79303d6a8dd + + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:10 GMT +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=GetGroup&GroupName=ops&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172010Z + X-Amz-Content-Sha256: + - db0f03bb6c536b0da1477fdd4e528f491b1c6ed8ca6ca34908ecf34329b9e685 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=791e4fa0cf54d56361e8ed043eb07524844d7a5958ae8b4d772370becbd74a78 + Content-Length: + - '48' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 3498debc-d822-11e6-ab10-214f93a0c1e1 + Content-Type: + - text/xml + Content-Length: + - '846' + Date: + - Wed, 11 Jan 2017 17:20:10 GMT + body: + encoding: UTF-8 + string: | + + + false + + + / + 2017-01-11T16:16:54Z + ishearin + arn:aws:iam::123456789012:user/ishearin + AIDAJD5YADU67WPGYXKYK + 2016-06-16T20:28:41Z + + + + / + ops + arn:aws:iam::123456789012:group/ops + AGPAIQCI4K2HPEBNN6QQM + 2016-06-16T18:23:08Z + + + + 3498debc-d822-11e6-ab10-214f93a0c1e1 + + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:10 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/iam_user-setup.yml b/fixtures/vcr_cassettes/iam_user-setup.yml new file mode 100644 index 00000000..3cfcead0 --- /dev/null +++ b/fixtures/vcr_cassettes/iam_user-setup.yml @@ -0,0 +1,153 @@ +--- +http_interactions: +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=ListUsers&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172013Z + X-Amz-Content-Sha256: + - b6359072c78d70ebee1e81adcbab4f01bf2c23245fa365ef83fe8f1f955085e2 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=51d6c9682d53349f0b9160ab22e611a6a5545ef3e6689f792efecab5bc305aea + Content-Length: + - '35' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 3667aa8d-d822-11e6-940d-b79303d6a8dd + Content-Type: + - text/xml + Content-Length: + - '1187' + Date: + - Wed, 11 Jan 2017 17:20:13 GMT + body: + encoding: UTF-8 + string: | + + + false + + + / + 2017-01-11T16:16:54Z + ishearin + arn:aws:iam::123456789012:user/ishearin + AIDAJD5YADU67WPGYXKYK + 2016-06-16T20:28:41Z + + + / + 2017-01-10T19:07:58Z + zleslie + arn:aws:iam::123456789012:user/zleslie + AIDAJEOSIABK4O2G5JGRQ + 2016-05-20T20:58:02Z + + + / + zleslie2 + arn:aws:iam::123456789012:user/zleslie2 + AIDAJXLSYDKUU7Q6G7F5S + 2016-06-16T20:28:40Z + + + + + 3667aa8d-d822-11e6-940d-b79303d6a8dd + + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:13 GMT +- request: + method: post + uri: https://iam.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=ListUsers&Version=2010-05-08 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170111T172013Z + X-Amz-Content-Sha256: + - b6359072c78d70ebee1e81adcbab4f01bf2c23245fa365ef83fe8f1f955085e2 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170111/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=51d6c9682d53349f0b9160ab22e611a6a5545ef3e6689f792efecab5bc305aea + Content-Length: + - '35' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 370cc43b-d822-11e6-ab10-214f93a0c1e1 + Content-Type: + - text/xml + Content-Length: + - '1187' + Date: + - Wed, 11 Jan 2017 17:20:14 GMT + body: + encoding: UTF-8 + string: | + + + false + + + / + 2017-01-11T16:16:54Z + ishearin + arn:aws:iam::123456789012:user/ishearin + AIDAJD5YADU67WPGYXKYK + 2016-06-16T20:28:41Z + + + / + 2017-01-10T19:07:58Z + zleslie + arn:aws:iam::123456789012:user/zleslie + AIDAJEOSIABK4O2G5JGRQ + 2016-05-20T20:58:02Z + + + / + zleslie2 + arn:aws:iam::123456789012:user/zleslie2 + AIDAJXLSYDKUU7Q6G7F5S + 2016-06-16T20:28:40Z + + + + + 370cc43b-d822-11e6-ab10-214f93a0c1e1 + + + http_version: + recorded_at: Wed, 11 Jan 2017 17:20:14 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/instance-profiles-named.yml b/fixtures/vcr_cassettes/instance-profiles-named.yml index 36c4a194..188713e6 100644 --- a/fixtures/vcr_cassettes/instance-profiles-named.yml +++ b/fixtures/vcr_cassettes/instance-profiles-named.yml @@ -12,14 +12,14 @@ http_interactions: Accept-Encoding: - '' User-Agent: - - aws-sdk-ruby2/2.3.3 ruby/2.1.7 x86_64-darwin14.0 + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 X-Amz-Date: - - 20160802T182439Z + - 20170119T190811Z X-Amz-Content-Sha256: - 44d83e3a0f5f6915cab0b95802111050b054a3353097341089af8a6c2ee48399 Authorization: - - AWS4-HMAC-SHA256 Credential=redacted/20160802/us-east-1/iam/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=222a01c263b05370d9bac5ddcd7ef1b5072e241be12b2726f5ca3e970ee2b5d1 + - AWS4-HMAC-SHA256 Credential=111111111111/20170119/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=7d207e4ede3bc52749f7e597c9dac19b459956db2898af2ae2e7e04b26b5a6ca Content-Length: - '46' Accept: @@ -30,13 +30,13 @@ http_interactions: message: OK headers: X-Amzn-Requestid: - - 5fe92ecc-58de-11e6-945e-5dbedde336ba + - 9ef56f49-de7a-11e6-b536-978c45088619 Content-Type: - text/xml Content-Length: - - '1253' + - '1306' Date: - - Tue, 02 Aug 2016 18:24:38 GMT + - Thu, 19 Jan 2017 19:08:11 GMT body: encoding: UTF-8 string: | @@ -46,27 +46,27 @@ http_interactions: / + ecsInstanceRole / - %7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D - AROAJTVOOGRMNHXZHEQKU - devtest - arn:aws:iam::111111111111:role/devtest - 2016-07-28T20:22:30Z + %7B%22Version%22%3A%222008-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D + AROAJTEW6IGCXX4HNR5T2 + ecsInstanceRole + arn:aws:iam::123456789012:role/ecsInstanceRole + 2017-01-11T21:32:55Z - devtest - arn:aws:iam::111111111111:instance-profile/devtest - AIPAIQX3NLS3B64FZNPAU - 2016-07-28T20:22:31Z + arn:aws:iam::123456789012:instance-profile/ecsInstanceRole + AIPAJFXZIVRDCVKHVT75G + 2017-01-11T21:32:55Z - 5fe92ecc-58de-11e6-945e-5dbedde336ba + 9ef56f49-de7a-11e6-b536-978c45088619 http_version: - recorded_at: Tue, 02 Aug 2016 18:24:39 GMT + recorded_at: Thu, 19 Jan 2017 19:08:11 GMT recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/no-elb-named-test.yml b/fixtures/vcr_cassettes/no-elb-named-test.yml index ae4ee6bd..32466017 100644 --- a/fixtures/vcr_cassettes/no-elb-named-test.yml +++ b/fixtures/vcr_cassettes/no-elb-named-test.yml @@ -1,48 +1,53 @@ ---- - http_interactions: - - request: - method: post - uri: "https://elasticloadbalancing.sa-east-1.amazonaws.com/" - body: - encoding: UTF-8 - string: "Action=DescribeLoadBalancers&Version=2012-06-01" - headers: - Content-Type: - - "application/x-www-form-urlencoded; charset=utf-8" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.1 ruby/2.1.1 x86_64-darwin13.0" - X-Amz-Date: - - "20141003T115030Z" - Host: - - elasticloadbalancing.sa-east-1.amazonaws.com - X-Amz-Content-Sha256: - - "236069f72bf74f0c7ddff0a34b0defa8a21d1d6a897e588764e1b2ff6319f94a" - Authorization: - - "AWS4-HMAC-SHA256 Credential=redacted/20141003/sa-east-1/elasticloadbalancing/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, Signature=redacted" - Content-Length: - - "47" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - "7a3e9ee3-4af3-11e4-b00c-49c743b99f71" - Content-Type: - - text/xml - Content-Length: - - "2110" - Vary: - - Accept-Encoding - Date: - - "Fri, 03 Oct 2014 11:50:30 GMT" - body: - encoding: UTF-8 - string: "\n \n \n \n \n 2014-10-01T12:06:59.550Z\n lb-1\n \n 30\n TCP:80\n 10\n 5\n 2\n \n \n \n \n \n TCP\n 80\n TCP\n 80\n \n \n \n \n \n i-3171f124\n \n \n i-1774f402\n \n \n \n \n \n \n \n \n sa-east-1a\n \n lb-1-1058535709.sa-east-1.elb.amazonaws.com\n Z2ES78Y61JGQKS\n internet-facing\n \n amazon-elb\n amazon-elb-sg\n \n lb-1-1058535709.sa-east-1.elb.amazonaws.com\n \n \n \n \n \n \n 7a3e9ee3-4af3-11e4-b00c-49c743b99f71\n \n\n" - http_version: - recorded_at: "Fri, 03 Oct 2014 11:50:31 GMT" - recorded_with: "VCR 2.9.3" +--- +http_interactions: +- request: + method: post + uri: https://elasticloadbalancing.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeLoadBalancers&Version=2012-06-01 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170112T183144Z + X-Amz-Content-Sha256: + - 236069f72bf74f0c7ddff0a34b0defa8a21d1d6a897e588764e1b2ff6319f94a + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=ba8de4cff157950664bcdd16a7b3d6fd3773d62111be884bbae93160cd94a6a9 + Content-Length: + - '47' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 5f2d73df-d8f5-11e6-8071-ed1c1bc4d23b + Content-Type: + - text/xml + Content-Length: + - '335' + Date: + - Thu, 12 Jan 2017 18:31:45 GMT + body: + encoding: UTF-8 + string: | + + + + + + 5f2d73df-d8f5-11e6-8071-ed1c1bc4d23b + + + http_version: + recorded_at: Thu, 12 Jan 2017 18:31:45 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/roles-named.yml b/fixtures/vcr_cassettes/roles-named.yml index 55825a78..d4e50e94 100644 --- a/fixtures/vcr_cassettes/roles-named.yml +++ b/fixtures/vcr_cassettes/roles-named.yml @@ -12,15 +12,14 @@ http_interactions: Accept-Encoding: - '' User-Agent: - - aws-sdk-ruby2/2.3.3 ruby/2.1.7 x86_64-darwin14.0 + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 X-Amz-Date: - - 20160728T202344Z + - 20170119T190839Z X-Amz-Content-Sha256: - 8e689dc6b69b17003f0460011582254d8643f0dfb48ac46e093a24df58170b3f Authorization: - - AWS4-HMAC-SHA256 Credential=redacted/20160728/us-east-1/iam/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, - Signature=bfaf846ce12189c1b0a1346f056397b72de78058195dfe675220da75fcfa7a3b + - AWS4-HMAC-SHA256 Credential=111111111111/20170119/us-east-1/iam/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=0afedc231de941617eaf5821424f8e451b1c8613c6395235b2920f9af3b91a3b Content-Length: - '35' Accept: @@ -31,13 +30,13 @@ http_interactions: message: OK headers: X-Amzn-Requestid: - - 2e8f4ba7-5501-11e6-945e-5dbedde336ba + - aff0f7ec-de7a-11e6-8fa1-13f0566b0f73 Content-Type: - text/xml Content-Length: - - '816' + - '853' Date: - - Thu, 28 Jul 2016 20:23:44 GMT + - Thu, 19 Jan 2017 19:08:39 GMT body: encoding: UTF-8 string: | @@ -47,18 +46,18 @@ http_interactions: / - %7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D - AROAJTVOOGRMNHXZHEQKU - devtest - arn:aws:iam::111111111111:role/devtest - 2016-07-28T20:22:30Z + %7B%22Version%22%3A%222008-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D + AROAJTEW6IGCXX4HNR5T2 + ecsInstanceRole + arn:aws:iam::123456789012:role/ecsInstanceRole + 2017-01-11T21:32:55Z - 2e8f4ba7-5501-11e6-945e-5dbedde336ba + aff0f7ec-de7a-11e6-8fa1-13f0566b0f73 http_version: - recorded_at: Thu, 28 Jul 2016 20:23:44 GMT + recorded_at: Thu, 19 Jan 2017 19:08:40 GMT recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/s3-bucket.yml b/fixtures/vcr_cassettes/s3-bucket.yml index a05d9cd4..80d85c8c 100644 --- a/fixtures/vcr_cassettes/s3-bucket.yml +++ b/fixtures/vcr_cassettes/s3-bucket.yml @@ -2,7 +2,7 @@ http_interactions: - request: method: get - uri: https://s3-us-west-2.amazonaws.com/ + uri: https://s3-sa-east-1.amazonaws.com/ body: encoding: ASCII-8BIT string: '' @@ -12,14 +12,14 @@ http_interactions: Accept-Encoding: - '' User-Agent: - - aws-sdk-ruby2/2.3.22 ruby/2.2.5 x86_64-darwin15 + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 X-Amz-Date: - - 20161003T175451Z + - 20170112T185742Z X-Amz-Content-Sha256: - e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 Authorization: - - AWS4-HMAC-SHA256 Credential=redacterd/20161003/us-west-2/s3/aws4_request, - SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=5223213dc365212e97be9ec8187a610d4afd536ac4918a32534bf288992f8111 + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/s3/aws4_request, + SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=3dc0788593a1cb7a8e9a4f78afc7cce7f726398b528e69a14ec4a440be56b737 Content-Length: - '0' Accept: @@ -30,11 +30,11 @@ http_interactions: message: OK headers: X-Amz-Id-2: - - kzxyZKE1VVrl283VFWefo/1mEMfjb+PPuGXmcqhHKLmA6MFczM+XHtSl+shdPz9cNyQ0PdBZ77M= + - tFb0nwYvFnKIb5mFvYfK5ljGv3qNxYzXNrCNFS9Q9zSAJjWPzEonZE7I0FcMnL8YfWIVRl6vn9Y= X-Amz-Request-Id: - - 7710E7151EB59B92 + - 7685AA828436692F Date: - - Mon, 03 Oct 2016 17:54:52 GMT + - Thu, 12 Jan 2017 18:57:43 GMT Content-Type: - application/xml Transfer-Encoding: @@ -45,12 +45,12 @@ http_interactions: encoding: UTF-8 string: |- - 577c9c2d571b1e27f12e417c5835e62c7e8c062a9290027c399719177d9631f4zlesliezlesliebucketnamegoeshere2016-10-03T17:54:33.000Z + 577c9c2d571b1e27f12e417c5835e62c7e8c062a9290027c399719177d9631f4zlesliewomply-ishearin2017-01-03T20:39:18.000Z http_version: - recorded_at: Mon, 03 Oct 2016 17:54:51 GMT + recorded_at: Thu, 12 Jan 2017 18:57:43 GMT - request: method: get - uri: https://zlesliebucketnamegoeshere.s3-us-west-2.amazonaws.com/?policy + uri: https://womply-ishearin.s3-sa-east-1.amazonaws.com/?policy body: encoding: ASCII-8BIT string: '' @@ -60,45 +60,47 @@ http_interactions: Accept-Encoding: - '' User-Agent: - - aws-sdk-ruby2/2.3.22 ruby/2.2.5 x86_64-darwin15 + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 X-Amz-Date: - - 20161003T175451Z + - 20170112T185743Z X-Amz-Content-Sha256: - e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 Authorization: - - AWS4-HMAC-SHA256 Credential=redacterd/20161003/us-west-2/s3/aws4_request, - SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=9319d9bbd8074a772afb85528acf89fc694644f4bbba63d5db8e16c7931de3ed + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/s3/aws4_request, + SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=2e2f30a6c4a3746659fbfb8bec549e1658870f7627e8a82c1ded7d39b3c4d626 Content-Length: - '0' Accept: - "*/*" response: status: - code: 404 - message: Not Found + code: 301 + message: Moved Permanently headers: + X-Amz-Bucket-Region: + - us-west-2 X-Amz-Request-Id: - - 2890EB2EB669B1D8 + - E940B1E21A5CF4CA X-Amz-Id-2: - - zlw94CgEcb1B7iGAW7qIuWOZML4IEv0zANmOMxAOOs+BILfx1je1R2HR2Tx/ykT+Kk/Q6RG8RpY= + - y86zCjWdZxjEKGGX7KH15shnli4pZmN+QDlhQdj7ESYQTKFXlN2dR6gCF7agiKtY0BGpfzLxnpM= Content-Type: - application/xml Transfer-Encoding: - chunked Date: - - Mon, 03 Oct 2016 17:54:51 GMT + - Thu, 12 Jan 2017 18:57:43 GMT Server: - AmazonS3 body: encoding: UTF-8 string: |- - NoSuchBucketPolicyThe bucket policy does not existzlesliebucketnamegoeshere2890EB2EB669B1D8zlw94CgEcb1B7iGAW7qIuWOZML4IEv0zANmOMxAOOs+BILfx1je1R2HR2Tx/ykT+Kk/Q6RG8RpY= + PermanentRedirectThe bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.womply-ishearinwomply-ishearin.s3-us-west-2.amazonaws.comE940B1E21A5CF4CAy86zCjWdZxjEKGGX7KH15shnli4pZmN+QDlhQdj7ESYQTKFXlN2dR6gCF7agiKtY0BGpfzLxnpM= http_version: - recorded_at: Mon, 03 Oct 2016 17:54:52 GMT + recorded_at: Thu, 12 Jan 2017 18:57:44 GMT - request: method: get - uri: https://s3-us-west-2.amazonaws.com/ + uri: https://s3-sa-east-1.amazonaws.com/ body: encoding: ASCII-8BIT string: '' @@ -108,14 +110,14 @@ http_interactions: Accept-Encoding: - '' User-Agent: - - aws-sdk-ruby2/2.3.22 ruby/2.2.5 x86_64-darwin15 + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 X-Amz-Date: - - 20161003T175452Z + - 20170112T185744Z X-Amz-Content-Sha256: - e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 Authorization: - - AWS4-HMAC-SHA256 Credential=redacterd/20161003/us-west-2/s3/aws4_request, - SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=8b75f520648d7eb0b1470ba41c9476e2e136ac60c89ca702f1dbd0ee494e4924 + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/s3/aws4_request, + SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=529441c552678e88eb62ae3f721de09f7de8c05368d67e0117a6a7fde4e771e4 Content-Length: - '0' Accept: @@ -126,11 +128,11 @@ http_interactions: message: OK headers: X-Amz-Id-2: - - Jrp4qujYZ9obm4WXVT3OANYpLBzMzgCW3PCUS/09JamyQ44RqXdxFEahkIB7w6YUdIk3BICH7cE= + - IOS5I1VM76Ao6duX1+/LfjIOS616ywkmSd40U7Bdpig8C+mnbB2GeYpgcNBhsJoLxAWdmhg89Mc= X-Amz-Request-Id: - - 2A7CA4B018ABA890 + - 3FE52B8192093C82 Date: - - Mon, 03 Oct 2016 17:54:53 GMT + - Thu, 12 Jan 2017 18:57:46 GMT Content-Type: - application/xml Transfer-Encoding: @@ -141,12 +143,12 @@ http_interactions: encoding: UTF-8 string: |- - 577c9c2d571b1e27f12e417c5835e62c7e8c062a9290027c399719177d9631f4zlesliezlesliebucketnamegoeshere2016-10-03T17:54:33.000Z + 577c9c2d571b1e27f12e417c5835e62c7e8c062a9290027c399719177d9631f4zlesliewomply-ishearin2017-01-03T20:39:18.000Z http_version: - recorded_at: Mon, 03 Oct 2016 17:54:52 GMT + recorded_at: Thu, 12 Jan 2017 18:57:45 GMT - request: method: get - uri: https://zlesliebucketnamegoeshere.s3-us-west-2.amazonaws.com/?policy + uri: https://womply-ishearin.s3-sa-east-1.amazonaws.com/?policy body: encoding: ASCII-8BIT string: '' @@ -156,40 +158,42 @@ http_interactions: Accept-Encoding: - '' User-Agent: - - aws-sdk-ruby2/2.3.22 ruby/2.2.5 x86_64-darwin15 + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 X-Amz-Date: - - 20161003T175452Z + - 20170112T185745Z X-Amz-Content-Sha256: - e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 Authorization: - - AWS4-HMAC-SHA256 Credential=redacterd/20161003/us-west-2/s3/aws4_request, - SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=8ae8f90ceda8b5dc4afd1f17b6962ff223c674a8c99779b4f3711254098a5be5 + - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/s3/aws4_request, + SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=cd887d3c964356b3a88740f0fb21002858a0bc36341eeb8d2f0149ddee1c1db3 Content-Length: - '0' Accept: - "*/*" response: status: - code: 404 - message: Not Found + code: 301 + message: Moved Permanently headers: + X-Amz-Bucket-Region: + - us-west-2 X-Amz-Request-Id: - - A9DF0A30C0E89FEB + - 047794514329C006 X-Amz-Id-2: - - k1IYDVZkceHv4Kp7+aDS3EwhshQm3gjS7tjLk0pSR6sL5CoOoCaaLfPivzGyP9Y5o5RbeC1iEqQ= + - swY/n/s1/KxkprrdyNnJpMV/SmBS4sAVlR2I8ZGdd+bVz74aO3ybW2ueYQBYoBxU4kdiXAt3qGA= Content-Type: - application/xml Transfer-Encoding: - chunked Date: - - Mon, 03 Oct 2016 17:54:51 GMT + - Thu, 12 Jan 2017 18:57:45 GMT Server: - AmazonS3 body: encoding: UTF-8 string: |- - NoSuchBucketPolicyThe bucket policy does not existzlesliebucketnamegoeshereA9DF0A30C0E89FEBk1IYDVZkceHv4Kp7+aDS3EwhshQm3gjS7tjLk0pSR6sL5CoOoCaaLfPivzGyP9Y5o5RbeC1iEqQ= + PermanentRedirectThe bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.womply-ishearinwomply-ishearin.s3-us-west-2.amazonaws.com047794514329C006swY/n/s1/KxkprrdyNnJpMV/SmBS4sAVlR2I8ZGdd+bVz74aO3ybW2ueYQBYoBxU4kdiXAt3qGA= http_version: - recorded_at: Mon, 03 Oct 2016 17:54:52 GMT + recorded_at: Thu, 12 Jan 2017 18:57:46 GMT recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/users-named.yml b/fixtures/vcr_cassettes/users-named.yml deleted file mode 100644 index 6cdd936a..00000000 --- a/fixtures/vcr_cassettes/users-named.yml +++ /dev/null @@ -1,64 +0,0 @@ ---- -http_interactions: -- request: - method: post - uri: https://iam.amazonaws.com/ - body: - encoding: UTF-8 - string: Action=ListUsers&Version=2010-05-08 - headers: - Content-Type: - - application/x-www-form-urlencoded; charset=utf-8 - Accept-Encoding: - - '' - User-Agent: - - aws-sdk-ruby2/2.0.5 ruby/2.2.3 x86_64-darwin15 - X-Amz-Date: - - 20160523T191020Z - X-Amz-Content-Sha256: - - b6359072c78d70ebee1e81adcbab4f01bf2c23245fa365ef83fe8f1f955085e2 - Authorization: - - AWS4-HMAC-SHA256 Credential=redacterd/20160523/us-east-1/iam/aws4_request, - SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date, - Signature=582d4b396d43288e53c781afd197361dfcce49e42bb9b91e23aa68f72c838a43 - Content-Length: - - '35' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - fe41e8f3-2119-11e6-aa8d-9b4f3d48f980 - Content-Type: - - text/xml - Content-Length: - - '617' - Date: - - Mon, 23 May 2016 19:10:20 GMT - body: - encoding: UTF-8 - string: | - - - false - - - / - 2016-05-20T20:59:26Z - zleslie - arn:aws:iam::111111111111:user/zleslie - AAAAAAAAAAAAAAAAAAAAA - 2016-05-20T20:58:02Z - - - - - fe41e8f3-2119-11e6-aa8d-9b4f3d48f980 - - - http_version: - recorded_at: Mon, 23 May 2016 19:10:20 GMT -recorded_with: VCR 3.0.1 diff --git a/lib/puppet/provider/ecs_service/v2.rb b/lib/puppet/provider/ecs_service/v2.rb index 500e4773..c146217d 100644 --- a/lib/puppet/provider/ecs_service/v2.rb +++ b/lib/puppet/provider/ecs_service/v2.rb @@ -160,8 +160,8 @@ def destroy Puppet.debug("Destroying ecs_service #{@property_hash[:name]}") ecs_client.delete_service({ - service: @property_hash[:name], - cluster: @property_hash[:cluster] + service: resource[:name], + cluster: resource[:cluster] }) @property_hash[:ensure] = :absent end diff --git a/lib/puppet/provider/ecs_task_definition/v2.rb b/lib/puppet/provider/ecs_task_definition/v2.rb index 60fb8e35..2eff2f68 100644 --- a/lib/puppet/provider/ecs_task_definition/v2.rb +++ b/lib/puppet/provider/ecs_task_definition/v2.rb @@ -34,8 +34,7 @@ def self.instances volumes: task.volumes, container_definitions: container_defs, }) - end - results.flatten.select {|i| i } + end.compact end def self.prefetch(resources) diff --git a/lib/puppet/provider/elb_loadbalancer/v2.rb b/lib/puppet/provider/elb_loadbalancer/v2.rb index 1c79d280..f639fdf0 100644 --- a/lib/puppet/provider/elb_loadbalancer/v2.rb +++ b/lib/puppet/provider/elb_loadbalancer/v2.rb @@ -483,15 +483,15 @@ def create tags: tags_for_resource, ) - @property_hash[:ensure] = :present - @property_hash[:availability_zones] = zones - @property_hash[:subnets] = subnets - instances = resource[:instances] if ! instances.nil? instances = [instances] unless instances.is_a?(Array) self.class.add_instances_to_load_balancer(resource[:region], name, instances) end + + @property_hash[:ensure] = :present + @property_hash[:availability_zones] = zones + @property_hash[:subnets] = subnets end def self.add_instances_to_load_balancer(region, load_balancer_name, instance_names) diff --git a/lib/puppet/provider/iam_group/v2.rb b/lib/puppet/provider/iam_group/v2.rb index b083c5dc..11e7363c 100644 --- a/lib/puppet/provider/iam_group/v2.rb +++ b/lib/puppet/provider/iam_group/v2.rb @@ -68,13 +68,15 @@ def destroy } # Delete all the members from the group - @property_hash[:members].each {|member| - Puppet.debug("Removing user #{member} from IAM group #{group.group_name}") - iam_client.remove_user_from_group({ - group_name: group.group_name, - user_name: member - }) - } + if @property_hash[:members] + @property_hash[:members].each {|member| + Puppet.debug("Removing user #{member} from IAM group #{group.group_name}") + iam_client.remove_user_from_group({ + group_name: group.group_name, + user_name: member + }) + } + end Puppet.info("Deleting IAM group #{group}") iam_client.delete_group({group_name: group.group_name}) diff --git a/spec/unit/provider/ecs_service/v2_spec.rb b/spec/unit/provider/ecs_service/v2_spec.rb index 217d9561..0bee5332 100644 --- a/spec/unit/provider/ecs_service/v2_spec.rb +++ b/spec/unit/provider/ecs_service/v2_spec.rb @@ -2,27 +2,41 @@ provider_class = Puppet::Type.type(:ecs_service).provider(:v2) + describe provider_class do let(:resource) { Puppet::Type.type(:ecs_service).new( - name: 'myshinyservice', - cluster: 'mycluster', + name: 'testservice', + cluster: 'test', + task_definition: 'testtask', + desired_count: 0, ) } let(:provider) { resource.provider } - VCR.use_cassette('ecs-service-setup') do - let(:instance) { provider.class.instances.first } + let(:instance) { provider.class.instances.first } + + before do + # ECS is not supported in the spec_helper default region + ENV['AWS_REGION'] = 'us-west-2' end it 'should be an instance of the ProviderV2' do expect(provider).to be_an_instance_of Puppet::Type::Ecs_service::ProviderV2 end + describe 'create' do + it 'should make the call to create the service' do + VCR.use_cassette('create-ecs_service') do + expect(provider.create).to be_truthy + end + end + end + describe 'self.prefetch' do it 'should exist' do - VCR.use_cassette('ecs-service-setup') do + VCR.use_cassette('ecs_service-setup') do provider.class.instances provider.class.prefetch({}) expect(instance.exists?).to be_truthy @@ -30,6 +44,13 @@ end end -end + describe 'destroy' do + it 'should make the call to create the service' do + VCR.use_cassette('destroy-ecs_service') do + expect(provider.destroy).to be_truthy + end + end + end +end diff --git a/spec/unit/provider/ecs_task_definition/v2_spec.rb b/spec/unit/provider/ecs_task_definition/v2_spec.rb index cec9ee6e..baacf15c 100644 --- a/spec/unit/provider/ecs_task_definition/v2_spec.rb +++ b/spec/unit/provider/ecs_task_definition/v2_spec.rb @@ -5,42 +5,83 @@ describe provider_class do + let(:resource_hash) { + { + name: 'testtask', + container_definitions: [ + {'cpu' => '1024', 'environment' => {'one' => 'one', 'two' => '2'}, 'essential' => 'true', 'image' => 'debian:jessie17', 'memory' => '512', 'name' => 'zleslietesting', 'port_mappings' => [{'container_port' => '8081', 'host_port' => '8082', 'protocol' => 'tcp'}]}, + {'cpu' => '1024', 'environment' => {'one' => 'one', 'two' => '2'}, 'essential' => 'true', 'image' => 'debian:jessie17', 'memory' => '512', 'name' => 'zleslietesting2', 'port_mappings' => [{'container_port' => '8082', 'host_port' => '8083', 'protocol' => 'tcp'}]}, + ] + } + } + let(:resource) { - Puppet::Type.type(:ecs_task_definition).new( - name: 'omgolly123', - container_definitions: [] - ) + Puppet::Type.type(:ecs_task_definition).new(resource_hash) } - let(:provider) { resource.provider } - VCR.use_cassette('ecs-setup') do - let(:instance) { provider.class.instances.first } + before do + # ECS is not supported in the spec_helper default region + ENV['AWS_REGION'] = 'us-west-2' end + let(:provider) { resource.provider } + let(:instance) { + provider.class.instances.select {|i| + i.name == 'testtask' + }[0] + } + it 'should be an instance of the ProviderV2' do expect(provider).to be_an_instance_of Puppet::Type::Ecs_task_definition::ProviderV2 end describe 'self.prefetch' do - it 'should exist' do - VCR.use_cassette('ecs-setup') do + it 'exists' do + VCR.use_cassette('ecs_task_definition-setup') do provider.class.instances provider.class.prefetch({}) - expect(instance.exists?).to be_truthy + end + end + end + + describe 'exists?' do + it 'should correctly report non-existent task definitions' do + VCR.use_cassette('ecs_task_definition-setup') do + expect(provider.exists?).to be_falsy + end + end + end + + describe 'create' do + it 'shold make the call to create the task definition' do + VCR.use_cassette('create-ecs_task_definition') do + expect(provider.create).to be_truthy + expect(provider.exists?).to be_truthy + end + end + end + + describe 'destroy' do + it 'shold make the call to create the task definition' do + VCR.use_cassette('destroy-ecs_task_definition') do + data = provider.class.prefetch({"lb-1" => resource}) + prov = data.select {|m| m.name == 'testtask' }[0] + expect(prov.destroy).to be_truthy + expect(prov.exists?).to be_falsy end end end describe 'container_definitions' do it 'should retrieve the container_definition' do - VCR.use_cassette('ecs-setup') do - instance = provider.class.instances.first - expect(instance.container_definitions.size).to eq(2) - expect(instance.name).to eq('netflix-ice') - container1 = instance.container_definitions[1] + VCR.use_cassette('ecs_task_definition-setup') do + data = provider.class.prefetch({"lb-1" => resource}) + prov = data.select {|m| m.name == 'testtask' }[0] + expect(prov.name).to eq('testtask') + container1 = prov.container_definitions[1] expect(container1['memory']).to eq(512) - expect(container1['image']).to eq('debian:jessie') - expect(container1['environment']['one']).to eq('1') + expect(container1['image']).to eq('debian:jessie17') + expect(container1['environment']['one']).to eq('one') expect(container1['environment']['two']).to eq('2') end end @@ -48,7 +89,7 @@ describe 'container_definitions=' do it 'should set the container_definition' do - VCR.use_cassette('ecs-setup') do + VCR.use_cassette('ecs_task_definition-setup') do instance = provider.class.instances.first container_defs = [ @@ -65,7 +106,7 @@ describe 'rectify_container_delta' do it 'should return zero results when containers match' do - VCR.use_cassette('ecs-setup') do + VCR.use_cassette('ecs_task_definition-setup') do container_defs = [ { 'cpu' => 1, @@ -96,7 +137,7 @@ end it 'should use discovered values in palce of missing values' do - VCR.use_cassette('ecs-setup') do + VCR.use_cassette('ecs_task_definition-setup') do hsh = [ { diff --git a/spec/unit/provider/elb_loadbalancer/v2_spec.rb b/spec/unit/provider/elb_loadbalancer/v2_spec.rb index eaabf057..01af67fd 100644 --- a/spec/unit/provider/elb_loadbalancer/v2_spec.rb +++ b/spec/unit/provider/elb_loadbalancer/v2_spec.rb @@ -6,18 +6,28 @@ describe provider_class do context 'with the minimum params' do - let(:resource) { - Puppet::Type.type(:elb_loadbalancer).new( + let(:resource_hash) { + { name: 'lb-1', instances: ['web-1'], - listeners: [], + listeners: [ + { + 'instance_port' => '80', + 'instance_protocol' => 'TCP', + 'load_balancer_port' => '80', + 'protocol' => 'TCP' + } + ], availability_zones: ['sa-east-1a'], region: 'sa-east-1', - ) + } } - let(:provider) { resource.provider } + let(:resource) { + Puppet::Type.type(:elb_loadbalancer).new(resource_hash) + } + let(:provider) { resource.provider } let(:instance) { provider.class.instances.first } it 'should be an instance of the ProviderV2' do @@ -36,13 +46,15 @@ describe 'exists?' do it 'should correctly report non-existent load balancers' do VCR.use_cassette('no-elb-named-test') do + provider.class.prefetch({"lb-1" => resource}) expect(provider.exists?).to be_falsy end end it 'should correctly find existing load balancers' do VCR.use_cassette('elb-named-test') do - expect(instance.exists?).to be_truthy + data = provider.class.prefetch({"lb-1" => resource}) + expect(data[0].exists?).to be_truthy end end end diff --git a/spec/unit/provider/iam_group/v2_spec.rb b/spec/unit/provider/iam_group/v2_spec.rb new file mode 100644 index 00000000..3ddded85 --- /dev/null +++ b/spec/unit/provider/iam_group/v2_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' + +provider_class = Puppet::Type.type(:iam_group).provider(:v2) + + +describe provider_class do + + context 'with the minimum params' do + let(:resource) { + Puppet::Type.type(:iam_group).new( + name: 'tgroup', + members: [], + ) + } + + let(:provider) { resource.provider } + + let(:instance) { provider.class.instances.first } + + it 'should be an instance of the ProviderV2' do + expect(provider).to be_an_instance_of Puppet::Type::Iam_group::ProviderV2 + end + + describe 'self.prefetch' do + it 'exists' do + VCR.use_cassette('iam_group-setup') do + provider.class.instances + provider.class.prefetch({}) + end + end + end + + describe 'exists?' do + it 'should correctly report non-existent users' do + VCR.use_cassette('exists-iam_group') do + expect(provider.exists?).to be_falsy + end + end + end + + describe 'create' do + it 'should make the call to create the user' do + VCR.use_cassette('create-iam_group') do + expect(provider.create).to be_truthy + end + end + end + + describe 'destroy' do + it 'should make the call to destroy the user' do + VCR.use_cassette('destroy-iam_group') do + expect(provider.destroy).to be_truthy + end + end + end + + end +end + diff --git a/spec/unit/provider/iam_instance_profile/v2_spec.rb b/spec/unit/provider/iam_instance_profile/v2_spec.rb index 1f7d51a6..369be2bb 100644 --- a/spec/unit/provider/iam_instance_profile/v2_spec.rb +++ b/spec/unit/provider/iam_instance_profile/v2_spec.rb @@ -4,12 +4,6 @@ describe provider_class do - before do - ENV['AWS_ACCESS_KEY_ID'] = 'redacted' - ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' - ENV['AWS_REGION'] = 'sa-east-1' - end - context 'with the minimum params' do let(:resource) { Puppet::Type.type(:iam_instance_profile).new( diff --git a/spec/unit/provider/iam_role/v2_spec.rb b/spec/unit/provider/iam_role/v2_spec.rb index 3d0c93b1..3432c30a 100644 --- a/spec/unit/provider/iam_role/v2_spec.rb +++ b/spec/unit/provider/iam_role/v2_spec.rb @@ -4,12 +4,6 @@ describe provider_class do - before do - ENV['AWS_ACCESS_KEY_ID'] = 'redacted' - ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' - ENV['AWS_REGION'] = 'sa-east-1' - end - context 'with the minimum params' do let(:resource) { Puppet::Type.type(:iam_role).new( diff --git a/spec/unit/provider/iam_user/v2_spec.rb b/spec/unit/provider/iam_user/v2_spec.rb index 8adc4ca4..65ba4dab 100644 --- a/spec/unit/provider/iam_user/v2_spec.rb +++ b/spec/unit/provider/iam_user/v2_spec.rb @@ -8,7 +8,7 @@ context 'with the minimum params' do let(:resource) { Puppet::Type.type(:iam_user).new( - name: 'zleslie2', + name: 'tuser', ) } @@ -22,7 +22,7 @@ describe 'self.prefetch' do it 'exists' do - VCR.use_cassette('create-user') do + VCR.use_cassette('iam_user-setup') do provider.class.instances provider.class.prefetch({}) end @@ -31,14 +31,24 @@ describe 'exists?' do it 'should correctly report non-existent users' do - VCR.use_cassette('no-user-named') do + VCR.use_cassette('exists-iam_user') do expect(provider.exists?).to be_falsy end end + end + + describe 'create' do + it 'should make the call to create the user' do + VCR.use_cassette('create-iam_user') do + expect(provider.create).to be_truthy + end + end + end - it 'should correctly find existing users' do - VCR.use_cassette('users-named') do - expect(instance.exists?).to be_truthy + describe 'destroy' do + it 'should make the call to destroy the user' do + VCR.use_cassette('destroy-iam_user') do + expect(provider.destroy).to be_truthy end end end diff --git a/spec/unit/type/iam_instance_profile_spec.rb b/spec/unit/type/iam_instance_profile_spec.rb index 86beb95d..05ae4582 100644 --- a/spec/unit/type/iam_instance_profile_spec.rb +++ b/spec/unit/type/iam_instance_profile_spec.rb @@ -4,12 +4,6 @@ describe type_class do - before do - ENV['AWS_ACCESS_KEY_ID'] = 'redacted' - ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' - ENV['AWS_REGION'] = 'sa-east-1' - end - let :params do [ :name, diff --git a/spec/unit/type/iam_role_spec.rb b/spec/unit/type/iam_role_spec.rb index a60ada64..19579ac2 100644 --- a/spec/unit/type/iam_role_spec.rb +++ b/spec/unit/type/iam_role_spec.rb @@ -4,12 +4,6 @@ describe type_class do - before do - ENV['AWS_ACCESS_KEY_ID'] = 'redacted' - ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' - ENV['AWS_REGION'] = 'sa-east-1' - end - let :params do [ :name, From 33372a23b57d485a1fd4e1dedc5d555a7502b300 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Thu, 2 Feb 2017 10:57:33 -0800 Subject: [PATCH 46/72] Drop semantic require reference Without this change, the Rakefile references a path in Puppet that has changed in the recently released 4.9. This doesn't appear to be required any longer. --- Rakefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Rakefile b/Rakefile index d6e576df..39a8209c 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,4 @@ require 'puppetlabs_spec_helper/rake_tasks' -require 'puppet/vendor/semantic/lib/semantic' begin require 'puppet_blacksmith/rake_tasks' From 10a2b4525c57acd20b0b4df641bf436e365cb83d Mon Sep 17 00:00:00 2001 From: Dave Seff Date: Wed, 19 Oct 2016 16:25:21 +1000 Subject: [PATCH 47/72] Tags support for rds --- README.md | 3 +++ lib/puppet/provider/rds_instance/v2.rb | 22 +++++++++++++++++++++- lib/puppet/type/rds_instance.rb | 4 ++++ lib/puppet_x/puppetlabs/aws.rb | 14 ++++++++++++++ spec/acceptance/rds_spec.rb | 9 +++++++++ 5 files changed, 51 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 285e6ac9..ce4df3b7 100644 --- a/README.md +++ b/README.md @@ -1396,6 +1396,9 @@ that skip_final_snapshot must be set to false. #####`backup_retention_period` The number of days to retain backups. Defaults to 30 days. +#####`tags` +*Optional* The tags for the instance. Accepts a 'key => value' hash of tags. + #### Type: route53 The route53 types set up various types of Route53 records: diff --git a/lib/puppet/provider/rds_instance/v2.rb b/lib/puppet/provider/rds_instance/v2.rb index 9fedec32..3f735d22 100644 --- a/lib/puppet/provider/rds_instance/v2.rb +++ b/lib/puppet/provider/rds_instance/v2.rb @@ -2,8 +2,10 @@ Puppet::Type.type(:rds_instance).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do confine feature: :aws + confine feature: :retries mk_resource_methods + remove_method :rds_tags= def initialize(value={}) super(value) @@ -40,6 +42,14 @@ def self.prefetch(resources) def self.db_instance_to_hash(region, instance) db_subnet = instance.db_subnet_group ? instance.db_subnet_group.db_subnet_group_name : nil + + # tags stuff requires aws sdk >= 2.6.11 + rds_tags = {} + db_tags = rds_client(region).list_tags_for_resource( resource_name: instance.db_instance_arn ) + db_tags.tag_list.each do |rds_tag| + rds_tags[rds_tag.key] = rds_tag.value unless rds_tag.key == 'Name' + end + config = { ensure: :present, name: instance.db_instance_identifier, @@ -54,12 +64,14 @@ def self.db_instance_to_hash(region, instance) license_model: instance.license_model, multi_az: instance.multi_az, iops: instance.iops, + rds_tags: rds_tags, db_subnet: db_subnet, db_parameter_group: instance.db_parameter_groups.collect(&:db_parameter_group_name).first, db_security_groups: instance.db_security_groups.collect(&:db_security_group_name), vpc_security_groups: instance.vpc_security_groups.collect(&:vpc_security_group_id), backup_retention_period: instance.backup_retention_period, - availability_zone: instance.availability_zone + availability_zone: instance.availability_zone, + arn: instance.db_instance_arn } if instance.respond_to?('endpoint') && !instance.endpoint.nil? config[:endpoint] = instance.endpoint.address @@ -122,6 +134,14 @@ def create Puppet.info("Starting DB instance #{name}") rds_client(resource[:region]).create_db_instance(config) end + + with_retries(:max_tries => 5) do + rds_client(region).add_tags_to_resource( + resources: response.data.db_instance.db_instance_arn, + tags: tags_for_resource + ) + end + @property_hash[:ensure] = :present end diff --git a/lib/puppet/type/rds_instance.rb b/lib/puppet/type/rds_instance.rb index 6c65e196..65426858 100644 --- a/lib/puppet/type/rds_instance.rb +++ b/lib/puppet/type/rds_instance.rb @@ -1,4 +1,5 @@ require_relative '../../puppet_x/puppetlabs/property/region.rb' +require_relative '../../puppet_x/puppetlabs/property/tag.rb' Puppet::Type.newtype(:rds_instance) do @doc = 'Type representing an RDS instance.' @@ -223,4 +224,7 @@ def insync?(is) groups.is_a?(Array) ? groups : [groups] end + newproperty(:rds_tags, :parent => PuppetX::Property::AwsTag) do + desc 'The tags for the db instance.' + end end diff --git a/lib/puppet_x/puppetlabs/aws.rb b/lib/puppet_x/puppetlabs/aws.rb index dbbd13e5..fdb67f97 100644 --- a/lib/puppet_x/puppetlabs/aws.rb +++ b/lib/puppet_x/puppetlabs/aws.rb @@ -274,6 +274,20 @@ def tags=(value) ) unless missing_tags.empty? end + def rds_tags=(value) + Puppet.info("Updating RDS tags for #{name} in region #{target_region}") + rds = rds_client(target_region) + rds.add_tags_to_resource( + resource_name: @property_hash[:arn], + tags: value.collect { |k,v| { :key => k, :value => v } } + ) unless value.empty? + missing_tags = rds_tags.keys - value.keys + rds.remove_tags_from_resource( + resource_name: @property_hash[:arn], + tag_keys: missing_tags.collect { |k| { :key => k } } + ) unless missing_tags.empty? + end + def self.has_name?(hash) !hash[:name].nil? && !hash[:name].empty? end diff --git a/spec/acceptance/rds_spec.rb b/spec/acceptance/rds_spec.rb index 7e0804ee..a6b8b306 100644 --- a/spec/acceptance/rds_spec.rb +++ b/spec/acceptance/rds_spec.rb @@ -34,6 +34,11 @@ def get_rds_instance(name) :multi_az => false, :skip_final_snapshot => true, :backup_retention_period => 5, + :rds_tags => { + :department => 'engineering', + :project => 'cloud', + :created_by => 'aws-acceptance' + }, } @result = PuppetManifest.new(@template, @config).apply @@ -58,6 +63,10 @@ def get_rds_instance(name) expect(@rds_instance.db_instance_identifier).to eq(@config[:name]) end + it "with the specified tags" do + expect(@aws.tag_difference(@rds_instance, @config[:rds_tags])).to be_empty + end + it 'with the specified db_name' do expect(@rds_instance.db_name).to eq(@config[:db_name]) end From 9ad6ad33a536e5b6b9953b1a5dcc8348180862ec Mon Sep 17 00:00:00 2001 From: Sean Vaughan Date: Mon, 6 Feb 2017 14:15:34 -0800 Subject: [PATCH 48/72] Add support for CloudFormation. --- README.md | 106 ++++++++ .../cloudformation-01-create.pp | 6 + .../cloudformation-02-update.pp | 71 ++++++ .../cloudformation-03-destroy.pp | 6 + .../provider/cloudformation_stack/v2.rb | 195 +++++++++++++++ lib/puppet/type/cloudformation_stack.rb | 232 ++++++++++++++++++ lib/puppet_x/puppetlabs/aws.rb | 8 + 7 files changed, 624 insertions(+) create mode 100644 examples/basic-cloudformation-example/cloudformation-01-create.pp create mode 100644 examples/basic-cloudformation-example/cloudformation-02-update.pp create mode 100644 examples/basic-cloudformation-example/cloudformation-03-destroy.pp create mode 100644 lib/puppet/provider/cloudformation_stack/v2.rb create mode 100644 lib/puppet/type/cloudformation_stack.rb diff --git a/README.md b/README.md index ce4df3b7..ab5209ec 100644 --- a/README.md +++ b/README.md @@ -311,6 +311,7 @@ You can use the aws module to audit AWS resources, launch autoscaling groups in ### Types +* `cloudformation_stack`: Create, update, or destroy a CloudFormation Stack. * `cloudfront_distribution`: Sets up a CloudFront distribution. * `ec2_instance`: Sets up an EC2 instance. * `ec2_securitygroup`: Sets up an EC2 security group. @@ -356,6 +357,111 @@ You can use the aws module to audit AWS resources, launch autoscaling groups in ###Parameters +#### Type: cloudformation_stack + +##### `capabilities` +*Optional* The list of stack capabilities, including CAPABILITY_IAM, +CAPABILITY_NAMED_IAM, an empty list, or unspecified. + +##### `change_set_id` +*Readonly* Unique identifier of the stack. + +##### `creation_time` +*Readonly* The time at which the stack was created. + +##### `description` +*Readonly* A user-defined description found in the cloudformation template associated with the stack. + +##### `disable_rollback` +*Optional* Whether to disable rollback on stack creation failures. +Valid values are `true`, `false`. + +##### `ensure` +*Required* The ensure value for the stack. + +"present" will create the stack but not apply updates. + +"updated" will create or apply any updates to the stack. + +"absent" will delete the stack. + +Valid values are `present`, `updated`, `absent`. + +##### `id` +*Readonly* The unique ID of the stack. + +##### `last_updated_time` +*Readonly* The time the stack was last updated. + +##### `name` +*Required* The name of the stack. + +##### `notification_arns` +*Optional* List of SNS topic ARNs to which stack related events are published. + +##### `on_failure` +*Optional* Determines what action will be taken if stack creation fails. This must +be one of: "DO_NOTHING", "ROLLBACK", or "DELETE". You can specify either +on_failure or disable_rollback, but not both. +Valid values are `DO_NOTHING`, `ROLLBACK`, `DELETE`. + +##### `outputs` +*Readonly* A hash of stack outputs. + +##### `parameters` +*Optional* A hash of input parameters. + +##### `policy_body` +*Optional* Structure containing the stack policy body. For more information, go to +Prevent Updates to Stack Resources in the AWS CloudFormation User Guide. +You can specify either the policy_body or the policy_url parameter, but +not both. + +##### `policy_url` +*Optional* Location of a file containing the stack policy. The URL must point to a +policy (maximum size: 16 KB) located in an S3 bucket in the same region +as the stack. You can specify either the policy_body or the policy_url +parameter, but not both. + +##### `region` +*Required* The region in which to launch the stack. + +##### `resource_types` +*Optional* The list of resource types that you have permissions to work with for +this stack. + +##### `role_arn` +*Optional* The Amazon Resource Name (ARN) of an AWS Identity and Access Management +(IAM) role that is associated with the stack. + +##### `status` +*Readonly* The status of the stack. +Valid values are `CREATE_IN_PROGRESS`, `CREATE_FAILED`, +`CREATE_COMPLETE`, `ROLLBACK_IN_PROGRESS`, `ROLLBACK_FAILED`, +`ROLLBACK_COMPLETE`, `DELETE_IN_PROGRESS`, `DELETE_FAILED`, +`DELETE_COMPLETE`, `UPDATE_IN_PROGRESS`, +`UPDATE_COMPLETE_CLEANUP_IN_PROGRESS`, `UPDATE_COMPLETE`, +`UPDATE_ROLLBACK_IN_PROGRESS`, `UPDATE_ROLLBACK_FAILED`, +`UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS`, +`UPDATE_ROLLBACK_COMPLETE`, `REVIEW_IN_PROGRESS`. + +##### `tags` +*Optional* The tags for the instance. + +##### `template_body` +*Optional* Structure containing the template body with a minimum length of 1 byte +and a maximum length of 51,200 bytes. For more information, go to +Template Anatomy in the AWS CloudFormation User Guide. + +##### `template_url` +*Optional* Location of file containing the template body. The URL must point to a +template (max size: 460,800 bytes) that is located in an Amazon S3 +bucket. For more information, go to the Template Anatomy in the AWS +CloudFormation User Guide. + +##### `timeout_in_minutes` +*Optional* The amount of time within which stack creation should complete. + #### Type: cloudfront_distribution ##### `ensure` diff --git a/examples/basic-cloudformation-example/cloudformation-01-create.pp b/examples/basic-cloudformation-example/cloudformation-01-create.pp new file mode 100644 index 00000000..e31b46ec --- /dev/null +++ b/examples/basic-cloudformation-example/cloudformation-01-create.pp @@ -0,0 +1,6 @@ + +cloudformation_stack { 's3-bucket-test': + ensure => updated, + region => 'us-west-2', + template_url => 'https://s3-us-west-2.amazonaws.com/cloudformation-templates-us-west-2/S3_Website_Bucket_With_Retain_On_Delete.template', +} diff --git a/examples/basic-cloudformation-example/cloudformation-02-update.pp b/examples/basic-cloudformation-example/cloudformation-02-update.pp new file mode 100644 index 00000000..3e176f32 --- /dev/null +++ b/examples/basic-cloudformation-example/cloudformation-02-update.pp @@ -0,0 +1,71 @@ + +# Added some tags, +# added a WalrusLabel Parameter for BucketName, +# changed IndexDocument and ErrorDocument from *.html to *.htm, +# and DeletionPolicy to Delete. + +cloudformation_stack { 's3-bucket-test': + ensure => updated, + region => 'us-west-2', + tags => { + 'product' => 'S3', + 'environment' => 'test', + }, + parameters => { 'WalrusLabel' => "puppet-cloudformation-stack-bucket-name-walrus" }, + template_body => ' +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "AWS CloudFormation Sample Template S3_Website_Bucket_With_Delete_On_Delete: Sample template showing how to create a publicly accessible S3 bucket configured for website access with a deletion policy of retail on delete. **WARNING** This template creates an S3 bucket that will NOT be deleted when the stack is deleted. You will be billed for the AWS resources used if you create a stack from this template.", + "Parameters": { + "WalrusLabel": { + "Type": "String", + "Description": "The S3 Bucket name.", + "AllowedPattern": "(?!-)[a-zA-Z0-9-.]{1,63}(? absent, + region => 'us-west-2', +} + diff --git a/lib/puppet/provider/cloudformation_stack/v2.rb b/lib/puppet/provider/cloudformation_stack/v2.rb new file mode 100644 index 00000000..3c348081 --- /dev/null +++ b/lib/puppet/provider/cloudformation_stack/v2.rb @@ -0,0 +1,195 @@ +require_relative '../../../puppet_x/puppetlabs/aws.rb' +require 'base64' + +Puppet::Type.type(:cloudformation_stack).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do + confine feature: :aws + confine feature: :retries + + mk_resource_methods + remove_method :tags= + + def initialize(value={}) + super(value) + @property_flush = {} + end + + def self.instances + regions.collect do |region| + begin + stacks = [] + + cloudformation_client(region).describe_stacks().each do |response| + response.data.stacks.each do |stack| + hash = stack_to_hash(region, stack) + stacks << new(hash) if has_name?(hash) + end + end + stacks + rescue Timeout::Error, StandardError => e + raise PuppetX::Puppetlabs::FetchingAWSDataError.new(region, self.resource_type.name.to_s, e.message) + end + end.flatten + end + + read_only(:change_set_id, :change_set_id, :creation_time, :description, + :id, :last_update_time, :outputs, :region, :status ) + + def self.prefetch(resources) + instances.each do |prov| + if resource = resources[prov.name] # rubocop:disable Lint/AssignmentInCondition + resource.provider = prov if resource[:region] == prov.region + end + end + end + + def self.enable_from_status(status) + case status + when 'CREATE_FAILED', 'ROLLBACK_IN_PROGRESS', 'ROLLBACK_COMPLETE', + 'DELETE_IN_PROGRESS', 'DELETE_COMPLETE' + :absent + when 'CREATE_IN_PROGRESS', 'CREATE_COMPLETE', 'ROLLBACK_FAILED', + 'DELETE_FAILED' + :present + when 'UPDATE_COMPLETE', 'UPDATE_ROLLBACK_FAILED', + 'UPDATE_ROLLBACK_COMPLETE', 'UPDATE_IN_PROGRESS', + 'UPDATE_COMPLETE_CLEANUP_IN_PROGRESS', 'UPDATE_ROLLBACK_IN_PROGRESS', + 'UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS', 'REVIEW_IN_PROGRESS' + :updated + end + end + + def self.stack_to_hash(region, stack) + name = stack.stack_name + return {} unless name + tags = {} + stack.tags.each do |tag| + tags[tag.key] = tag.value + end + + parameters = {} + stack.parameters.each do |parameter| + parameters[parameter.parameter_key] = parameter.parameter_value + end + + outputs = {} + stack.outputs.each do |output| + outputs[output.output_key] = output.output_value + end + + puppet_ensure = enable_from_status(stack.stack_status) + + config = { + capabilities: stack.capabilities, + change_set_id: stack.change_set_id, + creation_time: stack.creation_time, + description: stack.description, + disable_rollback: stack.disable_rollback, + ensure: puppet_ensure, + id: stack.stack_id, + last_updated_time: stack.last_updated_time, + name: name, + notification_arns: stack.notification_arns, + outputs: outputs, + parameters: parameters, + region: region, + role_arn: stack.role_arn, + status: stack.stack_status.to_sym, + tags: tags, + timeout_in_minutes: stack.timeout_in_minutes, + } + + config + end + + def exists? + Puppet.debug("Checking if stack #{name} exists in region #{target_region}") + return false if @property_hash[:status] == nil + enable = Puppet::Type::Cloudformation_stack::ProviderV2::enable_from_status(@property_hash[:status].to_s) + return [:present,:updated].include? enable + end + + def get_config + parameters = [] + resource[:parameters].each_key { |key| + parameters.push( { + parameter_key: key, + parameter_value: resource[:parameters][key], + use_previous_value: false, + } + ) + } unless resource[:parameters] == nil + + tags = [] + resource[:tags].each_key { |key| + tags.push( { + key: key, + value: resource[:tags][key], + } + ) + } unless resource[:tags] == nil + + { + stack_name: resource[:name], # required + template_body: resource[:template_body], + template_url: resource[:template_url], + parameters: parameters, + disable_rollback: resource[:disable_rollback], + timeout_in_minutes: resource[:timeout_in_minutes], + notification_arns: resource[:notification_arns], + capabilities: resource[:capabilities], # accepts CAPABILITY_IAM, CAPABILITY_NAMED_IAM + resource_types: resource[:resource_types], + role_arn: resource[:role_arn], + on_failure: resource[:on_failure], # accepts DO_NOTHING, ROLLBACK, DELETE + stack_policy_body: resource[:policy_body], + stack_policy_url: resource[:policy_url], + tags: tags, + } + end + + def create + Puppet.info("Starting stack #{name} in region #{resource[:region]}") + + cloudformation = cloudformation_client(resource[:region]) + + config = get_config + response = cloudformation.create_stack(config) + + @property_hash[:ensure] = :present + end + + def update + cloudformation = cloudformation_client(resource[:region]) + config = get_config + + # disable_rollback, on_failure, and timeout_in_minutes only apply during + # stack creation. + config.delete(:disable_rollback) + config.delete(:on_failure) + config.delete(:timeout_in_minutes) + + begin + response = cloudformation.update_stack(config) + Puppet.info("Updated stack #{name} in region #{resource[:region]}") + @property_hash[:ensure] = :updated + return true + rescue Aws::CloudFormation::Errors::ServiceError => e + fail e unless e.message == 'No updates are to be performed.' + @property_hash[:ensure] = :updated + return false + end + end + + def destroy + Puppet.info("Deleting stack #{name} in region #{target_region}") + cloudformation = cloudformation_client(target_region) + + cloudformation.delete_stack({ + stack_name: name, + retain_resources: [], + role_arn: nil, + }) + cloudformation.wait_until(:stack_delete_complete, stack_name: name) + @property_hash[:ensure] = :absent + end + +end diff --git a/lib/puppet/type/cloudformation_stack.rb b/lib/puppet/type/cloudformation_stack.rb new file mode 100644 index 00000000..5d1b80e5 --- /dev/null +++ b/lib/puppet/type/cloudformation_stack.rb @@ -0,0 +1,232 @@ +require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require 'puppet/parameter/boolean' + +Puppet::Type.newtype(:cloudformation_stack) do + @doc = ' + Type representing a CloudFormation stack. + + Example: + + cloudformation_stack { \'s3-bucket-test\': + ensure => updated, + region => \'us-west-2\', + template_url => \'https://s3-us-west-2.amazonaws.com/cloudformation-templates-us-west-2/S3_Website_Bucket_With_Retain_On_Delete.template\', + } + ' + + newproperty(:ensure) do + desc ' + The ensure value for the stack. + "present" will create the stack but not apply updates. + "updated" will create or apply any updates to the stack. + "absent" will delete the stack.' + newvalue(:present) do + provider.create if !provider.exists? + end + newvalue(:updated) + newvalue(:absent) do + provider.destroy if provider.exists? + end + def change_to_s(current, desired) + current = :updated if current == :present + desired = :updated if desired == :present + current == desired ? current : "changed #{current} to #{desired}" + end + def insync?(is) + return is.to_s == should.to_s unless should.to_s == 'updated' + if !provider.exists? + provider.create + return true + else + # provider.update will return true when updates applied, otherwise false + return !provider.update + end + end + end + + newparam(:name, namevar: true) do + desc 'The name of the stack.' + validate do |value| + fail 'Stacks must have a name' if value == '' + fail 'name should be a String' unless value.is_a?(String) + end + end + + newproperty(:capabilities, :array_matching => :all) do + desc 'The list of stack capabilities, including CAPABILITY_IAM, CAPABILITY_NAMED_IAM, an empty list, or unspecified.' + def insync?(is) + is.to_set == should.to_set + end + validate do |value| + fail 'Capabilities array must contain one or more of \'CAPABILITY_IAM\' or \'CAPABILITY_NAMED_IAM\'.' \ + unless value == 'CAPABILITY_IAM' or value == 'CAPABILITY_NAMED_IAM' + end + end + + newproperty(:change_set_id) do + desc 'Unique identifier of the stack. (readonly)' + end + + newproperty(:creation_time) do + desc 'The time at which the stack was created. (readonly)' + end + + newproperty(:description) do + desc 'A user-defined description associated with the stack. (readonly)' + end + + newparam(:disable_rollback, :boolean => true, :parent => Puppet::Parameter::Boolean) do + desc 'Whether to disable rollback on stack creation failures. (boolean)' + end + + newproperty(:id) do + desc 'The unique ID of the stack. (readonly)' + end + + newproperty(:last_updated_time) do + desc 'The time the stack was last updated. (readonly)' + end + + newproperty(:notification_arns, :array_matching => :all) do + desc 'List of SNS topic ARNs to which stack related events are published.' + def insync?(is) + is.to_set == should.to_set + end + validate do |value| + fail 'notification_arns should be a String' unless value.is_a?(String) + end + end + + newproperty(:on_failure) do + desc 'Determines what action will be taken if stack creation fails. This must be one of: "DO_NOTHING", "ROLLBACK", or "DELETE". You can specify either on_failure or disable_rollback, but not both.' + newvalues('DO_NOTHING', 'ROLLBACK', 'DELETE') + end + + newproperty(:outputs) do + desc 'A hash of stack outputs. (readonly)' + def should_to_s(value) + value.inspect + end + def is_to_s(value) + value.inspect + end + end + + newproperty(:parameters) do + desc 'A hash of input parameters.' + def insync?(is) + is == should + end + def should_to_s(value) + value.inspect + end + def is_to_s(value) + value.inspect + end + end + + newparam(:policy_body) do + desc 'JSON structure containing the stack policy body. For more information, go to Prevent Updates to Stack Resources in the AWS CloudFormation User Guide. You can specify either the policy_body or the policy_url parameter, but not both.' + validate do |value| + fail 'policy_body must be a String' unless value.is_a?(String) + end + + munge do |value| + begin + data = JSON.parse(value) + JSON.pretty_generate(data) + rescue + fail('policy_body string is not valid JSON') + end + end + end + + newparam(:policy_url) do + desc 'Location of a file containing the stack policy. The URL must point to a policy (maximum size: 16 KB) located in an S3 bucket in the same region as the stack. You can specify either the policy_body or the policy_url parameter, but not both.' + validate do |value| + fail 'policy_url must be a String' unless value.is_a?(String) + end + end + + validate do + fail "You can specify either policy_body or policy_url but not both for the cloudformation stack [#{self[:name]}]" if self[:policy_body] && self[:policy_url] + end + + newparam(:resource_types, :array_matching => :all) do + desc 'The list of resource types that you have permissions to work with for this stack. (optional)' + def insync?(is) + is.to_set == should.to_set + end + validate do |value| + fail 'resource_types must be a string.' unless value.is_a?(String) + end + end + + newproperty(:role_arn) do + desc 'The Amazon Resource Name (ARN) of an AWS Identity and Access Management (IAM) role that is associated with the stack.' + validate do |value| + fail 'role_arn must be a String' unless value.is_a?(String) + end + end + + newproperty(:status) do + desc 'The status of the stack. (readonly)' + newvalue(:CREATE_IN_PROGRESS) + newvalue(:CREATE_FAILED) + newvalue(:CREATE_COMPLETE) + newvalue(:ROLLBACK_IN_PROGRESS) + newvalue(:ROLLBACK_FAILED) + newvalue(:ROLLBACK_COMPLETE) + newvalue(:DELETE_IN_PROGRESS) + newvalue(:DELETE_FAILED) + newvalue(:DELETE_COMPLETE) + newvalue(:UPDATE_IN_PROGRESS) + newvalue(:UPDATE_COMPLETE_CLEANUP_IN_PROGRESS) + newvalue(:UPDATE_COMPLETE) + newvalue(:UPDATE_ROLLBACK_IN_PROGRESS) + newvalue(:UPDATE_ROLLBACK_FAILED) + newvalue(:UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS) + newvalue(:UPDATE_ROLLBACK_COMPLETE) + newvalue(:REVIEW_IN_PROGRESS) + end + + newparam(:template_body) do + desc 'Structure containing the template body with a minimum length of 1 byte and a maximum length of 51,200 bytes. For more information, go to Template Anatomy in the AWS CloudFormation User Guide.' + validate do |value| + fail 'template_body must be a String' unless value.is_a?(String) + fail 'template_body must be longer than 1 byte' unless value.size > 1 + fail 'template_body must be shorter than 51,200 bytes' unless value.size < 51200 + end + end + + newparam(:template_url) do + desc 'Location of file containing the template body. The URL must point to a template (max size: 460,800 bytes) that is located in an Amazon S3 bucket. For more information, go to the Template Anatomy in the AWS CloudFormation User Guide.' + validate do |value| + fail 'template_url must be a String' unless value.is_a?(String) + end + end + + validate do + fail "You can specify either template_body or template_url but not both for the cloudformation stack [#{self[:name]}]" if self[:template_body] && self[:template_url] + end + + newproperty(:timeout_in_minutes) do + desc 'The amount of time within which stack creation should complete.' + validate do |value| + fail 'timeout_in_minutes must be an positive Integer' unless value.is_a?(Integer) and value >= 0 + end + end + + newproperty(:tags, :parent => PuppetX::Property::AwsTag) do + desc 'The tags for the instance.' + end + + newproperty(:region) do + desc 'The region in which to launch the stack.' + validate do |value| + fail 'region should not contain spaces' if value =~ /\s/ + fail 'region should be a String' unless value.is_a?(String) + end + end + +end diff --git a/lib/puppet_x/puppetlabs/aws.rb b/lib/puppet_x/puppetlabs/aws.rb index fdb67f97..e8a36d6d 100644 --- a/lib/puppet_x/puppetlabs/aws.rb +++ b/lib/puppet_x/puppetlabs/aws.rb @@ -178,6 +178,14 @@ def autoscaling_client(region = default_region) self.class.autoscaling_client(region) end + def self.cloudformation_client(region = default_region) + ::Aws::CloudFormation::Client.new(client_config(region)) + end + + def cloudformation_client(region = default_region) + self.class.cloudformation_client(region) + end + def self.cloudwatch_client(region = default_region) ::Aws::CloudWatch::Client.new(client_config(region)) end From df789cbb57387a4ed4baaf1b32e64e34bf737ca9 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 30 Jan 2017 13:32:46 -0800 Subject: [PATCH 49/72] Begin KMS management Without this change, there is no functionality in this module to manage the lifecycle and policy of a KMS key in amazon. Here we add a simple type and provider with just enough to create, destroy, and manage the policy. There are testing updates for the normalization code here, since the KMS policy exercises data structures that are not exercised elsewhere, so we extend the use case a bit of the normalize method calls. --- README.md | 18 ++ lib/puppet/provider/kms/v2.rb | 139 +++++++++++++ lib/puppet/type/kms.rb | 43 ++++ lib/puppet_x/puppetlabs/aws.rb | 46 ++++- .../provider/ecs_task_definition/v2_spec.rb | 192 ++++++++++++++++++ spec/unit/type/kms_spec.rb | 56 +++++ 6 files changed, 489 insertions(+), 5 deletions(-) create mode 100644 lib/puppet/provider/kms/v2.rb create mode 100644 lib/puppet/type/kms.rb create mode 100644 spec/unit/type/kms_spec.rb diff --git a/README.md b/README.md index ab5209ec..27e39be5 100644 --- a/README.md +++ b/README.md @@ -339,6 +339,7 @@ You can use the aws module to audit AWS resources, launch autoscaling groups in * `iam_policy_attachment`: Manage an IAM 'managed' policy attachments. * `iam_role`: Manage an IAM role. * `iam_user`: Manage IAM users. +* `kms`: Manage KMS keys and their policies. * `rds_db_parameter_group`: Allows read access to DB Parameter Groups. * `rds_db_securitygroup`: Sets up an RDS DB Security Group. * `rds_instance`: Sets up an RDS Database instance. @@ -1363,6 +1364,23 @@ iam_user { 'bob': } ``` +#### Type: kms +The `kms` type manages KMS key lifecycle and their policies. The name of the +resource is prefixed with `alias/` to set the alias of the KMS key, since keys +themselves don't have any notion of name, outside of an attached alias. + +``` Puppet +kms { 'somekey': + ensure => present, + policy => template('my/policy.json'), +} +``` + +The above resource may be viewable elsewhere as `alias/somekey`. + +#####`policy` +The JSON policy document to manage on the given KMS key. + #### Type: rds_db_parameter_group Note that currently, this type can only be listed via puppet resource, diff --git a/lib/puppet/provider/kms/v2.rb b/lib/puppet/provider/kms/v2.rb new file mode 100644 index 00000000..631eddb1 --- /dev/null +++ b/lib/puppet/provider/kms/v2.rb @@ -0,0 +1,139 @@ +require_relative '../../../puppet_x/puppetlabs/aws.rb' + +Puppet::Type.type(:kms).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do + confine feature: :aws + mk_resource_methods + + def self.instances + aliases = get_aliases() + + aliases.collect do |key_alias| + alias_name = /alias\/(.*)/.match(key_alias.alias_name)[1] + key_alias_target = key_alias.target_key_id + next unless key_alias_target + + key_id = key_alias.target_key_id + kms_key = kms_client.describe_key({key_id: key_id}) + + begin + # There is only ever one policy, and that policy is named default. + kms_policies = get_policy('default', key_id) + rescue + Puppet.warning("Unable to get the policy_names for #{alias_name}") + end + + next if alias_name =~ %r{^aws/.*$} + + new({ + name: alias_name, + ensure: :present, + key_id: kms_key.key_metadata.key_id, + description: kms_key.key_metadata.description, + creation_date: kms_key.key_metadata.creation_date, + deletion_date: kms_key.key_metadata.deletion_date, + policy: kms_policies, + arn: kms_key.key_metadata.arn, + }) + end.compact + end + + def self.prefetch(resources) + instances.each do |prov| + if resource = resources[prov.name] + resource.provider = prov + end + end + end + + def self.get_policy_names(key_id) + policy_name_results = kms_client.list_key_policies({ + key_id: key_id + }) + policy_names = policy_name_results.policy_names + + truncated = policy_name_results.truncated + marker = policy_name_results.next_marker + + while truncated and marker + Puppet.debug('KMS policy_names results truncated, proceeding with discovery') + response = kms_client.list_key_policies({ + key_id: key_id, + marker: marker + }) + response.policy_names.each {|p| policy_names << p } + + truncated = response.truncated + marker = response.next_marker + end + + policy_names + end + + def self.get_aliases + alias_results = kms_client.list_aliases() + aliases = alias_results.aliases + + truncated = alias_results.truncated + marker = alias_results.next_marker + + while truncated and marker + Puppet.debug('KMS alias results truncated, proceeding with discovery') + response = kms_client.list_aliases({marker: marker}) + response.aliases.each {|a| aliases << a } + + truncated = response.truncated + marker = response.next_marker + end + + aliases + end + + def self.get_policy(policy_name, key_id) + policy_results = kms_client.get_key_policy({ + key_id: key_id, + policy_name: policy_name + }) + + policy_data = JSON.parse(URI.unescape(policy_results.policy)) + policy_document = JSON.pretty_generate(policy_data) + policy_document + end + + def exists? + @property_hash[:ensure] == :present + end + + def policy=(value) + Puppet.debug("Replacing policy on KMS key #{resource[:name]}") + kms_client.put_key_policy({ + key_id: @property_hash[:key_id], + policy_name: 'default', + policy: resource[:policy] + }) + end + + def create + Puppet.debug("Creating new KMS key #{resource[:name]}") + new_key = kms_client.create_key({}) + key_id = new_key.key_metadata.key_id + alias_name = "alias/#{resource[:name]}" + + kms_client.create_alias({ + alias_name: alias_name, + target_key_id: key_id, + }) + + kms_client.put_key_policy({ + key_id: key_id, + policy_name: 'default', + policy: resource[:policy] + }) + end + + def destroy + Puppet.debug("Scheduling deletion KMS key #{resource[:name]}") + kms_client.schedule_key_deletion({ + key_id: @property_hash[:key_id], + }) + end +end diff --git a/lib/puppet/type/kms.rb b/lib/puppet/type/kms.rb new file mode 100644 index 00000000..11faf2ca --- /dev/null +++ b/lib/puppet/type/kms.rb @@ -0,0 +1,43 @@ +Puppet::Type.newtype(:kms) do + @doc = 'Type representing a KMS key instance.' + + ensurable + + newparam(:name, namevar: true) do + desc 'The alias name of the KMS key to manage.' + validate do |value| + fail Puppet::Error, 'Empty usernames are not allowed' if value == '' + end + end + + newproperty(:arn) + newproperty(:key_id) + newproperty(:enabled) + newproperty(:description) + newproperty(:creation_date) + newproperty(:deletion_date) + newproperty(:policy) do + desc 'The policy document JSON string' + isrequired + validate do |value| + fail Puppet::Error, 'Policy documents must be JSON strings' unless value.is_a? String + JSON.parse(value) + end + + munge do |value| + begin + data = JSON.parse(value) + JSON.pretty_generate(data) + rescue + fail('Document string is not valid JSON') + end + end + + def insync?(is) + one = JSON.parse(is) + two = JSON.parse(should) + provider.class.normalize_hash(one) == provider.class.normalize_hash(two) + end + end + +end diff --git a/lib/puppet_x/puppetlabs/aws.rb b/lib/puppet_x/puppetlabs/aws.rb index e8a36d6d..d2db8287 100644 --- a/lib/puppet_x/puppetlabs/aws.rb +++ b/lib/puppet_x/puppetlabs/aws.rb @@ -226,6 +226,14 @@ def iam_client(region = default_region) self.class.iam_client(region) end + def self.kms_client(region = default_region) + ::Aws::KMS::Client.new(client_config(region)) + end + + def kms_client(region = default_region) + self.class.kms_client(region) + end + def self.s3_client(region = default_region) ::Aws::S3::Client.new(client_config(region)) end @@ -357,7 +365,7 @@ def self.name_cache_hash(&block) end end - def queue_url_from_name (queue_name ) + def queue_url_from_name(queue_name ) sqs = sqs_client(target_region) response = sqs.get_queue_url ({queue_name: name}) response.data.queue_url @@ -394,6 +402,9 @@ def self.normalize_hash(hash) # normalize_values method for processing. Returns a hash sorted by keys. # data = {} + + fail "Invalid data type when attempting normalize of hash: #{hash.class}" unless hash.is_a? Hash + hash.keys.sort_by{|k|k.to_s}.each {|k| value = hash[k] data[k.to_s] = self.normalize_values(value) @@ -413,6 +424,7 @@ def self.normalize_values(value) # integers to integers, etc. Array values are recursively normalized. # Hash values are normalized using the normalize_hash method. # + require 'pp' if value.is_a? String return true if value == 'true' return false if value == 'false' @@ -432,13 +444,37 @@ def self.normalize_values(value) elsif value.is_a? Hash return self.normalize_hash(value) elsif value.is_a? Array + value_class_list = value.map(&:class).uniq + + return [] unless value.size > 0 + + if value_class_list.include? String + return value.sort + elsif value_class_list.include? Hash + value_list = value + else + value_list = value + end + #return nil if value.size == 0 - results = value.map {|v| + results = value_list.map {|v| self.normalize_values(v) } - class_list = results.map {|v| v.class}.uniq - if class_list.include? Hash - results = results.sort_by{|k| k.flatten} + + results_class_list = results.map(&:class).uniq + if results_class_list.include? Hash + nested_results__value_class_list = results.collect {|i| + i.collect {|k,v| + v.class + } + }.flatten.uniq + + # If we've got a nestd hash, this sorting will fail + unless nested_results__value_class_list.include? Hash + results = results.sort_by{|k| + k.flatten + } + end end return results else diff --git a/spec/unit/provider/ecs_task_definition/v2_spec.rb b/spec/unit/provider/ecs_task_definition/v2_spec.rb index baacf15c..fd1510b7 100644 --- a/spec/unit/provider/ecs_task_definition/v2_spec.rb +++ b/spec/unit/provider/ecs_task_definition/v2_spec.rb @@ -347,6 +347,198 @@ expect(normalized['essential'].class).to be(TrueClass) expect(normalized['cpu'].class).to be(Fixnum) end + + it 'should sort array when processing array values' do + + hsh = { + "Sid"=>"Allow access for Key Administrators", + "Effect"=>"Allow", + "Principal"=> { + "AWS"=> [ + "arn:aws:iam::123456789012:user/u3", + "arn:aws:iam::123456789012:user/u2", + "arn:aws:iam::123456789012:user/u1", + "arn:aws:iam::123456789012:user/u4" + ] + }, + "Action"=> [ + "kms:Describe*", + "kms:Enable*", + "kms:Update*", + "kms:Revoke*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion", + "kms:List*", + "kms:Put*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:Create*" + ], + "Resource"=>"*" + } + + wanted = { + "Sid"=>"Allow access for Key Administrators", + "Effect"=>"Allow", + "Principal"=> { + "AWS"=> [ + "arn:aws:iam::123456789012:user/u1", + "arn:aws:iam::123456789012:user/u2", + "arn:aws:iam::123456789012:user/u3", + "arn:aws:iam::123456789012:user/u4" + ] + }, + "Action"=> [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion" + ], + "Resource"=>"*" + } + + normalized = provider.class.normalize_hash(hsh) + expect(normalized).to eq(provider.class.normalize_hash(wanted)) + end + + it 'should fail when incorrect data type is passed' do + expect do + provider.class.normalize_hash([1,2,3]) + end.to raise_error(RuntimeError, /Invalid data type/) + end + + it 'should handle a kms policy example' do + + hsh = {"Version"=>"2012-10-17", "Id"=>"key-consolepolicy-2", + "Statement"=> [{"Sid"=>"Enable IAM User Permissions", + "Effect"=>"Allow", + "Principal"=>{"AWS"=>"arn:aws:iam::123456789012:root"}, + "Action"=>"kms:*", "Resource"=>"*"}, + {"Sid"=>"Allow access for Key Administrators", + "Effect"=>"Allow", "Principal"=> {"AWS"=> + ["arn:aws:iam::123456789012:user/t1", + "arn:aws:iam::123456789012:user/t2", + "arn:aws:iam::123456789012:user/t3", + "arn:aws:iam::123456789012:user/t4"]}, + "Action"=> + ["kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion"], + "Resource"=>"*"}, + {"Sid"=>"Allow + use of the + key", + "Effect"=>"Allow", + "Principal"=> + {"AWS"=> + ["arn:aws:iam::123456789012:user/t10", + "arn:aws:iam::123456789012:user/t11", + "arn:aws:iam::123456789012:user/t12", + "arn:aws:iam::123456789012:user/t13"]}, + "Action"=> + ["kms:Encrypt", + "kms:Decrypt", + "kms:ReEncrypt*", + "kms:GenerateDataKey*", + "kms:DescribeKey"], + "Resource"=>"*"}, + {"Sid"=>"Allow + attachment + of persistent + resources", + "Effect"=>"Allow", + "Principal"=> + {"AWS"=> + ["arn:aws:iam::123456789012:user/t10", + "arn:aws:iam::123456789012:user/t11", + "arn:aws:iam::123456789012:user/t12", + "arn:aws:iam::123456789012:user/t13"]}, + "Action"=>["kms:CreateGrant", + "kms:ListGrants", + "kms:RevokeGrant"], + "Resource"=>"*", + "Condition"=>{"Bool"=>{"kms:GrantIsForAWSResource"=>"true"}}}]} + + wanted = {"Version"=>"2012-10-17", "Id"=>"key-consolepolicy-2", + "Statement"=> [{"Sid"=>"Enable IAM User Permissions", + "Effect"=>"Allow", + "Principal"=>{"AWS"=>"arn:aws:iam::123456789012:root"}, + "Action"=>"kms:*", "Resource"=>"*"}, + {"Sid"=>"Allow access for Key Administrators", + "Effect"=>"Allow", "Principal"=> {"AWS"=> + ["arn:aws:iam::123456789012:user/t3", + "arn:aws:iam::123456789012:user/t4", + "arn:aws:iam::123456789012:user/t1", + "arn:aws:iam::123456789012:user/t2"]}, + "Action"=> + ["kms:Create*", + "kms:Get*", + "kms:Describe*", + "kms:Put*", + "kms:Update*", + "kms:Delete*", + "kms:Revoke*", + "kms:Disable*", + "kms:Enable*", + "kms:List*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion"], + "Resource"=>"*"}, + {"Sid"=>"Allow + use of the + key", + "Effect"=>"Allow", + "Principal"=> + {"AWS"=> + ["arn:aws:iam::123456789012:user/t10", + "arn:aws:iam::123456789012:user/t11", + "arn:aws:iam::123456789012:user/t12", + "arn:aws:iam::123456789012:user/t13"]}, + "Action"=> + ["kms:Encrypt", + "kms:Decrypt", + "kms:ReEncrypt*", + "kms:GenerateDataKey*", + "kms:DescribeKey"], + "Resource"=>"*"}, + {"Sid"=>"Allow + attachment + of persistent + resources", + "Effect"=>"Allow", + "Principal"=> + {"AWS"=> + ["arn:aws:iam::123456789012:user/t10", + "arn:aws:iam::123456789012:user/t11", + "arn:aws:iam::123456789012:user/t12", + "arn:aws:iam::123456789012:user/t13"]}, + "Action"=>["kms:CreateGrant", + "kms:ListGrants", + "kms:RevokeGrant"], + "Resource"=>"*", + "Condition"=>{"Bool"=>{"kms:GrantIsForAWSResource"=>"true"}}}]} + + + + end end describe "self.serialize_container_definitions" do diff --git a/spec/unit/type/kms_spec.rb b/spec/unit/type/kms_spec.rb new file mode 100644 index 00000000..32ec09ec --- /dev/null +++ b/spec/unit/type/kms_spec.rb @@ -0,0 +1,56 @@ +require 'spec_helper' + +type_class = Puppet::Type.type(:kms) + +describe type_class do + + let :params do + [ + :name, + ] + end + + let :properties do + [ + :ensure, + :policy, + :arn, + :enabled, + :description, + :creation_date, + :deletion_date, + ] + end + + it 'should have expected properties' do + properties.each do |property| + expect(type_class.properties.map(&:name)).to be_include(property) + end + end + + it 'should have expected parameters' do + params.each do |param| + expect(type_class.parameters).to be_include(param) + end + end + + it 'should require a name' do + expect { + type_class.new({}) + }.to raise_error(Puppet::Error, 'Title or name must be provided') + end + + it 'should require a non-blank name' do + expect { + type_class.new({ name: '' }) + }.to raise_error(Puppet::Error, /Empty usernames are not allowed/) + end + + context 'with a valid name' do + it 'should create a valid instance' do + type_class.new({ name: 'name' }) + end + end + +end + From 2eb339d1e3b549be7197da80536ab9d618222e9b Mon Sep 17 00:00:00 2001 From: Kris M Date: Sat, 7 Jan 2017 11:19:31 -0700 Subject: [PATCH 50/72] Allows specifying public and private ip address. --- lib/puppet/provider/ec2_instance/v2.rb | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/puppet/provider/ec2_instance/v2.rb b/lib/puppet/provider/ec2_instance/v2.rb index 7915a49d..86c6edc3 100644 --- a/lib/puppet/provider/ec2_instance/v2.rb +++ b/lib/puppet/provider/ec2_instance/v2.rb @@ -261,12 +261,7 @@ def config_with_key_details(config) config end - def config_with_private_ip(config) - config['private_ip_address'] = resource['private_ip_address'] if resource['private_ip_address'] && using_vpc? - config - end - - def config_with_public_interface(config) + def config_with_ip(config) if resource[:associate_public_ip_address] == :true config[:network_interfaces] = [{ device_index: 0, @@ -274,9 +269,16 @@ def config_with_public_interface(config) groups: config[:security_group_ids], associate_public_ip_address: true, }] + # If both public and private ip specified, then the private_ip_address must be within the network_interfaces structure + if resource['private_ip_address'] && using_vpc? + config[:network_interfaces].first[:private_ip_address] = resource['private_ip_address'] + end config[:subnet_id] = nil config[:security_group_ids] = nil + elsif resource['private_ip_address'] && using_vpc? + config['private_ip_address'] = resource['private_ip_address'] if resource['private_ip_address'] && using_vpc? end + config end @@ -312,8 +314,7 @@ def create config = config_with_key_details(config) config = config_with_devices(config) config = config_with_network_details(config) - config = config_with_private_ip(config) - config = config_with_public_interface(config) + config = config_with_ip(config) response = ec2.run_instances(config) From 333ae1bf8188ea7bd7446281d469a18ec4e6def2 Mon Sep 17 00:00:00 2001 From: Kris Macoskey Date: Fri, 10 Feb 2017 09:05:21 -0700 Subject: [PATCH 51/72] Fixed indentation, duplicate conditional, and added comments. --- lib/puppet/provider/ec2_instance/v2.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/puppet/provider/ec2_instance/v2.rb b/lib/puppet/provider/ec2_instance/v2.rb index 86c6edc3..2f3d25c4 100644 --- a/lib/puppet/provider/ec2_instance/v2.rb +++ b/lib/puppet/provider/ec2_instance/v2.rb @@ -270,13 +270,15 @@ def config_with_ip(config) associate_public_ip_address: true, }] # If both public and private ip specified, then the private_ip_address must be within the network_interfaces structure + # Module currently only supports a single network interface, therefore attatch any specified private ip address + # to the first network interface. if resource['private_ip_address'] && using_vpc? - config[:network_interfaces].first[:private_ip_address] = resource['private_ip_address'] + config[:network_interfaces].first[:private_ip_address] = resource['private_ip_address'] end config[:subnet_id] = nil config[:security_group_ids] = nil elsif resource['private_ip_address'] && using_vpc? - config['private_ip_address'] = resource['private_ip_address'] if resource['private_ip_address'] && using_vpc? + config['private_ip_address'] = resource['private_ip_address'] end config From 2f08672a09357aed06e41f204e9635bf8d7353eb Mon Sep 17 00:00:00 2001 From: Andy Henroid Date: Sun, 12 Feb 2017 06:38:42 -0800 Subject: [PATCH 52/72] (MAINT) Minor fix for ELB acceptance tests --- lib/puppet/provider/elb_loadbalancer/v2.rb | 27 ++++++++++++++++------ 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/lib/puppet/provider/elb_loadbalancer/v2.rb b/lib/puppet/provider/elb_loadbalancer/v2.rb index f639fdf0..d83abd94 100644 --- a/lib/puppet/provider/elb_loadbalancer/v2.rb +++ b/lib/puppet/provider/elb_loadbalancer/v2.rb @@ -298,7 +298,12 @@ def update_listeners # which to add, and which need modification. The modification is a bit of # a misnomer, since it really ends up being a delete followed by an add. - is_listener_ports = @property_hash[:listeners].collect {|x| x['load_balancer_port'].to_i } + + is_listener_ports = if @property_hash[:listeners] + @property_hash[:listeners].collect {|x| x['load_balancer_port'].to_i } + else + [] + end should_listener_ports = resource[:listeners].collect {|x| x['load_balancer_port'].to_i } # Collect a list of ports for listeners that should be deleted @@ -320,9 +325,13 @@ def update_listeners # Identify and retrieve the existing listener to our current 'should' # listener by port - is_listener = @property_hash[:listeners].select {|x| - x['load_balancer_port'].to_i == should_listener['load_balancer_port'].to_i - }.first + is_listener = if @property_hash[:listeners] + @property_hash[:listeners].select {|x| + x['load_balancer_port'].to_i == should_listener['load_balancer_port'].to_i + }.first + else + nil + end # Unless we found a match, there is no comparison needed next unless is_listener @@ -409,9 +418,13 @@ def update_listeners next unless should_listener['policy_names'] # Match the should_listener to the is_listener - is_listener = @property_hash[:listeners].select {|x| - x['load_balancer_port'].to_i == should_listener['load_balancer_port'].to_i - }.first + is_listener = if @property_hash[:listeners] + @property_hash[:listeners].select {|x| + x['load_balancer_port'].to_i == should_listener['load_balancer_port'].to_i + }.first + else + {} + end # Update the working listener policy if requested if should_listener['policy_names'] and should_listener['policy_names'] != is_listener['policy_names'] From 15c5a88dec173d8ece69d61ea86fdac64ea2c02f Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 30 Jan 2017 10:33:31 -0800 Subject: [PATCH 53/72] Enable autorequire for iam_role for policy attachment Without this change, the autorequire for iam_role is not enabled for the iam_policy_attachment. This was originally commented because the iam_role code had not been merged. Now that the code has been merged, we can enable this here to allow the automatic and correct ordering for IAM resources. --- lib/puppet/type/iam_policy_attachment.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/puppet/type/iam_policy_attachment.rb b/lib/puppet/type/iam_policy_attachment.rb index 147c7718..05a2b586 100644 --- a/lib/puppet/type/iam_policy_attachment.rb +++ b/lib/puppet/type/iam_policy_attachment.rb @@ -9,9 +9,9 @@ self[:users] end - #autorequire(:iam_role) do - # self[:users] - #end + autorequire(:iam_role) do + self[:roles] + end autorequire(:iam_policy) do self[:name] From c300262721fd96a904ab3ca37e98c489b3d482d5 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 30 Jan 2017 16:08:03 -0800 Subject: [PATCH 54/72] Add role management for ECS tasks Without this change, the ECS tasks are unable to assume a role when under puppet management. This work adds a new 'role' property that allows tasks to assume a given IAM role. --- README.md | 6 ++-- lib/puppet/provider/ecs_task_definition/v2.rb | 30 ++++++++++++++----- lib/puppet/type/ecs_task_definition.rb | 10 ++++++- .../provider/ecs_task_definition/v2_spec.rb | 11 +++---- spec/unit/type/ecs_task_definition_spec.rb | 1 + 5 files changed, 43 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 27e39be5..33e48e4f 100644 --- a/README.md +++ b/README.md @@ -1190,8 +1190,6 @@ In the case where a user wishes to remove an option from the container, one of t It's a small kludge, I know. - - ##### `container_definitions` An array of hashes representing the container definition. See the example above. @@ -1210,6 +1208,10 @@ This is useful in environments where external CI tooling is responsible for modifying the image of a container, allowing a dualistic approach for managing ECS. +##### `role` +A string of the short name or full ARN of the IAM role that containers in this task should assume. + + #### Type: iam_group ```Puppet diff --git a/lib/puppet/provider/ecs_task_definition/v2.rb b/lib/puppet/provider/ecs_task_definition/v2.rb index 2eff2f68..5e359fb7 100644 --- a/lib/puppet/provider/ecs_task_definition/v2.rb +++ b/lib/puppet/provider/ecs_task_definition/v2.rb @@ -25,6 +25,9 @@ def self.instances end container_defs = deserialize_container_definitions(task.container_definitions) + if task.task_role_arn + task_role = /arn:aws:iam:.*:role\/(.*)/.match(task.task_role_arn)[1] + end new({ name: task.family, @@ -33,6 +36,7 @@ def self.instances revision: task.revision, volumes: task.volumes, container_definitions: container_defs, + role: task_role }) end.compact end @@ -120,6 +124,10 @@ def container_definitions=(value) @property_flush[:container_definitions] = value end + def role=(value) + @property_flush[:role] = value + end + def flush Puppet.debug("Flushing ECS task definition for #{@property_hash[:name]}") @@ -136,16 +144,24 @@ def flush end end - if containers.size > 0 - Puppet.debug("Registering new task definition for #{@property_hash[:name]}") + Puppet.debug("Registering new task definition for #{@property_hash[:name]}") - ecs_client.register_task_definition({ - family: @property_hash[:name], - container_definitions: self.class.serialize_container_definitions(containers), - }) + if containers.size > 0 + container_definitions = containers else - Puppet.debug("No container modifications needed on ECS task #{@property_hash[:name]}") + container_definitions = @property_hash[:container_definitions] end + + task = { + family: @property_hash[:name], + container_definitions: self.class.serialize_container_definitions(container_definitions), + } + + if resource[:role] + task[:task_role_arn] = resource[:role] + end + + ecs_client.register_task_definition(task) end def rectify_container_delta(is_containers, should_containers) diff --git a/lib/puppet/type/ecs_task_definition.rb b/lib/puppet/type/ecs_task_definition.rb index 8e080c81..7fc8a43a 100644 --- a/lib/puppet/type/ecs_task_definition.rb +++ b/lib/puppet/type/ecs_task_definition.rb @@ -1,6 +1,10 @@ Puppet::Type.newtype(:ecs_task_definition) do @doc = 'Type representing ECS clusters.' + autorequire(:iam_role) do + self[:role] + end + ensurable newparam(:name, namevar: true) do @@ -28,7 +32,7 @@ desc 'An array of hashes to handle for the task' end - newproperty( :container_definitions, :array_matching => :all) do + newproperty(:container_definitions, :array_matching => :all) do desc 'An array of hashes representing the container definition' isrequired def insync?(is) @@ -39,5 +43,9 @@ def insync?(is) end end + + newproperty(:role) do + desc 'The short name or full ARN of the IAM role that containers in this task can assume.' + end end diff --git a/spec/unit/provider/ecs_task_definition/v2_spec.rb b/spec/unit/provider/ecs_task_definition/v2_spec.rb index fd1510b7..47e7c1e5 100644 --- a/spec/unit/provider/ecs_task_definition/v2_spec.rb +++ b/spec/unit/provider/ecs_task_definition/v2_spec.rb @@ -64,7 +64,7 @@ describe 'destroy' do it 'shold make the call to create the task definition' do VCR.use_cassette('destroy-ecs_task_definition') do - data = provider.class.prefetch({"lb-1" => resource}) + data = provider.class.prefetch({"testtask" => resource}) prov = data.select {|m| m.name == 'testtask' }[0] expect(prov.destroy).to be_truthy expect(prov.exists?).to be_falsy @@ -75,7 +75,7 @@ describe 'container_definitions' do it 'should retrieve the container_definition' do VCR.use_cassette('ecs_task_definition-setup') do - data = provider.class.prefetch({"lb-1" => resource}) + data = provider.class.prefetch({"testtask" => resource}) prov = data.select {|m| m.name == 'testtask' }[0] expect(prov.name).to eq('testtask') container1 = prov.container_definitions[1] @@ -90,7 +90,8 @@ describe 'container_definitions=' do it 'should set the container_definition' do VCR.use_cassette('ecs_task_definition-setup') do - instance = provider.class.instances.first + data = provider.class.prefetch({"testtask" => resource}) + prov = data.select {|m| m.name == 'testtask' }[0] container_defs = [ { @@ -98,8 +99,8 @@ } ] - instance.container_definitions=container_defs - instance.flush + prov.container_definitions=container_defs + prov.flush end end end diff --git a/spec/unit/type/ecs_task_definition_spec.rb b/spec/unit/type/ecs_task_definition_spec.rb index 2a47a160..53eae669 100644 --- a/spec/unit/type/ecs_task_definition_spec.rb +++ b/spec/unit/type/ecs_task_definition_spec.rb @@ -16,6 +16,7 @@ :revision, :volumes, :container_definitions, + :role, ] end From c32a9ec12a95f4ff52ca3ca36fd22c2a98e3b01a Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Tue, 31 Jan 2017 12:43:03 -0800 Subject: [PATCH 55/72] Remove print from IAM user provider This mistakenly made it through and should be removed. We should not be printing data here. --- lib/puppet/provider/iam_user/v2.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/puppet/provider/iam_user/v2.rb b/lib/puppet/provider/iam_user/v2.rb index 009a5f0d..51124855 100644 --- a/lib/puppet/provider/iam_user/v2.rb +++ b/lib/puppet/provider/iam_user/v2.rb @@ -65,7 +65,6 @@ def destroy begin iam_client.list_access_keys({user_name: user.user_name}).access_key_metadata.each {|k| - pp k iam_client.delete_access_key({ user_name: user.user_name, access_key_id: k['access_key_id'], From 94dbe426df9531737170d550bd03d4bc7fcfe580 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Thu, 12 Jan 2017 18:01:37 -0800 Subject: [PATCH 56/72] Begin ELB listener policy management Without this change, the module does not have the facility to manage the ELB policies, which include a policy type for managing the cipher suite accepted on HTTPS listeners. This work adds the initial functionality to set the listener polices. --- README.md | 35 +- fixtures/vcr_cassettes/elb-named-test.yml | 892 ++++++++++++- .../elb_loadbalancer-policies.yml | 805 ++++++++++++ .../elb_loadbalancer-policy-types.yml | 774 ++++++++++++ fixtures/vcr_cassettes/no-elb-named-test.yml | 1103 ++++++++++++++++- lib/puppet/provider/elb_loadbalancer/v2.rb | 203 ++- lib/puppet/type/elb_loadbalancer.rb | 104 +- spec/unit/provider/ec2_volume/v2_spec.rb | 4 - .../unit/provider/elb_loadbalancer/v2_spec.rb | 189 ++- spec/unit/puppet_x/puppetlabs/aws_spec.rb | 280 +++++ spec/unit/type/elb_loadbalancer_spec.rb | 186 ++- 11 files changed, 4487 insertions(+), 88 deletions(-) create mode 100644 fixtures/vcr_cassettes/elb_loadbalancer-policies.yml create mode 100644 fixtures/vcr_cassettes/elb_loadbalancer-policy-types.yml create mode 100644 spec/unit/puppet_x/puppetlabs/aws_spec.rb diff --git a/README.md b/README.md index 33e48e4f..9e51e94c 100644 --- a/README.md +++ b/README.md @@ -192,18 +192,29 @@ elb_loadbalancer { 'name-of-load-balancer': availability_zones => ['us-east-1a', 'us-east-1b'], instances => ['name-of-instance', 'another-instance'], security_groups => ['name-of-security-group'], - listeners => [{ - protocol => 'HTTP', - load_balancer_port => 80, - instance_protocol => 'HTTP', - instance_port => 80, - },{ - protocol => 'HTTPS', - load_balancer_port => 443, - instance_protocol => 'HTTPS', - instance_port => 8080, - ssl_certificate_id => 'arn:aws:iam::123456789000:server-certificate/yourcert.com', - }], + listeners => [ + { + protocol => 'HTTP', + load_balancer_port => 80, + instance_protocol => 'HTTP', + instance_port => 80, + },{ + protocol => 'HTTPS', + load_balancer_port => 443, + instance_protocol => 'HTTPS', + instance_port => 8080, + ssl_certificate_id => 'arn:aws:iam::123456789000:server-certificate/yourcert.com', + policies => [ + { + 'policy_type' => 'SSLNegotiationPolicyType', + 'policy_attributes' => { + 'Protocol-TLSv1.1' => false, + 'Protocol-TLSv1.2' => true, + } + } + ] + } + ], health_check => { 'healthy_threshold' => '10', 'interval' => '30', diff --git a/fixtures/vcr_cassettes/elb-named-test.yml b/fixtures/vcr_cassettes/elb-named-test.yml index a360a9e5..aa4095a5 100644 --- a/fixtures/vcr_cassettes/elb-named-test.yml +++ b/fixtures/vcr_cassettes/elb-named-test.yml @@ -14,12 +14,12 @@ http_interactions: User-Agent: - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 X-Amz-Date: - - 20170112T183706Z + - 20170118T000509Z X-Amz-Content-Sha256: - 236069f72bf74f0c7ddff0a34b0defa8a21d1d6a897e588764e1b2ff6319f94a Authorization: - - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/elasticloadbalancing/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=135abb66f84eaf73903fa7170f2ea7c05e21cbc77d4b7d8caac90d5b0190570b + - AWS4-HMAC-SHA256 Credential=111111111111/20170118/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=6fa8742a238766a1dc81e3cd44873ab2ed9e944e7b111f3654019cec3f749549 Content-Length: - '47' Accept: @@ -30,15 +30,15 @@ http_interactions: message: OK headers: X-Amzn-Requestid: - - 1f087142-d8f6-11e6-93b1-21728663efa0 + - c73f36b9-dd11-11e6-846d-71c7730df7c3 Content-Type: - text/xml Content-Length: - - '2112' + - '2800' Vary: - Accept-Encoding Date: - - Thu, 12 Jan 2017 18:37:07 GMT + - Wed, 18 Jan 2017 00:05:10 GMT body: encoding: UTF-8 string: | @@ -46,19 +46,22 @@ http_interactions: - vpc-8f0019ea Z2P70J7HTTTPLU + vpc-8f0019ea internet-facing - + + AWSConsole-SSLNegotiationPolicy-lb-1-1484696260015 + ELBSecurityPolicy-2016-08 + sa-east-1a - lb-1-836530285.sa-east-1.elb.amazonaws.com + lb-1-22921474.sa-east-1.elb.amazonaws.com 123456789012 @@ -75,6 +78,18 @@ http_interactions: + + + 443 + arn:aws:iam::123456789012:server-certificate/zleslie-2016 + HTTP + HTTPS + 443 + + + AWSConsole-SSLNegotiationPolicy-lb-1-1484696260015 + + 2 @@ -83,23 +98,836 @@ http_interactions: 5 TCP:80 - 2017-01-12T18:36:58.480Z + 2017-01-12T21:54:33.700Z subnet-0af6436e sg-0ce2ad68 - lb-1-836530285.sa-east-1.elb.amazonaws.com + lb-1-22921474.sa-east-1.elb.amazonaws.com - 1f087142-d8f6-11e6-93b1-21728663efa0 + c73f36b9-dd11-11e6-846d-71c7730df7c3 http_version: - recorded_at: Thu, 12 Jan 2017 18:37:07 GMT + recorded_at: Wed, 18 Jan 2017 00:05:10 GMT +- request: + method: post + uri: https://elasticloadbalancing.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeLoadBalancerPolicies&LoadBalancerName=lb-1&Version=2012-06-01 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170118T000510Z + X-Amz-Content-Sha256: + - 2e001c9ec5bb4d2bd96c10f335b63c15c06b3d5c3c4d7e52e8324663d01b13f5 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170118/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=2561d53a8ee0159d0e1b10126c75cf1f0a8a21df96418d396b285d8a493183c5 + Content-Length: + - '76' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - c7cd4614-dd11-11e6-8071-ed1c1bc4d23b + Content-Type: + - text/xml + Content-Length: + - '29253' + Vary: + - Accept-Encoding + Date: + - Wed, 18 Jan 2017 00:05:11 GMT + body: + encoding: UTF-8 + string: | + + + + + SSLNegotiationPolicyType + + + false + Protocol-TLSv1 + + + false + Protocol-SSLv3 + + + true + Protocol-TLSv1.1 + + + true + Protocol-TLSv1.2 + + + true + Server-Defined-Cipher-Order + + + true + ECDHE-ECDSA-AES128-GCM-SHA256 + + + true + ECDHE-RSA-AES128-GCM-SHA256 + + + true + ECDHE-ECDSA-AES128-SHA256 + + + true + ECDHE-RSA-AES128-SHA256 + + + true + ECDHE-ECDSA-AES128-SHA + + + true + ECDHE-RSA-AES128-SHA + + + false + DHE-RSA-AES128-SHA + + + true + ECDHE-ECDSA-AES256-GCM-SHA384 + + + true + ECDHE-RSA-AES256-GCM-SHA384 + + + true + ECDHE-ECDSA-AES256-SHA384 + + + true + ECDHE-RSA-AES256-SHA384 + + + true + ECDHE-RSA-AES256-SHA + + + true + ECDHE-ECDSA-AES256-SHA + + + true + AES128-GCM-SHA256 + + + true + AES128-SHA256 + + + true + AES128-SHA + + + true + AES256-GCM-SHA384 + + + true + AES256-SHA256 + + + true + AES256-SHA + + + false + DHE-DSS-AES128-SHA + + + false + CAMELLIA128-SHA + + + false + EDH-RSA-DES-CBC3-SHA + + + false + DES-CBC3-SHA + + + false + ECDHE-RSA-RC4-SHA + + + false + RC4-SHA + + + false + ECDHE-ECDSA-RC4-SHA + + + false + DHE-DSS-AES256-GCM-SHA384 + + + false + DHE-RSA-AES256-GCM-SHA384 + + + false + DHE-RSA-AES256-SHA256 + + + false + DHE-DSS-AES256-SHA256 + + + false + DHE-RSA-AES256-SHA + + + false + DHE-DSS-AES256-SHA + + + false + DHE-RSA-CAMELLIA256-SHA + + + false + DHE-DSS-CAMELLIA256-SHA + + + false + CAMELLIA256-SHA + + + false + EDH-DSS-DES-CBC3-SHA + + + false + DHE-DSS-AES128-GCM-SHA256 + + + false + DHE-RSA-AES128-GCM-SHA256 + + + false + DHE-RSA-AES128-SHA256 + + + false + DHE-DSS-AES128-SHA256 + + + false + DHE-RSA-CAMELLIA128-SHA + + + false + DHE-DSS-CAMELLIA128-SHA + + + false + ADH-AES128-GCM-SHA256 + + + false + ADH-AES128-SHA + + + false + ADH-AES128-SHA256 + + + false + ADH-AES256-GCM-SHA384 + + + false + ADH-AES256-SHA + + + false + ADH-AES256-SHA256 + + + false + ADH-CAMELLIA128-SHA + + + false + ADH-CAMELLIA256-SHA + + + false + ADH-DES-CBC3-SHA + + + false + ADH-DES-CBC-SHA + + + false + ADH-RC4-MD5 + + + false + ADH-SEED-SHA + + + false + DES-CBC-SHA + + + false + DHE-DSS-SEED-SHA + + + false + DHE-RSA-SEED-SHA + + + false + EDH-DSS-DES-CBC-SHA + + + false + EDH-RSA-DES-CBC-SHA + + + false + IDEA-CBC-SHA + + + false + RC4-MD5 + + + false + SEED-SHA + + + false + DES-CBC3-MD5 + + + false + DES-CBC-MD5 + + + false + RC2-CBC-MD5 + + + false + PSK-AES256-CBC-SHA + + + false + PSK-3DES-EDE-CBC-SHA + + + false + KRB5-DES-CBC3-SHA + + + false + KRB5-DES-CBC3-MD5 + + + false + PSK-AES128-CBC-SHA + + + false + PSK-RC4-SHA + + + false + KRB5-RC4-SHA + + + false + KRB5-RC4-MD5 + + + false + KRB5-DES-CBC-SHA + + + false + KRB5-DES-CBC-MD5 + + + false + EXP-EDH-RSA-DES-CBC-SHA + + + false + EXP-EDH-DSS-DES-CBC-SHA + + + false + EXP-ADH-DES-CBC-SHA + + + false + EXP-DES-CBC-SHA + + + false + EXP-RC2-CBC-MD5 + + + false + EXP-KRB5-RC2-CBC-SHA + + + false + EXP-KRB5-DES-CBC-SHA + + + false + EXP-KRB5-RC2-CBC-MD5 + + + false + EXP-KRB5-DES-CBC-MD5 + + + false + EXP-ADH-RC4-MD5 + + + false + EXP-RC4-MD5 + + + false + EXP-KRB5-RC4-SHA + + + false + EXP-KRB5-RC4-MD5 + + + AWSConsole-SSLNegotiationPolicy-lb-1-1484696260015 + + + SSLNegotiationPolicyType + + + ELBSecurityPolicy-2016-08 + Reference-Security-Policy + + + true + Protocol-TLSv1 + + + false + Protocol-SSLv3 + + + true + Protocol-TLSv1.1 + + + true + Protocol-TLSv1.2 + + + true + Server-Defined-Cipher-Order + + + true + ECDHE-ECDSA-AES128-GCM-SHA256 + + + true + ECDHE-RSA-AES128-GCM-SHA256 + + + true + ECDHE-ECDSA-AES128-SHA256 + + + true + ECDHE-RSA-AES128-SHA256 + + + true + ECDHE-ECDSA-AES128-SHA + + + true + ECDHE-RSA-AES128-SHA + + + false + DHE-RSA-AES128-SHA + + + true + ECDHE-ECDSA-AES256-GCM-SHA384 + + + true + ECDHE-RSA-AES256-GCM-SHA384 + + + true + ECDHE-ECDSA-AES256-SHA384 + + + true + ECDHE-RSA-AES256-SHA384 + + + true + ECDHE-RSA-AES256-SHA + + + true + ECDHE-ECDSA-AES256-SHA + + + true + AES128-GCM-SHA256 + + + true + AES128-SHA256 + + + true + AES128-SHA + + + true + AES256-GCM-SHA384 + + + true + AES256-SHA256 + + + true + AES256-SHA + + + false + DHE-DSS-AES128-SHA + + + false + CAMELLIA128-SHA + + + false + EDH-RSA-DES-CBC3-SHA + + + false + DES-CBC3-SHA + + + false + ECDHE-RSA-RC4-SHA + + + false + RC4-SHA + + + false + ECDHE-ECDSA-RC4-SHA + + + false + DHE-DSS-AES256-GCM-SHA384 + + + false + DHE-RSA-AES256-GCM-SHA384 + + + false + DHE-RSA-AES256-SHA256 + + + false + DHE-DSS-AES256-SHA256 + + + false + DHE-RSA-AES256-SHA + + + false + DHE-DSS-AES256-SHA + + + false + DHE-RSA-CAMELLIA256-SHA + + + false + DHE-DSS-CAMELLIA256-SHA + + + false + CAMELLIA256-SHA + + + false + EDH-DSS-DES-CBC3-SHA + + + false + DHE-DSS-AES128-GCM-SHA256 + + + false + DHE-RSA-AES128-GCM-SHA256 + + + false + DHE-RSA-AES128-SHA256 + + + false + DHE-DSS-AES128-SHA256 + + + false + DHE-RSA-CAMELLIA128-SHA + + + false + DHE-DSS-CAMELLIA128-SHA + + + false + ADH-AES128-GCM-SHA256 + + + false + ADH-AES128-SHA + + + false + ADH-AES128-SHA256 + + + false + ADH-AES256-GCM-SHA384 + + + false + ADH-AES256-SHA + + + false + ADH-AES256-SHA256 + + + false + ADH-CAMELLIA128-SHA + + + false + ADH-CAMELLIA256-SHA + + + false + ADH-DES-CBC3-SHA + + + false + ADH-DES-CBC-SHA + + + false + ADH-RC4-MD5 + + + false + ADH-SEED-SHA + + + false + DES-CBC-SHA + + + false + DHE-DSS-SEED-SHA + + + false + DHE-RSA-SEED-SHA + + + false + EDH-DSS-DES-CBC-SHA + + + false + EDH-RSA-DES-CBC-SHA + + + false + IDEA-CBC-SHA + + + false + RC4-MD5 + + + false + SEED-SHA + + + false + DES-CBC3-MD5 + + + false + DES-CBC-MD5 + + + false + RC2-CBC-MD5 + + + false + PSK-AES256-CBC-SHA + + + false + PSK-3DES-EDE-CBC-SHA + + + false + KRB5-DES-CBC3-SHA + + + false + KRB5-DES-CBC3-MD5 + + + false + PSK-AES128-CBC-SHA + + + false + PSK-RC4-SHA + + + false + KRB5-RC4-SHA + + + false + KRB5-RC4-MD5 + + + false + KRB5-DES-CBC-SHA + + + false + KRB5-DES-CBC-MD5 + + + false + EXP-EDH-RSA-DES-CBC-SHA + + + false + EXP-EDH-DSS-DES-CBC-SHA + + + false + EXP-ADH-DES-CBC-SHA + + + false + EXP-DES-CBC-SHA + + + false + EXP-RC2-CBC-MD5 + + + false + EXP-KRB5-RC2-CBC-SHA + + + false + EXP-KRB5-DES-CBC-SHA + + + false + EXP-KRB5-RC2-CBC-MD5 + + + false + EXP-KRB5-DES-CBC-MD5 + + + false + EXP-ADH-RC4-MD5 + + + false + EXP-RC4-MD5 + + + false + EXP-KRB5-RC4-SHA + + + false + EXP-KRB5-RC4-MD5 + + + ELBSecurityPolicy-2016-08 + + + + + c7cd4614-dd11-11e6-8071-ed1c1bc4d23b + + + http_version: + recorded_at: Wed, 18 Jan 2017 00:05:12 GMT - request: method: post uri: https://elasticloadbalancing.sa-east-1.amazonaws.com/ @@ -114,12 +942,12 @@ http_interactions: User-Agent: - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 X-Amz-Date: - - 20170112T183707Z + - 20170118T000512Z X-Amz-Content-Sha256: - 667b7cad12519b7eb3be43722330c19a8cc170d896753a4bebaab30d44d93801 Authorization: - - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/elasticloadbalancing/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=3d9d70ab1b6c8f50df0642ddbb2430288ff1b90fcbbbb255d75f7c762e94ee1e + - AWS4-HMAC-SHA256 Credential=111111111111/20170118/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=ae0b751350df26ae3fe7062074125919faa63610fe8340f0cd3d2d9b6ae4a644 Content-Length: - '70' Accept: @@ -130,13 +958,13 @@ http_interactions: message: OK headers: X-Amzn-Requestid: - - 1f72f2e6-d8f6-11e6-93b1-21728663efa0 + - c8932e30-dd11-11e6-8071-ed1c1bc4d23b Content-Type: - text/xml Content-Length: - '523' Date: - - Thu, 12 Jan 2017 18:37:08 GMT + - Wed, 18 Jan 2017 00:05:13 GMT body: encoding: UTF-8 string: | @@ -155,11 +983,11 @@ http_interactions: - 1f72f2e6-d8f6-11e6-93b1-21728663efa0 + c8932e30-dd11-11e6-8071-ed1c1bc4d23b http_version: - recorded_at: Thu, 12 Jan 2017 18:37:08 GMT + recorded_at: Wed, 18 Jan 2017 00:05:13 GMT - request: method: post uri: https://ec2.sa-east-1.amazonaws.com/ @@ -174,12 +1002,12 @@ http_interactions: User-Agent: - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 X-Amz-Date: - - 20170112T183708Z + - 20170118T000513Z X-Amz-Content-Sha256: - 2b7e0c9eaa89b98b70b3784bc41b7b21bda0b808db0c80cc18e8000626e0d142 Authorization: - - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/ec2/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=0c291922245c8db7c61a0e574c00e35b2a4a16cbade02b7acedb7ff2c4a4419b + - AWS4-HMAC-SHA256 Credential=111111111111/20170118/sa-east-1/ec2/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=75a9ce7c3da280aa2584e730d34857cce3ef74cac1b4eb522770d4929585e23b Content-Length: - '68' Accept: @@ -196,7 +1024,7 @@ http_interactions: Vary: - Accept-Encoding Date: - - Thu, 12 Jan 2017 18:37:08 GMT + - Wed, 18 Jan 2017 00:05:14 GMT Server: - AmazonEC2 body: @@ -204,7 +1032,7 @@ http_interactions: string: |- - 32de270a-3821-46c0-bb37-a98daac0b384 + deee1825-8669-4653-86a3-784347040adf subnet-0af6436e @@ -221,7 +1049,7 @@ http_interactions: http_version: - recorded_at: Thu, 12 Jan 2017 18:37:09 GMT + recorded_at: Wed, 18 Jan 2017 00:05:14 GMT - request: method: post uri: https://ec2.sa-east-1.amazonaws.com/ @@ -236,12 +1064,12 @@ http_interactions: User-Agent: - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 X-Amz-Date: - - 20170112T183709Z + - 20170118T000514Z X-Amz-Content-Sha256: - a598e638d441e5df353a1e19707221b07f439cbff6de6518dd3fe84683252b33 Authorization: - - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/ec2/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=918879d2bd376649ad6bee7da9fc9672cf5df2a9a361be219ad0ed2873b130e4 + - AWS4-HMAC-SHA256 Credential=111111111111/20170118/sa-east-1/ec2/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=444101097fe6eaf731a920f0b2181914b30f44fa9aa37d0c68c852231ebccf17 Content-Length: - '70' Accept: @@ -258,7 +1086,7 @@ http_interactions: Vary: - Accept-Encoding Date: - - Thu, 12 Jan 2017 18:37:09 GMT + - Wed, 18 Jan 2017 00:05:15 GMT Server: - AmazonEC2 body: @@ -266,7 +1094,7 @@ http_interactions: string: |- - f9200506-64f3-406f-bfd9-ab684db1a27f + 8e780456-9563-4278-b824-0c022c6f17a3 123456789012 @@ -306,5 +1134,5 @@ http_interactions: http_version: - recorded_at: Thu, 12 Jan 2017 18:37:10 GMT + recorded_at: Wed, 18 Jan 2017 00:05:15 GMT recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/elb_loadbalancer-policies.yml b/fixtures/vcr_cassettes/elb_loadbalancer-policies.yml new file mode 100644 index 00000000..f219492d --- /dev/null +++ b/fixtures/vcr_cassettes/elb_loadbalancer-policies.yml @@ -0,0 +1,805 @@ +--- +http_interactions: +- request: + method: post + uri: https://elasticloadbalancing.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeLoadBalancers&Version=2012-06-01 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170203T182152Z + X-Amz-Content-Sha256: + - 236069f72bf74f0c7ddff0a34b0defa8a21d1d6a897e588764e1b2ff6319f94a + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170203/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=420a1983fc705a4c5b6538f91ac238151f47691ce5fba86e37d9e68cc1760972 + Content-Length: + - '47' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - a3197d87-ea3d-11e6-9654-6de86110cb8b + Content-Type: + - text/xml + Content-Length: + - '2800' + Vary: + - Accept-Encoding + Date: + - Fri, 03 Feb 2017 18:21:52 GMT + body: + encoding: UTF-8 + string: | + + + + + vpc-8f0019ea + Z2P70J7HTTTPLU + internet-facing + + + + + + AWSConsole-SSLNegotiationPolicy-lb-1-1484696260015 + ELBSecurityPolicy-2016-08 + + + + sa-east-1a + + lb-1-22921474.sa-east-1.elb.amazonaws.com + + + 123456789012 + default_elb_623306e1-2dd9-3d43-b10d-da5d3df14af2 + + lb-1 + + + + 80 + TCP + TCP + 80 + + + + + + 443 + arn:aws:iam::123456789012:server-certificate/zleslie-2016 + HTTP + HTTPS + 443 + + + AWSConsole-SSLNegotiationPolicy-lb-1-1484696260015 + + + + + 2 + 30 + 10 + 5 + TCP:80 + + 2017-01-12T21:54:33.700Z + + subnet-0af6436e + + + sg-0ce2ad68 + + lb-1-22921474.sa-east-1.elb.amazonaws.com + + + + + a3197d87-ea3d-11e6-9654-6de86110cb8b + + + http_version: + recorded_at: Fri, 03 Feb 2017 18:21:53 GMT +- request: + method: post + uri: https://elasticloadbalancing.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeLoadBalancerPolicies&LoadBalancerName=lb-1&PolicyNames.member.1=AWSConsole-SSLNegotiationPolicy-lb-1-1484696260015&Version=2012-06-01 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170203T182153Z + X-Amz-Content-Sha256: + - e0a7216d056916242a3b1e0c1056bda5bb7b012d579f5bf6c80440dc6fc9b74b + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170203/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=577eb3607ed0d205880c910c4711dfea21a144c58a75811205afc16ae2e4cbbc + Content-Length: + - '148' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - a39d2ca3-ea3d-11e6-bf84-c91820ddbccf + Content-Type: + - text/xml + Content-Length: + - '14741' + Vary: + - Accept-Encoding + Date: + - Fri, 03 Feb 2017 18:21:53 GMT + body: + encoding: UTF-8 + string: | + + + + + SSLNegotiationPolicyType + + + false + Protocol-TLSv1 + + + false + Protocol-SSLv3 + + + true + Protocol-TLSv1.1 + + + true + Protocol-TLSv1.2 + + + true + Server-Defined-Cipher-Order + + + true + ECDHE-ECDSA-AES128-GCM-SHA256 + + + true + ECDHE-RSA-AES128-GCM-SHA256 + + + true + ECDHE-ECDSA-AES128-SHA256 + + + true + ECDHE-RSA-AES128-SHA256 + + + true + ECDHE-ECDSA-AES128-SHA + + + true + ECDHE-RSA-AES128-SHA + + + false + DHE-RSA-AES128-SHA + + + true + ECDHE-ECDSA-AES256-GCM-SHA384 + + + true + ECDHE-RSA-AES256-GCM-SHA384 + + + true + ECDHE-ECDSA-AES256-SHA384 + + + true + ECDHE-RSA-AES256-SHA384 + + + true + ECDHE-RSA-AES256-SHA + + + true + ECDHE-ECDSA-AES256-SHA + + + true + AES128-GCM-SHA256 + + + true + AES128-SHA256 + + + true + AES128-SHA + + + true + AES256-GCM-SHA384 + + + true + AES256-SHA256 + + + true + AES256-SHA + + + false + DHE-DSS-AES128-SHA + + + false + CAMELLIA128-SHA + + + false + EDH-RSA-DES-CBC3-SHA + + + false + DES-CBC3-SHA + + + false + ECDHE-RSA-RC4-SHA + + + false + RC4-SHA + + + false + ECDHE-ECDSA-RC4-SHA + + + false + DHE-DSS-AES256-GCM-SHA384 + + + false + DHE-RSA-AES256-GCM-SHA384 + + + false + DHE-RSA-AES256-SHA256 + + + false + DHE-DSS-AES256-SHA256 + + + false + DHE-RSA-AES256-SHA + + + false + DHE-DSS-AES256-SHA + + + false + DHE-RSA-CAMELLIA256-SHA + + + false + DHE-DSS-CAMELLIA256-SHA + + + false + CAMELLIA256-SHA + + + false + EDH-DSS-DES-CBC3-SHA + + + false + DHE-DSS-AES128-GCM-SHA256 + + + false + DHE-RSA-AES128-GCM-SHA256 + + + false + DHE-RSA-AES128-SHA256 + + + false + DHE-DSS-AES128-SHA256 + + + false + DHE-RSA-CAMELLIA128-SHA + + + false + DHE-DSS-CAMELLIA128-SHA + + + false + ADH-AES128-GCM-SHA256 + + + false + ADH-AES128-SHA + + + false + ADH-AES128-SHA256 + + + false + ADH-AES256-GCM-SHA384 + + + false + ADH-AES256-SHA + + + false + ADH-AES256-SHA256 + + + false + ADH-CAMELLIA128-SHA + + + false + ADH-CAMELLIA256-SHA + + + false + ADH-DES-CBC3-SHA + + + false + ADH-DES-CBC-SHA + + + false + ADH-RC4-MD5 + + + false + ADH-SEED-SHA + + + false + DES-CBC-SHA + + + false + DHE-DSS-SEED-SHA + + + false + DHE-RSA-SEED-SHA + + + false + EDH-DSS-DES-CBC-SHA + + + false + EDH-RSA-DES-CBC-SHA + + + false + IDEA-CBC-SHA + + + false + RC4-MD5 + + + false + SEED-SHA + + + false + DES-CBC3-MD5 + + + false + DES-CBC-MD5 + + + false + RC2-CBC-MD5 + + + false + PSK-AES256-CBC-SHA + + + false + PSK-3DES-EDE-CBC-SHA + + + false + KRB5-DES-CBC3-SHA + + + false + KRB5-DES-CBC3-MD5 + + + false + PSK-AES128-CBC-SHA + + + false + PSK-RC4-SHA + + + false + KRB5-RC4-SHA + + + false + KRB5-RC4-MD5 + + + false + KRB5-DES-CBC-SHA + + + false + KRB5-DES-CBC-MD5 + + + false + EXP-EDH-RSA-DES-CBC-SHA + + + false + EXP-EDH-DSS-DES-CBC-SHA + + + false + EXP-ADH-DES-CBC-SHA + + + false + EXP-DES-CBC-SHA + + + false + EXP-RC2-CBC-MD5 + + + false + EXP-KRB5-RC2-CBC-SHA + + + false + EXP-KRB5-DES-CBC-SHA + + + false + EXP-KRB5-RC2-CBC-MD5 + + + false + EXP-KRB5-DES-CBC-MD5 + + + false + EXP-ADH-RC4-MD5 + + + false + EXP-RC4-MD5 + + + false + EXP-KRB5-RC4-SHA + + + false + EXP-KRB5-RC4-MD5 + + + AWSConsole-SSLNegotiationPolicy-lb-1-1484696260015 + + + + + a39d2ca3-ea3d-11e6-bf84-c91820ddbccf + + + http_version: + recorded_at: Fri, 03 Feb 2017 18:21:54 GMT +- request: + method: post + uri: https://elasticloadbalancing.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeTags&LoadBalancerNames.member.1=lb-1&Version=2012-06-01 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170203T182154Z + X-Amz-Content-Sha256: + - 667b7cad12519b7eb3be43722330c19a8cc170d896753a4bebaab30d44d93801 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170203/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=cfbd55d4b56f9d3ee409afbb96bf2f2689b99fb46bff671e115cc77676bf8aab + Content-Length: + - '70' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - a4577b98-ea3d-11e6-b071-8976e3b1df48 + Content-Type: + - text/xml + Content-Length: + - '523' + Date: + - Fri, 03 Feb 2017 18:21:54 GMT + body: + encoding: UTF-8 + string: | + + + + + lb-1 + + + lb-1 + Name + + + + + + + a4577b98-ea3d-11e6-b071-8976e3b1df48 + + + http_version: + recorded_at: Fri, 03 Feb 2017 18:21:55 GMT +- request: + method: post + uri: https://ec2.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeSubnets&SubnetId.1=subnet-0af6436e&Version=2016-11-15 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170203T182155Z + X-Amz-Content-Sha256: + - 2b7e0c9eaa89b98b70b3784bc41b7b21bda0b808db0c80cc18e8000626e0d142 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170203/sa-east-1/ec2/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=2606d3f239068af4734163a89061dbebb3c8557d62b7f6fd9a6af82d0ab207cc + Content-Length: + - '68' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - text/xml;charset=UTF-8 + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + Date: + - Fri, 03 Feb 2017 18:21:55 GMT + Server: + - AmazonEC2 + body: + encoding: UTF-8 + string: |- + + + 7bce9fbd-ef59-4676-8220-a000191c701a + + + subnet-0af6436e + available + vpc-8f0019ea + 172.31.0.0/20 + + 4090 + sa-east-1a + true + true + false + + + + http_version: + recorded_at: Fri, 03 Feb 2017 18:21:56 GMT +- request: + method: post + uri: https://ec2.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeSecurityGroups&GroupId.1=sg-0ce2ad68&Version=2016-11-15 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170203T182156Z + X-Amz-Content-Sha256: + - a598e638d441e5df353a1e19707221b07f439cbff6de6518dd3fe84683252b33 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170203/sa-east-1/ec2/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=b91b866254034dba0d813b7e6f4b7aef763e25f4ed4594be5abdf8f953703aa7 + Content-Length: + - '70' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - text/xml;charset=UTF-8 + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + Date: + - Fri, 03 Feb 2017 18:21:56 GMT + Server: + - AmazonEC2 + body: + encoding: UTF-8 + string: |- + + + 40f48c08-068a-4301-b937-a1241f6fac6c + + + 123456789012 + sg-0ce2ad68 + default_elb_623306e1-2dd9-3d43-b10d-da5d3df14af2 + ELB created security group used when no security group is specified during ELB creation - modifications could impact traffic to future ELBs + vpc-8f0019ea + + + tcp + 80 + 80 + + + + 0.0.0.0/0 + + + + + + + + + -1 + + + + 0.0.0.0/0 + + + + + + + + + + http_version: + recorded_at: Fri, 03 Feb 2017 18:21:57 GMT +- request: + method: post + uri: https://ec2.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeInstances&Filter.1.Name=tag%3AName&Filter.1.Value.1=web-1&Filter.2.Name=instance-state-name&Filter.2.Value.1=pending&Filter.2.Value.2=running&Version=2016-11-15 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170203T182157Z + X-Amz-Content-Sha256: + - c56603cbdf45c89429925da0c8e72355856b953cba3fe6d7726125c3c3c7b073 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170203/sa-east-1/ec2/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=2cf7273ae12875e8b21c76c7176357e3a574745b96ec091b94b2436b3fabaeb3 + Content-Length: + - '175' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - text/xml;charset=UTF-8 + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + Date: + - Fri, 03 Feb 2017 18:21:57 GMT + Server: + - AmazonEC2 + body: + encoding: UTF-8 + string: |- + + + 0917266e-49ff-4d6c-868d-1dd94f87c5ec + + + http_version: + recorded_at: Fri, 03 Feb 2017 18:21:58 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/elb_loadbalancer-policy-types.yml b/fixtures/vcr_cassettes/elb_loadbalancer-policy-types.yml new file mode 100644 index 00000000..2a717072 --- /dev/null +++ b/fixtures/vcr_cassettes/elb_loadbalancer-policy-types.yml @@ -0,0 +1,774 @@ +--- +http_interactions: +- request: + method: post + uri: https://elasticloadbalancing.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeLoadBalancerPolicyTypes&Version=2012-06-01 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170127T185336Z + X-Amz-Content-Sha256: + - cbc14f76b82758f16f8cd40ecf196ed1ad0a912e314aecb260063863f6c9b578 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170127/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=2d9154f0c5a58aefaf07aec50110a1cafb825ba7f8216707088f33bc16cf507f + Content-Length: + - '57' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - eacaa9b2-e4c1-11e6-874e-41a12b67ae98 + Content-Type: + - text/xml + Content-Length: + - '34444' + Vary: + - Accept-Encoding + Date: + - Fri, 27 Jan 2017 18:53:39 GMT + body: + encoding: UTF-8 + string: | + + + + + Listener policy that defines the ciphers and protocols that will be accepted by the load balancer. This policy can be associated only with HTTPS/SSL listeners. + SSLNegotiationPolicyType + + + A description for Protocol-TLSv1 + Protocol-TLSv1 + Boolean + false + ZERO_OR_ONE + + + A description for Protocol-SSLv3 + Protocol-SSLv3 + Boolean + false + ZERO_OR_ONE + + + A description for Protocol-TLSv1.1 + Protocol-TLSv1.1 + Boolean + false + ZERO_OR_ONE + + + A description for Protocol-TLSv1.2 + Protocol-TLSv1.2 + Boolean + false + ZERO_OR_ONE + + + The value of this attribute is the name of our sample policy (referring to our sample policy) + Reference-Security-Policy + String + ZERO_OR_ONE + + + The value true means the policy will follow the cipher order + Server-Defined-Cipher-Order + Boolean + false + ZERO_OR_ONE + + + A description for ECDHE-ECDSA-AES128-GCM-SHA256 + ECDHE-ECDSA-AES128-GCM-SHA256 + Boolean + false + ZERO_OR_ONE + + + A description for ECDHE-RSA-AES128-GCM-SHA256 + ECDHE-RSA-AES128-GCM-SHA256 + Boolean + false + ZERO_OR_ONE + + + A description for ECDHE-ECDSA-AES128-SHA256 + ECDHE-ECDSA-AES128-SHA256 + Boolean + false + ZERO_OR_ONE + + + A description for ECDHE-RSA-AES128-SHA256 + ECDHE-RSA-AES128-SHA256 + Boolean + false + ZERO_OR_ONE + + + A description for ECDHE-ECDSA-AES128-SHA + ECDHE-ECDSA-AES128-SHA + Boolean + false + ZERO_OR_ONE + + + A description for ECDHE-RSA-AES128-SHA + ECDHE-RSA-AES128-SHA + Boolean + false + ZERO_OR_ONE + + + A description for DHE-RSA-AES128-SHA + DHE-RSA-AES128-SHA + Boolean + false + ZERO_OR_ONE + + + A description for ECDHE-ECDSA-AES256-GCM-SHA384 + ECDHE-ECDSA-AES256-GCM-SHA384 + Boolean + false + ZERO_OR_ONE + + + A description for ECDHE-RSA-AES256-GCM-SHA384 + ECDHE-RSA-AES256-GCM-SHA384 + Boolean + false + ZERO_OR_ONE + + + A description for ECDHE-ECDSA-AES256-SHA384 + ECDHE-ECDSA-AES256-SHA384 + Boolean + false + ZERO_OR_ONE + + + A description for ECDHE-RSA-AES256-SHA384 + ECDHE-RSA-AES256-SHA384 + Boolean + false + ZERO_OR_ONE + + + A description for ECDHE-RSA-AES256-SHA + ECDHE-RSA-AES256-SHA + Boolean + false + ZERO_OR_ONE + + + A description for ECDHE-ECDSA-AES256-SHA + ECDHE-ECDSA-AES256-SHA + Boolean + false + ZERO_OR_ONE + + + A description for AES128-GCM-SHA256 + AES128-GCM-SHA256 + Boolean + false + ZERO_OR_ONE + + + A description for AES128-SHA256 + AES128-SHA256 + Boolean + false + ZERO_OR_ONE + + + A description for AES128-SHA + AES128-SHA + Boolean + false + ZERO_OR_ONE + + + A description for AES256-GCM-SHA384 + AES256-GCM-SHA384 + Boolean + false + ZERO_OR_ONE + + + A description for AES256-SHA256 + AES256-SHA256 + Boolean + false + ZERO_OR_ONE + + + A description for AES256-SHA + AES256-SHA + Boolean + false + ZERO_OR_ONE + + + A description for DHE-DSS-AES128-SHA + DHE-DSS-AES128-SHA + Boolean + false + ZERO_OR_ONE + + + A description for CAMELLIA128-SHA + CAMELLIA128-SHA + Boolean + false + ZERO_OR_ONE + + + A description for EDH-RSA-DES-CBC3-SHA + EDH-RSA-DES-CBC3-SHA + Boolean + false + ZERO_OR_ONE + + + A description for DES-CBC3-SHA + DES-CBC3-SHA + Boolean + false + ZERO_OR_ONE + + + A description for ECDHE-RSA-RC4-SHA + ECDHE-RSA-RC4-SHA + Boolean + false + ZERO_OR_ONE + + + A description for RC4-SHA + RC4-SHA + Boolean + false + ZERO_OR_ONE + + + A description for ECDHE-ECDSA-RC4-SHA + ECDHE-ECDSA-RC4-SHA + Boolean + false + ZERO_OR_ONE + + + A description for DHE-DSS-AES256-GCM-SHA384 + DHE-DSS-AES256-GCM-SHA384 + Boolean + false + ZERO_OR_ONE + + + A description for DHE-RSA-AES256-GCM-SHA384 + DHE-RSA-AES256-GCM-SHA384 + Boolean + false + ZERO_OR_ONE + + + A description for DHE-RSA-AES256-SHA256 + DHE-RSA-AES256-SHA256 + Boolean + false + ZERO_OR_ONE + + + A description for DHE-DSS-AES256-SHA256 + DHE-DSS-AES256-SHA256 + Boolean + false + ZERO_OR_ONE + + + A description for DHE-RSA-AES256-SHA + DHE-RSA-AES256-SHA + Boolean + false + ZERO_OR_ONE + + + A description for DHE-DSS-AES256-SHA + DHE-DSS-AES256-SHA + Boolean + false + ZERO_OR_ONE + + + A description for DHE-RSA-CAMELLIA256-SHA + DHE-RSA-CAMELLIA256-SHA + Boolean + false + ZERO_OR_ONE + + + A description for DHE-DSS-CAMELLIA256-SHA + DHE-DSS-CAMELLIA256-SHA + Boolean + false + ZERO_OR_ONE + + + A description for CAMELLIA256-SHA + CAMELLIA256-SHA + Boolean + false + ZERO_OR_ONE + + + A description for EDH-DSS-DES-CBC3-SHA + EDH-DSS-DES-CBC3-SHA + Boolean + false + ZERO_OR_ONE + + + A description for DHE-DSS-AES128-GCM-SHA256 + DHE-DSS-AES128-GCM-SHA256 + Boolean + false + ZERO_OR_ONE + + + A description for DHE-RSA-AES128-GCM-SHA256 + DHE-RSA-AES128-GCM-SHA256 + Boolean + false + ZERO_OR_ONE + + + A description for DHE-RSA-AES128-SHA256 + DHE-RSA-AES128-SHA256 + Boolean + false + ZERO_OR_ONE + + + A description for DHE-DSS-AES128-SHA256 + DHE-DSS-AES128-SHA256 + Boolean + false + ZERO_OR_ONE + + + A description for DHE-RSA-CAMELLIA128-SHA + DHE-RSA-CAMELLIA128-SHA + Boolean + false + ZERO_OR_ONE + + + A description for DHE-DSS-CAMELLIA128-SHA + DHE-DSS-CAMELLIA128-SHA + Boolean + false + ZERO_OR_ONE + + + A description for ADH-AES128-GCM-SHA256 + ADH-AES128-GCM-SHA256 + Boolean + false + ZERO_OR_ONE + + + A description for ADH-AES128-SHA + ADH-AES128-SHA + Boolean + false + ZERO_OR_ONE + + + A description for ADH-AES128-SHA256 + ADH-AES128-SHA256 + Boolean + false + ZERO_OR_ONE + + + A description for ADH-AES256-GCM-SHA384 + ADH-AES256-GCM-SHA384 + Boolean + false + ZERO_OR_ONE + + + A description for ADH-AES256-SHA + ADH-AES256-SHA + Boolean + false + ZERO_OR_ONE + + + A description for ADH-AES256-SHA256 + ADH-AES256-SHA256 + Boolean + false + ZERO_OR_ONE + + + A description for ADH-CAMELLIA128-SHA + ADH-CAMELLIA128-SHA + Boolean + false + ZERO_OR_ONE + + + A description for ADH-CAMELLIA256-SHA + ADH-CAMELLIA256-SHA + Boolean + false + ZERO_OR_ONE + + + A description for ADH-DES-CBC3-SHA + ADH-DES-CBC3-SHA + Boolean + false + ZERO_OR_ONE + + + A description for ADH-DES-CBC-SHA + ADH-DES-CBC-SHA + Boolean + false + ZERO_OR_ONE + + + A description for ADH-RC4-MD5 + ADH-RC4-MD5 + Boolean + false + ZERO_OR_ONE + + + A description for ADH-SEED-SHA + ADH-SEED-SHA + Boolean + false + ZERO_OR_ONE + + + A description for DES-CBC-SHA + DES-CBC-SHA + Boolean + false + ZERO_OR_ONE + + + A description for DHE-DSS-SEED-SHA + DHE-DSS-SEED-SHA + Boolean + false + ZERO_OR_ONE + + + A description for DHE-RSA-SEED-SHA + DHE-RSA-SEED-SHA + Boolean + false + ZERO_OR_ONE + + + A description for EDH-DSS-DES-CBC-SHA + EDH-DSS-DES-CBC-SHA + Boolean + false + ZERO_OR_ONE + + + A description for EDH-RSA-DES-CBC-SHA + EDH-RSA-DES-CBC-SHA + Boolean + false + ZERO_OR_ONE + + + A description for IDEA-CBC-SHA + IDEA-CBC-SHA + Boolean + false + ZERO_OR_ONE + + + A description for RC4-MD5 + RC4-MD5 + Boolean + false + ZERO_OR_ONE + + + A description for SEED-SHA + SEED-SHA + Boolean + false + ZERO_OR_ONE + + + A description for DES-CBC3-MD5 + DES-CBC3-MD5 + Boolean + false + ZERO_OR_ONE + + + A description for DES-CBC-MD5 + DES-CBC-MD5 + Boolean + false + ZERO_OR_ONE + + + A description for RC2-CBC-MD5 + RC2-CBC-MD5 + Boolean + false + ZERO_OR_ONE + + + A description for PSK-AES256-CBC-SHA + PSK-AES256-CBC-SHA + Boolean + false + ZERO_OR_ONE + + + A description for PSK-3DES-EDE-CBC-SHA + PSK-3DES-EDE-CBC-SHA + Boolean + false + ZERO_OR_ONE + + + A description for KRB5-DES-CBC3-SHA + KRB5-DES-CBC3-SHA + Boolean + false + ZERO_OR_ONE + + + A description for KRB5-DES-CBC3-MD5 + KRB5-DES-CBC3-MD5 + Boolean + false + ZERO_OR_ONE + + + A description for PSK-AES128-CBC-SHA + PSK-AES128-CBC-SHA + Boolean + false + ZERO_OR_ONE + + + A description for PSK-RC4-SHA + PSK-RC4-SHA + Boolean + false + ZERO_OR_ONE + + + A description for KRB5-RC4-SHA + KRB5-RC4-SHA + Boolean + false + ZERO_OR_ONE + + + A description for KRB5-RC4-MD5 + KRB5-RC4-MD5 + Boolean + false + ZERO_OR_ONE + + + A description for KRB5-DES-CBC-SHA + KRB5-DES-CBC-SHA + Boolean + false + ZERO_OR_ONE + + + A description for KRB5-DES-CBC-MD5 + KRB5-DES-CBC-MD5 + Boolean + false + ZERO_OR_ONE + + + A description for EXP-EDH-RSA-DES-CBC-SHA + EXP-EDH-RSA-DES-CBC-SHA + Boolean + false + ZERO_OR_ONE + + + A description for EXP-EDH-DSS-DES-CBC-SHA + EXP-EDH-DSS-DES-CBC-SHA + Boolean + false + ZERO_OR_ONE + + + A description for EXP-ADH-DES-CBC-SHA + EXP-ADH-DES-CBC-SHA + Boolean + false + ZERO_OR_ONE + + + A description for EXP-DES-CBC-SHA + EXP-DES-CBC-SHA + Boolean + false + ZERO_OR_ONE + + + A description for EXP-RC2-CBC-MD5 + EXP-RC2-CBC-MD5 + Boolean + false + ZERO_OR_ONE + + + A description for EXP-KRB5-RC2-CBC-SHA + EXP-KRB5-RC2-CBC-SHA + Boolean + false + ZERO_OR_ONE + + + A description for EXP-KRB5-DES-CBC-SHA + EXP-KRB5-DES-CBC-SHA + Boolean + false + ZERO_OR_ONE + + + A description for EXP-KRB5-RC2-CBC-MD5 + EXP-KRB5-RC2-CBC-MD5 + Boolean + false + ZERO_OR_ONE + + + A description for EXP-KRB5-DES-CBC-MD5 + EXP-KRB5-DES-CBC-MD5 + Boolean + false + ZERO_OR_ONE + + + A description for EXP-ADH-RC4-MD5 + EXP-ADH-RC4-MD5 + Boolean + false + ZERO_OR_ONE + + + A description for EXP-RC4-MD5 + EXP-RC4-MD5 + Boolean + false + ZERO_OR_ONE + + + A description for EXP-KRB5-RC4-SHA + EXP-KRB5-RC4-SHA + Boolean + false + ZERO_OR_ONE + + + A description for EXP-KRB5-RC4-MD5 + EXP-KRB5-RC4-MD5 + Boolean + false + ZERO_OR_ONE + + + + + Stickiness policy with session lifetimes controlled by the browser (user-agent) or a specified expiration period. This policy can be associated only with HTTP/HTTPS listeners. + LBCookieStickinessPolicyType + + + CookieExpirationPeriod + Long + ZERO_OR_ONE + + + + + Policy that controls authentication to back-end server(s) and contains one or more policies, such as an instance of a PublicKeyPolicyType. This policy can be associated only with back-end servers that are using HTTPS/SSL. + BackendServerAuthenticationPolicyType + + + PublicKeyPolicyName + PolicyName + ONE_OR_MORE + + + + + Policy that controls whether to include the IP address and port of the originating request for TCP messages. This policy operates on TCP listeners only. + ProxyProtocolPolicyType + + + ProxyProtocol + Boolean + ONE + + + + + Policy containing a list of public keys to accept when authenticating the back-end server(s). This policy cannot be applied directly to back-end servers or listeners but must be part of a BackendServerAuthenticationPolicyType. + PublicKeyPolicyType + + + PublicKey + String + ONE + + + + + Stickiness policy with session lifetimes controlled by the lifetime of the application-generated cookie. This policy can be associated only with HTTP/HTTPS listeners. + AppCookieStickinessPolicyType + + + CookieName + String + ONE + + + + + + + eacaa9b2-e4c1-11e6-874e-41a12b67ae98 + + + http_version: + recorded_at: Fri, 27 Jan 2017 18:53:45 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/no-elb-named-test.yml b/fixtures/vcr_cassettes/no-elb-named-test.yml index 32466017..8d0871fe 100644 --- a/fixtures/vcr_cassettes/no-elb-named-test.yml +++ b/fixtures/vcr_cassettes/no-elb-named-test.yml @@ -14,12 +14,12 @@ http_interactions: User-Agent: - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 X-Amz-Date: - - 20170112T183144Z + - 20170118T000503Z X-Amz-Content-Sha256: - 236069f72bf74f0c7ddff0a34b0defa8a21d1d6a897e588764e1b2ff6319f94a Authorization: - - AWS4-HMAC-SHA256 Credential=111111111111/20170112/sa-east-1/elasticloadbalancing/aws4_request, - SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=ba8de4cff157950664bcdd16a7b3d6fd3773d62111be884bbae93160cd94a6a9 + - AWS4-HMAC-SHA256 Credential=111111111111/20170118/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=9bf79b11636e51170f218e41a142545f70008c0dc887110643bfc9949e07cf1f Content-Length: - '47' Accept: @@ -30,24 +30,1109 @@ http_interactions: message: OK headers: X-Amzn-Requestid: - - 5f2d73df-d8f5-11e6-8071-ed1c1bc4d23b + - c35e7aad-dd11-11e6-9df5-d35ef90998c0 Content-Type: - text/xml Content-Length: - - '335' + - '2800' + Vary: + - Accept-Encoding Date: - - Thu, 12 Jan 2017 18:31:45 GMT + - Wed, 18 Jan 2017 00:05:04 GMT body: encoding: UTF-8 string: | - + + + vpc-8f0019ea + Z2P70J7HTTTPLU + internet-facing + + + + + + AWSConsole-SSLNegotiationPolicy-lb-1-1484696260015 + ELBSecurityPolicy-2016-08 + + + + sa-east-1a + + lb-1-22921474.sa-east-1.elb.amazonaws.com + + + 123456789012 + default_elb_623306e1-2dd9-3d43-b10d-da5d3df14af2 + + lb-1 + + + + 80 + TCP + TCP + 80 + + + + + + arn:aws:iam::123456789012:server-certificate/zleslie-2016 + 443 + HTTP + HTTPS + 443 + + + AWSConsole-SSLNegotiationPolicy-lb-1-1484696260015 + + + + + 2 + 30 + 10 + 5 + TCP:80 + + 2017-01-12T21:54:33.700Z + + subnet-0af6436e + + + sg-0ce2ad68 + + lb-1-22921474.sa-east-1.elb.amazonaws.com + + - 5f2d73df-d8f5-11e6-8071-ed1c1bc4d23b + c35e7aad-dd11-11e6-9df5-d35ef90998c0 http_version: - recorded_at: Thu, 12 Jan 2017 18:31:45 GMT + recorded_at: Wed, 18 Jan 2017 00:05:04 GMT +- request: + method: post + uri: https://elasticloadbalancing.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeLoadBalancerPolicies&LoadBalancerName=lb-1&Version=2012-06-01 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170118T000504Z + X-Amz-Content-Sha256: + - 2e001c9ec5bb4d2bd96c10f335b63c15c06b3d5c3c4d7e52e8324663d01b13f5 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170118/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=4780a38b956f307bcd8e9d1fb51c9d6fd3e70047ac606d2d4923e388c9a766b2 + Content-Length: + - '76' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - c41baf71-dd11-11e6-846d-71c7730df7c3 + Content-Type: + - text/xml + Content-Length: + - '29253' + Vary: + - Accept-Encoding + Date: + - Wed, 18 Jan 2017 00:05:04 GMT + body: + encoding: UTF-8 + string: | + + + + + SSLNegotiationPolicyType + + + false + Protocol-TLSv1 + + + false + Protocol-SSLv3 + + + true + Protocol-TLSv1.1 + + + true + Protocol-TLSv1.2 + + + true + Server-Defined-Cipher-Order + + + true + ECDHE-ECDSA-AES128-GCM-SHA256 + + + true + ECDHE-RSA-AES128-GCM-SHA256 + + + true + ECDHE-ECDSA-AES128-SHA256 + + + true + ECDHE-RSA-AES128-SHA256 + + + true + ECDHE-ECDSA-AES128-SHA + + + true + ECDHE-RSA-AES128-SHA + + + false + DHE-RSA-AES128-SHA + + + true + ECDHE-ECDSA-AES256-GCM-SHA384 + + + true + ECDHE-RSA-AES256-GCM-SHA384 + + + true + ECDHE-ECDSA-AES256-SHA384 + + + true + ECDHE-RSA-AES256-SHA384 + + + true + ECDHE-RSA-AES256-SHA + + + true + ECDHE-ECDSA-AES256-SHA + + + true + AES128-GCM-SHA256 + + + true + AES128-SHA256 + + + true + AES128-SHA + + + true + AES256-GCM-SHA384 + + + true + AES256-SHA256 + + + true + AES256-SHA + + + false + DHE-DSS-AES128-SHA + + + false + CAMELLIA128-SHA + + + false + EDH-RSA-DES-CBC3-SHA + + + false + DES-CBC3-SHA + + + false + ECDHE-RSA-RC4-SHA + + + false + RC4-SHA + + + false + ECDHE-ECDSA-RC4-SHA + + + false + DHE-DSS-AES256-GCM-SHA384 + + + false + DHE-RSA-AES256-GCM-SHA384 + + + false + DHE-RSA-AES256-SHA256 + + + false + DHE-DSS-AES256-SHA256 + + + false + DHE-RSA-AES256-SHA + + + false + DHE-DSS-AES256-SHA + + + false + DHE-RSA-CAMELLIA256-SHA + + + false + DHE-DSS-CAMELLIA256-SHA + + + false + CAMELLIA256-SHA + + + false + EDH-DSS-DES-CBC3-SHA + + + false + DHE-DSS-AES128-GCM-SHA256 + + + false + DHE-RSA-AES128-GCM-SHA256 + + + false + DHE-RSA-AES128-SHA256 + + + false + DHE-DSS-AES128-SHA256 + + + false + DHE-RSA-CAMELLIA128-SHA + + + false + DHE-DSS-CAMELLIA128-SHA + + + false + ADH-AES128-GCM-SHA256 + + + false + ADH-AES128-SHA + + + false + ADH-AES128-SHA256 + + + false + ADH-AES256-GCM-SHA384 + + + false + ADH-AES256-SHA + + + false + ADH-AES256-SHA256 + + + false + ADH-CAMELLIA128-SHA + + + false + ADH-CAMELLIA256-SHA + + + false + ADH-DES-CBC3-SHA + + + false + ADH-DES-CBC-SHA + + + false + ADH-RC4-MD5 + + + false + ADH-SEED-SHA + + + false + DES-CBC-SHA + + + false + DHE-DSS-SEED-SHA + + + false + DHE-RSA-SEED-SHA + + + false + EDH-DSS-DES-CBC-SHA + + + false + EDH-RSA-DES-CBC-SHA + + + false + IDEA-CBC-SHA + + + false + RC4-MD5 + + + false + SEED-SHA + + + false + DES-CBC3-MD5 + + + false + DES-CBC-MD5 + + + false + RC2-CBC-MD5 + + + false + PSK-AES256-CBC-SHA + + + false + PSK-3DES-EDE-CBC-SHA + + + false + KRB5-DES-CBC3-SHA + + + false + KRB5-DES-CBC3-MD5 + + + false + PSK-AES128-CBC-SHA + + + false + PSK-RC4-SHA + + + false + KRB5-RC4-SHA + + + false + KRB5-RC4-MD5 + + + false + KRB5-DES-CBC-SHA + + + false + KRB5-DES-CBC-MD5 + + + false + EXP-EDH-RSA-DES-CBC-SHA + + + false + EXP-EDH-DSS-DES-CBC-SHA + + + false + EXP-ADH-DES-CBC-SHA + + + false + EXP-DES-CBC-SHA + + + false + EXP-RC2-CBC-MD5 + + + false + EXP-KRB5-RC2-CBC-SHA + + + false + EXP-KRB5-DES-CBC-SHA + + + false + EXP-KRB5-RC2-CBC-MD5 + + + false + EXP-KRB5-DES-CBC-MD5 + + + false + EXP-ADH-RC4-MD5 + + + false + EXP-RC4-MD5 + + + false + EXP-KRB5-RC4-SHA + + + false + EXP-KRB5-RC4-MD5 + + + AWSConsole-SSLNegotiationPolicy-lb-1-1484696260015 + + + SSLNegotiationPolicyType + + + ELBSecurityPolicy-2016-08 + Reference-Security-Policy + + + true + Protocol-TLSv1 + + + false + Protocol-SSLv3 + + + true + Protocol-TLSv1.1 + + + true + Protocol-TLSv1.2 + + + true + Server-Defined-Cipher-Order + + + true + ECDHE-ECDSA-AES128-GCM-SHA256 + + + true + ECDHE-RSA-AES128-GCM-SHA256 + + + true + ECDHE-ECDSA-AES128-SHA256 + + + true + ECDHE-RSA-AES128-SHA256 + + + true + ECDHE-ECDSA-AES128-SHA + + + true + ECDHE-RSA-AES128-SHA + + + false + DHE-RSA-AES128-SHA + + + true + ECDHE-ECDSA-AES256-GCM-SHA384 + + + true + ECDHE-RSA-AES256-GCM-SHA384 + + + true + ECDHE-ECDSA-AES256-SHA384 + + + true + ECDHE-RSA-AES256-SHA384 + + + true + ECDHE-RSA-AES256-SHA + + + true + ECDHE-ECDSA-AES256-SHA + + + true + AES128-GCM-SHA256 + + + true + AES128-SHA256 + + + true + AES128-SHA + + + true + AES256-GCM-SHA384 + + + true + AES256-SHA256 + + + true + AES256-SHA + + + false + DHE-DSS-AES128-SHA + + + false + CAMELLIA128-SHA + + + false + EDH-RSA-DES-CBC3-SHA + + + false + DES-CBC3-SHA + + + false + ECDHE-RSA-RC4-SHA + + + false + RC4-SHA + + + false + ECDHE-ECDSA-RC4-SHA + + + false + DHE-DSS-AES256-GCM-SHA384 + + + false + DHE-RSA-AES256-GCM-SHA384 + + + false + DHE-RSA-AES256-SHA256 + + + false + DHE-DSS-AES256-SHA256 + + + false + DHE-RSA-AES256-SHA + + + false + DHE-DSS-AES256-SHA + + + false + DHE-RSA-CAMELLIA256-SHA + + + false + DHE-DSS-CAMELLIA256-SHA + + + false + CAMELLIA256-SHA + + + false + EDH-DSS-DES-CBC3-SHA + + + false + DHE-DSS-AES128-GCM-SHA256 + + + false + DHE-RSA-AES128-GCM-SHA256 + + + false + DHE-RSA-AES128-SHA256 + + + false + DHE-DSS-AES128-SHA256 + + + false + DHE-RSA-CAMELLIA128-SHA + + + false + DHE-DSS-CAMELLIA128-SHA + + + false + ADH-AES128-GCM-SHA256 + + + false + ADH-AES128-SHA + + + false + ADH-AES128-SHA256 + + + false + ADH-AES256-GCM-SHA384 + + + false + ADH-AES256-SHA + + + false + ADH-AES256-SHA256 + + + false + ADH-CAMELLIA128-SHA + + + false + ADH-CAMELLIA256-SHA + + + false + ADH-DES-CBC3-SHA + + + false + ADH-DES-CBC-SHA + + + false + ADH-RC4-MD5 + + + false + ADH-SEED-SHA + + + false + DES-CBC-SHA + + + false + DHE-DSS-SEED-SHA + + + false + DHE-RSA-SEED-SHA + + + false + EDH-DSS-DES-CBC-SHA + + + false + EDH-RSA-DES-CBC-SHA + + + false + IDEA-CBC-SHA + + + false + RC4-MD5 + + + false + SEED-SHA + + + false + DES-CBC3-MD5 + + + false + DES-CBC-MD5 + + + false + RC2-CBC-MD5 + + + false + PSK-AES256-CBC-SHA + + + false + PSK-3DES-EDE-CBC-SHA + + + false + KRB5-DES-CBC3-SHA + + + false + KRB5-DES-CBC3-MD5 + + + false + PSK-AES128-CBC-SHA + + + false + PSK-RC4-SHA + + + false + KRB5-RC4-SHA + + + false + KRB5-RC4-MD5 + + + false + KRB5-DES-CBC-SHA + + + false + KRB5-DES-CBC-MD5 + + + false + EXP-EDH-RSA-DES-CBC-SHA + + + false + EXP-EDH-DSS-DES-CBC-SHA + + + false + EXP-ADH-DES-CBC-SHA + + + false + EXP-DES-CBC-SHA + + + false + EXP-RC2-CBC-MD5 + + + false + EXP-KRB5-RC2-CBC-SHA + + + false + EXP-KRB5-DES-CBC-SHA + + + false + EXP-KRB5-RC2-CBC-MD5 + + + false + EXP-KRB5-DES-CBC-MD5 + + + false + EXP-ADH-RC4-MD5 + + + false + EXP-RC4-MD5 + + + false + EXP-KRB5-RC4-SHA + + + false + EXP-KRB5-RC4-MD5 + + + ELBSecurityPolicy-2016-08 + + + + + c41baf71-dd11-11e6-846d-71c7730df7c3 + + + http_version: + recorded_at: Wed, 18 Jan 2017 00:05:06 GMT +- request: + method: post + uri: https://elasticloadbalancing.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeTags&LoadBalancerNames.member.1=lb-1&Version=2012-06-01 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170118T000506Z + X-Amz-Content-Sha256: + - 667b7cad12519b7eb3be43722330c19a8cc170d896753a4bebaab30d44d93801 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170118/sa-east-1/elasticloadbalancing/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=0ea6cf257ecdba5e1ffd4c8436d097b9f3da6362df61f0f2eb94c7a089e0b0f7 + Content-Length: + - '70' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - c4f60a06-dd11-11e6-8071-ed1c1bc4d23b + Content-Type: + - text/xml + Content-Length: + - '523' + Date: + - Wed, 18 Jan 2017 00:05:06 GMT + body: + encoding: UTF-8 + string: | + + + + + lb-1 + + + lb-1 + Name + + + + + + + c4f60a06-dd11-11e6-8071-ed1c1bc4d23b + + + http_version: + recorded_at: Wed, 18 Jan 2017 00:05:07 GMT +- request: + method: post + uri: https://ec2.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeSubnets&SubnetId.1=subnet-0af6436e&Version=2016-11-15 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170118T000507Z + X-Amz-Content-Sha256: + - 2b7e0c9eaa89b98b70b3784bc41b7b21bda0b808db0c80cc18e8000626e0d142 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170118/sa-east-1/ec2/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=1772ea152c71cb110af735f4fe66fa1b9de6faf43dda82672361e6af2b1e77af + Content-Length: + - '68' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - text/xml;charset=UTF-8 + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + Date: + - Wed, 18 Jan 2017 00:05:07 GMT + Server: + - AmazonEC2 + body: + encoding: UTF-8 + string: |- + + + ddaf0e3d-020b-44c3-a804-6d42a22a41ce + + + subnet-0af6436e + available + vpc-8f0019ea + 172.31.0.0/20 + + 4090 + sa-east-1a + true + true + false + + + + http_version: + recorded_at: Wed, 18 Jan 2017 00:05:08 GMT +- request: + method: post + uri: https://ec2.sa-east-1.amazonaws.com/ + body: + encoding: UTF-8 + string: Action=DescribeSecurityGroups&GroupId.1=sg-0ce2ad68&Version=2016-11-15 + headers: + Content-Type: + - application/x-www-form-urlencoded; charset=utf-8 + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.1 x86_64-darwin15 + X-Amz-Date: + - 20170118T000508Z + X-Amz-Content-Sha256: + - a598e638d441e5df353a1e19707221b07f439cbff6de6518dd3fe84683252b33 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170118/sa-east-1/ec2/aws4_request, + SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=62982543b9ae12aa78865851d3460fb209e6582bb128dbf399bf4e0d3949cd02 + Content-Length: + - '70' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - text/xml;charset=UTF-8 + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + Date: + - Wed, 18 Jan 2017 00:05:08 GMT + Server: + - AmazonEC2 + body: + encoding: UTF-8 + string: |- + + + b67ec672-7bb5-4320-97c2-c622a0807216 + + + 123456789012 + sg-0ce2ad68 + default_elb_623306e1-2dd9-3d43-b10d-da5d3df14af2 + ELB created security group used when no security group is specified during ELB creation - modifications could impact traffic to future ELBs + vpc-8f0019ea + + + tcp + 80 + 80 + + + + 0.0.0.0/0 + + + + + + + + + -1 + + + + 0.0.0.0/0 + + + + + + + + + + http_version: + recorded_at: Wed, 18 Jan 2017 00:05:09 GMT recorded_with: VCR 3.0.3 diff --git a/lib/puppet/provider/elb_loadbalancer/v2.rb b/lib/puppet/provider/elb_loadbalancer/v2.rb index d83abd94..1a28df4b 100644 --- a/lib/puppet/provider/elb_loadbalancer/v2.rb +++ b/lib/puppet/provider/elb_loadbalancer/v2.rb @@ -122,7 +122,15 @@ def self.load_balancer_to_hash(region, load_balancer, ref_catalog=nil) 'instance_port' => listener.listener.instance_port, } result['ssl_certificate_id'] = listener.listener.ssl_certificate_id unless listener.listener.ssl_certificate_id.nil? - result['policy_names'] = listener.policy_names unless listener.policy_names.nil? or listener.policy_names.size == 0 + unless listener.policy_names.nil? or listener.policy_names.length == 0 + policy_names = listener.policy_names + end + + if policy_names + result['policy_names'] = policy_names + result['policies'] = load_balancer_policies(load_balancer.load_balancer_name, policy_names) + end + result end @@ -217,7 +225,7 @@ def self.load_balancer_to_hash(region, load_balancer, ref_catalog=nil) region: region, availability_zones: load_balancer.availability_zones, instances: instance_names, - listeners: listeners, + listeners: normalize_values(listeners), health_check: health_check, tags: tags, subnets: subnet_names, @@ -227,6 +235,102 @@ def self.load_balancer_to_hash(region, load_balancer, ref_catalog=nil) } end + def self.load_balancer_policies(load_balancer_name, policy_names) + results = elb_client.describe_load_balancer_policies( + load_balancer_name: load_balancer_name, + policy_names: policy_names + ) + + results.policy_descriptions.collect {|policy| + policy_attributes = {} + + next unless policy_names.include? policy.policy_name + + policy.policy_attribute_descriptions.each {|pa| + policy_attributes[pa.attribute_name] = pa.attribute_value + } + + { + policy.policy_type_name => policy_attributes + } + }.compact + end + + # Call for the policy type information and cache it + # + # This is not specific to the individual ELB, but rather this information + # pertains to which policy types may be managed, and furthermore, the + # attributes on those policy types as well as their data type, and + # (sometimes) their default values. + # + def self.load_balancer_policy_types + unless @load_balancer_policy_types + results = elb_client.describe_load_balancer_policy_types + @load_balancer_policy_types = results.policy_type_descriptions + end + @load_balancer_policy_types + end + + # Return a list of valid Policy Type strings + def self.valid_policy_types + self.load_balancer_policy_types.map {|p| + p.policy_type_name + } + end + + # Returns attribute information for the specified policy_type + def self.valid_policy_attributes(policy_type) + valid_policy_type_attributes = {} + + load_balancer_policy_type(policy_type).policy_attribute_type_descriptions.each {|p| + valid_policy_type_attributes[p.attribute_name] = {'attribute_type' => p.attribute_type } + + if p.respond_to? :default_value + valid_policy_type_attributes[p.attribute_type] = p.default_value + end + } + valid_policy_type_attributes + end + + def self.load_balancer_policy_type(policy_type) + load_balancer_policy_types.select {|p| + p.policy_type_name == policy_type + }[0] + end + + def self.default_policy_attributes(policy_type) + defaults = {} + + self.load_balancer_policy_type(policy_type).policy_attribute_type_descriptions.map {|p| + if p.respond_to? :default_value + defaults[p.attribute_name] = p.default_value + end + } + defaults + end + + # Takes two arrays of policy hashes + # + # Update the keys on each 'is' policy with that from the 'should' policy. + # Useful for determining if a two hashses are deemed identical, given a + # partial 'should' policy. + def self.merge_policies(is_policies, should_policies) + should_policies.collect do |should_policy| + is_policy = is_policies.select do |x| + should_policy.keys == x.keys + end.first + + unless is_policy + Puppet.warning('When comparing policies, a matching is_policy was not found') + next + end + + is_policy.collect do |k, v| + {k => v.merge(should_policy[k])} + end.first + end.compact + end + def exists? Puppet.debug("Checking if load balancer #{name} exists in region #{target_region}") @property_hash[:ensure] == :present @@ -411,11 +515,11 @@ def update_listeners load_balancer_name: resource[:name], listeners: listeners }) + end + # Process the listener policies and update if necessary resource[:listeners].each do |should_listener| - # If the resource does not specify a policy_name, do nothing - next unless should_listener['policy_names'] # Match the should_listener to the is_listener is_listener = if @property_hash[:listeners] @@ -426,15 +530,90 @@ def update_listeners {} end - # Update the working listener policy if requested - if should_listener['policy_names'] and should_listener['policy_names'] != is_listener['policy_names'] - Puppet.debug("Calling elb_client for policy_names update on #{resource[:name]}") - elb_client.set_load_balancer_policies_of_listener({ - load_balancer_name: resource[:name], - load_balancer_port: should_listener['load_balancer_port'], - policy_names: should_listener['policy_names'], - }) + generated_policy_names = [] + + # Proceed only if the current listener has requested a set of policies + + if should_listener['policies'] + should_listener['policies'].each do |should_policy| + + # Match the current listener policy to what currently exists + is_policy = is_listener['policies'].select do |x| + should_policy.keys == x.keys + end.first + + # Get a policy based on the existing policy and update its keys with + # that from what should be + merged_policy = is_policy.collect do |k, v| + {k => v.merge(should_policy[k])} + end.first + + # Skip proceeding if the merged policy alread matches what exists + next if merged_policy == is_policy + + # Create the new set of policies + merged_policy.each do |policy_type, policy_attributes| + merged_policy_attributes = policy_attributes.map do |attribute_name, attribute_value| + + # Reference-Security-Policy is the name in use by the default + # policy set on ELBs upon creation. As such, we skip this name, + # since we are in the process of modifying the ELB policy, we are + # no longer the default. + next if attribute_name == 'Reference-Security-Policy' + + { + attribute_name: attribute_name, + attribute_value: attribute_value.to_s + } + end.compact + + # Make new policy from merged + generated_policy_name = "PuppetManaged-#{Time.now.to_i}" + + Puppet.debug("Creating new policy #{generated_policy_name} for ELB #{resource[:name]}") + elb_client.create_load_balancer_policy( + load_balancer_name: resource[:name], + policy_attributes: merged_policy_attributes, + policy_name: generated_policy_name, + policy_type_name: policy_type + ) + + generated_policy_names << generated_policy_name + end + + end + + # TODO: BUG: It is possible to arrive at a situation where multiple + # policies currently exiset, and we have only updated one of them. In + # which case, the updated policy gets tracked, and below we st the + # active policies on the ELB only to what has been udpated, which would + # drop the policy that did exist, but an update was not requested. We + # should track the policy types that we are updating to ensure that + # when we set the policies for an ELB listener, that we also include + # the previous policiy that was not udpated as part of this run. + # + # Fixing this might be as simple as tracking the policy names that were + # captured on the ELB during the call to instances, and determining the + # type of those that existed. Once we have the name of the type that + # matches that which we create below, we can ensure that the names for + # policy types not being created below can be added to the array also. + # + # In any case, this is not a good situation, but will only come up when + # multiple policies are in use on a single ELB lisitener, and I have no + # idea how common that is. + + # Set the policies to what has been requested. + if generated_policy_names.length > 0 + Puppet.debug("Calling elb_client for policy_names update on #{resource[:name]} listener #{should_listener['load_balancer_port']}") + elb_client.set_load_balancer_policies_of_listener({ + load_balancer_name: resource[:name], + load_balancer_port: should_listener['load_balancer_port'], + policy_names: generated_policy_names, + }) + end + end + end end diff --git a/lib/puppet/type/elb_loadbalancer.rb b/lib/puppet/type/elb_loadbalancer.rb index 970aa249..8e846ddc 100644 --- a/lib/puppet/type/elb_loadbalancer.rb +++ b/lib/puppet/type/elb_loadbalancer.rb @@ -20,22 +20,114 @@ newproperty(:listeners, :array_matching => :all) do desc 'The ports and protocols the load balancer listens to.' + def insync?(is) - one = provider.class.normalize_values(is).collect do |obj| - obj.each { |k,v| obj[k] = v.to_s.downcase } + normal_is = provider.class.normalize_values(is).collect do |obj| + obj.each { |k,v| + if v.is_a? String + obj[k] = v.downcase + else + obj[k] = v + end + } + end + normal_should = provider.class.normalize_values(should).collect do |obj| + obj.each { |k,v| + if v.is_a? String + obj[k] = v.downcase + else + obj[k] = v + end + } + end + + # Handle the policy attribute comparison + # + # First, discoer the correct policy from the listener to compare, merge + # the desired policy_attributes into the existing policy_attributes to + # replace the existing keys with the desired keys, then compare the + # existing policy_attributes with merge result + # + matched_listeners = normal_should.collect do |should_listener| + # Identify the is_listener that matches this should_listener + is_listener_match = normal_is.select {|i| i['load_balancer_port'] == should_listener['load_balancer_port']} + unless is_listener_match + Puppet.debug("Mathing existing listener was not found for #{should_listener['load_balancer_port']}") + next + end + is_listener = is_listener_match.first + + if should_listener['ssl_certificate_id'] != is_listener['ssl_certificate_id'] + false + elsif should_listener['policies'] and is_listener['policies'] + is_policies = is_listener['policies'] + should_policies = should_listener['policies'] + + merged_policies = provider.class.merge_policies(is_policies, should_policies) + merged_policies == is_policies + else + is_listener == should_listener + end end - two = provider.class.normalize_values(should).collect do |obj| - obj.each { |k,v| obj[k] = v.to_s.downcase } + + if matched_listeners.length > 0 + not matched_listeners.include? false + else + false end - one == two end + + munge do |value| + provider.class.normalize_values(value) + end + validate do |value| value = [value] unless value.is_a?(Array) fail "you must provide a set of listeners for the load balancer" if value.empty? + + required_listener_keys = ['protocol', 'load_balancer_port', 'instance_protocol', 'instance_port'] + optional_keys = ['ssl_certificate_id', 'policies'] + all_keys = [required_listener_keys, optional_keys].flatten + value.each do |listener| - ['protocol', 'load_balancer_port', 'instance_protocol', 'instance_port'].each do |key| + required_listener_keys.each do |key| fail "listeners must include #{key}" unless listener.keys.include?(key) end + + listener.keys.each do |listener_key| + unless required_listener_keys.include? listener_key or optional_keys.include? listener_key + fail "unknown listener option #{listener_key}, must be one of #{all_keys}" + end + end + + if /HTTPS/i.match(listener['protocol']) + unless listener.keys.include? 'ssl_certificate_id' + fail 'When protocol is HTTPS, ssl_certificate_id must be specified' + end + end + + if listener.keys.include? 'policies' + listener['policies'].each do |listener_policies| + + listener_policies.each do |policy_type, policy_attributes| + unless provider.class.valid_policy_types.include? policy_type + fail "Invalid policy type #{policy_type}, must be one of #{provider.class.valid_policy_types}" + end + + next unless policy_attributes + + valid_attributes = provider.class.valid_policy_attributes(policy_type) + policy_attributes.each do |attribute_name, attribute_value| + unless valid_attributes.keys.include? attribute_name + fail "Invalid attribute #{attribute_name}, must be one of #{valid_attributes.keys}" + end + + end + end + + end + end + end end end diff --git a/spec/unit/provider/ec2_volume/v2_spec.rb b/spec/unit/provider/ec2_volume/v2_spec.rb index cfebd760..8209ea70 100644 --- a/spec/unit/provider/ec2_volume/v2_spec.rb +++ b/spec/unit/provider/ec2_volume/v2_spec.rb @@ -2,10 +2,6 @@ provider_class = Puppet::Type.type(:ec2_volume).provider(:v2) -ENV['AWS_ACCESS_KEY_ID'] = 'redacted' -ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' -ENV['AWS_REGION'] = 'sa-east-1' - describe provider_class do let(:resource) { diff --git a/spec/unit/provider/elb_loadbalancer/v2_spec.rb b/spec/unit/provider/elb_loadbalancer/v2_spec.rb index 01af67fd..891c7b60 100644 --- a/spec/unit/provider/elb_loadbalancer/v2_spec.rb +++ b/spec/unit/provider/elb_loadbalancer/v2_spec.rb @@ -46,7 +46,7 @@ describe 'exists?' do it 'should correctly report non-existent load balancers' do VCR.use_cassette('no-elb-named-test') do - provider.class.prefetch({"lb-1" => resource}) + provider.class.prefetch({"lb-2" => resource}) expect(provider.exists?).to be_falsy end end @@ -77,4 +77,191 @@ end + context 'listener handling' do + let(:resource_hash) { + { + name: 'lb-1', + instances: ['web-1'], + listeners: [ + { + 'instance_port' => '80', + 'instance_protocol' => 'TCP', + 'load_balancer_port' => '80', + 'protocol' => 'TCP' + }, + { + 'instance_port' => '443', + 'instance_protocol' => 'HTTP', + 'load_balancer_port' => '443', + 'protocol' => 'HTTPS', + 'ssl_certificate_id' => "arn:aws:iam::671116509167:server-certificate/zleslie-2016", + } + ], + availability_zones: ['sa-east-1a'], + region: 'sa-east-1', + } + } + + let(:resource) { Puppet::Type.type(:elb_loadbalancer).new(resource_hash) } + let(:provider) { resource.provider } + + describe 'policy' do + it 'should correctly detect existing policies' do + VCR.use_cassette('elb_loadbalancer-policies', :allow_playback_repeats => true) do + data = provider.class.prefetch({"lb-1" => resource}) + instance = data[0] + instance.flush + listeners = instance.listeners.dup + expect(listeners[0]['protocol']).to eq('TCP') + expect(listeners[0]['load_balancer_port']).to eq(80) + + expect(listeners[1]['policies'][0]['SSLNegotiationPolicyType']['Protocol-TLSv1.1']).to be(true) + + end + end + + end + end + + context 'merge_policies' do + let(:resource_hash) { + { + name: 'lb-1', + instances: ['web-1'], + listeners: [ + { + 'instance_port' => '80', + 'instance_protocol' => 'TCP', + 'load_balancer_port' => '80', + 'protocol' => 'TCP' + } + ], + availability_zones: ['sa-east-1a'], + region: 'sa-east-1', + } + } + + let(:resource) { + Puppet::Type.type(:elb_loadbalancer).new(resource_hash) + } + + let(:provider) { resource.provider } + + context 'when the is and should key values match' do + let(:is_policies) { + [ + { + "SSLNegotiationPolicyType"=> { + "Protocol-TLSv1.1" => false, + "Protocol-TLSv1.2" => true, + "ADH-AES128-GCM-SHA256"=>false, + "ADH-AES128-SHA"=>false, + "ADH-AES128-SHA256"=>false, + "ADH-AES256-GCM-SHA384"=>false, + "ADH-AES256-SHA"=>false, + "ADH-AES256-SHA256"=>false, + "ADH-CAMELLIA128-SHA"=>false, + "ADH-CAMELLIA256-SHA"=>false, + "ADH-DES-CBC-SHA"=>false, + } + } + ] + } + + let(:should_policies) { + [ + { + 'SSLNegotiationPolicyType' => { + 'Protocol-TLSv1.1' => false, + 'Protocol-TLSv1.2' => true, + } + } + ] + } + + it 'should be equal' do + merged_policies = provider.class.merge_policies(is_policies, should_policies) + expect(merged_policies).to eq(is_policies) + end + + end + + context 'when the is and should key values differ' do + let(:is_policies) { + [ + { + "SSLNegotiationPolicyType"=> { + "Protocol-TLSv1.1" => false, + "Protocol-TLSv1.2" => true, + "ADH-AES128-GCM-SHA256"=>false, + "ADH-AES128-SHA"=>false, + "ADH-AES128-SHA256"=>false, + "ADH-AES256-GCM-SHA384"=>false, + "ADH-AES256-SHA"=>false, + "ADH-AES256-SHA256"=>false, + "ADH-CAMELLIA128-SHA"=>false, + "ADH-CAMELLIA256-SHA"=>false, + "ADH-DES-CBC-SHA"=>false, + } + } + ] + } + + let(:should_policies) { + [ + { + 'SSLNegotiationPolicyType' => { + 'Protocol-TLSv1.1' => true, + 'Protocol-TLSv1.2' => true, + } + } + ] + } + + it 'should be unequal' do + merged_policies = provider.class.merge_policies(is_policies, should_policies) + expect(merged_policies).to_not eq(is_policies) + end + end + + context 'when the is and should key values differ' do + let(:is_policies) { + [ + { + "SSLNegotiationPolicyType"=> { + "Protocol-TLSv1.1" => false, + "Protocol-TLSv1.2" => true, + "ADH-AES128-GCM-SHA256"=>false, + "ADH-AES128-SHA"=>false, + "ADH-AES128-SHA256"=>false, + "ADH-AES256-GCM-SHA384"=>false, + "ADH-AES256-SHA"=>false, + "ADH-AES256-SHA256"=>false, + "ADH-CAMELLIA128-SHA"=>false, + "ADH-CAMELLIA256-SHA"=>false, + "ADH-DES-CBC-SHA"=>false, + } + } + ] + } + + let(:should_policies) { + [ + { + 'PublicKeyPolicyType' => { + 'PublicKey' => 'something goes here', + } + } + ] + } + + it 'should be unequal' do + merged_policies = provider.class.merge_policies(is_policies, should_policies) + expect(merged_policies).to_not eq(is_policies) + end + + end + + end + end diff --git a/spec/unit/puppet_x/puppetlabs/aws_spec.rb b/spec/unit/puppet_x/puppetlabs/aws_spec.rb new file mode 100644 index 00000000..8a5443c8 --- /dev/null +++ b/spec/unit/puppet_x/puppetlabs/aws_spec.rb @@ -0,0 +1,280 @@ +require 'spec_helper' +require_relative '../../../../lib/puppet_x/puppetlabs/aws.rb' + +describe 'PuppetX::Puppetlabs::Aws' do + let(:aws) { PuppetX::Puppetlabs::Aws } + + describe 'self.normalize_hash' do + + it 'should process a simple hash' do + hsh = { + 'cpu' => 1024, + :memory => '128' + } + + wanted = { + 'memory' => '128', + 'cpu' => '1024' + } + + expect(aws.normalize_hash(hsh)).to eq(aws.normalize_hash(wanted)) + expect(aws.normalize_hash(hsh)).to eq({"cpu"=>1024, "memory"=>128}) + end + + it 'should process a more complpicated hash' do + hsh = { + 'environment' => [ + { + 'name' => 'NONEMPTY', + 'value' => 'something goes here' + }, + { + 'value' => '1', + 'name' => 'one' + }, + { + 'value' => '2', + 'name' => 'two' + }, + ], + 'essential' => 'true', + 'port_mappings' => [ + { + 'protocol' => 'tcp', + 'container_port' => '8081', + 'host_port' => '8082', + }, { + 'host_port' => '8080', + 'container_port' => '8080', + 'protocol' => 'tcp', + } + ], + 'name' => 'zleslietesting', + 'memory' => '512', + 'image' => 'debian:jessie', + :cpu => '1023', + } + + wanted = { + 'cpu' => '1023', + 'environment' => [ + { + 'name' => 'two', + 'value' => '2' + }, + { + 'name' => 'one', + 'value' => 1 + }, + { + 'name' => 'NONEMPTY', + 'value' => 'something goes here' + }, + ], + 'image' => 'debian:jessie', + 'memory' => '512', + 'name' => 'zleslietesting', + 'essential' => true, + 'port_mappings' => [ + { + 'container_port' => '8081', + 'host_port' => '8082', + 'protocol' => 'tcp' + }, { + 'container_port' => '8080', + 'host_port' => '8080', + 'protocol' => 'tcp' + } + ], + } + normalized = aws.normalize_hash(hsh) + + expect(normalized).to eq(aws.normalize_hash(wanted)) + expect(normalized['environment'].class).to be(Array) + expect(normalized['essential'].class).to be(TrueClass) + expect(normalized['cpu'].class).to be(Fixnum) + end + + it 'should handle nested hashes correct' do + hsh = { + 'policy_attributes' => { + 'one' => true, + 'two' => false, + 'three' => false, + }, + 'policy_attributes2' => { + 'one' => 'true', + 'two' => false, + 'three' => 'false', + 'four' => { + 'eh' => 'bee', + 'cee' => 'true' + } + } + } + + wanted = { + 'policy_attributes' => { + 'one' => true, + 'two' => false, + 'three' => false, + }, + 'policy_attributes2' => { + 'one' => 'true', + 'two' => false, + 'three' => 'false', + 'four' => { + 'eh' => 'bee', + 'cee' => true + } + } + } + + normalized = aws.normalize_hash(hsh) + wanted_normalized = aws.normalize_hash(wanted) + + expect(normalized).to eq(aws.normalize_hash(wanted)) + expect(normalized['policy_attributes']['one']).to be(true) + expect(normalized['policy_attributes']['one']).to be(true) + + expect(normalized['policy_attributes2']['four']['cee']).to be(true) + expect(wanted_normalized['policy_attributes2']['four']['cee']).to be(true) + + end + end + + describe 'self.normalize_values' do + + ary = [ + { + "protocol"=>"HTTPS", + "load_balancer_port"=>443, + "instance_protocol"=>"HTTP", + "instance_port"=>80, + "ssl_certificate_id"=> + "arn:aws:iam::111111111111:server-certificate/zleslie-2016", + "policy_attributes"=> { + "Protocol-TLSv1"=>"false", + "Protocol-SSLv3"=>"false", + "Protocol-TLSv1.1"=>"true", + "Protocol-TLSv1.2"=>"true", + "Server-Defined-Cipher-Order"=>"true", + "ECDHE-ECDSA-AES128-GCM-SHA256"=>"true", + "ECDHE-RSA-AES128-GCM-SHA256"=>"true", + "ECDHE-ECDSA-AES128-SHA256"=>"true", + "ECDHE-RSA-AES128-SHA256"=>"true", + "ECDHE-ECDSA-AES128-SHA"=>"true", + "ECDHE-RSA-AES128-SHA"=>"true", + "DHE-RSA-AES128-SHA"=>"false", + "ECDHE-ECDSA-AES256-GCM-SHA384"=>"true", + "ECDHE-RSA-AES256-GCM-SHA384"=>"true", + "ECDHE-ECDSA-AES256-SHA384"=>"true", + "ECDHE-RSA-AES256-SHA384"=>"true", + "ECDHE-RSA-AES256-SHA"=>"true", + "ECDHE-ECDSA-AES256-SHA"=>"true", + "AES128-GCM-SHA256"=>"true", + "AES128-SHA256"=>"true", + "AES128-SHA"=>"true", + "AES256-GCM-SHA384"=>"true", + "AES256-SHA256"=>"true", + "AES256-SHA"=>"true", + "DHE-DSS-AES128-SHA"=>"false", + "CAMELLIA128-SHA"=>"false", + "EDH-RSA-DES-CBC3-SHA"=>"false", + "DES-CBC3-SHA"=>"false", + "ECDHE-RSA-RC4-SHA"=>"false", + "RC4-SHA"=>"false", + "ECDHE-ECDSA-RC4-SHA"=>"false", + "DHE-DSS-AES256-GCM-SHA384"=>"false", + "DHE-RSA-AES256-GCM-SHA384"=>"false", + "DHE-RSA-AES256-SHA256"=>"false", + "DHE-DSS-AES256-SHA256"=>"false", + "DHE-RSA-AES256-SHA"=>"false", + "DHE-DSS-AES256-SHA"=>"false", + "DHE-RSA-CAMELLIA256-SHA"=>"false", + "DHE-DSS-CAMELLIA256-SHA"=>"false", + "CAMELLIA256-SHA"=>"false", + "EDH-DSS-DES-CBC3-SHA"=>"false", + "DHE-DSS-AES128-GCM-SHA256"=>"false", + "DHE-RSA-AES128-GCM-SHA256"=>"false", + "DHE-RSA-AES128-SHA256"=>"false", + "DHE-DSS-AES128-SHA256"=>"false", + "DHE-RSA-CAMELLIA128-SHA"=>"false", + "DHE-DSS-CAMELLIA128-SHA"=>"false", + "ADH-AES128-GCM-SHA256"=>"false", + "ADH-AES128-SHA"=>"false", + "ADH-AES128-SHA256"=>"false", + "ADH-AES256-GCM-SHA384"=>"false", + "ADH-AES256-SHA"=>"false", + "ADH-AES256-SHA256"=>"false", + "ADH-CAMELLIA128-SHA"=>"false", + "ADH-CAMELLIA256-SHA"=>"false", + "ADH-DES-CBC3-SHA"=>"false", + "ADH-DES-CBC-SHA"=>"false", + "ADH-RC4-MD5"=>"false", + "ADH-SEED-SHA"=>"false", + "DES-CBC-SHA"=>"false", + "DHE-DSS-SEED-SHA"=>"false", + "DHE-RSA-SEED-SHA"=>"false", + "EDH-DSS-DES-CBC-SHA"=>"false", + "EDH-RSA-DES-CBC-SHA"=>"false", + "IDEA-CBC-SHA"=>"false", + "RC4-MD5"=>"false", + "SEED-SHA"=>"false", + "DES-CBC3-MD5"=>"false", + "DES-CBC-MD5"=>"false", + "RC2-CBC-MD5"=>"false", + "PSK-AES256-CBC-SHA"=>"false", + "PSK-3DES-EDE-CBC-SHA"=>"false", + "KRB5-DES-CBC3-SHA"=>"false", + "KRB5-DES-CBC3-MD5"=>"false", + "PSK-AES128-CBC-SHA"=>"false", + "PSK-RC4-SHA"=>"false", + "KRB5-RC4-SHA"=>"false", + "KRB5-RC4-MD5"=>"false", + "KRB5-DES-CBC-SHA"=>"false", + "KRB5-DES-CBC-MD5"=>"false", + "EXP-EDH-RSA-DES-CBC-SHA"=>"false", + "EXP-EDH-DSS-DES-CBC-SHA"=>"false", + "EXP-ADH-DES-CBC-SHA"=>"false", + "EXP-DES-CBC-SHA"=>"false", + "EXP-RC2-CBC-MD5"=>"false", + "EXP-KRB5-RC2-CBC-SHA"=>"false", + "EXP-KRB5-DES-CBC-SHA"=>"false", + "EXP-KRB5-RC2-CBC-MD5"=>"false", + "EXP-KRB5-DES-CBC-MD5"=>"false", + "EXP-ADH-RC4-MD5"=>"false", + "EXP-RC4-MD5"=>"false", + "EXP-KRB5-RC4-SHA"=>"false", + "EXP-KRB5-RC4-MD5"=>"false" + } + }, + { + "protocol"=>"TCP", + "load_balancer_port"=>80, + "instance_protocol"=>"TCP", + "instance_port"=>80 + } + ] + + it 'should not mangle up the nested hash' do + normalized = aws.normalize_values(ary) + expect(normalized.class).to be(Array) + + expect(normalized.length).to eq(2) + + expect(normalized[0].class).to be(Hash) + expect(normalized[0]['protocol']).to eq('HTTPS') + expect(normalized[0]['load_balancer_port']).to eq(443) + expect(normalized[0]['instance_port']).to eq(80) + expect(normalized[0]['policy_attributes'].class).to be(Hash) + expect(normalized[0]['policy_attributes']['Protocol-TLSv1']).to eq(false) + + expect(normalized[1].class).to be(Hash) + expect(normalized[1]['protocol']).to eq('TCP') + expect(normalized[1]['instance_port']).to eq(80) + + end + end + +end diff --git a/spec/unit/type/elb_loadbalancer_spec.rb b/spec/unit/type/elb_loadbalancer_spec.rb index 1630fe1b..5b5e566d 100644 --- a/spec/unit/type/elb_loadbalancer_spec.rb +++ b/spec/unit/type/elb_loadbalancer_spec.rb @@ -74,21 +74,183 @@ def elb_config }.to raise_error(Puppet::Error) end - it "should require a valid listener" do + context 'when validating a listener' do + context 'with all required keys are met' do + it 'should not fail' do + valid_listener = { + 'protocol' => 'https', + 'load_balancer_port' => 443, + 'instance_protocol' => 'tcp', + 'instance_port' => 80, + } - valid_listener = { - 'protocol' => 'tcp', - 'load_balancer_port' => 80, - 'instance_protocol' => 'tcp', - 'instance_port' => 80, - } + expect { + type_class.new({:name => 'sample', :listener => [valid_listener]}) + }.to raise_error(Puppet::Error) + end + end + + context 'when not all requried keys are met' do + it 'should fail' do + valid_listener = { + 'protocol' => 'https', + 'load_balancer_port' => 443, + 'instance_protocol' => 'tcp', + 'instance_port' => 80, + } - valid_listener.keys.each do |key| - listener = valid_listener.tap { |inner| inner.delete(key) } - expect { - type_class.new({:name => 'sample', :listener => [listener]}) - }.to raise_error(Puppet::Error) + valid_listener.keys.each do |key| + listener = valid_listener.tap { |inner| inner.delete(key) } + expect { + type_class.new({:name => 'sample', :listener => [listener]}) + }.to raise_error(Puppet::Error) + end + end end + + context 'with https listener' do + it 'should raise an error when no ssl_certificate_id is present' do + invalid_listener = { + 'protocol' => 'https', + 'load_balancer_port' => 443, + 'instance_protocol' => 'tcp', + 'instance_port' => 80, + } + + expect { + type_class.new(:name => 'sample', :listeners => [invalid_listener]) + }.to raise_error(Puppet::Error) + + end + + it 'should not raise an error when ssl_certificate_id is present' do + + valid_listener = { + 'protocol' => 'https', + 'load_balancer_port' => 443, + 'instance_protocol' => 'tcp', + 'instance_port' => 80, + 'ssl_certificate_id' => 'something/made/up' + } + + type_class.new(:name => 'sample', :listeners => [valid_listener]) + + expect { + type_class.new(:name => 'sample', :listeners => [valid_listener]) + }.to_not raise_error + end + end + + context 'when validating a listener policy' do + context 'a correct policy type is used' do + let(:listener) { + { + 'protocol' => 'https', + 'load_balancer_port' => 443, + 'instance_protocol' => 'tcp', + 'instance_port' => 80, + 'ssl_certificate_id' => 'something/made/up', + 'policies' => [ + { + 'SSLNegotiationPolicyType' => { + 'Protocol-TLSv1.1' => true, + } + } + ] + } + } + + it 'should validate' do + VCR.use_cassette('elb_loadbalancer-policy-types') do + expect { + type_class.new(:name => 'sample', :listeners => [listener]) + }.to_not raise_error + end + end + + context 'with invalid policy_attribtues' do + let(:listener) { + { + 'protocol' => 'https', + 'load_balancer_port' => 443, + 'instance_protocol' => 'tcp', + 'instance_port' => 80, + 'ssl_certificate_id' => 'something/made/up', + 'policies' => [ + { + 'SSLNegotiationPolicyType' => { + 'Protocol-TLSv0.9' => true, + } + } + ] + } + } + + it 'shoud not validate' do + VCR.use_cassette('elb_loadbalancer-policy-types') do + expect { + type_class.new(:name => 'sample', :listeners => [listener]) + }.to raise_error(Puppet::Error, /Invalid attribute/) + end + end + end + context 'with valid policy_attribtues' do + let(:listener) { + { + 'protocol' => 'https', + 'load_balancer_port' => 443, + 'instance_protocol' => 'tcp', + 'instance_port' => 80, + 'ssl_certificate_id' => 'something/made/up', + 'policies' => [ + { + 'SSLNegotiationPolicyType' => { + 'Protocol-TLSv1.1' => true, + 'Protocol-TLSv1.2' => true, + } + } + ] + } + } + it 'shoud validate' do + VCR.use_cassette('elb_loadbalancer-policy-types') do + expect { + type_class.new(:name => 'sample', :listeners => [listener]) + }.to_not raise_error + end + end + end + end + + context 'when an invalid policy type is set' do + let(:listener) { + { + 'protocol' => 'https', + 'load_balancer_port' => 443, + 'instance_protocol' => 'tcp', + 'instance_port' => 80, + 'ssl_certificate_id' => 'something/made/up', + 'policies' => [ + { + 'SSLNegotiationPolicyTypo' => { + 'Protocol-TLSv1.1' => true, + } + } + ] + } + } + + it 'should fail to validate' do + VCR.use_cassette('elb_loadbalancer-policy-types') do + expect { + type_class.new(:name => 'sample', :listeners => [listener]) + }.to raise_error(Puppet::Error, /Invalid policy type/) + end + end + + end + end + end it 'with a valid config it should not error' do From 6b5f9d27ffccb61c52d4ef07f3bfbec11a01b993 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Fri, 3 Feb 2017 11:51:01 -0800 Subject: [PATCH 57/72] Remove the securitygroup autorequire Without this change, it is not possible for security groups to use other security groups in a circular fashion due to creating a dependency loop in Puppet. As of the following commit, we no longer fail when a security group reference to another security group is not found, and instead simply throw a warning and drop the rule's inclusion in the rule set. bd0ac4b5e3e6df864dc04ac2318d0931b92de64e This now means that two security groups that have not yet been created, can be set to reference eachother, but will take two runs to be accurate. The first run to create the security groups, which will skip the rules that reference the currently nonexistent security group peers, and the second run to set the reference rules correctly. This now opens up the potential for circular dependencies. Ec2_securitygroup { ensure => present, region => 'us-west-2', vpc => 'Z', } ec2_securitygroup { 'first': description => 'first', ingress => [{'port' => '666', 'protocol' => 'tcp', 'security_group' => 'second'}], } ec2_securitygroup { 'second': description => 'second', ingress => [{'port' => '666', 'protocol' => 'tcp', 'security_group' => 'third'}], } ec2_securitygroup { 'third': description => 'thrid', ingress => [{'port' => '666', 'protocol' => 'tcp', 'security_group' => 'first'}], } This is a valid use case for security groups, but not in Puppet. This is now only possible to function in this way because we skip security group references that don't exist. However, this now means that the autorequire rules will create a circular dependency and fail to deploy. Here we remove the autorequire from the securitygroup type for other security group references to allow the above scenario to complete the catalog compile and manage the groups as needed completely. This solves both the case of creation of groups that don't exist, but are referenced in other security groups, as well as circular group references, without causing puppet to loop. --- lib/puppet/type/ec2_securitygroup.rb | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/lib/puppet/type/ec2_securitygroup.rb b/lib/puppet/type/ec2_securitygroup.rb index 1ef502fd..f1f4e61f 100644 --- a/lib/puppet/type/ec2_securitygroup.rb +++ b/lib/puppet/type/ec2_securitygroup.rb @@ -53,18 +53,8 @@ def insync?(is) end end - newproperty(:id) - - def should_autorequire?(rule) - !rule.nil? and rule.key? 'security_group' and rule['security_group'] != name - end - - autorequire(:ec2_securitygroup) do - rules = self[:ingress] - rules = [rules] unless rules.is_a?(Array) - rules.collect do |rule| - rule['security_group'] if should_autorequire?(rule) - end + newproperty(:id) do + desc 'The unique identifier for the security group' end autorequire(:ec2_vpc) do From b6401af1afb637577eb2cf547c00a868bab67e4a Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 30 Jan 2017 16:46:35 -0800 Subject: [PATCH 58/72] Enable volume management for ECS tasks Without this change, the volumes property is not property respected, either on modification, or on creation. Here we add the necessary logic to to set the volumes for a task upon creation of an ECS task, as well as modification after the initial creation. --- README.md | 12 ++++++- lib/puppet/provider/ecs_task_definition/v2.rb | 35 +++++++++++++++++-- lib/puppet/type/ecs_task_definition.rb | 9 +++-- 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9e51e94c..372abce1 100644 --- a/README.md +++ b/README.md @@ -1209,7 +1209,17 @@ above. *Required* The name of the task to manage. ##### `volumes` -An array of hashes to handle for the task. +An array of hashes to handle for the task. The hashes representing a volume should be in the following form: + +``` +{ + name => "StringNameForReference", + host => { + source_path => "/some/path", + }, +} + +``` ##### `replace_image` A boolean to turn off the replacement of container images. This enables Puppet diff --git a/lib/puppet/provider/ecs_task_definition/v2.rb b/lib/puppet/provider/ecs_task_definition/v2.rb index 5e359fb7..0f46b540 100644 --- a/lib/puppet/provider/ecs_task_definition/v2.rb +++ b/lib/puppet/provider/ecs_task_definition/v2.rb @@ -29,12 +29,23 @@ def self.instances task_role = /arn:aws:iam:.*:role\/(.*)/.match(task.task_role_arn)[1] end + if task.volumes + task_volumes = task.volumes.collect do |v| + { + name: v.name, + host: { + source_path: v.host.source_path + } + } + end + end + new({ name: task.family, ensure: :present, arn: task.task_definition_arn, revision: task.revision, - volumes: task.volumes, + volumes: task_volumes, container_definitions: container_defs, role: task_role }) @@ -106,10 +117,20 @@ def exists? end def create - ecs_client.register_task_definition({ + task = { family: resource[:name], container_definitions: self.class.serialize_container_definitions(resource[:container_definitions]), - }) + } + + if resource[:role] + task[:task_role_arn] = resource[:role] + end + + if resource[:volumes] + task[:volumes] = resource[:volumes] + end + + ecs_client.register_task_definition(task) @property_hash[:ensure] = :present end @@ -128,6 +149,10 @@ def role=(value) @property_flush[:role] = value end + def volumes=(value) + @property_flush[:volumes] = value + end + def flush Puppet.debug("Flushing ECS task definition for #{@property_hash[:name]}") @@ -161,6 +186,10 @@ def flush task[:task_role_arn] = resource[:role] end + if resource[:volumes] + task[:volumes] = resource[:volumes] + end + ecs_client.register_task_definition(task) end diff --git a/lib/puppet/type/ecs_task_definition.rb b/lib/puppet/type/ecs_task_definition.rb index 7fc8a43a..ce6cf2d0 100644 --- a/lib/puppet/type/ecs_task_definition.rb +++ b/lib/puppet/type/ecs_task_definition.rb @@ -28,8 +28,14 @@ desc 'Read-only revision number of the task definition' end - newproperty(:volumes) do + newproperty(:volumes, :array_matching => :all) do desc 'An array of hashes to handle for the task' + + def insync?(is) + one = provider.class.normalize_values(is) + two = provider.class.normalize_values(should) + one == two + end end newproperty(:container_definitions, :array_matching => :all) do @@ -41,7 +47,6 @@ def insync?(is) two = provider.class.normalize_values(is) one == two end - end newproperty(:role) do From 28ff58bcbc5ead06d428060c99625c5eb205eaf1 Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 1 Mar 2017 10:31:05 -0800 Subject: [PATCH 59/72] Reduce log verbosity for iam_role Without this change, iam_role is a bit noisy by using Puppet.info. To quiet up the log messages, here we change those log entries to be debug in place of info. This is more in line with the rest of the providers. --- lib/puppet/provider/iam_role/v2.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/puppet/provider/iam_role/v2.rb b/lib/puppet/provider/iam_role/v2.rb index f18bae91..f04ac221 100644 --- a/lib/puppet/provider/iam_role/v2.rb +++ b/lib/puppet/provider/iam_role/v2.rb @@ -32,12 +32,12 @@ def self.prefetch(resources) end def exists? - Puppet.info("Checking if IAM role #{name} exists") + Puppet.debug("Checking if IAM role #{name} exists") @property_hash[:ensure] == :present end def create - Puppet.info("Creating IAM role #{name}") + Puppet.debug("Creating IAM role #{name}") iam_client.create_role({ role_name: name, @@ -63,7 +63,7 @@ def get_iam_attached_policies_for_role(role) end def destroy - Puppet.info("Deleting IAM role #{name}") + Puppet.debug("Deleting IAM role #{name}") profiles = get_iam_instance_profiles_for_role(name) From 3bebc5a9a6947264130ec35ca2eba177ce9c9d0f Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Wed, 1 Mar 2017 16:36:48 -0800 Subject: [PATCH 60/72] Improve ELB listener detection Without this change, an ELB with no listeners causes a stacktrace due to an incorrect detection of existing listner. Here we adjust the logic to account for an empty array, by checking that we have at least 1 listener before we proceed inspecting the delta between the desired listeners and the actual listeners. --- lib/puppet/type/elb_loadbalancer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/puppet/type/elb_loadbalancer.rb b/lib/puppet/type/elb_loadbalancer.rb index 8e846ddc..356299f5 100644 --- a/lib/puppet/type/elb_loadbalancer.rb +++ b/lib/puppet/type/elb_loadbalancer.rb @@ -51,7 +51,7 @@ def insync?(is) matched_listeners = normal_should.collect do |should_listener| # Identify the is_listener that matches this should_listener is_listener_match = normal_is.select {|i| i['load_balancer_port'] == should_listener['load_balancer_port']} - unless is_listener_match + unless is_listener_match and is_listener_match.size > 0 Puppet.debug("Mathing existing listener was not found for #{should_listener['load_balancer_port']}") next end From 257612439c878aac93f6ead394d69250a2a17feb Mon Sep 17 00:00:00 2001 From: Andy Henroid Date: Thu, 2 Mar 2017 23:42:47 -0800 Subject: [PATCH 61/72] Add public DNS resolution and hostname properties to VPC --- README.md | 6 ++++++ lib/puppet/provider/ec2_vpc/v2.rb | 3 +++ lib/puppet/type/ec2_vpc.rb | 18 ++++++++++++++++ spec/unit/type/ec2_vpc_spec.rb | 34 +++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+) diff --git a/README.md b/README.md index 372abce1..c7a2b59d 100644 --- a/README.md +++ b/README.md @@ -898,6 +898,12 @@ block_devices => [ #####`instance_tenancy` *Optional* The supported tenancy options for instances in this VPC. This parameter is set at creation only; it is not affected by updates. Valid values are 'default', 'dedicated'. Defaults to 'default'. +#####`enable_dns_support` +*Optional* Whether or not DNS resolution is supported for the VPC. Valid values are 'true', 'false'. Defaults to 'true'. + +#####`enable_dns_hostnames` +*Optional* Whether or not instances launched in the VPC get public DNS hostnames. Valid values are 'true', 'false'. Defaults to 'true'. + #####`tags` *Optional* The tags to assign to the VPC. Accepts a 'key => value' hash of tags. diff --git a/lib/puppet/provider/ec2_vpc/v2.rb b/lib/puppet/provider/ec2_vpc/v2.rb index 63e5ea9c..eff8aa53 100644 --- a/lib/puppet/provider/ec2_vpc/v2.rb +++ b/lib/puppet/provider/ec2_vpc/v2.rb @@ -36,6 +36,7 @@ def self.prefetch(resources) def self.vpc_to_hash(region, vpc) name = name_from_tag(vpc) return {} unless name + ec2 = ec2_client(region) { name: name, id: vpc.vpc_id, @@ -43,6 +44,8 @@ def self.vpc_to_hash(region, vpc) instance_tenancy: vpc.instance_tenancy, ensure: :present, region: region, + enable_dns_support: ec2.describe_vpc_attribute({vpc_id: vpc.vpc_id, attribute: "enableDnsSupport"}).enable_dns_support.value, + enable_dns_hostnames: ec2.describe_vpc_attribute({vpc_id: vpc.vpc_id, attribute: "enableDnsHostnames"}).enable_dns_hostnames.value, tags: tags_for(vpc), dhcp_options: options_name_from_id(region, vpc.dhcp_options_id), } diff --git a/lib/puppet/type/ec2_vpc.rb b/lib/puppet/type/ec2_vpc.rb index 7221969f..6879b753 100644 --- a/lib/puppet/type/ec2_vpc.rb +++ b/lib/puppet/type/ec2_vpc.rb @@ -29,6 +29,24 @@ end end + newproperty(:enable_dns_support) do + desc 'Enable DNS support for this VPC.' + defaultto :true + newvalues(:true, :false) + def insync?(is) + is.to_s == should.to_s + end + end + + newproperty(:enable_dns_hostnames) do + desc 'Enable DNS hostnames for this VPC.' + defaultto :true + newvalues(:true, :false) + def insync?(is) + is.to_s == should.to_s + end + end + newproperty(:instance_tenancy) do desc 'The supported tenancy options for instances in this VPC.' defaultto 'default' diff --git a/spec/unit/type/ec2_vpc_spec.rb b/spec/unit/type/ec2_vpc_spec.rb index bbd55054..3a808666 100644 --- a/spec/unit/type/ec2_vpc_spec.rb +++ b/spec/unit/type/ec2_vpc_spec.rb @@ -16,6 +16,8 @@ :cidr_block, :dhcp_options, :region, + :enable_dns_support, + :enable_dns_hostnames, :instance_tenancy, ] end @@ -74,6 +76,38 @@ end end + it 'should default to dns support enabled' do + vpc = type_class.new({:name => 'sample'}) + expect(vpc[:enable_dns_support]).to eq(:true) + end + + it 'should default to dns hostnames enabled' do + vpc = type_class.new({:name => 'sample'}) + expect(vpc[:enable_dns_hostnames]).to eq(:true) + end + + it 'should not allow invalid values for dns support' do + expect { + type_class.new({:name => 'sample', :enable_dns_support => 'invalid'}) + }.to raise_error(Puppet::Error) + end + + it 'should not allow invalid values for dns hostnames' do + expect { + type_class.new({:name => 'sample', :enable_dns_hostnames => 'invalid'}) + }.to raise_error(Puppet::Error) + end + + it 'should allow valid values for dns support' do + vpc = type_class.new({:name => 'sample', :enable_dns_support => false}) + expect(vpc[:enable_dns_support]).to eq(:false) + end + + it 'should allow valid values for dns hostnames' do + vpc = type_class.new({:name => 'sample', :enable_dns_hostnames => false}) + expect(vpc[:enable_dns_hostnames]).to eq(:false) + end + it "should require tags to be a hash" do expect(type_class).to require_hash_for('tags') end From 61a76026d962909d3a3ffad896d7b336c30cf0aa Mon Sep 17 00:00:00 2001 From: Ian Shearin Date: Wed, 22 Feb 2017 11:17:10 -0800 Subject: [PATCH 62/72] Add support for private Route53 zones This adds functionality to the *route53_zone* resource type to manage private Route53 zones. Previously, only public zones could be created and destroyed, and there were no properties to manage. This also adds properties to discovery and management, including which VPCs to associate with private zones. Without these changes, only 100 zones could be managed. This updates the discovery API call to handle pagination to remove this limitation. The shared code to discover a VPC name by ID is changed to also allow discovery of a VPC ID by name. Internal structure is changed, but method parameters and returns retain previous functionality. Existing Route53 Zone tests are updated for these changes. --- README.md | 33 +++- fixtures/vcr_cassettes/create-zone.yml | 102 ++++++----- fixtures/vcr_cassettes/destory-zone.yml | 135 ++++++++++++++ fixtures/vcr_cassettes/destroy-zone.yml | 85 --------- fixtures/vcr_cassettes/init-zone.yml | 47 +++++ fixtures/vcr_cassettes/zone-exists.yml | 91 ++++++++++ fixtures/vcr_cassettes/zone-gone.yml | 47 +++++ fixtures/vcr_cassettes/zone-named.yml | 44 ----- fixtures/vcr_cassettes/zone-setup.yml | 85 --------- lib/puppet/provider/route53_zone/v2.rb | 202 +++++++++++++++++++-- lib/puppet/type/route53_zone.rb | 51 +++++- lib/puppet_x/puppetlabs/aws.rb | 54 +++++- spec/unit/provider/route53_zone/v2_spec.rb | 71 +++++--- spec/unit/type/route53_zone_spec.rb | 2 +- 14 files changed, 737 insertions(+), 312 deletions(-) create mode 100644 fixtures/vcr_cassettes/destory-zone.yml delete mode 100644 fixtures/vcr_cassettes/destroy-zone.yml create mode 100644 fixtures/vcr_cassettes/init-zone.yml create mode 100644 fixtures/vcr_cassettes/zone-exists.yml create mode 100644 fixtures/vcr_cassettes/zone-gone.yml delete mode 100644 fixtures/vcr_cassettes/zone-named.yml delete mode 100644 fixtures/vcr_cassettes/zone-setup.yml diff --git a/README.md b/README.md index c7a2b59d..3c4ca98d 100644 --- a/README.md +++ b/README.md @@ -1604,7 +1604,38 @@ All Route53 record types use the same parameters: #### Type: route53_zone #####`name` -*Required* The name of DNS zone group. This is the value of the AWS Name tag. +*Required* The name of DNS zone. This is the value of the AWS Name tag. +Trailing dot is optional. + +#####`id` +*Readonly* The AWS-generated alphanumeric ID of the zone, excluding the leading +"/hostedzone/". + +#####`is_private` +*Optional* True if the zone is private. Private zones require at least one +associated VPC. False if the zone is public (default). Set at creation and +cannot be changed. + +#####`record_count` +*Readonly* The AWS-reported number of records in the zone. Includes NS and SOA +records, so new zones start with two records. + +#####`comment` +*Optional* The comment on the zone. + +#####`tags` +*Optional* The tags for the zone. Accepts a 'key => value' hash of tags. +Excludes 'Name' tag. + +#####`vpcs` +*Conditional* For private zones, an array of at least one VPC. Each VPC is a +hash with the following keys: + +* `region` — *Required* Region the VPC is in. +* `vpc` — *Required* Name of the VPC. Puppet will display the VPC ID if it has + no name, but cannot manage VPC associations by ID; they must be named. + +For public zones, validated but not used. #### Type: s3_bucket diff --git a/fixtures/vcr_cassettes/create-zone.yml b/fixtures/vcr_cassettes/create-zone.yml index 74932d7f..f283d8c9 100644 --- a/fixtures/vcr_cassettes/create-zone.yml +++ b/fixtures/vcr_cassettes/create-zone.yml @@ -1,46 +1,56 @@ ---- - http_interactions: - - request: - method: post - uri: "https://route53.amazonaws.com/2013-04-01/hostedzone" - body: - encoding: UTF-8 - string: "\n devopscentral.com\n e1277a98454434fa3b1926676a89f73a\n\n" - headers: - Content-Type: - - "" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.1 ruby/2.1.1 x86_64-darwin13.0" - Date: - - "Tue, 07 Oct 2014 11:18:08 GMT" - X-Amzn-Authorization: - - "AWS3-HTTPS AWSAccessKeyId=redacted,Algorithm=HmacSHA256,Signature=redacted" - Content-Length: - - "210" - Accept: - - "*/*" - response: - status: - code: 201 - message: Created - headers: - X-Amzn-Requestid: - - "9d3fda45-4e13-11e4-b329-1de520403147" - Location: - - "https://route53.amazonaws.com/2013-04-01//hostedzone/Z1WG8P3OIYT9CD" - Content-Type: - - text/xml - Content-Length: - - "719" - Date: - - "Tue, 07 Oct 2014 11:18:07 GMT" - body: - encoding: UTF-8 - string: |- - - /hostedzone/Z1WG8P3OIYT9CDdevopscentral.com.e1277a98454434fa3b1926676a89f73a2/change/C373O1KYQE448GPENDING2014-10-07T11:18:07.818Zns-302.awsdns-37.comns-2003.awsdns-58.co.ukns-695.awsdns-22.netns-1045.awsdns-02.org - http_version: - recorded_at: "Tue, 07 Oct 2014 11:18:08 GMT" - recorded_with: "VCR 2.9.3" +--- +http_interactions: +- request: + method: post + uri: https://route53.amazonaws.com/2013-04-01/hostedzone + body: + encoding: UTF-8 + string: | + + devopscentral.com. + 513225554085e039e1670470be830f76 + + + + + headers: + Content-Type: + - '' + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.3 x86_64-darwin15 + X-Amz-Date: + - 20170228T211309Z + X-Amz-Content-Sha256: + - 6f431940676ccbff5e8b9307a606e65cd77b8db6ce2acf5136bb05e579e59ec4 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170228/us-east-1/route53/aws4_request, + SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=ffdd04d87467fed66def140e2ef1e961e1c5f8f2cb0110d3c10aa018c42df7a1 + Content-Length: + - '278' + Accept: + - "*/*" + response: + status: + code: 201 + message: Created + headers: + X-Amzn-Requestid: + - b493dfb7-fdfa-11e6-bd0d-9d511825b2e3 + Location: + - https://route53.amazonaws.com/2013-04-01/hostedzone/Z1Y34IMK1IXRPL + Content-Type: + - text/xml + Content-Length: + - '759' + Date: + - Tue, 28 Feb 2017 21:13:09 GMT + body: + encoding: UTF-8 + string: |- + + /hostedzone/Z1Y34IMK1IXRPLdevopscentral.com.513225554085e039e1670470be830f76false2/change/C3EI17BP95EZVSPENDING2017-02-28T21:13:09.561Zns-235.awsdns-29.comns-2001.awsdns-58.co.ukns-953.awsdns-55.netns-1398.awsdns-46.org + http_version: + recorded_at: Tue, 28 Feb 2017 21:13:09 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/destory-zone.yml b/fixtures/vcr_cassettes/destory-zone.yml new file mode 100644 index 00000000..37c64127 --- /dev/null +++ b/fixtures/vcr_cassettes/destory-zone.yml @@ -0,0 +1,135 @@ +--- +http_interactions: +- request: + method: get + uri: https://route53.amazonaws.com/2013-04-01/hostedzone + body: + encoding: ASCII-8BIT + string: '' + headers: + Content-Type: + - '' + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.3 x86_64-darwin15 + X-Amz-Date: + - 20170228T211702Z + X-Amz-Content-Sha256: + - e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170228/us-east-1/route53/aws4_request, + SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=238ee4b75f016e3141991f35e39fd6a3475aa1413fcf16d3503213f607d090ec + Content-Length: + - '0' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 3f68cc2f-fdfb-11e6-85dc-efa28d9c095d + Content-Type: + - text/xml + Content-Length: + - '467' + Date: + - Tue, 28 Feb 2017 21:17:01 GMT + body: + encoding: UTF-8 + string: |- + + /hostedzone/Z1Y34IMK1IXRPLdevopscentral.com.513225554085e039e1670470be830f76false2false100 + http_version: + recorded_at: Tue, 28 Feb 2017 21:17:02 GMT +- request: + method: get + uri: https://route53.amazonaws.com/2013-04-01/tags/hostedzone/Z1Y34IMK1IXRPL + body: + encoding: ASCII-8BIT + string: '' + headers: + Content-Type: + - '' + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.3 x86_64-darwin15 + X-Amz-Date: + - 20170228T211702Z + X-Amz-Content-Sha256: + - e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170228/us-east-1/route53/aws4_request, + SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=8ad2784f970bac3b29931c9ff40f61cb98827621709f45d93714c0e6ab821165 + Content-Length: + - '0' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 3fa20472-fdfb-11e6-9beb-f3d90ff717ab + Content-Type: + - text/xml + Content-Length: + - '253' + Date: + - Tue, 28 Feb 2017 21:17:02 GMT + body: + encoding: UTF-8 + string: |- + + hostedzoneZ1Y34IMK1IXRPL + http_version: + recorded_at: Tue, 28 Feb 2017 21:17:02 GMT +- request: + method: delete + uri: https://route53.amazonaws.com/2013-04-01/hostedzone/Z1Y34IMK1IXRPL + body: + encoding: ASCII-8BIT + string: '' + headers: + Content-Type: + - '' + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.3 x86_64-darwin15 + X-Amz-Date: + - 20170228T211702Z + X-Amz-Content-Sha256: + - e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170228/us-east-1/route53/aws4_request, + SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=f04c5c2c717a77844e41aa44cb752130b99b7f7aac3762e2dff156893fa640a7 + Content-Length: + - '0' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 3fd8cca3-fdfb-11e6-85dc-efa28d9c095d + Content-Type: + - text/xml + Content-Length: + - '260' + Date: + - Tue, 28 Feb 2017 21:17:02 GMT + body: + encoding: UTF-8 + string: |- + + /change/C30W1N7MWPU6JQPENDING2017-02-28T21:17:03.158Z + http_version: + recorded_at: Tue, 28 Feb 2017 21:17:03 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/destroy-zone.yml b/fixtures/vcr_cassettes/destroy-zone.yml deleted file mode 100644 index e9749db2..00000000 --- a/fixtures/vcr_cassettes/destroy-zone.yml +++ /dev/null @@ -1,85 +0,0 @@ ---- - http_interactions: - - request: - method: get - uri: "https://route53.amazonaws.com/2013-04-01/hostedzone" - body: - encoding: ASCII-8BIT - string: "" - headers: - Content-Type: - - "" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.1 ruby/2.1.1 x86_64-darwin13.0" - Date: - - "Tue, 07 Oct 2014 11:14:32 GMT" - X-Amzn-Authorization: - - "AWS3-HTTPS AWSAccessKeyId=redacted,Algorithm=HmacSHA256,Signature=redacted" - Content-Length: - - "0" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - "1c74a8fb-4e13-11e4-99af-4f00d7e73c16" - Content-Type: - - text/xml - Content-Length: - - "427" - Date: - - "Tue, 07 Oct 2014 11:14:31 GMT" - body: - encoding: UTF-8 - string: |- - - /hostedzone/Z3VO2BZMEQK733devopscentral.com.652b4c6ed3a75cf27e37f5736d7bf77c2false100 - http_version: - recorded_at: "Tue, 07 Oct 2014 11:14:32 GMT" - - request: - method: delete - uri: "https://route53.amazonaws.com/2013-04-01/hostedzone/Z3VO2BZMEQK733" - body: - encoding: ASCII-8BIT - string: "" - headers: - Content-Type: - - "" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.1 ruby/2.1.1 x86_64-darwin13.0" - Date: - - "Tue, 07 Oct 2014 11:14:32 GMT" - X-Amzn-Authorization: - - "AWS3-HTTPS AWSAccessKeyId=redacted,Algorithm=HmacSHA256,Signature=redacted" - Content-Length: - - "0" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - "1cc31742-4e13-11e4-87ed-e9f2af50b6a1" - Content-Type: - - text/xml - Content-Length: - - "260" - Date: - - "Tue, 07 Oct 2014 11:14:32 GMT" - body: - encoding: UTF-8 - string: |- - - /change/C2QMH6QN3T9U3PPENDING2014-10-07T11:14:32.249Z - http_version: - recorded_at: "Tue, 07 Oct 2014 11:14:33 GMT" - recorded_with: "VCR 2.9.3" diff --git a/fixtures/vcr_cassettes/init-zone.yml b/fixtures/vcr_cassettes/init-zone.yml new file mode 100644 index 00000000..fcb0ab40 --- /dev/null +++ b/fixtures/vcr_cassettes/init-zone.yml @@ -0,0 +1,47 @@ +--- +http_interactions: +- request: + method: get + uri: https://route53.amazonaws.com/2013-04-01/hostedzone + body: + encoding: ASCII-8BIT + string: '' + headers: + Content-Type: + - '' + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.3 x86_64-darwin15 + X-Amz-Date: + - 20170228T211308Z + X-Amz-Content-Sha256: + - e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170228/us-east-1/route53/aws4_request, + SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=d8e14f25ef48ea6585ab7e9a77ff81213025d12fb1d4169ded9a46c4fcb33656 + Content-Length: + - '0' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - b45db465-fdfa-11e6-bd0d-9d511825b2e3 + Content-Type: + - text/xml + Content-Length: + - '197' + Date: + - Tue, 28 Feb 2017 21:13:08 GMT + body: + encoding: UTF-8 + string: |- + + false100 + http_version: + recorded_at: Tue, 28 Feb 2017 21:13:09 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/zone-exists.yml b/fixtures/vcr_cassettes/zone-exists.yml new file mode 100644 index 00000000..92af6302 --- /dev/null +++ b/fixtures/vcr_cassettes/zone-exists.yml @@ -0,0 +1,91 @@ +--- +http_interactions: +- request: + method: get + uri: https://route53.amazonaws.com/2013-04-01/hostedzone + body: + encoding: ASCII-8BIT + string: '' + headers: + Content-Type: + - '' + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.3 x86_64-darwin15 + X-Amz-Date: + - 20170228T211309Z + X-Amz-Content-Sha256: + - e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170228/us-east-1/route53/aws4_request, + SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=2d5beb61691edb3fd999089c658e4f927c744bbfdd404df15bb7f47923424a34 + Content-Length: + - '0' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - b4d97421-fdfa-11e6-89ca-b79ffd12e9a5 + Content-Type: + - text/xml + Content-Length: + - '467' + Date: + - Tue, 28 Feb 2017 21:13:09 GMT + body: + encoding: UTF-8 + string: |- + + /hostedzone/Z1Y34IMK1IXRPLdevopscentral.com.513225554085e039e1670470be830f76false2false100 + http_version: + recorded_at: Tue, 28 Feb 2017 21:13:09 GMT +- request: + method: get + uri: https://route53.amazonaws.com/2013-04-01/tags/hostedzone/Z1Y34IMK1IXRPL + body: + encoding: ASCII-8BIT + string: '' + headers: + Content-Type: + - '' + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.3 x86_64-darwin15 + X-Amz-Date: + - 20170228T211309Z + X-Amz-Content-Sha256: + - e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170228/us-east-1/route53/aws4_request, + SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=0cf96433fe42d50910edc07db85c73c696f5257f91067ccb6be3149657415175 + Content-Length: + - '0' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - b50a216a-fdfa-11e6-9beb-f3d90ff717ab + Content-Type: + - text/xml + Content-Length: + - '253' + Date: + - Tue, 28 Feb 2017 21:13:10 GMT + body: + encoding: UTF-8 + string: |- + + hostedzoneZ1Y34IMK1IXRPL + http_version: + recorded_at: Tue, 28 Feb 2017 21:13:10 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/zone-gone.yml b/fixtures/vcr_cassettes/zone-gone.yml new file mode 100644 index 00000000..a6db70d7 --- /dev/null +++ b/fixtures/vcr_cassettes/zone-gone.yml @@ -0,0 +1,47 @@ +--- +http_interactions: +- request: + method: get + uri: https://route53.amazonaws.com/2013-04-01/hostedzone + body: + encoding: ASCII-8BIT + string: '' + headers: + Content-Type: + - '' + Accept-Encoding: + - '' + User-Agent: + - aws-sdk-ruby2/2.6.38 ruby/2.3.3 x86_64-darwin15 + X-Amz-Date: + - 20170228T211703Z + X-Amz-Content-Sha256: + - e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + Authorization: + - AWS4-HMAC-SHA256 Credential=111111111111/20170228/us-east-1/route53/aws4_request, + SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=f37578a47f3c948711ecf51dc972b91e3ed0e4bb786f33df43d65c7ff9e189ec + Content-Length: + - '0' + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Amzn-Requestid: + - 40175c09-fdfb-11e6-9beb-f3d90ff717ab + Content-Type: + - text/xml + Content-Length: + - '197' + Date: + - Tue, 28 Feb 2017 21:17:03 GMT + body: + encoding: UTF-8 + string: |- + + false100 + http_version: + recorded_at: Tue, 28 Feb 2017 21:17:03 GMT +recorded_with: VCR 3.0.3 diff --git a/fixtures/vcr_cassettes/zone-named.yml b/fixtures/vcr_cassettes/zone-named.yml deleted file mode 100644 index 5d1d137e..00000000 --- a/fixtures/vcr_cassettes/zone-named.yml +++ /dev/null @@ -1,44 +0,0 @@ ---- - http_interactions: - - request: - method: get - uri: "https://route53.amazonaws.com/2013-04-01/hostedzone" - body: - encoding: ASCII-8BIT - string: "" - headers: - Content-Type: - - "" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.1 ruby/2.1.1 x86_64-darwin13.0" - Date: - - "Tue, 07 Oct 2014 11:07:34 GMT" - X-Amzn-Authorization: - - "AWS3-HTTPS AWSAccessKeyId=redacted,Algorithm=HmacSHA256,Signature=redacted" - Content-Length: - - "0" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - "236cfba5-4e12-11e4-99af-4f00d7e73c16" - Content-Type: - - text/xml - Content-Length: - - "861" - Date: - - "Tue, 07 Oct 2014 11:07:33 GMT" - body: - encoding: UTF-8 - string: |- - - /hostedzone/Z3VO2BZMEQK733devopscentral.com.652b4c6ed3a75cf27e37f5736d7bf77c2/hostedzone/Z2RX2I1471TBSUdevopscentral.com.a7780e6f63b5122a1fe576fbb43fce7f2/hostedzone/Z2A78NH36PE988devopscentral.com.dc3285d28b76e9b0bd176ae33cfdcda22false100 - http_version: - recorded_at: "Tue, 07 Oct 2014 11:07:34 GMT" - recorded_with: "VCR 2.9.3" diff --git a/fixtures/vcr_cassettes/zone-setup.yml b/fixtures/vcr_cassettes/zone-setup.yml deleted file mode 100644 index cfc05240..00000000 --- a/fixtures/vcr_cassettes/zone-setup.yml +++ /dev/null @@ -1,85 +0,0 @@ ---- - http_interactions: - - request: - method: get - uri: "https://route53.amazonaws.com/2013-04-01/hostedzone" - body: - encoding: ASCII-8BIT - string: "" - headers: - Content-Type: - - "" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.1 ruby/2.1.1 x86_64-darwin13.0" - Date: - - "Tue, 07 Oct 2014 11:07:33 GMT" - X-Amzn-Authorization: - - "AWS3-HTTPS AWSAccessKeyId=redacted,Algorithm=HmacSHA256,Signature=redacted" - Content-Length: - - "0" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - "23007e4b-4e12-11e4-87ed-e9f2af50b6a1" - Content-Type: - - text/xml - Content-Length: - - "861" - Date: - - "Tue, 07 Oct 2014 11:07:32 GMT" - body: - encoding: UTF-8 - string: |- - - /hostedzone/Z3VO2BZMEQK733devopscentral.com.652b4c6ed3a75cf27e37f5736d7bf77c2/hostedzone/Z2RX2I1471TBSUdevopscentral.com.a7780e6f63b5122a1fe576fbb43fce7f2/hostedzone/Z2A78NH36PE988devopscentral.com.dc3285d28b76e9b0bd176ae33cfdcda22false100 - http_version: - recorded_at: "Tue, 07 Oct 2014 11:07:34 GMT" - - request: - method: get - uri: "https://route53.amazonaws.com/2013-04-01/hostedzone" - body: - encoding: ASCII-8BIT - string: "" - headers: - Content-Type: - - "" - Accept-Encoding: - - "" - User-Agent: - - "aws-sdk-ruby2/2.0.1 ruby/2.1.1 x86_64-darwin13.0" - Date: - - "Tue, 07 Oct 2014 11:07:34 GMT" - X-Amzn-Authorization: - - "AWS3-HTTPS AWSAccessKeyId=redacted,Algorithm=HmacSHA256,Signature=redacted" - Content-Length: - - "0" - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - X-Amzn-Requestid: - - "2335be28-4e12-11e4-87ed-e9f2af50b6a1" - Content-Type: - - text/xml - Content-Length: - - "861" - Date: - - "Tue, 07 Oct 2014 11:07:33 GMT" - body: - encoding: UTF-8 - string: |- - - /hostedzone/Z3VO2BZMEQK733devopscentral.com.652b4c6ed3a75cf27e37f5736d7bf77c2/hostedzone/Z2RX2I1471TBSUdevopscentral.com.a7780e6f63b5122a1fe576fbb43fce7f2/hostedzone/Z2A78NH36PE988devopscentral.com.dc3285d28b76e9b0bd176ae33cfdcda22false100 - http_version: - recorded_at: "Tue, 07 Oct 2014 11:07:34 GMT" - recorded_with: "VCR 2.9.3" diff --git a/lib/puppet/provider/route53_zone/v2.rb b/lib/puppet/provider/route53_zone/v2.rb index 82356941..8fae86a5 100644 --- a/lib/puppet/provider/route53_zone/v2.rb +++ b/lib/puppet/provider/route53_zone/v2.rb @@ -4,16 +4,69 @@ Puppet::Type.type(:route53_zone).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do confine feature: :aws + read_only(:id, :record_count, :is_private) + mk_resource_methods + def initialize(value={}) + super(value) + @property_flush = {} + end + def self.instances - response = route53_client.list_hosted_zones() - response.data.hosted_zones.collect do |zone| - new({ - name: zone.name, - ensure: :present, - }) + zones = [] + list_opts = {max_items: 100} + + # Loop over paginated API responses. + loop do + response = route53_client.list_hosted_zones() + + # Loop over each zone in one API response. + response.data.hosted_zones.collect do |zone| + # Basic zone data. + id = zone.id.sub(/^\/hostedzone\//, '') + zone_hash = { + name: zone.name, + ensure: :present, + is_private: zone.config['private_zone'], + id: id, + record_count: zone.resource_record_set_count, + comment: zone.config['comment'], + } + + # Zone tags. + tags = route53_client.list_tags_for_resource({ + resource_type: 'hostedzone', + resource_id: id, + }) + zone_hash[:tags] = self.tags_for(tags.resource_tag_set) + + # VPCs for private zones. + if zone_hash[:is_private] + zone_info = route53_client.get_hosted_zone(id: zone_hash[:id]) + # Yes, this method is actually named 'vp_cs'. + zone_hash[:vpcs] = zone_info.vp_cs.collect do |vpc| + region = vpc.vpc_region + name_tag = self.vpc_name_from_id(region, vpc.vpc_id) + + # Use ID for when there is no name. + vpc_name = name_tag ? name_tag : vpc.vpc_id + + { + 'region' => region, + 'vpc' => vpc_name, + } + end + end + + zones << new(zone_hash) + end + + break unless response.is_truncated + list_ops[:marker] = response.next_marker end + + zones end def self.prefetch(resources) @@ -32,19 +85,144 @@ def exists? def create reference = SecureRandom.hex Puppet.info("Creating zone #{name} with #{reference}") - route53_client.create_hosted_zone( + + zone = { name: name, caller_reference: reference, - ) + hosted_zone_config: { + comment: resource[:comment].to_s, + private_zone: resource[:is_private], + }, + } + + if resource[:is_private] + vpcs = discover_vpcs(resource[:vpcs]) + + fail "No VPCs found to associate with Route53 zone '#{name}'." if vpcs.empty? + + vpc_region = vpcs.first[:region] + vpc_name = vpcs.first[:name] + + # Add only first VPC to the creation request, as it only accepts one. + zone[:vpc] = { + vpc_region: vpcs.first[:region], + vpc_id: vpcs.first[:id], + } + + # This message is here to match those from additional VPCs, otherwise it + # looks like this one VPC was skipped. + Puppet.info("Associating VPC '#{vpc_name}' in #{vpc_region} with Route53 zone '#{name}'.") + end + + create_resp = route53_client.create_hosted_zone(zone) + @property_hash[:ensure] = :present + @property_hash[:id] = create_resp.hosted_zone.id.sub(/^\/hostedzone\//, '') + @property_hash[:record_count] = create_resp.hosted_zone.resource_record_set_count + + @property_flush[:tags] = resource[:tags] if resource[:tags] + + if resource[:is_private] + @property_hash[:vpcs] = [ + { + 'region' => vpc_region, + 'vpc' => vpc_name, + }, + ] + @property_flush[:vpcs] = resource[:vpcs] + end + end + + def discover_vpcs(vpcs) + vpcs.collect do |vpc| + region = vpc['region'] + vpc_id = self.class.vpc_id_from_name(region, vpc['vpc']) + + unless vpc_id + Puppet.warning("VPC '#{vpc['vpc']}' in #{vpc['region']} associated with Route53 zone '#{name}' not found.") + nil + next + end + + { + region: region, + name: vpc['vpc'], + id: vpc_id, + } + end.compact + end + + def comment=(value) + Puppet.debug("Updating comment for Route53 zone: #{name}") + route53_client.update_hosted_zone_comment( + id: @property_hash[:id], + comment: resource[:comment].to_s, + ) + end + + def tags=(value) + @property_flush[:tags] = value + end + + def vpcs=(value) + @property_flush[:vpcs] = value + end + + def flush + if @property_hash[:ensure] != :absent + if @property_flush.has_key?(:tags) + Puppet.debug("Updating tags for Route53 zone: #{name}") + change_request = { + resource_id: @property_hash[:id], + resource_type: 'hostedzone', + } + + updated_tags = (resource[:tags].to_a - @property_hash[:tags].to_a).to_h + unless updated_tags.empty? + change_request[:add_tags] = updated_tags.map { |k,v| {key: k, value: v} } + end + + removed_tags = @property_hash[:tags].keys - resource[:tags].keys + unless removed_tags.empty? + change_request[:remove_tag_keys] = removed_tags + end + + route53_client.change_tags_for_resource(change_request) + end + + if @property_flush.has_key?(:vpcs) and resource[:is_private] + Puppet.debug("Updating VPC associations for Route53 zone: #{name}") + + vpcs_add = discover_vpcs(resource[:vpcs] - @property_hash[:vpcs]) + vpcs_add.each do |vpc| + Puppet.info("Associating VPC '#{vpc[:name]}' in #{vpc[:region]} with Route53 zone '#{name}'.") + route53_client.associate_vpc_with_hosted_zone( + hosted_zone_id: @property_hash[:id], + vpc: { + vpc_region: vpc[:region], + vpc_id: vpc[:id], + } + ) + end + + vpcs_remove = discover_vpcs(@property_hash[:vpcs] - resource[:vpcs]) + vpcs_remove.each do |vpc| + Puppet.info("Disassociating VPC '#{vpc[:name]}' in #{vpc[:region]} from Route53 zone '#{name}'.") + route53_client.disassociate_vpc_from_hosted_zone( + hosted_zone_id: @property_hash[:id], + vpc: { + vpc_region: vpc[:region], + vpc_id: vpc[:id], + } + ) + end + end + end end def destroy Puppet.info("Deleting zone #{name}") - zones = route53_client.list_hosted_zones.data.hosted_zones.select { |zone| zone.name == name } - zones.each do |zone| - route53_client.delete_hosted_zone(id: zone.id) - end + route53_client.delete_hosted_zone(id: @property_hash[:id]) @property_hash[:ensure] = :absent end end diff --git a/lib/puppet/type/route53_zone.rb b/lib/puppet/type/route53_zone.rb index b60f558f..4b45adb0 100644 --- a/lib/puppet/type/route53_zone.rb +++ b/lib/puppet/type/route53_zone.rb @@ -1,12 +1,57 @@ +require 'puppet/property/boolean' +require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require_relative '../../puppet_x/puppetlabs/property/region.rb' + Puppet::Type.newtype(:route53_zone) do - @doc = 'Type representing an Route53 DNS zone.' + @doc = 'Type representing a Route53 DNS zone.' ensurable newparam(:name, namevar: true) do - desc 'The name of DNS zone group.' + desc 'The name of DNS zone.' + validate do |value| + fail Puppet::Error, 'Empty zone names are not allowed.' if value.empty? + end + + munge do |value| + # Ensure trailing dot. + value[-1] == '.' ? value : "#{value}." + end + end + + newproperty(:is_private, boolean: true, parent: Puppet::Property::Boolean) do + desc 'Whether the DNS zone is private or public. Private zones require associated VPCs.' + defaultto false + end + + newproperty(:id) do + desc 'AWS-generated ID of the DNS zone.' + end + + newproperty(:record_count) do + desc 'Number of records in the DNS zone.' + end + + newproperty(:comment) do + desc 'Comment on the DNS zone.' + end + + newproperty(:tags, parent: PuppetX::Property::AwsTag) do + desc 'Tags on the DNS zone.' + end + + newproperty(:vpcs, array_matching: :all, parent: PuppetX::Property::AwsRegion) do + desc 'For private zones, the associated VPCs.' + + # Validate any VPCs specified, even though only private zones use them. validate do |value| - fail Puppet::Error, 'Empty values are not allowed' if value == '' + # Validate region with PuppetX::Property::AwsRegion. + super(value['region']) + fail 'Missing VPC name.' if value['vpc'].nil? or value['vpc'].empty? + end + + def insync?(is) + is - should == should - is end end diff --git a/lib/puppet_x/puppetlabs/aws.rb b/lib/puppet_x/puppetlabs/aws.rb index d2db8287..cecf7a93 100644 --- a/lib/puppet_x/puppetlabs/aws.rb +++ b/lib/puppet_x/puppetlabs/aws.rb @@ -308,16 +308,54 @@ def self.has_name?(hash) !hash[:name].nil? && !hash[:name].empty? end + # Set up @vpcs. Always call this method before using @vpcs. @vpcs[region] + # keeps track of VPC IDs => names discovered per region, to prevent + # duplicate API calls. + def self.init_vpcs(region) + @vpcs ||= {} + @vpcs[region] ||= {} + end + + def self.vpc_id_from_name(region, vpc_name) + self.init_vpcs(region) + + unless @vpcs[region].key(vpc_name) + vpc_info = ec2_client(region).describe_vpcs(filters: [ + { + name: 'tag-key', + values: ['Name'], + }, + { + name: 'tag-value', + values: [vpc_name], + }, + ]) + + return nil if vpc_info.vpcs.empty? + + vpc_id = vpc_info.vpcs.first['vpc_id'] + @vpcs[region][vpc_id] = vpc_name + end + + @vpcs[region].key(vpc_name) + end + def self.vpc_name_from_id(region, vpc_id) - @vpcs ||= name_cache_hash do |ec2, key| - response = ec2.describe_vpcs(vpc_ids: [key]) - if response.data.vpcs.first.to_hash.keys.include?(:group_name) - response.data.vpcs.first.group_name - elsif response.data.vpcs.first.to_hash.keys.include?(:tags) - name_from_tag(response.data.vpcs.first) - end + self.init_vpcs(region) + + # Duplicate API calls will be made for unnamed VPCs, since they are + # saved with the name nil. + unless @vpcs[region][vpc_id] + response = ec2_client(region).describe_vpcs(vpc_ids: [vpc_id]) + @vpcs[region][vpc_id] = + if response.data.vpcs.first.to_hash.keys.include?(:group_name) + response.data.vpcs.first.group_name + elsif response.data.vpcs.first.to_hash.keys.include?(:tags) + name_from_tag(response.data.vpcs.first) + end end - @vpcs[[region, vpc_id]] + + @vpcs[region][vpc_id] end def self.security_group_name_from_id(region, group_id) diff --git a/spec/unit/provider/route53_zone/v2_spec.rb b/spec/unit/provider/route53_zone/v2_spec.rb index 2c5580ec..1d380ee0 100644 --- a/spec/unit/provider/route53_zone/v2_spec.rb +++ b/spec/unit/provider/route53_zone/v2_spec.rb @@ -2,61 +2,78 @@ provider_class = Puppet::Type.type(:route53_zone).provider(:v2) - describe provider_class do - context 'with the minimum params' do - let(:resource) { Puppet::Type.type(:route53_zone).new( - name: 'devopscentral.com.', - )} + context 'with the minimum params for a public zone' do + let(:resource_hash) { + { + name: 'devopscentral.com.', + } + } + + let(:resource) { + Puppet::Type.type(:route53_zone).new(resource_hash) + } + + let(:resources) { + { + 'devopscentral.com.' => resource, + } + } let(:provider) { resource.provider } - let(:instance) { provider.class.instances.first } it 'should be an instance of the ProviderV2' do expect(provider).to be_an_instance_of Puppet::Type::Route53_zone::ProviderV2 end describe 'self.prefetch' do - it 'exists' do - VCR.use_cassette('zone-setup') do - provider.class.instances - provider.class.prefetch({}) + it 'should find nothing to prefetch' do + VCR.use_cassette('init-zone') do + zones = provider.class.prefetch(resources) + expect(zones.empty?).to be_truthy end end end - describe 'exists?' do - it 'should correctly report non-existent zones' do - VCR.use_cassette('no-zone-named') do - expect(provider.exists?).to be_falsy + describe 'create' do + it 'should create the test zone' do + VCR.use_cassette('create-zone') do + provider.create + expect(provider.exists?).to be_truthy end end - it 'should correctly find existing zones' do - VCR.use_cassette('zone-named') do - expect(instance.exists?).to be_truthy + it 'should find the test zone with the correct properties after it is created' do + VCR.use_cassette('zone-exists') do + zones = provider.class.prefetch(resources) + zone = zones.first + expect(zone.exists?).to be_truthy + expect(zone.name).to eq('devopscentral.com.') + expect(zone.is_private).to be_falsy + expect(zone.tags.empty?).to be_truthy end end end - describe 'create' do - it 'should send a request to the EC2 API to create the zone' do - VCR.use_cassette('create-zone') do - expect(provider.create).to be_truthy + describe 'destory' do + it 'should destory the test zone' do + VCR.use_cassette('destory-zone') do + zones = provider.class.prefetch(resources) + zone = zones.first + zone.destroy + expect(zone.exists?).to be_falsy end end - end - describe 'destroy' do - it 'should send a request to the EC2 API to destroy the zone' do - VCR.use_cassette('destroy-zone') do - expect(provider.destroy).to be_truthy + it 'should not find the test zone after it is destroyed' do + VCR.use_cassette('zone-gone') do + zones = provider.class.prefetch(resources) + expect(zones.empty?).to be_truthy end end end - end end diff --git a/spec/unit/type/route53_zone_spec.rb b/spec/unit/type/route53_zone_spec.rb index 7e2a2f1a..8994882f 100644 --- a/spec/unit/type/route53_zone_spec.rb +++ b/spec/unit/type/route53_zone_spec.rb @@ -37,7 +37,7 @@ it 'should require a non-blank name' do expect { type_class.new({ name: '' }) - }.to raise_error(Puppet::Error, /Empty values are not allowed/) + }.to raise_error(Puppet::Error, /Empty zone names are not allowed/) end context 'with a valid name' do From c8ba03fe01c4af134a60e83a71889cddef086903 Mon Sep 17 00:00:00 2001 From: Andy Henroid Date: Sat, 4 Mar 2017 10:55:49 -0800 Subject: [PATCH 63/72] Minor update for README install instructions --- README.md | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 3c4ca98d..adce2bdc 100644 --- a/README.md +++ b/README.md @@ -45,29 +45,9 @@ to model the relationships between different components. ###Installing the aws module -1. Install the retries gem and the Amazon AWS Ruby SDK gem. +1. Install the retries gem and the Amazon AWS Ruby SDK gem, using the same Ruby used by Puppet. For Puppet 4.x and beyond, install the gems with this command: - * If you're using open source Puppet, the SDK gem should be installed into the same Ruby used by Puppet. Install the gems with these commands: - - `gem install aws-sdk-core` - - `gem install retries` - - * If you're running Puppet Enterprise, install both the gems with this command: - - `/opt/puppet/bin/gem install aws-sdk-core retries` - - * If you're running Puppet Enterprise 2015.2.0 or newer, install both the gems with this command: - - `/opt/puppetlabs/puppet/bin/gem install aws-sdk-core retries` - - This allows the gems to be used by the Puppet Enterprise Ruby. - - * If you're running [Puppet Server](https://github.com/puppetlabs/puppet-server), you need to make both gems available to JRuby with: - - `/opt/puppet/bin/puppetserver gem install aws-sdk-core retries` - - Once the gems are installed, restart Puppet Server. + `/opt/puppetlabs/puppet/bin/gem install aws-sdk-core retries` 2. Set these environment variables for your AWS access credentials: From 868a075930be5e9eb1add71bfa40109519ed8b52 Mon Sep 17 00:00:00 2001 From: apopp Date: Fri, 28 Oct 2016 13:51:37 -0400 Subject: [PATCH 64/72] created skeleton for the rds_db_subnet_group resource type defined standard properties and auto requires. Working on creating logic to enforce subnets from seperate AZ's last revision on type. Need to cleanup ensure settings, and make required properties enforced. beginning to write out provider Working on create and destroy options for resource. Should be able to report on values at this point. fix issue with missing PuppetX class removing fluff typo should have been using the method to hash working on subnet enumeration adding tags to resource hash fixing issues fixing more issues working version of resource. Need to achieve vpc name translation, and Subnet name resolution fixed vpc translation enumeration of first position subnet, need to fix to enumerate ALL subnets refined to return a hash record subnets resolving as hash Base resource generation achieved. Subnet name translation successful working out the config for the create action fixing missuse of param fixing issue with typo on method working version, resource created. Modifying v2 to allow for the update of the subnets value. Testing for description change now ability to destroy enabled. Doest not attempt to update when purged, does attempt to update at first build. fixing. cleanup. working version create,update,destroy. bug in create where update is attempted --- lib/puppet/provider/rds_db_subnet_group/v2.rb | 129 ++++++++++++++++++ lib/puppet/type/rds_db_subnet_group.rb | 63 +++++++++ 2 files changed, 192 insertions(+) create mode 100644 lib/puppet/provider/rds_db_subnet_group/v2.rb create mode 100644 lib/puppet/type/rds_db_subnet_group.rb diff --git a/lib/puppet/provider/rds_db_subnet_group/v2.rb b/lib/puppet/provider/rds_db_subnet_group/v2.rb new file mode 100644 index 00000000..b9a11530 --- /dev/null +++ b/lib/puppet/provider/rds_db_subnet_group/v2.rb @@ -0,0 +1,129 @@ +require_relative '../../../puppet_x/puppetlabs/aws.rb' + +Puppet::Type.type(:rds_db_subnet_group).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do + confine feature: :aws + + mk_resource_methods + + def self.instances() + Puppet.debug('Retrieving rds db subnets') + regions.collect do |region| + rds_subnets = [] + rds_client(region).describe_db_subnet_groups.each do |response| + response.data.db_subnet_groups.each do |db_subnet_group| + unless db_subnet_group.db_subnet_group_name =~ /^default$/ + hash = db_subnet_group_to_hash(region, db_subnet_group) + rds_subnets << new(hash) if hash[:name] + end + end + end + rds_subnets + end.flatten + end + + def self.prefetch(resources) + instances().each do |prov| + if resource = resources[prov.name] # rubocop:disable Lint/AssignmentInCondition + resource.provider = prov if resource[:region] == prov.region + end + end + end + + read_only(:vpc, :region ) + + def self.db_subnet_group_to_hash(region, db_subnet_group) + Puppet.debug("Checking for #{db_subnet_group.db_subnet_group_name} rds db subnet") + if vpc = db_subnet_group.vpc_id + name = vpc_name_from_id(region, vpc) + unless name.nil? + vpc_name = name + end + end + + subnet_data = db_subnet_group.subnets + subnet_ids = subnet_data.map{|x| x[:subnet_identifier]} + subnet_names = [] + subnet_response = ec2_client(region).describe_subnets(subnet_ids: subnet_ids) + subnet_response.data.subnets.each do |subnet| + subnet_name_tag = subnet.tags.detect { |tag| tag.key == 'Name'} + if subnet_name_tag + subnet_names << subnet_name_tag.value + end + end + + { + :ensure => :present, + :name => db_subnet_group.db_subnet_group_name, + :description => db_subnet_group.db_subnet_group_description, + :region => region, + :vpc => vpc_name, + :subnets => subnet_names, + } + end + + def exists? + Puppet.debug("Checking if rds db subnet #{name} exists in region #{target_region}") + @property_hash[:ensure] == :present + end + + def update + Puppet.info("Updating RDS db subnet #{name} in region #{target_region}") + subnets = resource[:subnets] + desc = resource[:description] + if ! subnets.nil? + subnets = [subnets] unless subnets.is_a?(Array) + modify_rds_subnet_group(resource[:region], name, subnets, desc) + end + end + + def create + Puppet.info("Deploying RDS db subnet #{name} in region #{target_region}") + subnets = subnet_ids_from_names(resource[:subnets] || []) + config = { + :db_subnet_group_name => resource[:name], + :db_subnet_group_description => resource[:description], + :subnet_ids => subnets, + } + ## Validate that subnets do not live in same AZ fail. + + rds_client(resource[:region]).create_db_subnet_group(config) + + @property_hash[:ensure] = :present + @property_hash[:subnets] = subnets + end + + def modify_rds_subnet_group(region, db_subnet_group_name, subnets, desc) + subnet_ids = subnet_ids_from_names(subnets || []) + rds_client(region).modify_db_subnet_group( + db_subnet_group_name: db_subnet_group_name, + subnet_ids: subnet_ids, + db_subnet_group_description: desc + ) + end + + def subnet_ids_from_names(names) + unless names.empty? + names = [names] unless names.is_a?(Array) + response = ec2_client(resource[:region]).describe_subnets(filters: [ + {name: 'tag:Name', values: names} + ]) + response.data.subnets.map(&:subnet_id) + else + [] + end + end + + def flush + update unless @property_hash[:ensure] == :absent + end + + def destroy + Puppet.info("Destroying rds db subnet #{name} in region #{target_region}") + config = { + db_subnet_group_name: name, + } + rds_client(resource[:region]).delete_db_subnet_group(config) + @property_hash[:ensure] = :absent + end + +end diff --git a/lib/puppet/type/rds_db_subnet_group.rb b/lib/puppet/type/rds_db_subnet_group.rb new file mode 100644 index 00000000..3180f504 --- /dev/null +++ b/lib/puppet/type/rds_db_subnet_group.rb @@ -0,0 +1,63 @@ +require_relative '../../puppet_x/puppetlabs/property/tag.rb' + +Puppet::Type.newtype(:rds_db_subnet_group) do + @doc = 'Type for the RDS DB subnet group which relies on the existence of corresponding ec2_subnets' + + ensurable + + #required + newparam(:name, namevar: true) do + desc 'The name of the RDS DB subnet group (db_subnet_group_name.)' + validate do |value| + fail 'RDS DB Subnet group must have a name' if value == '' + fail 'RDS DB Subnet group name cannot be default. It is a reserved name' if value =~ /^default$/ + fail 'RDS DB Subnet group name must be a string' unless value.is_a?(String) + end + end + + #required + newproperty(:description) do + desc 'a short description of the RDS DB subnet group (db_subnet_group_description)' + validate do |value| + fail 'description cannot be blank' if value == '' + fail 'description should be a String' unless value.is_a?(String) + end + end + + newproperty(:region) do + desc 'The region to deploy the RDS DB Subnet group, should be same region as associated rds_instance' + validate do |value| + fail 'region must not contain spaces' if value =~ /\s/ + fail 'region should be a String' unless value.is_a?(String) + end + end + + newproperty(:vpc) do + desc 'VPC to deploy the RDS DB Subnet group, should be same as VPC associated to rds_instance .' + validate do |value| + fail 'vpc should be a String' unless value.is_a?(String) + end + end + + #required + newproperty(:subnets, :array_matching => :all) do + desc 'The subnets in which to launch the RDS DB Subnet Group. DB subnet groups must contain at least one subnet in at least two AZs in the region.' + validate do |value| + fail 'subnets should be a String' unless value.is_a?(String) + end + def insync?(is) + is.to_set == should.to_set + end + end + + autorequire(:ec2_vpc_subnet) do + subnets = self[:subnets] + subnets.is_a?(Array) ? subnets : [subnets] + end + + autorequire(:ec2_vpc) do + self[:vpc] + end + +end + From 9b050b7c3ca404e3b9b984f4523477072c13af57 Mon Sep 17 00:00:00 2001 From: apopp Date: Tue, 8 Nov 2016 09:47:34 -0500 Subject: [PATCH 65/72] Working on tests --- lib/puppet/type/rds_db_subnet_group.rb | 2 +- spec/spec_helper_acceptance.rb | 7 +++++ .../provider/rds_db_subnet_group/v2_spec.rb | 28 +++++++++++++++++++ spec/unit/type/rds_db_subnet_group_spec.rb | 0 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 spec/unit/provider/rds_db_subnet_group/v2_spec.rb create mode 100644 spec/unit/type/rds_db_subnet_group_spec.rb diff --git a/lib/puppet/type/rds_db_subnet_group.rb b/lib/puppet/type/rds_db_subnet_group.rb index 3180f504..b9155c78 100644 --- a/lib/puppet/type/rds_db_subnet_group.rb +++ b/lib/puppet/type/rds_db_subnet_group.rb @@ -1,7 +1,7 @@ require_relative '../../puppet_x/puppetlabs/property/tag.rb' Puppet::Type.newtype(:rds_db_subnet_group) do - @doc = 'Type for the RDS DB subnet group which relies on the existence of corresponding ec2_subnets' + @doc = 'Type for the RDS DB subnet group which relies on the existence of corresponding ec2_subnets. Subnets are required to be in seperate AZs' ensurable diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb index b644c103..0dd849a1 100644 --- a/spec/spec_helper_acceptance.rb +++ b/spec/spec_helper_acceptance.rb @@ -140,6 +140,13 @@ def get_db_security_groups(name) response.data.db_security_groups end + def get_db_subnet_groups(name) + response = @rds_client.describe_db_subnet_groups( + db_subnet_group_name: name + ) + response.data.db_subnet_groups + end + def get_instances(name) response = @ec2_client.describe_instances(filters: [ {name: 'tag:Name', values: [name]}, diff --git a/spec/unit/provider/rds_db_subnet_group/v2_spec.rb b/spec/unit/provider/rds_db_subnet_group/v2_spec.rb new file mode 100644 index 00000000..96fc23d1 --- /dev/null +++ b/spec/unit/provider/rds_db_subnet_group/v2_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +provider_class = Puppet::Type.type(:rds_db_securitygroup).provider(:v2) + +ENV['AWS_ACCESS_KEY_ID'] = 'redacted' +ENV['AWS_SECRET_ACCESS_KEY'] = 'redacted' +ENV['AWS_REGION'] = 'sa-east-1' + +describe provider_class do + + let(:resource) { + Puppet::Type.type(:rds_db_subnet_group).new( + :name => "supercool_rds_subnet", + :ensure => 'present', + :description => 'RDS Test Subnet', + :subnets => [], + ) + } + + let(:provider) { resource.provider } + + let(:instance) { provider.class.instances.first } + + it 'should be an instance of the ProviderV2' do + expect(provider).to be_an_instance_of Puppet::Type::Rds_db_subnet_group::ProviderV2 + end + +end diff --git a/spec/unit/type/rds_db_subnet_group_spec.rb b/spec/unit/type/rds_db_subnet_group_spec.rb new file mode 100644 index 00000000..e69de29b From 247744dfbddc9f6f610dffa5e2b6ea4fe39efd62 Mon Sep 17 00:00:00 2001 From: Ben Ford Date: Thu, 9 Mar 2017 13:48:26 -0800 Subject: [PATCH 66/72] Looks like a typo here. --- lib/puppet_x/puppetlabs/aws_ingress_rules_parser.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/puppet_x/puppetlabs/aws_ingress_rules_parser.rb b/lib/puppet_x/puppetlabs/aws_ingress_rules_parser.rb index 2d19893f..0b81d70f 100644 --- a/lib/puppet_x/puppetlabs/aws_ingress_rules_parser.rb +++ b/lib/puppet_x/puppetlabs/aws_ingress_rules_parser.rb @@ -16,7 +16,7 @@ def initialize(rules) end # add default ports if missing unless new_rule.key? 'to_port' - if rule['protocol'] == 'icpm' + if rule['protocol'] == 'icmp' new_rule['from_port']= -1 new_rule['to_port']= -1 else From b6674f41df68d24b4422259affd8e158d99601ef Mon Sep 17 00:00:00 2001 From: Ian Shearin Date: Mon, 13 Mar 2017 09:14:57 -0700 Subject: [PATCH 67/72] Add missing backtick in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index adce2bdc..bddb624d 100644 --- a/README.md +++ b/README.md @@ -1519,7 +1519,7 @@ is deleted. Defaults to false. The name of an associated DB parameter group. Should be a string. This parameter is set at creation only; it is not affected by updates. -#####`restore_snapshot +#####`restore_snapshot` Specify the snapshot name to optionally trigger creating the RDS DB from a snapshot. #####`final_db_snapshot_identifier` From 46e7b05214681c3111b218ec54b0a02f46301069 Mon Sep 17 00:00:00 2001 From: Ian Shearin Date: Mon, 13 Mar 2017 14:16:11 -0700 Subject: [PATCH 68/72] Correct name of RDS tags property in readme This updates the readme to match the code. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bddb624d..afa808ef 100644 --- a/README.md +++ b/README.md @@ -1529,7 +1529,7 @@ that skip_final_snapshot must be set to false. #####`backup_retention_period` The number of days to retain backups. Defaults to 30 days. -#####`tags` +#####`rds_tags` *Optional* The tags for the instance. Accepts a 'key => value' hash of tags. #### Type: route53 From 73cabf6aacad4117e6a3f7e68121727ac7910fda Mon Sep 17 00:00:00 2001 From: Zach Leslie Date: Mon, 6 Mar 2017 17:26:08 -0800 Subject: [PATCH 69/72] Look for truncated results on ecs_task_definition resources Without this change, if the task family count is larger than the results AWS is willing to hand back in a single request, we don't correctly discover all of the resources. Here we add the logic we use elsewhere to ensure that all resources are collected. --- lib/puppet/provider/ecs_task_definition/v2.rb | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/puppet/provider/ecs_task_definition/v2.rb b/lib/puppet/provider/ecs_task_definition/v2.rb index 0f46b540..dc12910d 100644 --- a/lib/puppet/provider/ecs_task_definition/v2.rb +++ b/lib/puppet/provider/ecs_task_definition/v2.rb @@ -13,9 +13,22 @@ def initialize(value={}) def self.instances - task_families = ecs_client.list_task_definition_families({status: 'ACTIVE'}).families + task_families_results = ecs_client.list_task_definition_families({status: 'ACTIVE'}) + task_families = task_families_results.families + next_token = task_families_results.next_token + + while next_token + Puppet.debug('Results truncated, proceeding with discovery') + response = ecs_client.list_task_definition_families({ + status: 'ACTIVE', + next_token: next_token + }) + + response.families.each {|f| task_families << f } + next_token = response.next_token + end - results = task_families.collect do |task_family| + task_families.collect do |task_family| begin task = ecs_client.describe_task_definition({task_definition: task_family}).task_definition From 367c8f6dfe1c7b03fea62213157a733ae656e9c2 Mon Sep 17 00:00:00 2001 From: Chris Edester Date: Thu, 9 Mar 2017 14:53:52 -0500 Subject: [PATCH 70/72] Properly handle array of domain_name for ec2_vpc_dhcp_options --- README.md | 4 ++-- lib/puppet/provider/ec2_vpc_dhcp_options/v2.rb | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index afa808ef..7a25ad0c 100644 --- a/README.md +++ b/README.md @@ -919,7 +919,7 @@ The type of customer gateway. The only currently supported value --- and the def *Optional* The region in which to assign the DHCP option set. For valid values, see [AWS Regions](http://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region). #####`domain_name` -*Optional* The domain name for the DHCP options. This parameter is set at creation only; it is not affected by updates. Accepts any valid domain. +*Optional* The domain name for the DHCP options. This parameter is set at creation only; it is not affected by updates. Accepts an array or a single valid domain. An array is converted to a space separated list, as Linux supports. Other OSes may not support more than one according to Amazon. #####`domain_name_servers` *Optional* A list of domain name servers to use for the DHCP options set. This parameter is set at creation only; it is not affected by updates. Accepts an array of domain server names. @@ -1340,7 +1340,7 @@ Role path (optional) #####`policy_document` A string containing the IAM policy in JSON format which controls which entities may assume this role, e.g. the default: - + ``` { "Version": "2012-10-17", diff --git a/lib/puppet/provider/ec2_vpc_dhcp_options/v2.rb b/lib/puppet/provider/ec2_vpc_dhcp_options/v2.rb index ac8ef38c..5ecf11ed 100644 --- a/lib/puppet/provider/ec2_vpc_dhcp_options/v2.rb +++ b/lib/puppet/provider/ec2_vpc_dhcp_options/v2.rb @@ -39,13 +39,14 @@ def self.dhcp_option_to_hash(region, option) option.dhcp_configurations.each do |conf| config[conf[:key]] = conf[:values].collect(&:value) end + domain_name = config.keys.include?('domain-name') ? config['domain-name'].first.split(' ') : nil node_type = config.keys.include?('netbios-node-type') ? config['netbios-node-type'].first : nil { name: name_from_tag(option), id: option.dhcp_options_id, region: region, ensure: :present, - domain_name: config['domain-name'], + domain_name: domain_name, ntp_servers: config['ntp-servers'], domain_name_servers: config['domain-name-servers'], netbios_name_servers: config['netbios-name-servers'], @@ -66,6 +67,7 @@ def create options = [] ['domain_name', 'ntp_servers', 'domain_name_servers', 'netbios_name_servers', 'netbios_node_type'].each do |key| value = resource[key.to_sym] + value = value.join(' ') if key.eql?('domain_name') and value.is_a?(Array) options << {:key => key.gsub('_', '-'), :values => Array(value)} if value end From 437ac6201e4ca300ec94f83946c6e007c54af74e Mon Sep 17 00:00:00 2001 From: Ian Shearin Date: Mon, 20 Mar 2017 16:28:53 -0700 Subject: [PATCH 71/72] Drop Puppet Enterprise from metadata Without this change, tests are failing due to a Puppet Forge change. --- metadata.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/metadata.json b/metadata.json index 5a62f1a1..a2dea0bd 100644 --- a/metadata.json +++ b/metadata.json @@ -8,10 +8,6 @@ "project_page": "https://github.com/puppetlabs/puppetlabs-aws", "issues_url": "https://github.com/puppetlabs/puppetlabs-aws/issues", "requirements": [ - { - "name": "pe", - "version_requirement": ">=3.7.0 < 2015.4.0" - }, { "name": "puppet", "version_requirement": ">= 3.3.0" From 14a5c0315209547788c2be032e1788916869513c Mon Sep 17 00:00:00 2001 From: Mark Wilkinson Date: Tue, 13 Dec 2016 21:50:53 +0000 Subject: [PATCH 72/72] initial work adding elbv2 loadbalancer and targetgroup --- README.md | 79 +++++ lib/puppet/provider/elbv2_loadbalancer/v2.rb | 200 ++++++++++++ lib/puppet/provider/elbv2_targetgroup/v2.rb | 322 +++++++++++++++++++ lib/puppet/type/elbv2_loadbalancer.rb | 92 ++++++ lib/puppet/type/elbv2_targetgroup.rb | 164 ++++++++++ 5 files changed, 857 insertions(+) create mode 100644 lib/puppet/provider/elbv2_loadbalancer/v2.rb create mode 100644 lib/puppet/provider/elbv2_targetgroup/v2.rb create mode 100644 lib/puppet/type/elbv2_loadbalancer.rb create mode 100644 lib/puppet/type/elbv2_targetgroup.rb diff --git a/README.md b/README.md index 7a25ad0c..6e88bab3 100644 --- a/README.md +++ b/README.md @@ -308,6 +308,8 @@ You can use the aws module to audit AWS resources, launch autoscaling groups in * `ec2_securitygroup`: Sets up an EC2 security group. * `ec2_volume`: Sets up an EC2 EBS volume. * `elb_loadbalancer`: Sets up an ELB load balancer. +* `elbv2_loadbalancer`: Sets up an ELBv2 load balancer. +* `elbv2_targetgroup`: Sets up a ELBv2 target group. * `cloudwatch_alarm`: Sets up a Cloudwatch Alarm. * `ec2_autoscalinggroup`: Sets up an EC2 auto scaling group. * `ec2_elastic_ip`: Sets up an Elastic IP and its association. @@ -697,6 +699,83 @@ back- end instances. Accepts a hash with the following keys: ##### `snapshot_id` *Optional* The snapshot from which to create the volume. +#### Type: elbv2_loadbalancer + +#####`name` +*Required* The name of the load balancer. This is the value of the AWS Name tag. + +#####`region` +*Required* The region in which to launch the target group. For valid values, see [AWS Regions](http://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region). + +#####`listeners` + +#####`health_check` + +#####`subnets` + +#####`security_groups` + +#####`scheme` +#####`instancs` +#####`availability_zones` +#####`dns_name` + +#####`tags` +*Optional* The tags for the target group. This parameter is set at creation only; it is not affected by updates. Accepts a 'key => value' hash of tags. + +#### Type: elbv2_targetgroup + +#####`name` +*Required* The name of the target group. This is the value of the AWS Name tag. + +#####`region` +*Required* The region in which to launch the target group. For valid values, see [AWS Regions](http://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region). + +#####`protocol` +*Required* + +#####`port` +*Required* + +#####`vpc` +*Required* + +#####`health_check_success_codes` +*Optional* + +#####`health_check_path` +*Optional* + +#####`health_check_port` +*Optional* + +#####`health_check_protocol` +*Optional* + +#####`health_check_interval` +*Optional* + +#####`health_check_timeout` +*Optional* + +#####`healthy_threshold` +*Optional* + +#####`unhealthy_threshold` +*Optional* + +#####`deregistration_delay` +*Optional* + +#####`stickiness` +*Optional* + +#####`stickiness_duration` +*Optional* + +#####`tags` +*Optional* The tags for the target group. This parameter is set at creation only; it is not affected by updates. Accepts a 'key => value' hash of tags. + #### Type: cloudwatch_alarm ##### `name` diff --git a/lib/puppet/provider/elbv2_loadbalancer/v2.rb b/lib/puppet/provider/elbv2_loadbalancer/v2.rb new file mode 100644 index 00000000..ee67bc7a --- /dev/null +++ b/lib/puppet/provider/elbv2_loadbalancer/v2.rb @@ -0,0 +1,200 @@ +require_relative '../../../puppet_x/puppetlabs/aws.rb' + +Puppet::Type.type(:elbv2_loadbalancer).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do + + confine feature: :aws + + mk_resource_methods + + def self.instances() + Puppet.debug("Fetching ELBv2 Load Balancers (instances)") + regions.collect do |region| + vpc_names = {} + vpc_response = ec2_client(region).describe_vpcs() + vpc_response.data.vpcs.each do |vpc| + vpc_name = name_from_tag(vpc) + vpc_names[vpc.vpc_id] = vpc_name if vpc_name + end + + tg_names = {} + tg_response = elbv2_client(region).describe_target_groups() + tg_response.data.target_groups.each do |tg| + tg_names[tg.target_group_arn] = tg.target_group_name + end + + cert_names = {} + cert_response = iam_client(region).list_server_certificates() + cert_response.data.server_certificate_metadata_list.each do |cert| + cert_names[cert.arn] = cert.server_certificate_name + end + + load_balancers = [] + elbs(region) do |elb| + load_balancers << new(load_balancer_to_hash(region, elb, vpc_names, tg_names, cert_names) ) + end + + load_balancers + end.flatten + end + + def self.prefetch(resources) + instances.each do |prov| + Puppet.debug("Prefetching #{prov.name}") + if resource = resources[prov.name] # rubocop:disable Lint/AssignmentInCondition + if resource[:region] == prov.region + Puppet.debug("Updating resource for #{prov.name}") + resource.provider = prov + end + end + end + end + + def self.elbs(region) + region_client = elbv2_client(region) + + response = region_client.describe_load_balancers() + marker = response.next_marker + + Puppet.debug(response) + + response.load_balancers.each do |elb| + yield elb + end + + while marker + response = region_client.describe_load_balancers( { + marker: marker + }) + marker = response.next_marker + response.load_balancers.each do |elb| + yield elb + end + end + end + + def self.listeners(region,lbarn) + Puppet.debug("listeners('#{region}','#{lbarn}')") + region_client = elbv2_client(region) + + response = region_client.describe_listeners( { + load_balancer_arn: lbarn, + }) + marker = response.next_marker + + response.listeners.each do |listener| + yield listener + end + + while marker + response = region_client.describe_listeners( { + marker: marker + }) + marker = response.next_marker + response.listeners.each do |listener| + yield listener + end + end + end + + def self.rules(region,lstnrarn) + Puppet.debug("rules('#{region}','#{lstnrarn}')") + region_client = elbv2_client(region) + + response = region_client.describe_rules( { + listener_arn: lstnrarn, + }) + response.rules.each do |rule| + next if rule.priority == 'default' + yield rule + end + end + + def self.load_balancer_to_hash(region, elb, vpcs, tgs, certs) + Puppet.debug("vpc id: #{elb.vpc_id}, Vpcs: #{vpcs}") + + elblisteners = [ ] + listeners(region, elb.load_balancer_arn) do |listener| + elblisteners << listener_to_hash(region, listener, tgs, certs) + end + + Puppet.debug("Listeners: #{elblisteners}") + + attributes = { } + tags = { } + + { + ensure: :present, + name: elb.load_balancer_name, + arn: elb.load_balancer_arn, + region: region, + vpc: vpcs[elb.vpc_id], + scheme: elb.scheme, + listeners: elblisteners, + tags: tags, + } + end + + def self.listener_to_hash(region, listener, tgs, certs) + Puppet.debug("listener_to_hash: #{listener}") + + rules = [ ] + rules(region,listener.listener_arn) do |rule| + rules << rule_to_hash(rule,tgs) + end + + lstnr = { + protocol: listener.protocol, + port: listener.port, + ssl_policy: listener.ssl_policy, + default_target_group: tgs[ listener.default_actions.first.target_group_arn ], + } + lstnr[:rules] = rules unless rules.empty? + lstnr[:certificate] = certs[listener.certificates.first.certificate_arn] unless listener.certificates.empty? + + lstnr + end + + def self.rule_to_hash(rule,tgs) + Puppet.debug("rule_to_hash: #{rule}") + + rh = { + priority: rule.priority, + target_group: tgs[rule.actions.first.target_group_arn], + } + + rh[:path_match] = rule.conditions.first.values.first unless rule.conditions.empty? + + rh + end + + def exists? + @property_hash[:ensure] == :present + end + + def create + Puppet.debug("Creating load balancer #{name} in region #{target_region}") + + elbv2 = elbv2_client(target_region) + ec2 = ec2_client(target_region) + ec2_response = ec2.describe_subnets() + + config = { + load_balancer_name: name, + + scheme: scheme.nil? ? scheme : :'internet-facing', + } + + end + + def destroy + Puppet.debug("Deleting load balancer #{name} in region #{target_region}") + elbv2 = elbv2_client(target_region) + + Puppet.debug("Load Balancer Arn: ${@property_hash[:arn]}") + + elbv2.delete_load_balancer({ + load_balancer_arn: @property_hash[:arn], + }) + @property_hash[:ensure] = :absent + end +end diff --git a/lib/puppet/provider/elbv2_targetgroup/v2.rb b/lib/puppet/provider/elbv2_targetgroup/v2.rb new file mode 100644 index 00000000..64d2a69c --- /dev/null +++ b/lib/puppet/provider/elbv2_targetgroup/v2.rb @@ -0,0 +1,322 @@ +require_relative '../../../puppet_x/puppetlabs/aws.rb' + +Puppet::Type.type(:elbv2_targetgroup).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do + + confine feature: :aws + + mk_resource_methods + + def self.instances() + Puppet.debug('Fetching ELBv2 Target Groups (instances)') + regions.collect do |region| + vpc_names = {} + vpc_response = ec2_client(region).describe_vpcs() + vpc_response.data.vpcs.each do |vpc| + vpc_name = name_from_tag(vpc) + vpc_names[vpc.vpc_id] = vpc_name if vpc_name + end + target_groups = [] + tgs(region) do |tg| + target_groups << new(target_group_to_hash(region, tg, vpc_names) ) + end + + target_groups + end.flatten + end + + def self.prefetch(resources) + instances.each do |prov| + Puppet.debug("Prefetching #{prov.name}") + if resource = resources[prov.name] # rubocop:disable Lint/AssignmentInCondition + if resource[:region] == prov.region + Puppet.debug("Updating resource for #{prov.name}") + resource.provider = prov + resource[:port] = prov.port + resource[:protocol] = prov.protocol +# resource[:healthy_threshold] = prov.healthy_threshold +# resource[:unhealthy_threshold] = prov.unhealthy_threshold + resource[:health_check_path] = prov.health_check_path + resource[:health_check_port] = prov.health_check_port + resource[:health_check_protocol] = prov.health_check_protocol +# resource[:health_check_interval] = prov.health_check_interval + resource[:health_check_success_codes] = prov.health_check_success_codes +# resource[:health_check_timeout] = prov.health_check_timeout +# resource[:deregistration_delay] = prov.deregistration_delay + resource[:stickiness] = prov.stickiness +# resource[:stickiness_duration] = prov.stickiness_duration + resource[:tags] = prov.tags + end + end + end + end + + def self.tgs(region) + region_client = elbv2_client(region) + + response = region_client.describe_target_groups() + marker = response.next_marker + + response.target_groups.each do |tg| + yield tg + end + + while marker + response = region_client.describe_target_groups( { + marker: marker + }) + marker = response.next_marker + response.target_group_descriptions.each do |tg| + yield tg + end + end + end + + def self.target_group_to_hash(region, target_group, vpcs) + attributes = { } + response = elbv2_client(region).describe_target_group_attributes(target_group_arn: target_group.target_group_arn) + response.attributes.collect do |attribute| + attributes[attribute.key] = attribute.value + end + + tag_response = elbv2_client(region).describe_tags( + resource_arns: [ target_group.target_group_arn ] + ) + tags = {} + unless tag_response.tag_descriptions.nil? || tag_response.tag_descriptions.empty? + tag_response.tag_descriptions.first.tags.each do |tag| + tags[tag.key] = tag.value + end + end + + load_balancers = [] + + { + name: target_group.target_group_name, + arn: target_group.target_group_arn, + ensure: :present, + region: region, + vpc: vpcs[target_group.vpc_id], + protocol: target_group.protocol, + port: target_group.port, + load_balancers: load_balancers, + healthy_threshold: target_group.healthy_threshold_count, + unhealthy_threshold: target_group.unhealthy_threshold_count, + health_check_path: target_group.health_check_path, + health_check_port: target_group.health_check_port, + health_check_protocol: target_group.health_check_protocol, + health_check_interval: target_group.health_check_interval_seconds, + health_check_success_codes: target_group.matcher.http_code, + health_check_timeout: target_group.health_check_timeout_seconds, + deregistration_delay: attributes['deregistration_delay.timeout_seconds'], + stickiness: (attributes['stickiness.enabled'] == 'true' ? :enabled : :disabled), + stickiness_duration: attributes['stickiness.lb_cookie.duration_seconds'], + tags: tags, + } + end + + def exists? + @property_hash[:ensure] == :present + end + + def healthy_threshold=(value) + Puppet.debug("Updating target group #{name} healthy_threshold to '#{value}'") + elbv2_client(region).modify_target_group( { + target_group_arn: arn, + healthy_threshold_count: value, + }) + end + + def unhealthy_threshold=(value) + Puppet.debug("Updating target group #{name} unhealthy_threshold to '#{value}'") + elbv2_client(region).modify_target_group( { + target_group_arn: arn, + unhealthy_threshold_count: value, + }) + end + + def health_check_path=(value) + Puppet.debug("Updating target group #{name} health_check_path to '#{value}'") + elbv2_client(region).modify_target_group( { + target_group_arn: arn, + health_check_path: value, + }) + end + + def health_check_port=(value) + Puppet.debug("Updating target group #{name} health_check_port to '#{value}'") + elbv2_client(region).modify_target_group( { + target_group_arn: arn, + health_check_port: value, + }) + end + + def health_check_protocol=(value) + Puppet.debug("Updating target group #{name} health_check_protocol to '#{value}'") + elbv2_client(region).modify_target_group( { + target_group_arn: arn, + health_check_protocol: value, + }) + end + + def health_check_interval=(value) + Puppet.debug("Updating target group #{name} health_check_interval to '#{value}'") + elbv2_client(region).modify_target_group( { + target_group_arn: arn, + health_check_interval_seconds: value, + }) + end + + def health_check_success_codes=(value) + Puppet.debug("Updating target group #{name} #{arn} health_check_success_codes to '#{value}'") + elbv2_client(region).modify_target_group( { + target_group_arn: arn, + matcher: { http_code: value }, + }) + end + + def health_check_timeout=(value) + Puppet.debug("Updating target group #{name} health_check_timeout to '#{value}'") + elbv2_client(region).modify_target_group( { + target_group_arn: arn, + health_check_timeout_seconds: value, + }) + end + + def stickiness=(value) + Puppet.debug("Updating target group #{name} stickiness to '#{value.to_s}'") + elbv2_client(region).modify_target_group_attributes( { + target_group_arn: arn, + attributes: [ { key: 'stickiness.enabled', + value: ( value == :enabled ? 'true' : 'false' ), } ], + }) + @property_hash[:stickiness] = value + end + + def stickiness_duration=(value) + Puppet.debug("Updating target group #{name} stickiness_duration to '#{value}'") + elbv2_client(region).modify_target_group_attributes( { + target_group_arn: arn, + attributes: [ { key: 'stickiness.lb_cookie.duration_seconds', + value: value.to_s } ], + }) + @property_hash[:stickiness_duration] = value + end + + def tags=(value) + Puppet.debug("Updating target group #{name} tags to '#{value}'") + client = elbv2_client(region) + resp = client.describe_tags( resource_arns: [ arn ] ) + is = resp.tag_descriptions.collect do |tds| + tds.tags.collect do |tag| + tag.key + end + end.flatten + should = value.keys + to_del = is - should + Puppet.info("Response: #{to_del}") + + client.remove_tags( resource_arns: [ arn ], + tag_keys: to_del ) + client.add_tags( resource_arns: [ arn ], + tags: value ? value.map{ |k,v| { key: k, value: v, } } : [] ) + + +# client.create_or_update_tags( +# tags: tags ? tags.map { |k,v| { key: k, value: v, } } : [] +# ) + + def stickiness_duration=(value) + Puppet.debug("Updating target group #{name} stickiness_duration") + elbv2_client(region).modify_target_group_attributes( { + target_group_arn: arn, + attributes: [ { key: 'stickiness.lb_cookie.duration_seconds', + value: value.to_s } ], + }) + @property_hash[:stickiness_duration] = value + end + + def tags=(value) + Puppet.debug("Updating target group #{name} tags to '#{value}'") + client = elbv2_client(region) + resp = client.describe_tags( resource_arns: [ arn ] ) + is = resp.tag_descriptions.collect do |tds| + tds.tags.collect do |tag| + tag.key + end + end.flatten + should = value.keys + to_del = is - should + Puppet.info("Response: #{to_del}") + + client.remove_tags( resource_arns: [ arn ], + tag_keys: to_del ) + client.add_tags( resource_arns: [ arn ], + tags: value ? value.map{ |k,v| { key: k, value: v, } } : [] ) + + +# client.create_or_update_tags( +# tags: tags ? tags.map { |k,v| { key: k, value: v, } } : [] +# ) + + end + + def create + Puppet.debug("Creating target group #{name} in region #{target_region} using #{resource[:protocol]}:#{resource[:port]}") + fail('You must specify the AWS region') unless target_region != :absent + fail('You must specify the Target protocol') if resource[:protocol].nil? + fail('You must specify the Target port') if resource[:port].nil? + + vpc_name = resource[:vpc] + if vpc_name + vpc_response = ec2_client(target_region).describe_vpcs(filters: [ + {name: 'tag:Name', values: [vpc_name]} + ]) + fail("No VPC found called #{vpc_name}") if vpc_response.data.vpcs.count == 0 + vpc_id = vpc_response.data.vpcs.first.vpc_id + Puppet.warning "Multiple VPCs found called #{vpc_name}, using #{vpc_id}" if vpc_response.data.vpcs.count > 1 + @property_hash[:vpc_id] = vpc_id + @property_hash[:vpc] = vpc_name + end + + config = { + name: resource[:name], + vpc_id: vpc_id, + protocol: resource[:protocol], + port: resource[:port], + } + + config[:health_check_protocol] = resource[:health_check_protocol] unless resource[:health_check_protocol].nil? + config[:health_check_port] = resource[:health_check_port] unless resource[:health_check_port].nil? + config[:health_check_path] = resource[:health_check_path] unless resource[:health_check_path].nil? + config[:health_check_interval_seconds] = resource[:health_check_interval] unless resource[:health_check_interval].nil? + config[:health_check_timeout_seconds] = resource[:health_check_timeout] unless resource[:health_check_timeout].nil? + config[:healthy_threshold_count] = resource[:healthy_threshold] unless resource[:healthy_threshold].nil? + config[:unhealthy_threshold_count] = resource[:unhealthy_threshold] unless resource[:unhealthy_threshold].nil? + config[:matcher] = { http_code: resource[:health_check_success_codes] } unless resource[:health_check_success_codes].nil? + + tg_response = elbv2_client(target_region).create_target_group(config) + + tg_arn = tg_response.data.target_groups.first.target_group_arn + + attrs = [] + attrs << { key: 'stickiness.enabled', + value: ( resource[:stickiness] == :enabled ? 'true' : 'false' ) } unless resource[:stickiness].nil? + attrs << { key: 'stickiness.lb_cookie.duration_seconds', + value: resource[:stickiness_duration] } unless resource[:stickiness_duration].nil? + + mtga_response = elbv2_client(target_region).modify_target_group_attributes( { + targetgrouparn: tg_arn, + attributes: attrs, + }) unless attrs.empty? + + tags = resource[:tags] ? resource[:tags].map { |k,v| {key: k, value: v} } : [] + + end + + def destroy + Puppet.debug("Deleting target group #{name} in region #{target_region}") + elbv2 = elbv2_client(target_region) + elbv2.delete_target_group(target_group_arn: arn) + @property_hash[:ensure] = :absent + end +end diff --git a/lib/puppet/type/elbv2_loadbalancer.rb b/lib/puppet/type/elbv2_loadbalancer.rb new file mode 100644 index 00000000..a642487f --- /dev/null +++ b/lib/puppet/type/elbv2_loadbalancer.rb @@ -0,0 +1,92 @@ +require_relative '../../puppet_x/puppetlabs/property/tag.rb' + +Puppet::Type.newtype(:elbv2_loadbalancer) do + @doc = 'Type representing an ELBv2 load balancer.' + + ensurable + + newparam(:name, namevar: true) do + desc 'The name of the load balancer.' + validate do |value| + fail 'Load Balancers must have a name' if value == '' + fail 'name should be a String' unless value.is_a?(String) + end + end + + newproperty(:region) do + desc 'The region in which to launch the load balancer.' + validate do |value| + fail 'region must not contain spaces' if value =~ /\s/ + fail 'region should be a String' unless value.is_a?(String) + end + end + + newproperty(:listeners, :array_matching => :all) do + desc 'The ports and protocols the load balancer listens to.' + def insync?(is) + normalise(is).to_set == normalise(should).to_set + end + def normalise(listeners) + listeners.collect do |obj| + obj.each { |k,v| obj[k] = v.to_s.downcase } + end + end + validate do |value| + value = [value] unless value.is_a?(Array) + fail "you must provide a set of listeners for the load balancer" if value.empty? + value.each do |listener| + ['protocol', 'port', 'target_group'].each do |key| + fail "listeners must include #{key}" unless listener.keys.include?(key) + end + end + end + end + + newproperty(:arn) + newproperty(:vpc) + + newproperty(:tags, :parent => PuppetX::Property::AwsTag) do + desc 'The tags for the load balancer.' + end + + newproperty(:subnets, :array_matching => :all) do + desc 'The region in which to launch the load balancer.' + validate do |value| + fail 'subnets should be a String' unless value.is_a?(String) + end + def insync?(is) + is.to_set == should.to_set + end + end + + newproperty(:security_groups, :array_matching => :all) do + desc 'The security groups to associate the load balancer (VPC only).' + validate do |value| + fail 'security_groups should be a String' unless value.is_a?(String) + end + def insync?(is) + is.to_set == should.to_set + end + end + + newproperty(:scheme) do + desc 'Whether the load balancer is internal or public facing.' + defaultto :'internet-facing' + newvalues(:'internet-facing', :internal) + end + + newproperty(:dns_name) do + desc 'The DNS name of the load balancer' + end + + autorequire(:ec2_securitygroup) do + groups = self[:security_groups] + groups.is_a?(Array) ? groups : [groups] + end + + autorequire(:ec2_vpc_subnet) do + subnets = self[:subnets] + subnets.is_a?(Array) ? subnets : [subnets] + end + +end diff --git a/lib/puppet/type/elbv2_targetgroup.rb b/lib/puppet/type/elbv2_targetgroup.rb new file mode 100644 index 00000000..e9600d82 --- /dev/null +++ b/lib/puppet/type/elbv2_targetgroup.rb @@ -0,0 +1,164 @@ +require_relative '../../puppet_x/puppetlabs/property/tag.rb' +require 'puppet/property/boolean' + +Puppet::Type.newtype(:elbv2_targetgroup) do + @doc = 'Type representing an ELBv2 target group.' + + ensurable + + newparam(:name, namevar: true) do + desc 'The name of the target group.' + validate do |value| + fail 'Target Groups must have a name' if value == '' + fail 'name should be a String' unless value.is_a?(String) + end + end + + newproperty(:region) do + desc 'The region in which to launch the load balancer.' + validate do |value| + fail 'region must be specified' unless value + fail 'region must not contain spaces' if value =~ /\s/ + fail 'region should be a String' unless value.is_a?(String) + end + end + + newproperty(:protocol) do + desc 'Protocol to use for routing traffic to targets (HTTP/HTTPS)' + newvalues(:HTTP, :HTTPS) + validate do |value| + file 'protocol must be specified' unless value + fail 'Invalid protocol - must be HTTP or HTTPS' unless value =~ /^HTTPS?$/ + end + end + + newproperty(:port) do + desc 'Port on which the targets receive traffic' + validate do |value| + file 'Target port must be specified' unless value + end + munge do |value| + value.to_i + end + end + + newproperty(:vpc) do + desc 'Id of the virtual private cloud (VPC)' + validate do |value| + fail 'VPC ID must be specified' unless value + end + end + + newproperty(:load_balancers) do + desc 'The load balancer to assign this target group too' + end + + newproperty(:health_check_success_codes) do + desc 'HTTP state codes to use when checking for a successful response from a target' + end + + newproperty(:health_check_path) do + desc 'Path to request when performing health checks' + end + + newproperty(:health_check_port) do + desc 'The port the elb uses when performing health checks' + validate do |value| + fail 'Invalid health check port - must be traffic-port or port number' unless value.downcase =~ /^(traffic-port|[0-9]+)$/ + end + end + + newproperty(:health_check_protocol) do + desc 'The protocol the elb uses when performing health checks on targets (HTTP/HTTPS)' + newvalues(:HTTP, :HTTPS) + validate do |value| + fail 'Invalid health check protocol - must be HTTP or HTTPS' unless value.upcase =~ /^HTTPS?$/ + end + munge do |value| + value.upcase + end + end + + newproperty(:health_check_interval) do + desc 'Approximate time (seconds) between health checks' + validate do |value| + fail 'health_check_interval must be a number' unless value =~ /^[0-9]+$/ + end + munge do |value| + value.to_i + end + end + + newproperty(:health_check_timeout) do + desc 'Amount of time (seconds) during which no response means a failed health check' + validate do |value| + fail 'health_check_timeout must be a number' unless value =~ /^[0-9]+$/ + end + munge do |value| + value.to_i + end + end + + newproperty(:healthy_threshold) do + desc 'Number of consecutive health check successes required before considering an unhealthy target healthy' + validate do |value| + fail 'healthy_threshold must be a number' unless value =~ /^[0-9]+$/ + end + munge do |value| + value.to_i + end + end + + newproperty(:unhealthy_threshold) do + desc 'Number of consecutive health check failures required before considering a healthy target unhealthy' + validate do |value| + fail 'unhealthy_threshold must be a number' unless value =~ /^[0-9]+$/ + end + munge do |value| + value.to_i + end + end + + newproperty(:deregistration_delay) do + desc 'Amount of time (seconds) for elb to wait before changing state of deregistering target from draining to unused (0-3600)' + validate do |value| + fail 'deregistration_delay must be a number' unless value =~ /^[0-9]+$/ + fail 'Invalid deregistration time - must be between 0 and 3600' if value.to_i < 0 or value.to_i > 3600 + end + munge do |value| + value.to_i + end + end + + newproperty(:arn) do + desc 'ARN of target group' + validate do |value| + fail 'arn is a readonly property' + end + end + + newproperty(:stickiness) do + newvalues(:enabled, :disabled) + desc 'Indicates whether sticky sessions are enabled' + end + + newproperty(:stickiness_duration) do + desc 'Amount of time (seconds) where requests should be routed to the same target (1-604800)' + validate do |value| + fail 'stickiness_duration must be a number' unless value =~ /^[0-9]+$/ + fail 'Invalid stickiness duration - must be between 1 and 604800' if value.to_i < 1 or value.to_i > 604800 + end + munge do |value| + value.to_i + end + end + + newproperty(:tags, :parent => PuppetX::Property::AwsTag) do + desc 'The tags for the instance.' + end + + autorequire(:ec2_vpc) do + self[:vpc] + end + +end