1111// express or implied. See the License for the specific language governing
1212// permissions and limitations under the License.
1313
14+ // Package amimetadata provides AMI metadata given an instance type.
1415package amimetadata
1516
1617import (
1718 "encoding/json"
18-
1919 "github.com/aws/amazon-ecs-cli/ecs-cli/modules/clients"
2020 "github.com/aws/amazon-ecs-cli/ecs-cli/modules/config"
2121 "github.com/aws/aws-sdk-go/aws"
2222 "github.com/aws/aws-sdk-go/aws/awserr"
2323 "github.com/aws/aws-sdk-go/service/ssm"
2424 "github.com/aws/aws-sdk-go/service/ssm/ssmiface"
2525 "github.com/pkg/errors"
26+ "github.com/sirupsen/logrus"
27+ "regexp"
28+ "strings"
2629)
2730
31+ // SSM parameter names to retrieve ECS optimized AMI.
32+ // See: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/retrieve-ecs-optimized_AMI.html
2833const (
29- amazonLinux2X86RecommendedParameterName = "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended"
30- amazonLinux2ARM64RecommendedParameterName = "/aws/service/ecs/optimized-ami/amazon-linux-2/arm64/recommended"
31- )
32-
33- const (
34- ArchitectureTypeARM64 = "arm64"
35- ArchitectureTypeX86 = "x86"
34+ amazonLinux2X86RecommendedParameterName = "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended"
35+ amazonLinux2ARM64RecommendedParameterName = "/aws/service/ecs/optimized-ami/amazon-linux-2/arm64/recommended"
36+ amazonLinux2X86GPURecommendedParameterName = "/aws/service/ecs/optimized-ami/amazon-linux-2/gpu/recommended"
3637)
3738
39+ // AMIMetadata is returned through ssm:GetParameters and can be used to retrieve the ImageId
40+ // while launching instances.
41+ //
42+ // See: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/retrieve-ecs-optimized_AMI.html
43+ // See: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-launchconfig.html#cfn-as-launchconfig-imageid
3844type AMIMetadata struct {
3945 ImageID string `json:"image_id"`
4046 OsName string `json:"os"`
@@ -47,13 +53,13 @@ type Client interface {
4753 GetRecommendedECSLinuxAMI (string ) (* AMIMetadata , error )
4854}
4955
50- // ssmClient implements Client
56+ // metadataClient implements Client.
5157type metadataClient struct {
5258 client ssmiface.SSMAPI
5359 region string
5460}
5561
56- // NewSSMClient creates an instance of Client.
62+ // NewMetadataClient creates an instance of Client.
5763func NewMetadataClient (commandConfig * config.CommandConfig ) Client {
5864 client := ssm .New (commandConfig .Session )
5965 client .Handlers .Build .PushBackNamed (clients .CustomUserAgentHandler ())
@@ -63,20 +69,31 @@ func NewMetadataClient(commandConfig *config.CommandConfig) Client {
6369 }
6470}
6571
66- func (c * metadataClient ) GetRecommendedECSLinuxAMI (architecture string ) (* AMIMetadata , error ) {
67- ssmParam := amazonLinux2X86RecommendedParameterName
68- if architecture == ArchitectureTypeARM64 {
69- ssmParam = amazonLinux2ARM64RecommendedParameterName
72+ // GetRecommendedECSLinuxAMI returns the recommended Amazon ECS-Optimized AMI Metadata given the instance type.
73+ func (c * metadataClient ) GetRecommendedECSLinuxAMI (instanceType string ) (* AMIMetadata , error ) {
74+ if isARM64Instance (instanceType ) {
75+ logrus .Infof ("Using Arm ecs-optimized AMI because instance type was %s" , instanceType )
76+ return c .parameterValueFor (amazonLinux2ARM64RecommendedParameterName )
77+ }
78+ if isGPUInstance (instanceType ) {
79+ logrus .Infof ("Using GPU ecs-optimized AMI because instance type was %s" , instanceType )
80+ return c .parameterValueFor (amazonLinux2X86GPURecommendedParameterName )
7081 }
82+ return c .parameterValueFor (amazonLinux2X86RecommendedParameterName )
83+ }
7184
85+ func (c * metadataClient ) parameterValueFor (ssmParamName string ) (* AMIMetadata , error ) {
7286 response , err := c .client .GetParameter (& ssm.GetParameterInput {
73- Name : aws .String (ssmParam ),
87+ Name : aws .String (ssmParamName ),
7488 })
7589 if err != nil {
7690 if aerr , ok := err .(awserr.Error ); ok {
7791 if aerr .Code () == ssm .ErrCodeParameterNotFound {
78- // Added for arm AMIs which are only supported in some regions
79- return nil , errors .Wrapf (err , "Could not find Recommended Amazon Linux 2 AMI in %s with architecture %s; the AMI may not be supported in this region" , c .region , architecture )
92+ // Added for AMIs which are only supported in some regions
93+ return nil , errors .Wrapf (err ,
94+ "Could not find Recommended Amazon Linux 2 AMI %s in %s; the AMI may not be supported in this region" ,
95+ ssmParamName ,
96+ c .region )
8097 }
8198 }
8299 return nil , err
@@ -85,3 +102,24 @@ func (c *metadataClient) GetRecommendedECSLinuxAMI(architecture string) (*AMIMet
85102 err = json .Unmarshal ([]byte (aws .StringValue (response .Parameter .Value )), metadata )
86103 return metadata , err
87104}
105+
106+ func isARM64Instance (instanceType string ) bool {
107+ r := regexp .MustCompile ("a1\\ .(medium|\\ d*x?large)" )
108+ if r .MatchString (instanceType ) {
109+ return true
110+ }
111+ return false
112+ }
113+
114+ func isGPUInstance (instanceType string ) bool {
115+ if strings .HasPrefix (instanceType , "p2." ) {
116+ return true
117+ }
118+ if strings .HasPrefix (instanceType , "p3." ) {
119+ return true
120+ }
121+ if strings .HasPrefix (instanceType , "p3dn." ) {
122+ return true
123+ }
124+ return false
125+ }
0 commit comments