chef-provisioning-aws 0.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5ec492afa3798bae513c3b61ea626958a6b7e954
4
- data.tar.gz: 1b8ecf59b63a169aaa7d744efe491f3f1627065c
3
+ metadata.gz: 3e941203fbc66689312f07ace28e6ea90413c25b
4
+ data.tar.gz: fd09857eee368a41188c6c36084aacf061b31eef
5
5
  SHA512:
6
- metadata.gz: bcbdddb1f0cc451ecd9b345e62fc95d6049e5e1d9c715dff1b000f859a80728d1670fb42064e65b4ca1b2e93d26e9c036177b36d40a3a5802ad67a1e14a344d4
7
- data.tar.gz: 8e17c7774db57b2e9774d366ffbe04f301c8bb5d09761a7a9f6fb1892567cd2163a6197a31591ca7a249f8f4216c1f65790a3c91f6e074c45b1a7ad197ab448f
6
+ metadata.gz: 8421e20240201c3c8e66a03017d700dbdb91c669a092793b003ba5ea24234449ebe8c5c4f9517c6c943ecfd1eb5ad138279fc5548045babb004fbf2455c2ca02
7
+ data.tar.gz: 08802b5ba314ce4840c4ef883164877c57291a98ae1d76720fff5c58d8e4308adfbb5bb1479d77bc46a3525fd9a5ccad99fc643db317a9b92c71806550cb889f
@@ -9,12 +9,12 @@ class Chef::Provider::AwsAutoScalingGroup < Chef::Provider::AwsProvider
9
9
  :max_size => new_resource.max_size,
10
10
  :availability_zones => availability_zones
11
11
  }
12
-
12
+
13
13
  auto_scaling_opts[:desired_capacity] = new_resource.desired_capacity if new_resource.desired_capacity
14
14
  auto_scaling_opts[:load_balancers] = new_resource.load_balancers if new_resource.load_balancers
15
-
16
- converge_by "Creating new Auto Scaling group #{new_resource.name} in #{new_resource.region_name}" do
17
- @existing_group = auto_scaling.groups.create(
15
+
16
+ converge_by "Creating new Auto Scaling group #{new_resource.name} in #{new_driver.aws_config.region}" do
17
+ @existing_group = new_driver.auto_scaling.groups.create(
18
18
  new_resource.name,
19
19
  auto_scaling_opts
20
20
  )
@@ -26,7 +26,7 @@ class Chef::Provider::AwsAutoScalingGroup < Chef::Provider::AwsProvider
26
26
 
27
27
  action :delete do
28
28
  if existing_group
29
- converge_by "Deleting Auto Scaling group #{new_resource.name} in #{new_resource.region_name}" do
29
+ converge_by "Deleting Auto Scaling group #{new_resource.name} in #{new_driver.aws_config.region}" do
30
30
  existing_group.delete!
31
31
  end
32
32
  end
@@ -35,12 +35,12 @@ class Chef::Provider::AwsAutoScalingGroup < Chef::Provider::AwsProvider
35
35
  end
36
36
 
37
37
  def availability_zones
38
- @availability_zones ||= ec2.availability_zones.reduce([]) { |result, az| result << az }
38
+ @availability_zones ||= new_driver.ec2.availability_zones.reduce([]) { |result, az| result << az }
39
39
  end
40
40
 
41
41
  def existing_group
42
42
  @existing_group ||= begin
43
- eg = auto_scaling.groups[new_resource.name]
43
+ eg = new_driver.auto_scaling.groups[new_resource.name]
44
44
  eg.exists? ? eg : nil
45
45
  end
46
46
  end
@@ -6,9 +6,9 @@ class Chef::Provider::AwsEbsVolume < Chef::Provider::AwsProvider
6
6
 
7
7
  action :create do
8
8
  if existing_volume == nil
9
- converge_by "Creating new EBS volume #{fqn} in #{new_resource.region_name}" do
9
+ converge_by "Creating new EBS volume #{fqn} in #{new_driver.aws_config.region}" do
10
10
 
11
- ebs = ec2.volumes.create(
11
+ ebs = new_driver.ec2.volumes.create(
12
12
  :availability_zone => new_resource.availability_zone,
13
13
  :size => new_resource.size.to_i
14
14
  )
@@ -27,7 +27,7 @@ class Chef::Provider::AwsEbsVolume < Chef::Provider::AwsProvider
27
27
 
28
28
  action :delete do
29
29
  if existing_volume
30
- converge_by "Deleting EBS volume #{fqn} in #{new_resource.region_name}" do
30
+ converge_by "Deleting EBS volume #{fqn} in #{new_driver.aws_config.region}" do
31
31
  existing_volume.delete
32
32
  end
33
33
  end
@@ -39,7 +39,7 @@ class Chef::Provider::AwsEbsVolume < Chef::Provider::AwsProvider
39
39
  def existing_volume
40
40
  @existing_volume ||= new_resource.volume_id == nil ? nil : begin
41
41
  Chef::Log.debug("Loading volume #{new_resource.volume_id}")
42
- volume = ec2.volumes[new_resource.volume_id]
42
+ volume = new_driver.ec2.volumes[new_resource.volume_id]
43
43
  if [:deleted, :deleting, :error].include? volume.status
44
44
  nil
45
45
  else
@@ -6,8 +6,8 @@ class Chef::Provider::AwsEipAddress < Chef::Provider::AwsProvider
6
6
 
7
7
  action :create do
8
8
  if existing_ip == nil
9
- converge_by "Creating new EIP address in #{new_resource.region_name}" do
10
- eip = ec2.elastic_ips.create :vpc => new_resource.associate_to_vpc
9
+ converge_by "Creating new EIP address in #{new_driver.aws_config.region}" do
10
+ eip = new_driver.ec2.elastic_ips.create :vpc => new_resource.associate_to_vpc
11
11
  new_resource.public_ip eip.public_ip
12
12
  new_resource.domain eip.domain
13
13
  new_resource.instance_id eip.instance_id
@@ -22,7 +22,7 @@ class Chef::Provider::AwsEipAddress < Chef::Provider::AwsProvider
22
22
 
23
23
  action :delete do
24
24
  if existing_ip
25
- converge_by "Deleting EIP Address #{new_resource.name} in #{new_resource.region_name}" do
25
+ converge_by "Deleting EIP Address #{new_resource.name} in #{new_driver.aws_config.region}" do
26
26
  #if it's attached to something in a vpc, disassociate first
27
27
  if existing_ip.instance_id != nil && existing_ip.domain == 'vpc'
28
28
  existing_ip.disassociate
@@ -34,11 +34,11 @@ class Chef::Provider::AwsEipAddress < Chef::Provider::AwsProvider
34
34
  end
35
35
 
36
36
  action :associate do
37
- converge_by "Associating EIP Address #{new_resource.name} in #{new_resource.region_name}" do
37
+ converge_by "Associating EIP Address #{new_resource.name} in #{new_driver.aws_config.region}" do
38
38
  if existing_ip == nil
39
39
  action_create
40
40
  end
41
- eip = ec2.elastic_ips[new_resource.public_ip]
41
+ eip = new_driver.ec2.elastic_ips[new_resource.public_ip]
42
42
  begin
43
43
  spec = Chef::Provisioning::ChefMachineSpec.get(new_resource.machine)
44
44
  if spec == nil
@@ -55,7 +55,7 @@ class Chef::Provider::AwsEipAddress < Chef::Provider::AwsProvider
55
55
  end
56
56
 
57
57
  action :disassociate do
58
- converge_by "Disassociating EIP Address #{new_resource.name} in #{new_resource.region_name}" do
58
+ converge_by "Disassociating EIP Address #{new_resource.name} in #{new_driver.aws_config.region}" do
59
59
  begin
60
60
  if existing_ip != nil
61
61
  existing_ip.disassociate
@@ -73,7 +73,7 @@ class Chef::Provider::AwsEipAddress < Chef::Provider::AwsProvider
73
73
  def existing_ip
74
74
  new_resource.hydrate
75
75
  @existing_ip ||= new_resource.public_ip == nil ? nil : begin
76
- eip = ec2.elastic_ips[new_resource.public_ip]
76
+ eip = new_driver.ec2.elastic_ips[new_resource.public_ip]
77
77
  eip
78
78
  rescue => e
79
79
  Chef::Application.fatal!("Error looking for EIP Address: #{e}")
@@ -18,7 +18,7 @@ class Chef::Provider::AwsKeyPair < Chef::Provider::AwsProvider
18
18
 
19
19
  action :delete do
20
20
  if current_resource_exists?
21
- ec2.key_pairs[new_resource.name].delete
21
+ new_driver.ec2.key_pairs[new_resource.name].delete
22
22
  end
23
23
  end
24
24
 
@@ -79,8 +79,8 @@ class Chef::Provider::AwsKeyPair < Chef::Provider::AwsProvider
79
79
  if !new_fingerprints.any? { |f| compare_public_key f }
80
80
  if new_resource.allow_overwrite
81
81
  converge_by "update #{key_description} to match local key at #{new_resource.private_key_path}" do
82
- ec2.key_pairs[new_resource.name].delete
83
- ec2.key_pairs.import(new_resource.name, Cheffish::KeyFormatter.encode(desired_key, :format => :openssh))
82
+ new_driver.ec2.key_pairs[new_resource.name].delete
83
+ new_driver.ec2.key_pairs.import(new_resource.name, Cheffish::KeyFormatter.encode(desired_key, :format => :openssh))
84
84
  end
85
85
  else
86
86
  raise "#{key_description} with fingerprint #{@current_fingerprint} does not match local key fingerprint(s) #{new_fingerprints}, and allow_overwrite is false!"
@@ -92,7 +92,7 @@ class Chef::Provider::AwsKeyPair < Chef::Provider::AwsProvider
92
92
 
93
93
  # Create key
94
94
  converge_by "create #{key_description} from local key at #{new_resource.private_key_path}" do
95
- ec2.key_pairs.import(new_resource.name, Cheffish::KeyFormatter.encode(desired_key, :format => :openssh))
95
+ new_driver.ec2.key_pairs.import(new_resource.name, Cheffish::KeyFormatter.encode(desired_key, :format => :openssh))
96
96
  end
97
97
  end
98
98
  end
@@ -136,7 +136,7 @@ class Chef::Provider::AwsKeyPair < Chef::Provider::AwsProvider
136
136
 
137
137
  def existing_keypair
138
138
  @existing_keypair ||= begin
139
- ec2.key_pairs[fqn]
139
+ new_driver.ec2.key_pairs[fqn]
140
140
  rescue
141
141
  nil
142
142
  end
@@ -175,7 +175,7 @@ class Chef::Provider::AwsKeyPair < Chef::Provider::AwsProvider
175
175
  def load_current_resource
176
176
  @current_resource = Chef::Resource::AwsKeyPair.new(new_resource.name, run_context)
177
177
 
178
- current_key_pair = ec2.key_pairs[new_resource.name]
178
+ current_key_pair = new_driver.ec2.key_pairs[new_resource.name]
179
179
  if current_key_pair && current_key_pair.exists?
180
180
  @current_fingerprint = current_key_pair ? current_key_pair.fingerprint : nil
181
181
  else
@@ -3,8 +3,8 @@ require 'chef/provider/aws_provider'
3
3
  class Chef::Provider::AwsLaunchConfig < Chef::Provider::AwsProvider
4
4
  action :create do
5
5
  if existing_launch_config.nil?
6
- converge_by "Creating new Launch Config #{id} in #{new_resource.region_name}" do
7
- @existing_launch_config = auto_scaling.launch_configurations.create(
6
+ converge_by "Creating new Launch Config #{id} in #{new_driver.aws_config.region}" do
7
+ @existing_launch_config = new_driver.auto_scaling.launch_configurations.create(
8
8
  new_resource.name,
9
9
  new_resource.image,
10
10
  new_resource.instance_type
@@ -17,7 +17,7 @@ class Chef::Provider::AwsLaunchConfig < Chef::Provider::AwsProvider
17
17
 
18
18
  action :delete do
19
19
  if existing_launch_config
20
- converge_by "Deleting Launch Config #{id} in #{new_resource.region_name}" do
20
+ converge_by "Deleting Launch Config #{id} in #{new_driver.aws_config.region}" do
21
21
  begin
22
22
  existing_launch_config.delete
23
23
  rescue AWS::AutoScaling::Errors::ResourceInUse
@@ -32,7 +32,7 @@ class Chef::Provider::AwsLaunchConfig < Chef::Provider::AwsProvider
32
32
 
33
33
  def existing_launch_config
34
34
  @existing_launch_config ||= begin
35
- elc = auto_scaling.launch_configurations[new_resource.name]
35
+ elc = new_driver.auto_scaling.launch_configurations[new_resource.name]
36
36
  elc.exists? ? elc : nil
37
37
  end
38
38
  end
@@ -1,89 +1,22 @@
1
1
  require 'chef/provider/lwrp_base'
2
- require 'chef/provisioning/aws_driver/credentials'
3
2
 
4
3
  class Chef::Provider::AwsProvider < Chef::Provider::LWRPBase
5
4
  use_inline_resources
6
5
 
7
- attr_reader :credentials
8
-
9
6
  # All these need to implement whyrun
10
7
  def whyrun_supported?
11
8
  true
12
9
  end
13
10
 
14
- def from_hash hash
15
- hash.each do |k,v|
16
- begin
17
- self.instance_variable_set("@#{k}", v)
18
- rescue NameError => ne
19
- # nothing...
20
- end
21
- end
22
- self
23
- end
24
-
25
- def resource_from_databag(fqn, chef_server = Cheffish.default_chef_server)
26
- chef_api = Cheffish.chef_server_api(chef_server)
27
- begin
28
- data = chef_api.get("/data/#{databag_name}/#{fqn}")
29
- rescue Net::HTTPServerException => e
30
- if e.response.code == '404'
31
- nil
32
- else
33
- raise
34
- end
35
- end
36
- end
37
-
38
- def initialize(*args)
39
- super
40
- # TODO - temporary, needs to be better
41
- @credentials = Chef::Provisioning::AWSDriver::Credentials.new
42
- @credentials.load_default
43
- credentials = @credentials.default
44
- AWS.config(:access_key_id => credentials[:aws_access_key_id],
45
- :secret_access_key => credentials[:aws_secret_access_key])
46
- end
47
-
48
- def self.databag_name
49
- raise 'Class does not implement databag name'
50
- end
51
-
52
11
  def fqn
53
12
  if id
54
13
  id
55
14
  else
56
- "#{new_resource.name}_#{new_resource.region_name}"
15
+ "#{new_resource.name}_#{new_driver.aws_config.region}"
57
16
  end
58
17
  end
59
18
 
60
- # AWS objects we might need
61
- def ec2
62
- @ec2 ||= aws_init { AWS::EC2.new }
63
- end
64
-
65
- def sns
66
- @sns ||= aws_init { AWS::SNS.new }
67
- end
68
-
69
- def sqs
70
- @sqs ||= aws_init { AWS::SQS.new }
71
- end
72
-
73
- def s3
74
- @s3 ||= aws_init { AWS::S3.new }
75
- end
76
-
77
- def auto_scaling
78
- @auto_scaling ||= aws_init { AWS::AutoScaling.new }
79
- end
80
-
81
- private
82
- def aws_init
83
- credentials = @credentials.default
84
- region = new_resource.region_name || credentials[:region]
85
- # Pivot region
86
- AWS.config(:region => region)
87
- yield
19
+ def new_driver
20
+ run_context.chef_provisioning.driver_for(new_resource.driver)
88
21
  end
89
22
  end
@@ -5,7 +5,7 @@ class Chef::Provider::AwsS3Bucket < Chef::Provider::AwsProvider
5
5
  action :create do
6
6
  if existing_bucket == nil
7
7
  converge_by "Creating new S3 bucket #{fqn}" do
8
- bucket = s3.buckets.create(fqn)
8
+ bucket = new_driver.s3.buckets.create(fqn)
9
9
  bucket.tags['Name'] = new_resource.name
10
10
  end
11
11
  end
@@ -38,7 +38,7 @@ class Chef::Provider::AwsS3Bucket < Chef::Provider::AwsProvider
38
38
 
39
39
  def existing_bucket
40
40
  Chef::Log.debug("Checking for S3 bucket #{fqn}")
41
- @existing_bucket ||= s3.buckets[fqn] if s3.buckets[fqn].exists?
41
+ @existing_bucket ||= new_driver.s3.buckets[fqn] if new_driver.s3.buckets[fqn].exists?
42
42
  end
43
43
 
44
44
  def modifies_website_configuration?
@@ -5,7 +5,7 @@ class Chef::Provider::AwsSecurityGroup < Chef::Provider::AwsProvider
5
5
 
6
6
  action :create do
7
7
  if existing_sg == nil
8
- converge_by "Creating new SG #{new_resource.name} in #{new_resource.region_name}" do
8
+ converge_by "Creating new SG #{new_resource.name} in #{new_driver.aws_config.region}" do
9
9
  opts = {
10
10
  :description => new_resource.description,
11
11
  :vpc => nil
@@ -14,14 +14,14 @@ class Chef::Provider::AwsSecurityGroup < Chef::Provider::AwsProvider
14
14
  if new_resource.vpc_id
15
15
  opts[:vpc] = new_resource.vpc_id
16
16
  elsif new_resource.vpc_name
17
- existing_vpc = ec2.vpcs.with_tag('Name', new_resource.vpc_name).first
17
+ existing_vpc = new_driver.ec2.vpcs.with_tag('Name', new_resource.vpc_name).first
18
18
  Chef::Log.debug("Existing VPC: #{existing_vpc.inspect}")
19
19
  if existing_vpc
20
20
  opts[:vpc] = existing_vpc
21
21
  end
22
22
  end
23
23
 
24
- sg = ec2.security_groups.create(new_resource.name, opts)
24
+ sg = new_driver.ec2.security_groups.create(new_resource.name, opts)
25
25
  new_resource.security_group_id sg.group_id
26
26
  new_resource.save
27
27
  end
@@ -33,7 +33,7 @@ class Chef::Provider::AwsSecurityGroup < Chef::Provider::AwsProvider
33
33
 
34
34
  action :delete do
35
35
  if existing_sg
36
- converge_by "Deleting SG #{new_resource.name} in #{new_resource.region_name}" do
36
+ converge_by "Deleting SG #{new_resource.name} in #{new_driver.aws_config.region}" do
37
37
  existing_sg.delete
38
38
  end
39
39
  end
@@ -47,7 +47,7 @@ class Chef::Provider::AwsSecurityGroup < Chef::Provider::AwsProvider
47
47
  if new_resource.inbound_rules
48
48
  new_resource.inbound_rules.each do |rule|
49
49
  begin
50
- converge_by "Updating SG #{new_resource.name} in #{new_resource.region_name} to allow inbound #{rule[:protocol]}/#{rule[:ports]} from #{rule[:sources]}" do
50
+ converge_by "Updating SG #{new_resource.name} in #{new_driver.aws_config.region} to allow inbound #{rule[:protocol]}/#{rule[:ports]} from #{rule[:sources]}" do
51
51
  security_group.authorize_ingress(rule[:protocol], rule[:ports], *rule[:sources])
52
52
  end
53
53
  rescue AWS::EC2::Errors::InvalidPermission::Duplicate
@@ -60,7 +60,7 @@ class Chef::Provider::AwsSecurityGroup < Chef::Provider::AwsProvider
60
60
  if new_resource.outbound_rules
61
61
  new_resource.outbound_rules.each do |rule|
62
62
  begin
63
- converge_by "Updating SG #{new_resource.name} in #{new_resource.region_name} to allow outbound #{rule[:protocol]}/#{rule[:ports]} to #{rule[:destinations]}" do
63
+ converge_by "Updating SG #{new_resource.name} in #{new_driver.aws_config.region} to allow outbound #{rule[:protocol]}/#{rule[:ports]} to #{rule[:destinations]}" do
64
64
  security_group.authorize_egress( *rule[:destinations], :protocol => rule[:protocol], :ports => rule[:ports])
65
65
  end
66
66
  rescue AWS::EC2::Errors::InvalidPermission::Duplicate
@@ -73,7 +73,7 @@ class Chef::Provider::AwsSecurityGroup < Chef::Provider::AwsProvider
73
73
  def existing_sg
74
74
  @existing_sg ||= begin
75
75
  if id != nil
76
- ec2.security_groups[id]
76
+ new_driver.ec2.security_groups[id]
77
77
  else
78
78
  nil
79
79
  end
@@ -5,8 +5,8 @@ class Chef::Provider::AwsSnsTopic < Chef::Provider::AwsProvider
5
5
 
6
6
  action :create do
7
7
  if existing_topic == nil
8
- converge_by "Creating new SNS topic #{fqn} in #{new_resource.region_name}" do
9
- sns.topics.create(fqn)
8
+ converge_by "Creating new SNS topic #{fqn} in #{new_driver.aws_config.region}" do
9
+ new_driver.sns.topics.create(fqn)
10
10
 
11
11
  new_resource.created_at DateTime.now.to_s
12
12
  new_resource.save
@@ -16,7 +16,7 @@ class Chef::Provider::AwsSnsTopic < Chef::Provider::AwsProvider
16
16
 
17
17
  action :delete do
18
18
  if existing_topic
19
- converge_by "Deleting SNS topic #{fqn} in #{new_resource.region_name}" do
19
+ converge_by "Deleting SNS topic #{fqn} in #{new_driver.aws_config.region}" do
20
20
  existing_topic.delete
21
21
  end
22
22
  end
@@ -26,7 +26,7 @@ class Chef::Provider::AwsSnsTopic < Chef::Provider::AwsProvider
26
26
 
27
27
  def existing_topic
28
28
  @existing_topic ||= begin
29
- sns.topics.named(fqn)
29
+ new_driver.sns.topics.named(fqn)
30
30
  rescue
31
31
  nil
32
32
  end
@@ -5,10 +5,10 @@ class Chef::Provider::AwsSqsQueue < Chef::Provider::AwsProvider
5
5
 
6
6
  action :create do
7
7
  if existing_queue == nil
8
- converge_by "Creating new SQS queue #{fqn} in #{new_resource.region_name}" do
8
+ converge_by "Creating new SQS queue #{fqn} in #{new_driver.aws_config.region}" do
9
9
  loop do
10
10
  begin
11
- sqs.queues.create(fqn)
11
+ new_driver.sqs.queues.create(fqn)
12
12
  break
13
13
  rescue AWS::SQS::Errors::QueueDeletedRecently
14
14
  sleep 5
@@ -23,7 +23,7 @@ class Chef::Provider::AwsSqsQueue < Chef::Provider::AwsProvider
23
23
 
24
24
  action :delete do
25
25
  if existing_queue
26
- converge_by "Deleting SQS queue #{fqn} in #{new_resource.region_name}" do
26
+ converge_by "Deleting SQS queue #{fqn} in #{new_driver.aws_config.region}" do
27
27
  existing_queue.delete
28
28
  end
29
29
  end
@@ -33,7 +33,7 @@ class Chef::Provider::AwsSqsQueue < Chef::Provider::AwsProvider
33
33
 
34
34
  def existing_queue
35
35
  @existing_queue ||= begin
36
- sqs.queues.named(fqn)
36
+ new_driver.sqs.queues.named(fqn)
37
37
  rescue
38
38
  nil
39
39
  end
@@ -7,10 +7,10 @@ class Chef::Provider::AwsSubnet < Chef::Provider::AwsProvider
7
7
  fail "Can't create a Subnet without a CIDR block" if new_resource.cidr_block.nil?
8
8
 
9
9
  if existing_subnet == nil
10
- converge_by "Creating new Subnet #{fqn} in VPC #{new_resource.vpc} in #{new_resource.region_name}" do
10
+ converge_by "Creating new Subnet #{fqn} in VPC #{new_resource.vpc} in #{new_driver.aws_config.region}" do
11
11
  opts = { :vpc => vpc_id }
12
12
  opts[:availability_zone] = new_resource.availability_zone if new_resource.availability_zone
13
- subnet = ec2.subnets.create(new_resource.cidr_block, opts)
13
+ subnet = new_driver.ec2.subnets.create(new_resource.cidr_block, opts)
14
14
  subnet.tags['Name'] = new_resource.name
15
15
  subnet.tags['VPC'] = new_resource.vpc
16
16
  new_resource.subnet_id subnet.id
@@ -21,7 +21,7 @@ class Chef::Provider::AwsSubnet < Chef::Provider::AwsProvider
21
21
 
22
22
  action :delete do
23
23
  if existing_subnet
24
- converge_by "Deleting subnet #{fqn} in VPC #{new_resource.vpc} in #{new_resource.region_name}" do
24
+ converge_by "Deleting subnet #{fqn} in VPC #{new_resource.vpc} in #{new_driver.aws_config.region}" do
25
25
  existing_subnet.delete
26
26
  end
27
27
  end
@@ -31,7 +31,7 @@ class Chef::Provider::AwsSubnet < Chef::Provider::AwsProvider
31
31
 
32
32
  def vpc_id
33
33
  @vpc_id ||= begin
34
- ec2.vpcs.with_tag('Name', new_resource.vpc).first
34
+ new_driver.ec2.vpcs.with_tag('Name', new_resource.vpc).first
35
35
  rescue
36
36
  nil
37
37
  end
@@ -39,7 +39,7 @@ class Chef::Provider::AwsSubnet < Chef::Provider::AwsProvider
39
39
 
40
40
  def existing_subnet
41
41
  @subnet_id ||= begin
42
- ec2.subnets.with_tag('Name', new_resource.name).first
42
+ new_driver.ec2.subnets.with_tag('Name', new_resource.name).first
43
43
  rescue
44
44
  nil
45
45
  end
@@ -7,9 +7,9 @@ class Chef::Provider::AwsVpc < Chef::Provider::AwsProvider
7
7
  fail "Can't create a VPC without a CIDR block" if new_resource.cidr_block.nil?
8
8
 
9
9
  if existing_vpc == nil
10
- converge_by "Creating new VPC #{fqn} in #{new_resource.region_name}" do
10
+ converge_by "Creating new VPC #{fqn} in #{new_driver.aws_config.region}" do
11
11
  opts = { :instance_tenancy => :default}
12
- vpc = ec2.vpcs.create(new_resource.cidr_block, opts)
12
+ vpc = new_driver.ec2.vpcs.create(new_resource.cidr_block, opts)
13
13
  vpc.tags['Name'] = new_resource.name
14
14
  new_resource.vpc_id vpc.id
15
15
  new_resource.save
@@ -19,7 +19,7 @@ class Chef::Provider::AwsVpc < Chef::Provider::AwsProvider
19
19
 
20
20
  action :delete do
21
21
  if existing_vpc
22
- converge_by "Deleting VPC #{fqn} in #{new_resource.region_name}" do
22
+ converge_by "Deleting VPC #{fqn} in #{new_driver.aws_config.region}" do
23
23
  existing_vpc.delete
24
24
  end
25
25
  end
@@ -29,7 +29,7 @@ class Chef::Provider::AwsVpc < Chef::Provider::AwsProvider
29
29
 
30
30
  def existing_vpc
31
31
  @existing_vpc ||= begin
32
- ec2.vpcs.with_tag('Name', new_resource.name).first
32
+ new_driver.ec2.vpcs.with_tag('Name', new_resource.name).first
33
33
  rescue
34
34
  nil
35
35
  end
@@ -29,7 +29,7 @@ module AWSDriver
29
29
 
30
30
  include Chef::Mixin::ShellOut
31
31
 
32
- attr_reader :region
32
+ attr_reader :aws_config
33
33
 
34
34
  # URL scheme:
35
35
  # aws:profilename:region
@@ -47,45 +47,58 @@ module AWSDriver
47
47
  region = nil if region && region.empty?
48
48
 
49
49
  credentials = profile_name ? aws_credentials[profile_name] : aws_credentials.default
50
- @region = region || credentials[:region]
51
- # TODO: fix credentials here
52
- AWS.config(:access_key_id => credentials[:aws_access_key_id],
53
- :secret_access_key => credentials[:aws_secret_access_key],
54
- :region => @region)
50
+ @aws_config = AWS::Core::Configuration.new(
51
+ access_key_id: credentials[:aws_access_key_id],
52
+ secret_access_key: credentials[:aws_secret_access_key],
53
+ region: region || credentials[:region]
54
+ )
55
55
  end
56
56
 
57
57
  def self.canonicalize_url(driver_url, config)
58
58
  [ driver_url, config ]
59
59
  end
60
60
 
61
-
62
61
  # Load balancer methods
63
62
  def allocate_load_balancer(action_handler, lb_spec, lb_options, machine_specs)
64
63
  lb_options ||= {}
65
- if lb_options[:security_group_id]
66
- security_group = ec2.security_groups[:security_group_id]
67
- elsif lb_options[:security_group_name]
68
- security_group = ec2.security_groups.filter('group-name', lb_options[:security_group_name])
64
+ if lb_options[:security_group_ids]
65
+ security_groups = ec2.security_groups.filter('group-id', lb_options[:security_group_ids]).to_a
66
+ elsif lb_options[:security_group_names]
67
+ security_groups = ec2.security_groups.filter('group-name', lb_options[:security_group_names]).to_a
68
+ else
69
+ security_groups = []
69
70
  end
71
+ security_group_ids = security_groups.map { |sg| sg.id }
70
72
 
71
- availability_zones = lb_options[:availability_zones]
73
+ availability_zones = lb_options[:availability_zones] || []
74
+ subnets = lb_options[:subnets] || []
72
75
  listeners = lb_options[:listeners]
76
+ scheme = lb_options[:scheme]
73
77
 
74
78
  validate_listeners(listeners)
79
+ if !availability_zones.empty? && !subnets.empty?
80
+ raise "You cannot specify both `availability_zones` and `subnets`"
81
+ end
75
82
 
76
83
  lb_optionals = {}
77
- lb_optionals[:security_groups] = [security_group] if security_group
78
- lb_optionals[:availability_zones] = availability_zones if availability_zones
84
+ lb_optionals[:security_groups] = security_group_ids unless security_group_ids.empty?
85
+ lb_optionals[:availability_zones] = availability_zones unless availability_zones.empty?
86
+ lb_optionals[:subnets] = subnets unless subnets.empty?
79
87
  lb_optionals[:listeners] = listeners if listeners
88
+ lb_optionals[:scheme] = scheme if scheme
80
89
 
90
+ old_elb = nil
81
91
  actual_elb = load_balancer_for(lb_spec)
82
92
  if !actual_elb.exists?
83
93
  perform_action = proc { |desc, &block| action_handler.perform_action(desc, &block) }
84
94
 
85
- updates = [ "Create load balancer #{lb_spec.name} in #{@region}" ]
86
- updates << " enable availability zones #{availability_zones.join(', ')}" if availability_zones && availability_zones.size > 0
95
+ security_group_names = security_groups.map { |sg| sg.name }.join(",")
96
+
97
+ updates = [ "Create load balancer #{lb_spec.name} in #{aws_config.region}" ]
98
+ updates << " enable availability zones #{availability_zones.join(', ')}" if availability_zones.size > 0
99
+ updates << " attach subnets #{subnets.join(', ')}" if subnets.size > 0
87
100
  updates << " with listeners #{listeners.join(', ')}" if listeners && listeners.size > 0
88
- updates << " with security group #{security_group.name}" if security_group
101
+ updates << " with security groups #{security_group_names}" if security_group_names
89
102
 
90
103
  action_handler.perform_action updates do
91
104
  actual_elb = elb.load_balancers.create(lb_spec.name, lb_optionals)
@@ -100,25 +113,113 @@ module AWSDriver
100
113
  # Header gets printed the first time we make an update
101
114
  perform_action = proc do |desc, &block|
102
115
  perform_action = proc { |desc, &block| action_handler.perform_action(desc, &block) }
103
- action_handler.perform_action [ "Update load balancer #{lb_spec.name} in #{@region}", desc ].flatten, &block
116
+ action_handler.perform_action [ "Update load balancer #{lb_spec.name} in #{aws_config.region}", desc ].flatten, &block
104
117
  end
105
118
 
106
- # Update availability zones
107
- enable_zones = (availability_zones || []).dup
108
- disable_zones = []
109
- actual_elb.availability_zones.each do |availability_zone|
110
- if !enable_zones.delete(availability_zone.name)
111
- disable_zones << availability_zone.name
119
+ # TODO: refactor this whole giant method into many smaller method calls
120
+ # Update scheme - scheme is immutable once set, so if it is changing we need to delete the old
121
+ # ELB and create a new one
122
+ if scheme && scheme.downcase != actual_elb.scheme
123
+ desc = [" updating scheme to #{scheme}"]
124
+ desc << " WARN: scheme is immutable, so deleting and re-creating the ELB"
125
+ perform_action.call(desc) do
126
+ old_elb = actual_elb
127
+ actual_elb = elb.load_balancers.create(lb_spec.name, lb_optionals)
112
128
  end
113
129
  end
114
- if enable_zones.size > 0
115
- perform_action.call(" enable availability zones #{enable_zones.join(', ')}") do
116
- actual_elb.availability_zones.enable(*enable_zones)
130
+
131
+ # Update security groups
132
+ if security_group_ids.empty?
133
+ Chef::Log.debug("No Security Groups specified. Load_balancer[#{actual_elb.name}] cannot have " +
134
+ "empty Security Groups, so assuming it only currently has the default Security Group. No action taken.")
135
+ else
136
+ current = actual_elb.security_group_ids
137
+ desired = security_group_ids
138
+ if current != desired
139
+ perform_action.call(" updating security groups to #{desired.to_a}") do
140
+ elb.client.apply_security_groups_to_load_balancer(
141
+ load_balancer_name: actual_elb.name,
142
+ security_groups: desired.to_a
143
+ )
144
+ end
117
145
  end
118
146
  end
119
- if disable_zones.size > 0
120
- perform_action.call(" disable availability zones #{disable_zones.join(', ')}") do
121
- actual_elb.availability_zones.disable(*disable_zones)
147
+
148
+ # A subnet always belongs to an availability zone. When specifying a ELB spec, you can either
149
+ # specify subnets OR AZs but not both. You cannot specify multiple subnets in the same AZ.
150
+ # You must specify at least 1 subnet or AZ. On an update you cannot remove all subnets
151
+ # or AZs - it must belong to one.
152
+ if !availability_zones.empty? && !subnets.empty?
153
+ # We do this check here because there is no atomic call we can make to specify both
154
+ # subnets and AZs at the same time
155
+ raise "You cannot specify both `availability_zones` and `subnets`"
156
+ end
157
+ # Users can switch from availability zones to subnets or vice versa. To ensure we do not
158
+ # unassign all (which causes an AWS error) we first add all available ones, then remove
159
+ # an unecessary ones
160
+ actual_zones_subnets = {}
161
+ actual_elb.subnets.each do |subnet|
162
+ actual_zones_subnets[subnet.id] = subnet.availability_zone.name
163
+ end
164
+
165
+ # Only 1 of subnet or AZ will be populated b/c of our check earlier
166
+ desired_subnets_zones = {}
167
+ availability_zones.each do |zone|
168
+ # If the user specifies availability zone, we find the default subnet for that
169
+ # AZ because this duplicates the create logic
170
+ zone = zone.downcase
171
+ filters = [
172
+ {:name => 'availabilityZone', :values => [zone]},
173
+ {:name => 'defaultForAz', :values => ['true']}
174
+ ]
175
+ default_subnet = ec2.client.describe_subnets(:filters => filters)[:subnet_set]
176
+ if default_subnet.size != 1
177
+ raise "Could not find default subnet in availability zone #{zone}"
178
+ end
179
+ default_subnet = default_subnet[0]
180
+ desired_subnets_zones[default_subnet[:subnet_id]] = zone
181
+ end
182
+ unless subnets.empty?
183
+ subnet_query = ec2.client.describe_subnets(:subnet_ids => subnets)[:subnet_set]
184
+ # AWS raises an error on an unknown subnet, but not an unknown AZ
185
+ subnet_query.each do |subnet|
186
+ zone = subnet[:availability_zone].downcase
187
+ desired_subnets_zones[subnet[:subnet_id]] = zone
188
+ end
189
+ end
190
+
191
+ # We only bother attaching subnets, because doing this automatically attaches the AZ
192
+ attach_subnets = desired_subnets_zones.keys - actual_zones_subnets.keys
193
+ unless attach_subnets.empty?
194
+ action = " attach subnets #{attach_subnets.join(', ')}"
195
+ enable_zones = (desired_subnets_zones.map {|s,z| z if attach_subnets.include?(s)}).compact
196
+ action += " (availability zones #{enable_zones.join(', ')})"
197
+ perform_action.call(action) do
198
+ begin
199
+ elb.client.attach_load_balancer_to_subnets(
200
+ load_balancer_name: actual_elb.name,
201
+ subnets: attach_subnets
202
+ )
203
+ rescue AWS::ELB::Errors::InvalidConfigurationRequest
204
+ raise "You cannot currently move from 1 subnet to another in the same availability zone. " +
205
+ "Amazon does not have an atomic operation which allows this. You must create a new " +
206
+ "ELB with the correct subnets and move instances into it. Tried to attach subets " +
207
+ "#{attach_subnets.join(', ')} (availability zones #{enable_zones.join(', ')}) to " +
208
+ "existing ELB named #{actual_elb.name}"
209
+ end
210
+ end
211
+ end
212
+
213
+ detach_subnets = actual_zones_subnets.keys - desired_subnets_zones.keys
214
+ unless detach_subnets.empty?
215
+ action = " detach subnets #{detach_subnets.join(', ')}"
216
+ disable_zones = (actual_zones_subnets.map {|s,z| z if detach_subnets.include?(s)}).compact
217
+ action += " (availability zones #{disable_zones.join(', ')})"
218
+ perform_action.call(action) do
219
+ elb.client.detach_load_balancer_from_subnets(
220
+ load_balancer_name: actual_elb.name,
221
+ subnets: detach_subnets
222
+ )
122
223
  end
123
224
  end
124
225
 
@@ -171,24 +272,39 @@ module AWSDriver
171
272
  end
172
273
  end
173
274
 
174
- # Update instance list
175
- actual_instance_ids = Set.new(actual_elb.instances.map { |i| i.instance_id })
176
-
177
- instances_to_add = machine_specs.select { |s| !actual_instance_ids.include?(s.location['instance_id']) }
178
- instance_ids_to_remove = actual_instance_ids - machine_specs.map { |s| s.location['instance_id'] }
275
+ # Update instance list, but only if there are machines specified
276
+ actual_instance_ids = actual_elb.instances.map { |i| i.instance_id }
179
277
 
180
- if instances_to_add.size > 0
181
- perform_action.call(" add machines #{instances_to_add.map { |s| s.name }.join(', ')}") do
182
- instance_ids_to_add = instances_to_add.map { |s| s.location['instance_id'] }
183
- Chef::Log.debug("Adding instances #{instance_ids_to_add.join(', ')} to load balancer #{actual_elb.name} in region #{@region}")
184
- actual_elb.instances.add(instance_ids_to_add)
278
+ if machine_specs
279
+ instances_to_add = machine_specs.select { |s| !actual_instance_ids.include?(s.location['instance_id']) }
280
+ instance_ids_to_remove = actual_instance_ids - machine_specs.map { |s| s.location['instance_id'] }
281
+
282
+ if instances_to_add.size > 0
283
+ perform_action.call(" add machines #{instances_to_add.map { |s| s.name }.join(', ')}") do
284
+ instance_ids_to_add = instances_to_add.map { |s| s.location['instance_id'] }
285
+ Chef::Log.debug("Adding instances #{instance_ids_to_add.join(', ')} to load balancer #{actual_elb.name} in region #{aws_config.region}")
286
+ actual_elb.instances.add(instance_ids_to_add)
287
+ end
288
+ end
289
+
290
+ if instance_ids_to_remove.size > 0
291
+ perform_action.call(" remove instances #{instance_ids_to_remove}") do
292
+ actual_elb.instances.remove(instance_ids_to_remove)
293
+ end
185
294
  end
186
295
  end
187
296
 
188
- if instance_ids_to_remove.size > 0
189
- perform_action.call(" remove instances #{instance_ids_to_remove}") do
190
- actual_elb.instances.remove(instance_ids_to_remove)
191
- end
297
+ # We have successfully switched all our instances to the (possibly) new LB
298
+ # so it is safe to delete the old one.
299
+ unless old_elb.nil?
300
+ old_elb.delete
301
+ end
302
+ ensure
303
+ # Something went wrong before we could moved instances from the old ELB to the new one
304
+ # Don't delete the old ELB, but warn users there could now be 2 ELBs with the same name
305
+ unless old_elb.nil?
306
+ Chef::Log.warn("It is possible there are now 2 ELB instances - #{old_elb.id} and #{actual_elb.id}. " +
307
+ "Determine which is correct and manually clean up the other.")
192
308
  end
193
309
  end
194
310
 
@@ -295,7 +411,7 @@ EOD
295
411
  if actual_instance == nil || !actual_instance.exists? || actual_instance.status == :terminated
296
412
  bootstrap_options = bootstrap_options_for(action_handler, machine_spec, machine_options)
297
413
 
298
- action_handler.perform_action "Create #{machine_spec.name} with AMI #{bootstrap_options[:image_id]} in #{@region}" do
414
+ action_handler.perform_action "Create #{machine_spec.name} with AMI #{bootstrap_options[:image_id]} in #{aws_config.region}" do
299
415
  Chef::Log.debug "Creating instance with bootstrap options #{bootstrap_options}"
300
416
 
301
417
  instance = ec2.instances.create(bootstrap_options.to_hash)
@@ -339,7 +455,7 @@ EOD
339
455
  if instance.status != :running
340
456
  wait_until_machine(action_handler, machine_spec, instance) { instance.status != :stopping }
341
457
  if instance.status == :stopped
342
- action_handler.perform_action "Start #{machine_spec.name} (#{machine_spec.location['instance_id']}) in #{@region} ..." do
458
+ action_handler.perform_action "Start #{machine_spec.name} (#{machine_spec.location['instance_id']}) in #{aws_config.region} ..." do
343
459
  instance.start
344
460
  end
345
461
  end
@@ -364,7 +480,7 @@ EOD
364
480
  instance = instance_for(machine_spec)
365
481
  if instance && instance.exists?
366
482
  # TODO do we need to wait_until(action_handler, machine_spec, instance) { instance.status != :shutting_down } ?
367
- action_handler.perform_action "Terminate #{machine_spec.name} (#{machine_spec.location['instance_id']}) in #{@region} ..." do
483
+ action_handler.perform_action "Terminate #{machine_spec.name} (#{machine_spec.location['instance_id']}) in #{aws_config.region} ..." do
368
484
  instance.terminate
369
485
  machine_spec.location = nil
370
486
  end
@@ -376,6 +492,30 @@ EOD
376
492
  strategy.cleanup_convergence(action_handler, machine_spec)
377
493
  end
378
494
 
495
+ def ec2
496
+ @ec2 ||= AWS::EC2.new(config: aws_config)
497
+ end
498
+
499
+ def elb
500
+ @elb ||= AWS::ELB.new(config: aws_config)
501
+ end
502
+
503
+ def sns
504
+ @sns ||= AWS::SNS.new(config: aws_config)
505
+ end
506
+
507
+ def sqs
508
+ @sqs ||= AWS::SQS.new(config: aws_config)
509
+ end
510
+
511
+ def s3
512
+ @s3 ||= AWS::S3.new(config: aws_config)
513
+ end
514
+
515
+ def auto_scaling
516
+ @auto_scaling ||= AWS::AutoScaling.new(config: aws_config)
517
+ end
518
+
379
519
  private
380
520
 
381
521
  # For creating things like AWS keypairs exclusively
@@ -397,7 +537,7 @@ EOD
397
537
 
398
538
  def bootstrap_options_for(action_handler, machine_spec, machine_options)
399
539
  bootstrap_options = (machine_options[:bootstrap_options] || {}).to_h.dup
400
- image_id = bootstrap_options[:image_id] || machine_options[:image_id] || default_ami_for_region(@region)
540
+ image_id = bootstrap_options[:image_id] || machine_options[:image_id] || default_ami_for_region(aws_config.region)
401
541
  bootstrap_options[:image_id] = image_id
402
542
  if !bootstrap_options[:key_name]
403
543
  Chef::Log.debug('No key specified, generating a default one...')
@@ -415,14 +555,6 @@ EOD
415
555
  bootstrap_options
416
556
  end
417
557
 
418
- def ec2
419
- @ec2 ||= AWS.ec2
420
- end
421
-
422
- def elb
423
- @elb ||= AWS::ELB.new
424
- end
425
-
426
558
  def default_ssh_username
427
559
  'ubuntu'
428
560
  end
@@ -747,13 +879,11 @@ EOD
747
879
  def default_aws_keypair(action_handler, machine_spec)
748
880
  driver = self
749
881
  default_key_name = default_aws_keypair_name(machine_spec)
750
- _region = region
751
882
  updated = @@chef_default_lock.synchronize do
752
883
  Provisioning.inline_resource(action_handler) do
753
884
  aws_key_pair default_key_name do
754
885
  driver driver
755
886
  allow_overwrite true
756
- region_name _region
757
887
  end
758
888
  end
759
889
  end
@@ -1,7 +1,7 @@
1
1
  class Chef
2
2
  module Provisioning
3
3
  module AWSDriver
4
- VERSION = '0.3'
4
+ VERSION = '0.4.0'
5
5
  end
6
6
  end
7
7
  end
@@ -4,15 +4,9 @@ require 'chef/resource/aws_resource'
4
4
  class Chef::Resource::AwsKeyPair < Chef::Resource::AwsResource
5
5
  self.resource_name = 'aws_key_pair'
6
6
 
7
- def initialize(*args)
8
- super
9
- @driver = run_context.chef_provisioning.current_driver
10
- end
11
-
12
7
  actions :create, :delete, :nothing
13
8
  default_action :create
14
9
 
15
- attribute :driver
16
10
  # Private key to use as input (will be generated if it does not exist)
17
11
  attribute :private_key_path, :kind_of => String
18
12
  # Public key to use as input (will be generated if it does not exist)
@@ -1,10 +1,10 @@
1
1
  # Common AWS resource - contains metadata that all AWS resources will need
2
2
  class Chef::Resource::AwsResource < Chef::Resource::ChefDataBagResource
3
- stored_attribute :region_name
3
+ stored_attribute :driver
4
4
 
5
5
  def initialize(*args)
6
6
  super
7
- @region_name = run_context.chef_provisioning.current_data_center
7
+ @driver = run_context.chef_provisioning.current_driver
8
8
  end
9
9
 
10
10
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-provisioning-aws
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.3'
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Ewart
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-26 00:00:00.000000000 Z
11
+ date: 2015-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef
@@ -136,7 +136,6 @@ files:
136
136
  - lib/chef/resource/aws_sqs_queue.rb
137
137
  - lib/chef/resource/aws_subnet.rb
138
138
  - lib/chef/resource/aws_vpc.rb
139
- - spec/acceptance/aws_ebs_volume/nodes/ettores-mbp.lan.json
140
139
  - spec/chef_zero_rspec_helper.rb
141
140
  - spec/spec_helper.rb
142
141
  - spec/unit/aws_driver/credentials_spec.rb
@@ -161,9 +160,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
161
160
  version: '0'
162
161
  requirements: []
163
162
  rubyforge_project:
164
- rubygems_version: 2.2.2
163
+ rubygems_version: 2.4.2
165
164
  signing_key:
166
165
  specification_version: 4
167
166
  summary: Provisioner for creating aws containers in Chef Provisioning.
168
167
  test_files: []
169
- has_rdoc:
@@ -1,3 +0,0 @@
1
- {
2
- "name": "ettores-mbp.lan"
3
- }