kitchen-ec2 3.22.9 → 3.22.10

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
  SHA256:
3
- metadata.gz: 54de858935bf91fcad58900283fd45042007c18d546797d098f29b955d177c87
4
- data.tar.gz: 95fc2485b796d0e87974e17de7b34dd858c08fdb2d2433cbae6975983cea1501
3
+ metadata.gz: adbbc52b9c77d773ae78ebd08798d629a6781793d0e91ff46fb14eb080c70595
4
+ data.tar.gz: 8df7160b05b65d0187b24d9525ea458593db0c95cf9cef261683229752ca1cf6
5
5
  SHA512:
6
- metadata.gz: dad42aca368360dd2d11c58583d13360f34fa77925a0fd40ede0c97da97092361c74ba7b61401918d7c1ae33732806fe8cdd7ddb84b2d23024dc21a20a94a835
7
- data.tar.gz: 5e3a1ce54adf7425bce0c70816b212b0a2e8be36f35e9a1f8a58ebe971cfda2ace1c004e9dea91dc5d334021ba8df5f7541d1f891b1121021a9321f82d0f311c
6
+ metadata.gz: 956f2322fd4e6bb42ad179c677159be0acb108b30c651c940e95b3c6e266466a548a982f9bb9bcc6edeea3e3ae9734ddc37d80dad14cce80a78c268d733a97ba
7
+ data.tar.gz: f98fe3846db116988011feefebae241fec7145cbbc49aa45d3e82620c1ba5fa36ae15222125144cf37405d7f373db0c5fbcf32505b62453b9f677e84cfa3c765
@@ -92,34 +92,29 @@ module Kitchen
92
92
  security_groups = []
93
93
  filters = [config[:security_group_filter]].flatten
94
94
  filters.each do |sg_filter|
95
- r = {}
95
+ # Built up rather than assigned, so that a filter carrying both a
96
+ # name and a tag searches on both. Assigning meant the tag
97
+ # replaced the name outright, silently widening the search to
98
+ # whatever else carried that tag.
99
+ criteria = []
96
100
  if sg_filter[:name]
97
- r[:filters] = [
98
- {
99
- name: "group-name",
100
- values: [sg_filter[:name]],
101
- },
102
- {
103
- name: "vpc-id",
104
- values: [vpc_id],
105
- },
106
- ]
101
+ criteria << { name: "group-name", values: [sg_filter[:name]] }
107
102
  end
108
-
109
103
  if sg_filter[:tag]
110
- r[:filters] = [
111
- {
112
- name: "tag:#{sg_filter[:tag]}",
113
- values: [sg_filter[:value]],
114
- },
115
- {
116
- name: "vpc-id",
117
- values: [vpc_id],
118
- },
119
- ]
104
+ criteria << { name: "tag:#{sg_filter[:tag]}", values: [sg_filter[:value]] }
105
+ end
106
+
107
+ # Refused rather than sent: describe_security_groups with no
108
+ # filters returns every security group in the region, and all of
109
+ # them were then attached to the instance.
110
+ if criteria.empty?
111
+ raise "A security_group_filter needs a `name` or a `tag`, but " \
112
+ "#{sg_filter.inspect} has neither."
120
113
  end
121
114
 
122
- security_group = client.describe_security_groups(r).security_groups
115
+ criteria << { name: "vpc-id", values: [vpc_id] }
116
+
117
+ security_group = client.describe_security_groups(filters: criteria).security_groups
123
118
 
124
119
  if security_group.any?
125
120
  security_group.each { |sg| security_groups.push(sg.group_id) }
@@ -98,6 +98,29 @@ module Kitchen
98
98
  search
99
99
  end
100
100
 
101
+ # Sort images newest release first, keeping backports images last.
102
+ #
103
+ # Debian publishes a backports image alongside each release, from the
104
+ # same account and under the same "debian-<release>-" prefix,
105
+ # differing only by the word "backports" in the name:
106
+ #
107
+ # debian-12-backports-amd64-20260821-2577
108
+ # debian-12-amd64-20260821-2577
109
+ #
110
+ # It runs the backports kernel rather than the release's own -- 6.12
111
+ # against 6.1 for Debian 12 -- and is often published minutes after
112
+ # its plain counterpart, so a tie broken on creation date handed
113
+ # every Debian platform the backports image.
114
+ #
115
+ # This is a preference rather than a filter, so a release with only
116
+ # backports images published is still selectable.
117
+ #
118
+ # @param images [Array<Aws::EC2::Image>] the images to sort
119
+ # @return [Array<Aws::EC2::Image>] the images, newest release first
120
+ def sort_by_version(images)
121
+ prefer(super) { |image| !image.name.include?("backports") }
122
+ end
123
+
101
124
  # Detect this platform from an EC2 image.
102
125
  #
103
126
  # Matching is done on the image name, which is the only reliable signal
@@ -19,6 +19,7 @@
19
19
  require "fileutils" unless defined?(FileUtils)
20
20
  require "sshkey" unless defined?(SSHKey)
21
21
  require "benchmark" unless defined?(Benchmark)
22
+ require "open3" unless defined?(Open3)
22
23
  require "json" unless defined?(JSON)
23
24
  require "kitchen"
24
25
  require_relative "ec2_version"
@@ -229,6 +230,19 @@ module Kitchen
229
230
  end
230
231
  end
231
232
 
233
+ # A placement group is named either by ID or by name, never both: EC2
234
+ # rejects a RunInstances call carrying the pair. The payload generator
235
+ # therefore only applies each one when the other is absent, which means
236
+ # setting both silently drops both and the instance launches in no
237
+ # placement group at all, with nothing in the output to say so.
238
+ validations[:placement] = lambda do |_attr, val, _driver|
239
+ if val.is_a?(Hash) && val[:group_id] && val[:group_name]
240
+ warn "Cannot set both 'group_id' and 'group_name' under 'placement'. " \
241
+ "A placement group is identified by one or the other, so please set only one."
242
+ exit!
243
+ end
244
+ end
245
+
232
246
  # empty keys cause failures when tagging and they make no sense
233
247
  validations[:tags] = lambda do |_attr, val, _driver|
234
248
  # if someone puts the tags each on their own line it's an array not a hash
@@ -295,7 +309,8 @@ module Kitchen
295
309
  exit!
296
310
  end
297
311
 
298
- allocate_host unless host_available?
312
+ # Remembered so that destroy releases this host and no other.
313
+ state[:allocated_host_id] = allocate_host unless host_available?
299
314
 
300
315
  info("Auto placement on one dedicated host out of: #{hosts_with_capacity.map(&:host_id).join(", ")}")
301
316
  end
@@ -438,11 +453,22 @@ module Kitchen
438
453
  delete_security_group(state)
439
454
  delete_key(state)
440
455
 
441
- # Clean up dedicated hosts matching instance_type and unused (if allowed)
456
+ # Release the dedicated host this instance's create allocated, if it
457
+ # allocated one and nothing else is left running on it.
458
+ #
459
+ # Only that host. Dedicated hosts are a shared pool -- create places
460
+ # onto any managed host with room rather than always allocating, so
461
+ # most runs allocate nothing -- and releasing every empty managed host
462
+ # tore down hosts belonging to other suites, including one allocated
463
+ # seconds earlier by a concurrent run whose instance had not launched
464
+ # onto it yet.
442
465
  return unless config[:tenancy] == "host" && allow_deallocate_host?
443
466
 
444
- empty_hosts = hosts_with_capacity.select { |host| host_unused?(host) }
445
- empty_hosts.each { |host| deallocate_host(host.host_id) }
467
+ host_id = state.delete(:allocated_host_id)
468
+ return unless host_id
469
+
470
+ host = host_for_id(host_id)
471
+ deallocate_host(host_id) if host && host_unused?(host)
446
472
  end
447
473
 
448
474
  # The EC2 image this instance will be created from.
@@ -954,20 +980,35 @@ module Kitchen
954
980
  # @return [String] a PowerShell script wrapped in `<powershell>` tags
955
981
  def default_windows_user_data
956
982
  base_script = Kitchen::Util.outdent!(<<-EOH)
957
- $OSVersion = (get-itemproperty -Path "HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion" -Name ProductName).ProductName
958
- If($OSVersion.contains('2016') -Or $OSVersion.contains('2019') -Or $OSVersion -eq 'Windows Server Datacenter') {
959
- New-Item -ItemType Directory -Force -Path 'C:\\ProgramData\\Amazon\\EC2-Windows\\Launch\\Log'
960
- $logfile='C:\\ProgramData\\Amazon\\EC2-Windows\\Launch\\Log\\kitchen-ec2.log'
961
- # EC2Launch doesn't init extra disks by default
962
- C:\\ProgramData\\Amazon\\EC2-Windows\\Launch\\Scripts\\InitializeDisks.ps1
963
- } Else {
964
- New-Item -ItemType Directory -Force -Path 'C:\\Program Files\\Amazon\\Ec2ConfigService\\Logs'
965
- $logfile='C:\\Program Files\\Amazon\\Ec2ConfigService\\Logs\\kitchen-ec2.log'
966
- }
967
-
968
- # Logfile fail-safe in case the directory does not exist
983
+ # Log where the installed launch agent already logs, chosen by looking
984
+ # for it rather than by matching the OS against known release names.
985
+ # Writing into the directory of an agent that is not installed would
986
+ # invent a misleading empty tree.
987
+ $logdir = If (Test-Path 'C:\\ProgramData\\Amazon\\EC2Launch') {
988
+ 'C:\\ProgramData\\Amazon\\EC2Launch\\log'
989
+ } ElseIf (Test-Path 'C:\\ProgramData\\Amazon\\EC2-Windows\\Launch') {
990
+ 'C:\\ProgramData\\Amazon\\EC2-Windows\\Launch\\Log'
991
+ } ElseIf (Test-Path 'C:\\Program Files\\Amazon\\Ec2ConfigService') {
992
+ 'C:\\Program Files\\Amazon\\Ec2ConfigService\\Logs'
993
+ } Else {
994
+ Join-Path $env:ProgramData 'Amazon\\kitchen-ec2'
995
+ }
996
+ New-Item -ItemType Directory -Force -Path $logdir | Out-Null
997
+ $logfile = Join-Path $logdir 'kitchen-ec2.log'
969
998
  New-Item $logfile -Type file -Force
970
999
 
1000
+ # Extra EBS volumes are attached but left uninitialized: no launch
1001
+ # agent partitions them by default, on any release. Done with the
1002
+ # storage cmdlets rather than by calling a particular agent's script,
1003
+ # so it does not matter which agent is installed. Only RAW disks are
1004
+ # touched, so a volume that already carries a filesystem is never
1005
+ # reformatted.
1006
+ "Initializing any uninitialized volumes" >> $logfile
1007
+ Get-Disk | Where-Object PartitionStyle -eq 'RAW' |
1008
+ Initialize-Disk -PartitionStyle MBR -PassThru |
1009
+ New-Partition -AssignDriveLetter -UseMaximumSize |
1010
+ Format-Volume -FileSystem NTFS -Confirm:$false >> $logfile
1011
+
971
1012
  # Allow script execution
972
1013
  Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force
973
1014
  #PS Remoting and & winrm.cmd basic config
@@ -980,7 +1021,6 @@ module Kitchen
980
1021
  & winrm.cmd set winrm/config '@{MaxTimeoutms="1800000"}' >> $logfile
981
1022
  & winrm.cmd set winrm/config/winrs '@{MaxMemoryPerShellMB="1024"}' >> $logfile
982
1023
  & winrm.cmd set winrm/config/winrs '@{MaxShellsPerUser="50"}' >> $logfile
983
- & winrm.cmd set winrm/config/winrs '@{MaxMemoryPerShellMB="1024"}' >> $logfile
984
1024
  #Firewall Config
985
1025
  & netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" profile=public protocol=tcp localport=5985 remoteip=localsubnet new remoteip=any >> $logfile
986
1026
  Set-ItemProperty -Name LocalAccountTokenFilterPolicy -Path HKLM:\\software\\Microsoft\\Windows\\CurrentVersion\\Policies\\system -Value 1
@@ -1620,6 +1660,9 @@ module Kitchen
1620
1660
  return File.read(public_key_path).strip
1621
1661
  end
1622
1662
 
1663
+ public_key = instance_connect_public_key_via_ssh_keygen(private_key_path)
1664
+ return public_key if public_key
1665
+
1623
1666
  begin
1624
1667
  key = SSHKey.new(File.read(private_key_path))
1625
1668
  key.ssh_public_key
@@ -1628,6 +1671,35 @@ module Kitchen
1628
1671
  end
1629
1672
  end
1630
1673
 
1674
+ # Derive the public half of a private key with ssh-keygen.
1675
+ #
1676
+ # OpenSSH reads every key type EC2 can create. The sshkey gem handles
1677
+ # only RSA and DSA, and raises "Neither PUB key nor PRIV key" on an
1678
+ # ed25519 key -- which is exactly what `aws_ssh_key_type: ed25519`
1679
+ # produces, so that documented setting could not be combined with
1680
+ # Instance Connect at all.
1681
+ #
1682
+ # Falling back to the gem rather than requiring ssh-keygen keeps the RSA
1683
+ # default working where OpenSSH is not installed.
1684
+ #
1685
+ # @param private_key_path [String] path to the private key
1686
+ # @return [String, nil] the public key in OpenSSH format, or nil when
1687
+ # ssh-keygen is unavailable or could not read the key
1688
+ def instance_connect_public_key_via_ssh_keygen(private_key_path)
1689
+ output, status = Open3.capture2e("ssh-keygen", "-y", "-f", private_key_path)
1690
+ return output.strip if status.success?
1691
+
1692
+ debug("ssh-keygen could not read #{private_key_path}: #{output.strip}")
1693
+ nil
1694
+ # ::StandardError, not StandardError: this file is nested inside `module
1695
+ # Kitchen`, which defines Kitchen::StandardError. An unqualified constant
1696
+ # resolves to that one, letting the Errno::ENOENT raised by a missing
1697
+ # ssh-keygen escape the check meant to detect it.
1698
+ rescue ::StandardError => e
1699
+ debug("Could not run ssh-keygen: #{e.message}")
1700
+ nil
1701
+ end
1702
+
1631
1703
  # SSM Session Manager Support Methods
1632
1704
 
1633
1705
  # The SSM Session Manager helper.
@@ -19,6 +19,6 @@
19
19
  module Kitchen
20
20
  module Driver
21
21
  # Version string for EC2 Test Kitchen driver
22
- EC2_VERSION = "3.22.9".freeze
22
+ EC2_VERSION = "3.22.10".freeze
23
23
  end
24
24
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kitchen-ec2
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.22.9
4
+ version: 3.22.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Test Kitchen Team