kitchen-ec2 3.13.0 → 3.15.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c5ed0f1bbc994d156a6374c98a1c48f00d2f789f8540b0cb33ae0755996ffca5
4
- data.tar.gz: 0f5f90acb192d7a649ebd9d7861ed2bfbec2ae1665d32c5e66d75685518b1eff
3
+ metadata.gz: f3b81a785bd64e6ae13091e71fe8faf3b295755fc9b30d4cee0c84246a107ea1
4
+ data.tar.gz: c0bfc45018438894ebb3775204d3e712ed5aef754a81b7588cb0cca79369e2ab
5
5
  SHA512:
6
- metadata.gz: 890a0a34755ab636605a8fcfbc45ce8c0f055adb0fa5404c48d516060da3089628091d37bbc9ad555601d742f40647183f2b34988dc703ca03477722b3dfb1bf
7
- data.tar.gz: 617aaee4fdd8b335e17731621abb9ae140b73286e4da2e77adbb46cdc560789f02eeb85f208217e3ffbd03746c52a46f4ae051d93ab1436fb2fb8f3f2b267351
6
+ metadata.gz: 0d13f84f11907b1fb657dca1a400173be055420c30a7a5282af7273c7f1ecfd48485abdf24dc1d1fbe1fa67f4642564b080243f1fdae9d1e400052e3119e7f68
7
+ data.tar.gz: bb606e4db8b58e7ed57951cca247e4c8271fdbe5430ba59102f2524c0de9201ab46ea38fb431101f92ea02ac720ea508f5b59abb383ed4ffab5821f251366a71
@@ -0,0 +1,135 @@
1
+ module Kitchen
2
+ module Driver
3
+ module Mixins
4
+ module DedicatedHosts
5
+ # check if a suitable dedicated host is available
6
+ # @return Boolean
7
+ def host_available?
8
+ !hosts_with_capacity.empty?
9
+ end
10
+
11
+ # get dedicated host with capacity for instance type
12
+ # @return Aws::EC2::Types::Host
13
+ def hosts_with_capacity
14
+ hosts_managed.select do |host|
15
+ # T-instance hosts do not report available capacity and can be overprovisioned
16
+ if host.available_capacity.nil?
17
+ true
18
+ else
19
+ instance_capacity = host.available_capacity.available_instance_capacity
20
+ capacity_for_type = instance_capacity.detect { |cap| cap.instance_type == config[:instance_type] }
21
+ capacity_for_type.available_capacity > 0
22
+ end
23
+ end
24
+ end
25
+
26
+ # check if host has no instances running
27
+ # @param host_id [Aws::EC2::Types::Host] dedicated host
28
+ # @return Boolean
29
+ def host_unused?(host)
30
+ host.instances.empty?
31
+ end
32
+
33
+ # get host data for host id
34
+ # @param host_id [Aws::EC2::Types::Host] dedicated host
35
+ # @return Array(Aws::EC2::Types::Host)
36
+ def host_for_id(host_id)
37
+ ec2.client.describe_hosts(host_ids: [host_id])&.first
38
+ end
39
+
40
+ # get dedicated hosts managed by Test Kitchen
41
+ # @return Array(Aws::EC2::Types::Host)
42
+ def hosts_managed
43
+ response = ec2.client.describe_hosts(
44
+ filter: [
45
+ { name: "tag:ManagedBy", values: ["Test Kitchen"] },
46
+ ]
47
+ )
48
+
49
+ response.hosts.select { |host| host.state == "available" }
50
+ end
51
+
52
+ # allocate new dedicated host for requested instance type
53
+ # @return String host id
54
+ def allocate_host
55
+ unless allow_allocate_host?
56
+ warn "ERROR: Attempted to allocate dedicated host but need environment variable TK_ALLOCATE_DEDICATED_HOST to be set"
57
+ exit!
58
+ end
59
+
60
+ unless config[:availability_zone]
61
+ warn "Attempted to allocate dedicated host but option 'availability_zone' is not set"
62
+ exit!
63
+ end
64
+
65
+ info("Allocating dedicated host for #{config[:instance_type]} instances. This will incur additional cost")
66
+
67
+ request = {
68
+ availability_zone: config[:availability_zone],
69
+ quantity: 1,
70
+
71
+ auto_placement: "on",
72
+
73
+ tag_specifications: [
74
+ {
75
+ resource_type: "dedicated-host",
76
+ tags: [
77
+ { key: "ManagedBy", value: "Test Kitchen" },
78
+ ],
79
+ },
80
+ ],
81
+ }
82
+
83
+ # ".metal" is a 1:1 association, everything else has multi-instance capability
84
+ if instance_size_from_type(config[:instance_type]) == "metal"
85
+ request[:instance_type] = config[:instance_type]
86
+ else
87
+ request[:instance_family] = instance_family_from_type(config[:instance_type])
88
+ end
89
+
90
+ response = ec2.client.allocate_hosts(request)
91
+ response.host_ids.first
92
+ end
93
+
94
+ # deallocate a dedicated host
95
+ # @param host_id [String] dedicated host id
96
+ # @return Aws::EC2::Types::ReleaseHostsResult
97
+ def deallocate_host(host_id)
98
+ info("Deallocating dedicated host #{host_id}")
99
+
100
+ response = ec2.client.release_hosts({ host_ids: [host_id] })
101
+ unless response.unsuccessful.empty?
102
+ warn "ERROR: Could not release dedicated host #{host_id}. Host may remain allocated and incur cost"
103
+ exit!
104
+ end
105
+ end
106
+
107
+ # return instance family from type
108
+ # @param instance_type [String] type in format family.size
109
+ # @return String instance family
110
+ def instance_family_from_type(instance_type)
111
+ instance_type.split(".").first
112
+ end
113
+
114
+ # return instance size from type
115
+ # @param instance_type [String] type in format family.size
116
+ # @return String instance size
117
+ def instance_size_from_type(instance_type)
118
+ instance_type.split(".").last
119
+ end
120
+
121
+ # check config, if host allocation is enabled
122
+ # @return Boolean
123
+ def allow_allocate_host?
124
+ config[:allocate_dedicated_host]
125
+ end
126
+
127
+ # check config, if host deallocation is enabled
128
+ # @return Boolean
129
+ def allow_deallocate_host?
130
+ config[:deallocate_dedicated_host]
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,51 @@
1
+ #
2
+ # Copyright:: 2016-2018, Chef Software, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require_relative "../standard_platform"
17
+
18
+ module Kitchen
19
+ module Driver
20
+ class Aws
21
+ class StandardPlatform
22
+ class MacOS < StandardPlatform
23
+ StandardPlatform.platforms["macos"] = self
24
+
25
+ # default username for this platform's ami
26
+ # @return [String]
27
+ def username
28
+ "ec2-user"
29
+ end
30
+
31
+ def image_search
32
+ search = {
33
+ "owner-id" => "100343932686",
34
+ "name" => version ? "amzn-ec2-macos-#{version}*" : "amzn2-ec2-macos-*",
35
+ }
36
+ search["architecture"] = architecture if architecture
37
+ search["architecture"] = "arm64_mac" if architecture == "arm64"
38
+ search
39
+ end
40
+
41
+ def self.from_image(driver, image)
42
+ if /amzn-ec2-macos/i.match?(image.name)
43
+ image.name =~ /\b(\d+(\.\d+[\.\d])?)/i
44
+ new(driver, "macos", (Regexp.last_match || [])[1], image.architecture)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -27,6 +27,7 @@ module Kitchen
27
27
  # rhel
28
28
  # fedora
29
29
  # freebsd
30
+ # macos
30
31
  # ubuntu
31
32
  # windows
32
33
  #
@@ -21,6 +21,7 @@ require "json" unless defined?(JSON)
21
21
  require "kitchen"
22
22
  require_relative "ec2_version"
23
23
  require_relative "aws/client"
24
+ require_relative "aws/dedicated_hosts"
24
25
  require_relative "aws/instance_generator"
25
26
  require_relative "aws/standard_platform"
26
27
  require_relative "aws/standard_platform/amazon"
@@ -30,6 +31,7 @@ require_relative "aws/standard_platform/debian"
30
31
  require_relative "aws/standard_platform/rhel"
31
32
  require_relative "aws/standard_platform/fedora"
32
33
  require_relative "aws/standard_platform/freebsd"
34
+ require_relative "aws/standard_platform/macos"
33
35
  require_relative "aws/standard_platform/ubuntu"
34
36
  require_relative "aws/standard_platform/windows"
35
37
  require "aws-sdk-ec2"
@@ -78,6 +80,7 @@ module Kitchen
78
80
  default_config :aws_secret_access_key, nil
79
81
  default_config :aws_session_token, nil
80
82
  default_config :aws_ssh_key_id, ENV["AWS_SSH_KEY_ID"]
83
+ default_config :aws_ssh_key_type, "rsa"
81
84
  default_config :image_id, &:default_ami
82
85
  default_config :image_search, nil
83
86
  default_config :username, nil
@@ -89,6 +92,10 @@ module Kitchen
89
92
  default_config :instance_initiated_shutdown_behavior, nil
90
93
  default_config :ssl_verify_peer, true
91
94
  default_config :skip_cost_warning, false
95
+ default_config :allocate_dedicated_host, false
96
+ default_config :deallocate_dedicated_host, false
97
+
98
+ include Kitchen::Driver::Mixins::DedicatedHosts
92
99
 
93
100
  def initialize(*args, &block)
94
101
  super
@@ -225,6 +232,18 @@ module Kitchen
225
232
  config[:aws_ssh_key_id] = nil
226
233
  end
227
234
 
235
+ # Allocate new dedicated hosts if needed and allowed
236
+ if config[:tenancy] == "host"
237
+ unless host_available? || allow_allocate_host?
238
+ warn "ERROR: tenancy `host` requested but no suitable host and allocation not allowed (set `allocate_dedicated_host` setting)"
239
+ exit!
240
+ end
241
+
242
+ allocate_host unless host_available?
243
+
244
+ info("Auto placement on one dedicated host out of: #{hosts_with_capacity.map(&:host_id).join(", ")}")
245
+ end
246
+
228
247
  if config[:spot_price]
229
248
  # Spot instance when a price is set
230
249
  server = with_request_limit_backoff(state) { submit_spots }
@@ -296,6 +315,12 @@ module Kitchen
296
315
  # Clean up any auto-created security groups or keys.
297
316
  delete_security_group(state)
298
317
  delete_key(state)
318
+
319
+ # Clean up dedicated hosts matching instance_type and unused (if allowed)
320
+ if config[:tenancy] == "host" && allow_deallocate_host?
321
+ empty_hosts = hosts_with_capacity.select { |host| host_unused?(host) }
322
+ empty_hosts.each { |host| deallocate_host(host.host_id) }
323
+ end
299
324
  end
300
325
 
301
326
  def image
@@ -830,7 +855,7 @@ module Kitchen
830
855
  # to rapidly exhaust local entropy by creating a lot of keys. So this is
831
856
  # probably fine. If you want very high security, probably don't use this
832
857
  # feature anyway.
833
- resp = ec2.client.create_key_pair(key_name: "kitchen-#{name_parts.join("-")}")
858
+ resp = ec2.client.create_key_pair(key_name: "kitchen-#{name_parts.join("-")}", key_type: config[:aws_ssh_key_type])
834
859
  state[:auto_key_id] = resp.key_name
835
860
  info("Created automatic key pair #{state[:auto_key_id]}")
836
861
  # Write the key out with safe permissions
@@ -21,6 +21,6 @@ module Kitchen
21
21
  module Driver
22
22
 
23
23
  # Version string for EC2 Test Kitchen driver
24
- EC2_VERSION = "3.13.0".freeze
24
+ EC2_VERSION = "3.15.0".freeze
25
25
  end
26
26
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kitchen-ec2
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.13.0
4
+ version: 3.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fletcher Nichol
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-30 00:00:00.000000000 Z
11
+ date: 2022-12-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: test-kitchen
@@ -73,6 +73,7 @@ extra_rdoc_files: []
73
73
  files:
74
74
  - LICENSE
75
75
  - lib/kitchen/driver/aws/client.rb
76
+ - lib/kitchen/driver/aws/dedicated_hosts.rb
76
77
  - lib/kitchen/driver/aws/instance_generator.rb
77
78
  - lib/kitchen/driver/aws/standard_platform.rb
78
79
  - lib/kitchen/driver/aws/standard_platform/amazon.rb
@@ -81,6 +82,7 @@ files:
81
82
  - lib/kitchen/driver/aws/standard_platform/debian.rb
82
83
  - lib/kitchen/driver/aws/standard_platform/fedora.rb
83
84
  - lib/kitchen/driver/aws/standard_platform/freebsd.rb
85
+ - lib/kitchen/driver/aws/standard_platform/macos.rb
84
86
  - lib/kitchen/driver/aws/standard_platform/rhel.rb
85
87
  - lib/kitchen/driver/aws/standard_platform/ubuntu.rb
86
88
  - lib/kitchen/driver/aws/standard_platform/windows.rb
@@ -105,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
107
  - !ruby/object:Gem::Version
106
108
  version: '0'
107
109
  requirements: []
108
- rubygems_version: 3.2.3
110
+ rubygems_version: 3.3.16
109
111
  signing_key:
110
112
  specification_version: 4
111
113
  summary: A Test Kitchen Driver for Amazon EC2