From 07b6e831f52ed6e7f1fdec3011c56b27bc27f3b5 Mon Sep 17 00:00:00 2001 From: Eric Herot Date: Mon, 7 Nov 2016 20:19:43 -0500 Subject: [PATCH 1/2] RuboCop: LineLength exception --- .rubocop.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.rubocop.yml b/.rubocop.yml index c124fca6..b6b9f4cd 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -22,3 +22,6 @@ Lint/UselessAssignment: # Configuration parameters: CountKeywordArgs. Metrics/ParameterLists: Max: 15 + +Metrics/LineLength: + Max: 100 From e0ca84335c61fd9b58ffea38b5ce8b6e6e03f6b3 Mon Sep 17 00:00:00 2001 From: Eric Herot Date: Mon, 7 Nov 2016 20:20:04 -0500 Subject: [PATCH 2/2] Check-in work in progress on ELBv2 support --- libraries/elbv2.rb | 16 ++++ providers/elastic_lb_v2.rb | 0 resources/elastic_lb_v2.rb | 82 ++++++++++++++++++++ resources/elastic_lb_v2_listener.rb | 3 + resources/elastic_lb_v2_target_group.rb | 99 +++++++++++++++++++++++++ 5 files changed, 200 insertions(+) create mode 100644 libraries/elbv2.rb create mode 100644 providers/elastic_lb_v2.rb create mode 100644 resources/elastic_lb_v2.rb create mode 100644 resources/elastic_lb_v2_listener.rb create mode 100644 resources/elastic_lb_v2_target_group.rb diff --git a/libraries/elbv2.rb b/libraries/elbv2.rb new file mode 100644 index 00000000..6572e4d7 --- /dev/null +++ b/libraries/elbv2.rb @@ -0,0 +1,16 @@ +require File.join(File.dirname(__FILE__), 'ec2') + +module Opscode + module Aws + module ElbV2 + include Opscode::Aws::Ec2 + + def elbv2 + require_aws_sdk + + Chef::Log.debug('Initializing the ElasticLoadBalancingV2 Client') + @elbv2 ||= create_aws_interface(::Aws::ElasticLoadBalancingV2::Client) + end + end + end +end diff --git a/providers/elastic_lb_v2.rb b/providers/elastic_lb_v2.rb new file mode 100644 index 00000000..e69de29b diff --git a/resources/elastic_lb_v2.rb b/resources/elastic_lb_v2.rb new file mode 100644 index 00000000..36a7c45a --- /dev/null +++ b/resources/elastic_lb_v2.rb @@ -0,0 +1,82 @@ +# Prerequisites: None + +include Opscode::Aws::ElbV2 + +actions :create, :delete +default_action :create + +property :aws_access_key, String +property :aws_secret_access_key, String +property :aws_session_token, String +property :aws_assume_role_arn, String +property :aws_role_session_name, String +property :region, String + +property :name, String +property :subnets, Array, required: true +property :tags, Hash +property :scheme, callbacks: { + 'Scheme must be either internet-facing or internal' => lambda do |scheme| + %w(internet-facing internal).include? scheme + end +} + +load_current_value do + current_value_does_not_exist! unless lb + subnets lb.availability_zones.map(&:subnet_id) + raise 'Scheme of an existing LB cannot be modified' unless scheme == lb.scheme + scheme lb.scheme + tags current_tags_hash +end + +action :create do + if lb + converge_if_changed :subnets do + converge_by("Modify the subnets associated with #{name}") do + elbv2.set_subnets(load_balancer_arn: lb.load_balancer_arn, subnets: subnets) + end + end + + converge_if_changed :tags do + converge_by("Modify the tags associated with #{name}") do + tags_to_add = Hash[*(tags.to_a - current_tags_hash.to_a).flatten].map { |k, v| { k => v } } + tags_to_remove = Hash[*(current_tags_hash.to_a - tags.to_a).flatten].map { |k, v| { k => v } } + + elbv2.add_tags resource_arns: [lb.load_balancer_arn], tags: tags_to_add + elbv2.remove_tags resource_arns: [lb.load_balancer_arn], tags: tags_to_remove + end + end + else + converge_by("Create v2 load balancer #{name}") do + elbv2.create_load_balancer( + name: name, + subnets: subnets, + security_groups: security_groups, + scheme: scheme, + tags: tags + ) + end + end +end + +action :delete do + return unless lb + converge_by("Removing v2 load balancer #{name}") do + elbv2.delete_load_balancer load_balacer_arn: lb.load_balancer_arn + end +end + +def lb + @lb ||= begin + elbv2.describe_load_balancers(names: [name]).load_balancers.first + rescue Aws::ElasticLoadBalancingV2::Errors::LoadBalancerNotFound + nil + end +end + +def current_tags_hash + @current_tags_hash ||= begin + tag_object = elbv2.describe_tags(resource_arns: [lb.load_balancer_arn]) + tag_object.tag_descriptions.first.tags.each_with_object { |tag, memo| memo[tag.key] = tag.value } + end +end diff --git a/resources/elastic_lb_v2_listener.rb b/resources/elastic_lb_v2_listener.rb new file mode 100644 index 00000000..d2aaf1b3 --- /dev/null +++ b/resources/elastic_lb_v2_listener.rb @@ -0,0 +1,3 @@ +# Prerequisites: +# - load_balancer_arn +# - target_group_arn diff --git a/resources/elastic_lb_v2_target_group.rb b/resources/elastic_lb_v2_target_group.rb new file mode 100644 index 00000000..618310c3 --- /dev/null +++ b/resources/elastic_lb_v2_target_group.rb @@ -0,0 +1,99 @@ +# Prerequisites: None + +include Opscode::Aws::ElbV2 + +actions :create, :delete +default_action :create + +property :aws_access_key, String +property :aws_secret_access_key, String +property :aws_session_token, String +property :aws_assume_role_arn, String +property :aws_role_session_name, String +property :region, String + +property :name, String +property :vpc_id, String, required: true +property :health_check, Hash +property :tags, Hash +property :protocol, String, required: true, callbacks: { + 'Protocol must be either HTTP or HTTPS' => ->(pr) { pr =~ /^https?$/ } +} +property :port, required: true, callbacks: { + 'Port must be a number between 1 and 65535' => lambda do |cur_port| + cur_port = cur_port.to_i + cur_port > 0 && cur_port < 2**16 + end +} + +load_current_value do + current_value_does_not_exist! unless tg + raise 'VPC ID of an existing target group cannot be modified' unless vpc_id == tg.vpc_id + tags current_tags_hash + health_check health_check_hash +end + +action :create do + if tg + converge_if_changed :tags do + converge_by("Modify the tags associated with #{name}") do + tags_to_add = Hash[*(tags.to_a - current_tags_hash.to_a).flatten].map { |k, v| { k => v } } + tags_to_remove = Hash[*(current_tags_hash.to_a - tags.to_a).flatten].map { |k, v| { k => v } } + + elbv2.add_tags resource_arns: [tg.target_group_arn], tags: tags_to_add + elbv2.remove_tags resource_arns: [tg.target_group_arn], tags: tags_to_remove + end + end + + converge_if_changed :health_check do + elbv2.modify_target_group health_check_hash.merge target_group_arn: tg.target_group_arn + end + else + converge_by("Create target group #{name}") do + elbv2.create_target_group( + name: name, + subnets: subnets, + security_groups: security_groups, + scheme: scheme, + tags: tags + ) + end + end +end + +action :delete do + return unless tg + converge_by("Removing target group #{name}") do + elbv2.delete_target_group target_group_arn: tg.target_group_arn + end +end + +def tg + @tg ||= begin + elbv2.describe_target_groups(names: [name]).target_groups.first + rescue Aws::ElasticLoadBalancingV2::Errors::TargetGroupNotFound + nil + end +end + +def health_check_hash + output = { matcher: { http_code: tg.matcher.http_code } } + + %i( + health_check_protocol + health_check_port + health_check_interval_seconds + health_check_timeout_seconds + healthy_threshold_count + unhealthy_threshold_count + health_check_path + ).each { |key_sym| output[key_sym] = tg.send key_sym } + output +end + +def current_tags_hash + @current_tags_hash ||= begin + tag_object = elbv2.describe_tags(resource_arns: [tg.target_group_arn]) + tag_object.tag_descriptions.first.tags.each_with_object { |tag, memo| memo[tag.key] = tag.value } + end +end