kitchen-ec2 3.22.3 → 3.22.4

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.
@@ -23,6 +23,12 @@ module Kitchen
23
23
  class Debian < StandardPlatform
24
24
  StandardPlatform.platforms["debian"] = self
25
25
 
26
+ # Debian release numbers to their codenames, newest first.
27
+ #
28
+ # The order matters: the first entry is the newest known release and
29
+ # is what an unversioned Debian platform resolves to.
30
+ #
31
+ # @return [Hash{Integer => String}]
26
32
  DEBIAN_CODENAMES = {
27
33
  13 => "trixie",
28
34
  12 => "bookworm",
@@ -34,21 +40,43 @@ module Kitchen
34
40
  6 => "squeeze",
35
41
  }.freeze
36
42
 
37
- # default username for this platform's ami
38
- # @return [String]
43
+ # The account EC2 creates on this platform's official AMIs.
44
+ #
45
+ # Debian uses "admin" rather than the "ec2-user" or distribution-named
46
+ # account most other platforms create.
47
+ #
48
+ # @return [String] the default SSH username
39
49
  def username
40
50
  "admin"
41
51
  end
42
52
 
53
+ # The Debian release codename for the requested version.
54
+ #
55
+ # Only the major version selects a codename, so a more precise version
56
+ # such as "12.5" is truncated, with a warning that the extra precision
57
+ # is being discarded. With no version at all, the newest known release
58
+ # is used.
59
+ #
60
+ # @return [String, nil] the codename, or nil for an unknown version
43
61
  def codename
44
62
  v = version
45
- if v && v.size > 1
63
+ # Warn only when truncating to the major version actually discards
64
+ # something. Comparing string forms keeps a version that arrived as
65
+ # an Integer from warning about itself.
66
+ if v && v.to_s != v.to_i.to_s
46
67
  warn("WARN: Debian version #{version} specified, but searching for #{version.to_i} instead.")
47
- v = v.to_i
48
68
  end
49
69
  v ? DEBIAN_CODENAMES[v.to_i] : DEBIAN_CODENAMES.values.first
50
70
  end
51
71
 
72
+ # EC2 image filters that select Debian cloud images.
73
+ #
74
+ # A filter is added for {StandardPlatform#architecture} only when one was
75
+ # requested, so that an unspecified architecture matches any of them.
76
+ #
77
+ # @return [Hash{String => String, Array<String>}] filter name to the value
78
+ # or values it must match
79
+ # @see StandardPlatform#find_image
52
80
  def image_search
53
81
  search = {}
54
82
 
@@ -70,15 +98,26 @@ module Kitchen
70
98
  search
71
99
  end
72
100
 
101
+ # Detect this platform from an EC2 image.
102
+ #
103
+ # Matching is done on the image name, which is the only reliable signal
104
+ # EC2 exposes about what an AMI actually contains.
105
+ #
106
+ # @param driver [Kitchen::Driver::Ec2] the driver requesting detection
107
+ # @param image [Aws::EC2::Image] the image to inspect
108
+ # @return [Debian, nil] a platform when the image is Debian, otherwise nil
73
109
  def self.from_image(driver, image)
74
110
  return unless /debian/i.match?(image.name)
75
111
 
76
112
  image.name =~ /\b(\d+|#{DEBIAN_CODENAMES.values.join("|")})\b/i
77
113
  version = (Regexp.last_match || [])[1]
78
114
  if version&.to_i&.zero?
115
+ # `to_s`, so that a codename-derived version is the same type as a
116
+ # version read straight out of the image name. Callers compare and
117
+ # display these without caring which path produced them.
79
118
  version = DEBIAN_CODENAMES.find do |_v, codename|
80
119
  codename == version.downcase
81
- end.first
120
+ end&.first&.to_s
82
121
  end
83
122
  new(driver, "debian", version, image.architecture)
84
123
  end
@@ -23,12 +23,23 @@ module Kitchen
23
23
  class Fedora < StandardPlatform
24
24
  StandardPlatform.platforms["fedora"] = self
25
25
 
26
- # default username for this platform's ami
27
- # @return [String]
26
+ # The account EC2 creates on this platform's official AMIs.
27
+ #
28
+ # Used as the SSH username when the transport does not specify one.
29
+ #
30
+ # @return [String] the default SSH username
28
31
  def username
29
32
  "fedora"
30
33
  end
31
34
 
35
+ # EC2 image filters that select Fedora Cloud Base images.
36
+ #
37
+ # A filter is added for {StandardPlatform#architecture} only when one was
38
+ # requested, so that an unspecified architecture matches any of them.
39
+ #
40
+ # @return [Hash{String => String, Array<String>}] filter name to the value
41
+ # or values it must match
42
+ # @see StandardPlatform#find_image
32
43
  def image_search
33
44
  search = {
34
45
  "owner-id" => "125523088429",
@@ -38,6 +49,14 @@ module Kitchen
38
49
  search
39
50
  end
40
51
 
52
+ # Detect this platform from an EC2 image.
53
+ #
54
+ # Matching is done on the image name, which is the only reliable signal
55
+ # EC2 exposes about what an AMI actually contains.
56
+ #
57
+ # @param driver [Kitchen::Driver::Ec2] the driver requesting detection
58
+ # @param image [Aws::EC2::Image] the image to inspect
59
+ # @return [Fedora, nil] a platform when the image is Fedora, otherwise nil
41
60
  def self.from_image(driver, image)
42
61
  return unless /fedora/i.match?(image.name)
43
62
 
@@ -23,14 +23,31 @@ module Kitchen
23
23
  class Freebsd < StandardPlatform
24
24
  StandardPlatform.platforms["freebsd"] = self
25
25
 
26
- # default username for this platform's ami
27
- # @return [String]
26
+ # The account EC2 creates on this platform's official AMIs.
27
+ #
28
+ # Used as the SSH username when the transport does not specify one.
29
+ #
30
+ # @return [String] the default SSH username
28
31
  def username
29
32
  "ec2-user"
30
33
  end
31
34
 
35
+ # The command used to elevate privileges on this platform.
36
+ #
37
+ # FreeBSD AMIs do not configure sudo for the default account, so this
38
+ # is deliberately nil rather than the usual "sudo".
39
+ #
40
+ # @return [nil] always
32
41
  def sudo_command; end
33
42
 
43
+ # EC2 image filters that select FreeBSD RELEASE images.
44
+ #
45
+ # A filter is added for {StandardPlatform#architecture} only when one was
46
+ # requested, so that an unspecified architecture matches any of them.
47
+ #
48
+ # @return [Hash{String => String, Array<String>}] filter name to the value
49
+ # or values it must match
50
+ # @see StandardPlatform#find_image
34
51
  def image_search
35
52
  search = {
36
53
  "owner-id" => "118940168514",
@@ -40,6 +57,14 @@ module Kitchen
40
57
  search
41
58
  end
42
59
 
60
+ # Detect this platform from an EC2 image.
61
+ #
62
+ # Matching is done on the image name, which is the only reliable signal
63
+ # EC2 exposes about what an AMI actually contains.
64
+ #
65
+ # @param driver [Kitchen::Driver::Ec2] the driver requesting detection
66
+ # @param image [Aws::EC2::Image] the image to inspect
67
+ # @return [Freebsd, nil] a platform when the image is FreeBSD, otherwise nil
43
68
  def self.from_image(driver, image)
44
69
  return unless /freebsd/i.match?(image.name)
45
70
 
@@ -19,29 +19,55 @@ module Kitchen
19
19
  module Driver
20
20
  class Aws
21
21
  class StandardPlatform
22
+ # Amazon's macOS images, which run only on dedicated Mac hosts.
23
+ #
24
+ # @see https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-macos-instances.html
22
25
  class MacOS < StandardPlatform
23
26
  StandardPlatform.platforms["macos"] = self
24
27
 
25
- # default username for this platform's ami
26
- # @return [String]
28
+ # The account EC2 creates on this platform's official AMIs.
29
+ #
30
+ # Used as the SSH username when the transport does not specify one.
31
+ #
32
+ # @return [String] the default SSH username
27
33
  def username
28
34
  "ec2-user"
29
35
  end
30
36
 
37
+ # EC2 image filters that select Amazon's macOS AMIs, which run only on dedicated Mac hosts.
38
+ #
39
+ # A filter is added for {StandardPlatform#architecture} only when one was
40
+ # requested, so that an unspecified architecture matches any of them.
41
+ #
42
+ # @return [Hash{String => String, Array<String>}] filter name to the value
43
+ # or values it must match
44
+ # @see StandardPlatform#find_image
31
45
  def image_search
32
46
  search = {
33
47
  "owner-id" => "100343932686",
34
- "name" => version ? "amzn-ec2-macos-#{version}*" : "amzn2-ec2-macos-*",
48
+ "name" => version ? "amzn-ec2-macos-#{version}*" : "amzn-ec2-macos-*",
35
49
  }
36
50
  search["architecture"] = architecture if architecture
37
51
  search["architecture"] = "arm64_mac" if architecture == "arm64"
38
52
  search
39
53
  end
40
54
 
55
+ # Detect this platform from an EC2 image.
56
+ #
57
+ # Matching is done on the image name, which is the only reliable signal
58
+ # EC2 exposes about what an AMI actually contains.
59
+ #
60
+ # @param driver [Kitchen::Driver::Ec2] the driver requesting detection
61
+ # @param image [Aws::EC2::Image] the image to inspect
62
+ # @return [MacOS, nil] a platform when the image is macOS, otherwise nil
41
63
  def self.from_image(driver, image)
42
64
  return unless /amzn-ec2-macos/i.match?(image.name)
43
65
 
44
- image.name =~ /\b(\d+(\.\d+[\.\d])?)/i
66
+ # `(\.\d+)?`, not `(\.\d+[\.\d])?`: the character class matched the
67
+ # separator that follows the minor version, capturing it into the
68
+ # version string ("2018.03.") and failing outright when the minor
69
+ # version was followed by anything but a dot or digit.
70
+ image.name =~ /\b(\d+(\.\d+)?)/i
45
71
  new(driver, "macos", (Regexp.last_match || [])[1], image.architecture)
46
72
  end
47
73
  end
@@ -24,17 +24,38 @@ module Kitchen
24
24
  StandardPlatform.platforms["rhel"] = self
25
25
  StandardPlatform.platforms["el"] = self
26
26
 
27
+ # Build a Red Hat Enterprise Linux platform.
28
+ #
29
+ # This class is registered under both "rhel" and "el", so the name it
30
+ # was constructed with is discarded and normalized to "rhel".
31
+ #
32
+ # @param driver [Kitchen::Driver::Ec2] the driver
33
+ # @param _name [String] the registered name, ignored
34
+ # @param version [String, nil] the requested version, e.g. "9.4"
35
+ # @param architecture [String, nil] the requested architecture
27
36
  def initialize(driver, _name, version, architecture)
28
37
  # rhel = el
29
38
  super(driver, "rhel", version, architecture)
30
39
  end
31
40
 
32
- # default username for this platform's ami
33
- # @return [String]
41
+ # The account EC2 creates on this platform's official AMIs.
42
+ #
43
+ # RHEL only gained the unprivileged "ec2-user" account in 6.4; earlier
44
+ # releases are logged into as root.
45
+ #
46
+ # @return [String] the default SSH username
34
47
  def username
35
48
  version && version.to_f < 6.4 ? "root" : "ec2-user"
36
49
  end
37
50
 
51
+ # EC2 image filters that select Red Hat Enterprise Linux AMIs published by Red Hat.
52
+ #
53
+ # A filter is added for {StandardPlatform#architecture} only when one was
54
+ # requested, so that an unspecified architecture matches any of them.
55
+ #
56
+ # @return [Hash{String => String, Array<String>}] filter name to the value
57
+ # or values it must match
58
+ # @see StandardPlatform#find_image
38
59
  def image_search
39
60
  search = {
40
61
  "owner-id" => "309956199498",
@@ -44,6 +65,14 @@ module Kitchen
44
65
  search
45
66
  end
46
67
 
68
+ # Detect this platform from an EC2 image.
69
+ #
70
+ # Matching is done on the image name, which is the only reliable signal
71
+ # EC2 exposes about what an AMI actually contains.
72
+ #
73
+ # @param driver [Kitchen::Driver::Ec2] the driver requesting detection
74
+ # @param image [Aws::EC2::Image] the image to inspect
75
+ # @return [El, nil] a platform when the image is Red Hat Enterprise Linux, otherwise nil
47
76
  def self.from_image(driver, image)
48
77
  return unless /rhel/i.match?(image.name)
49
78
 
@@ -51,6 +80,15 @@ module Kitchen
51
80
  new(driver, "rhel", (Regexp.last_match || [])[1], image.architecture)
52
81
  end
53
82
 
83
+ # Sort images newest release first, preferring generally available
84
+ # releases over betas.
85
+ #
86
+ # A Beta AMI carries a higher version number than the current GA
87
+ # release, so a plain version sort would select it. Betas are pushed
88
+ # to the back after sorting.
89
+ #
90
+ # @param images [Array<Aws::EC2::Image>] the images to sort
91
+ # @return [Array<Aws::EC2::Image>] the images, best match first
54
92
  def sort_by_version(images)
55
93
  # First do a normal version sort
56
94
  super(images)
@@ -19,16 +19,31 @@ module Kitchen
19
19
  module Driver
20
20
  class Aws
21
21
  class StandardPlatform
22
+ # Rocky Linux images published by the Rocky Enterprise Software
23
+ # Foundation.
24
+ #
25
+ # @see https://rockylinux.org/cloud-images
22
26
  class Rocky < StandardPlatform
23
27
  StandardPlatform.platforms["rocky"] = self
24
28
  StandardPlatform.platforms["rockylinux"] = self
25
29
 
26
- # default username for this platform's ami
27
- # @return [String]
30
+ # The account EC2 creates on this platform's official AMIs.
31
+ #
32
+ # Used as the SSH username when the transport does not specify one.
33
+ #
34
+ # @return [String] the default SSH username
28
35
  def username
29
36
  "rocky"
30
37
  end
31
38
 
39
+ # EC2 image filters that select Rocky Linux images published by the Rocky project.
40
+ #
41
+ # A filter is added for {StandardPlatform#architecture} only when one was
42
+ # requested, so that an unspecified architecture matches any of them.
43
+ #
44
+ # @return [Hash{String => String, Array<String>}] filter name to the value
45
+ # or values it must match
46
+ # @see StandardPlatform#find_image
32
47
  def image_search
33
48
  search = {
34
49
  "owner-id" => "792107900819",
@@ -38,10 +53,22 @@ module Kitchen
38
53
  search
39
54
  end
40
55
 
56
+ # Detect this platform from an EC2 image.
57
+ #
58
+ # Matching is done on the image name, which is the only reliable signal
59
+ # EC2 exposes about what an AMI actually contains.
60
+ #
61
+ # @param driver [Kitchen::Driver::Ec2] the driver requesting detection
62
+ # @param image [Aws::EC2::Image] the image to inspect
63
+ # @return [Rocky, nil] a platform when the image is Rocky Linux, otherwise nil
41
64
  def self.from_image(driver, image)
42
65
  return unless /Rocky-/i.match?(image.name)
43
66
 
44
- image.name =~ /\b(\d+(\.\d+[\.\d])?)/i
67
+ # `(\.\d+)?`, not `(\.\d+[\.\d])?`: the character class matched the
68
+ # separator that follows the minor version, capturing it into the
69
+ # version string ("2018.03.") and failing outright when the minor
70
+ # version was followed by anything but a dot or digit.
71
+ image.name =~ /\b(\d+(\.\d+)?)/i
45
72
  new(driver, "rocky", (Regexp.last_match || [])[1], image.architecture)
46
73
  end
47
74
  end
@@ -23,12 +23,23 @@ module Kitchen
23
23
  class Ubuntu < StandardPlatform
24
24
  StandardPlatform.platforms["ubuntu"] = self
25
25
 
26
- # default username for this platform's ami
27
- # @return [String]
26
+ # The account EC2 creates on this platform's official AMIs.
27
+ #
28
+ # Used as the SSH username when the transport does not specify one.
29
+ #
30
+ # @return [String] the default SSH username
28
31
  def username
29
32
  "ubuntu"
30
33
  end
31
34
 
35
+ # EC2 image filters that select Ubuntu cloud images published by Canonical.
36
+ #
37
+ # A filter is added for {StandardPlatform#architecture} only when one was
38
+ # requested, so that an unspecified architecture matches any of them.
39
+ #
40
+ # @return [Hash{String => String, Array<String>}] filter name to the value
41
+ # or values it must match
42
+ # @see StandardPlatform#find_image
32
43
  def image_search
33
44
  search = {
34
45
  "owner-id" => "099720109477",
@@ -38,6 +49,14 @@ module Kitchen
38
49
  search
39
50
  end
40
51
 
52
+ # Detect this platform from an EC2 image.
53
+ #
54
+ # Matching is done on the image name, which is the only reliable signal
55
+ # EC2 exposes about what an AMI actually contains.
56
+ #
57
+ # @param driver [Kitchen::Driver::Ec2] the driver requesting detection
58
+ # @param image [Aws::EC2::Image] the image to inspect
59
+ # @return [Ubuntu, nil] a platform when the image is Ubuntu, otherwise nil
41
60
  def self.from_image(driver, image)
42
61
  return unless /ubuntu/i.match?(image.name)
43
62
 
@@ -23,34 +23,39 @@ module Kitchen
23
23
  class Windows < StandardPlatform
24
24
  StandardPlatform.platforms["windows"] = self
25
25
 
26
- # default username for this platform's ami
27
- # @return [String]
26
+ # The account EC2 creates on this platform's official AMIs.
27
+ #
28
+ # Used as the SSH username when the transport does not specify one.
29
+ #
30
+ # @return [String] the default SSH username
28
31
  def username
29
32
  "administrator"
30
33
  end
31
34
 
32
- # Figure out the right set of names to search for:
35
+ # EC2 image filters that select Amazon's Windows Server AMIs.
36
+ #
37
+ # Windows AMI names encode the release, an optional revision ("R2")
38
+ # and an optional service pack, and the naming scheme changed with
39
+ # Server 2016. The requested version is decomposed by
40
+ # {#windows_version_parts} and turned into whichever set of name
41
+ # patterns can match it:
42
+ #
43
+ # "windows" Windows_Server-*-RTM-, -SP*-, -R*_RTM-,
44
+ # -R*_SP*-, and Windows_Server-*-Full-Base-*
45
+ # "windows-2012" Windows_Server-2012-RTM-, -2012-SP*-
46
+ # "windows-2012r2" Windows_Server-2012-R2_RTM-, -R2_SP*-
47
+ # "windows-2012sp1" Windows_Server-2012-SP1-
48
+ # "windows-2012r2sp1" Windows_Server-2012-R2_SP1-
49
+ # "windows-2016" Windows_Server-2016-English-Full-Base-*
50
+ # "windows-2019" Windows_Server-2019-English-Full-Base-*
33
51
  #
34
- # "windows" -> [nil, nil, nil]
35
- # Windows_Server-*-R*_RTM-, Windows_Server-*-R*_SP*-,
36
- # Windows_Server-*-RTM-, Windows_Server-*-SP*-,
37
- # Windows_Server-*-
38
- # "windows-2012" -> [2012, 0, nil]
39
- # Windows_Server-2012-RTM-, Windows_Server-2012-SP*-
40
- # "windows-2012r2" -> [2012, 2, nil]
41
- # Windows_Server-2012-R2_RTM-, Windows_Server-2012-R2_SP*-
42
- # "windows-2012sp1" -> [2012, 0, 1]
43
- # Windows_Server-2012-SP1-
44
- # "windows-2012rtm" -> [2012, 0, 0]
45
- # Windows_Server-2012-RTM-
46
- # "windows-2012r2sp1" -> [2012, 2, 1]
47
- # Windows_Server-2012-R2_SP1-
48
- # "windows-2012r2rtm" -> [2012, 2, 0]
49
- # Windows_Server-2012-R2_RTM-
50
- # "windows-2016" -> [2016, 0, nil]
51
- # Windows_Server-2016-
52
- # "windows-2019" -> [2019, 0, nil]
53
- # Windows_Server-2019-
52
+ # A filter is added for {StandardPlatform#architecture} only when one
53
+ # was requested, so that an unspecified architecture matches any.
54
+ #
55
+ # @return [Hash{String => String, Array<String>}] filter name to the
56
+ # value or values it must match
57
+ # @see #windows_name_filter
58
+ # @see StandardPlatform#find_image
54
59
  def image_search
55
60
  search = {
56
61
  "owner-alias" => "amazon",
@@ -60,6 +65,15 @@ module Kitchen
60
65
  search
61
66
  end
62
67
 
68
+ # Sort images newest release first.
69
+ #
70
+ # Windows versions cannot be compared as numbers -- "2012r2" is newer
71
+ # than "2012" but older than "2016" -- so each image is reduced to a
72
+ # [major, revision, service_pack] tuple and those are compared
73
+ # instead.
74
+ #
75
+ # @param images [Array<Aws::EC2::Image>] the images to sort
76
+ # @return [Array<Aws::EC2::Image>] the images, newest release first
63
77
  def sort_by_version(images)
64
78
  # 2008r2rtm -> [ img1, img2, img3 ]
65
79
  # 2012r2sp1 -> [ img4, img5 ]
@@ -69,6 +83,14 @@ module Kitchen
69
83
  .reverse.flat_map { |_version, platform_images| platform_images }
70
84
  end
71
85
 
86
+ # Detect this platform from an EC2 image.
87
+ #
88
+ # Matching is done on the image name, which is the only reliable signal
89
+ # EC2 exposes about what an AMI actually contains.
90
+ #
91
+ # @param driver [Kitchen::Driver::Ec2] the driver requesting detection
92
+ # @param image [Aws::EC2::Image] the image to inspect
93
+ # @return [Windows, nil] a platform when the image is Windows Server, otherwise nil
72
94
  def self.from_image(driver, image)
73
95
  return unless /Windows/i.match?(image.name)
74
96
 
@@ -88,18 +110,25 @@ module Kitchen
88
110
 
89
111
  protected
90
112
 
91
- # Turn windows version into [ major, revision, service_pack ]
113
+ # Decompose a Windows version string into comparable parts.
114
+ #
115
+ # A missing revision becomes 0 so that "2012" and "2012r2" order
116
+ # correctly against each other. A missing service pack stays nil,
117
+ # which means "any", while an explicit "rtm" becomes 0.
92
118
  #
93
- # nil -> [ nil, nil, nil ]
94
- # 2012 -> [ 2012, 0, nil ]
95
- # 2012r2 -> [ 2012, 2, nil ]
96
- # 2012r2sp4 -> [ 2012, 2, 4 ]
97
- # 2012sp4 -> [ 2012, 0, 4 ]
98
- # 2012rtm -> [ 2012, 0, 0 ]
99
- # 2016 -> [ 2016, 0, nil ]
100
- # 2019 -> [ 2019, 0, nil ]
101
- # 1709 -> [ 1709, 0, nil ]
102
- # 1803 -> [ 1803, 0, nil ]
119
+ # nil -> [nil, nil, nil]
120
+ # "2012" -> [2012, 0, nil]
121
+ # "2012r2" -> [2012, 2, nil]
122
+ # "2012rtm" -> [2012, 0, 0]
123
+ # "2012sp4" -> [2012, 0, 4]
124
+ # "2012r2sp4"-> [2012, 2, 4]
125
+ # "2016" -> [2016, 0, nil]
126
+ #
127
+ # A leading "server-" is stripped first, so that a platform named
128
+ # "windows-server-2019" behaves like "windows-2019".
129
+ #
130
+ # @return [Array(Integer, Integer, Integer), Array(nil, nil, nil)]
131
+ # the major version, revision and service pack
103
132
  def windows_version_parts
104
133
  version = self.version
105
134
  if version
@@ -131,6 +160,10 @@ module Kitchen
131
160
 
132
161
  private
133
162
 
163
+ # Build the AMI name patterns for the requested version.
164
+ #
165
+ # @return [String, Array<String>] a single pattern for releases with a
166
+ # predictable name, otherwise every pattern that could match
134
167
  def windows_name_filter
135
168
  major, revision, service_pack = windows_version_parts
136
169
  if [2025, 2022, 2019, 2016].include?(major)
@@ -99,7 +99,13 @@ module Kitchen
99
99
  #
100
100
  # Find the best matching image for the given image search.
101
101
  #
102
- # @return [String] The image ID (e.g. ami-213984723)
102
+ # The search hash is converted into EC2's filter format, and the results
103
+ # are ranked by {#sort_images} before the best match is taken.
104
+ #
105
+ # @param image_search [Hash{String => String, Array<String>}] EC2 image
106
+ # filters, keyed by filter name
107
+ # @return [String, nil] the image ID (e.g. "ami-213984723"), or nil when
108
+ # the search matched nothing
103
109
  def find_image(image_search)
104
110
  driver.debug("Searching for images matching #{image_search} ...")
105
111
  # Convert to ec2 search format (pairs of name+values)
@@ -120,12 +126,18 @@ module Kitchen
120
126
  # The list of StandardPlatform objects. StandardPlatforms register
121
127
  # themselves with this.
122
128
  #
123
- # @return Array[Kitchen::Driver::Aws::StandardPlatform]
129
+ # @return [Array<Kitchen::Driver::Aws::StandardPlatform>]
124
130
  #
125
131
  def self.platforms
126
132
  @platforms ||= {}
127
133
  end
128
134
 
135
+ # A human-readable description of this platform.
136
+ #
137
+ # Version and architecture are omitted when unknown, so an unqualified
138
+ # platform reads as just "ubuntu" rather than "ubuntu ".
139
+ #
140
+ # @return [String] e.g. "ubuntu 24.04 x86_64"
129
141
  def to_s
130
142
  "#{name}#{version ? " #{version}" : ""}#{architecture ? " #{architecture}" : ""}"
131
143
  end
@@ -162,6 +174,16 @@ module Kitchen
162
174
  nil
163
175
  end
164
176
 
177
+ # Split a platform string into its parts.
178
+ #
179
+ # The trailing segment is only treated as an architecture when it is one
180
+ # of {SUPPORTED_ARCHITECTURES}; anything else stays part of the version,
181
+ # so that a typo surfaces as an unmatched version rather than being
182
+ # silently discarded.
183
+ #
184
+ # @param platform_string [String] e.g. "centos-9-x86_64"
185
+ # @return [Array(String, String, String)] the platform name, version and
186
+ # architecture, any of which except the name may be nil
165
187
  def self.parse_platform_string(platform_string)
166
188
  platform, version = platform_string.split("-", 2)
167
189
 
@@ -203,6 +225,16 @@ module Kitchen
203
225
 
204
226
  # Not supported yet: aix mac_os_x nexus solaris
205
227
 
228
+ # Move images matching a predicate ahead of those that do not.
229
+ #
230
+ # This is a stable partition rather than a sort, so it expresses a
231
+ # preference without disturbing the ordering established by earlier
232
+ # preferences.
233
+ #
234
+ # @param images [Array<Aws::EC2::Image>] the images to reorder
235
+ # @yieldparam image [Aws::EC2::Image] an image to test
236
+ # @yieldreturn [Boolean] true when the image is preferred
237
+ # @return [Array<Aws::EC2::Image>] preferred images first
206
238
  def prefer(images, &block)
207
239
  # Put the matching ones *before* the non-matching ones.
208
240
  matching, non_matching = images.partition(&block)
@@ -211,6 +243,14 @@ module Kitchen
211
243
 
212
244
  private
213
245
 
246
+ # Rank candidate images, best match first.
247
+ #
248
+ # Preferences are applied from weakest to strongest, each one a stable
249
+ # partition, so the last applied wins: version beats virtualization
250
+ # type, which beats root device type, and so on down to creation date.
251
+ #
252
+ # @param images [Array<Aws::EC2::Image>] the images to rank
253
+ # @return [Array<Aws::EC2::Image>] the images, best match first
214
254
  def sort_images(images)
215
255
  # P6: We prefer more recent images over older ones
216
256
  images = images.sort_by(&:creation_date).reverse
@@ -230,6 +270,10 @@ module Kitchen
230
270
  sort_by_version(images)
231
271
  end
232
272
 
273
+ # Log the search results, with the platform detected for each image.
274
+ #
275
+ # @param images [Array<Aws::EC2::Image>] the images the search returned
276
+ # @return [void]
233
277
  def show_returned_images(images)
234
278
  if images.empty?
235
279
  driver.error("Search returned 0 images.")