From 10566f9d61ce9b779ac4d67fbde3eefea42fbe1d Mon Sep 17 00:00:00 2001 From: Davanum Srinivas Date: Sun, 13 Aug 2023 12:14:18 -0400 Subject: [PATCH] use singular --image on the command line, also make it optional to specify Signed-off-by: Davanum Srinivas --- kubetest2-ec2/pkg/deployer/deployer.go | 20 +++--- kubetest2-ec2/pkg/deployer/up.go | 93 +++++++++++++++---------- kubetest2-ec2/pkg/deployer/utils/ssm.go | 16 +++++ 3 files changed, 82 insertions(+), 47 deletions(-) create mode 100644 kubetest2-ec2/pkg/deployer/utils/ssm.go diff --git a/kubetest2-ec2/pkg/deployer/deployer.go b/kubetest2-ec2/pkg/deployer/deployer.go index 3794a92be..26581dba9 100644 --- a/kubetest2-ec2/pkg/deployer/deployer.go +++ b/kubetest2-ec2/pkg/deployer/deployer.go @@ -98,16 +98,16 @@ type deployer struct { KubeconfigPath string `flag:"kubeconfig" desc:"Absolute path to existing kubeconfig for cluster"` RepoRoot string `desc:"The path to the root of the local kubernetes/kubernetes repo."` - Region string `desc:"AWS region that the hosts live in (aws)"` - UserDataFile string `desc:"Path to user data to pass to created instances (aws)"` - InstanceProfile string `desc:"The name of the instance profile to assign to the node (aws)"` - RoleName string `desc:"The name of the role assign to the node (aws)"` - Ec2InstanceConnect bool `desc:"Use EC2 instance connect to generate a one time use key (aws)"` - InstanceType string `desc:"EC2 Instance type to use for test"` - Images []string `flag:"~images" desc:"images to test"` - SSHUser string `flag:"ssh-user" desc:"The SSH user to use for SSH access to instances"` - SSHEnv string `flag:"ssh-env" desc:"Use predefined ssh options for environment."` - NumNodes int `flag:"num-nodes" desc:"Number of nodes in the cluster."` + Region string `desc:"AWS region that the hosts live in (aws)"` + UserDataFile string `desc:"Path to user data to pass to created instances (aws)"` + InstanceProfile string `desc:"The name of the instance profile to assign to the node (aws)"` + RoleName string `desc:"The name of the role assign to the node (aws)"` + Ec2InstanceConnect bool `desc:"Use EC2 instance connect to generate a one time use key (aws)"` + InstanceType string `desc:"EC2 Instance type to use for test"` + Image string `flag:"image" desc:"Ubuntu image to use for test"` + SSHUser string `flag:"ssh-user" desc:"The SSH user to use for SSH access to instances"` + SSHEnv string `flag:"ssh-env" desc:"Use predefined ssh options for environment."` + NumNodes int `flag:"num-nodes" desc:"Number of nodes in the cluster."` runner *AWSRunner logsDir string diff --git a/kubetest2-ec2/pkg/deployer/up.go b/kubetest2-ec2/pkg/deployer/up.go index 42ba4293e..6364d3f11 100644 --- a/kubetest2-ec2/pkg/deployer/up.go +++ b/kubetest2-ec2/pkg/deployer/up.go @@ -193,40 +193,62 @@ func (d *deployer) NewAWSRunner() *AWSRunner { } func (a *AWSRunner) Validate() error { - if len(a.deployer.Images) == 0 { - klog.Fatalf("Must specify --images.") - } - for _, img := range a.deployer.Images { - if !strings.HasPrefix(img, "ami-") { - return fmt.Errorf("invalid AMI id format for %q", img) + sess, err := a.initializeServices() + if err != nil { + return fmt.Errorf("unable to initialize AWS services : %w", err) + } + + if a.deployer.Image == "" { + arch := strings.Split(a.deployer.BuildOptions.CommonBuildOptions.TargetBuildArch, "/")[1] + path := "/aws/service/canonical/ubuntu/server/jammy/stable/current/" + arch + "/hvm/ebs-gp2/ami-id" + klog.Infof("image was not specified, looking up latest image in SSM:") + klog.Infof("%s", path) + id, err := utils.GetSSMImage(a.ssmService, path) + if err == nil { + klog.Infof("using image id from ssm %s", id) + a.deployer.Image = id + } else { + return fmt.Errorf("error looking up ssm : %w", err) } } + + if len(a.deployer.Image) == 0 { + return fmt.Errorf("must specify an Ubuntu AMI using --image") + } + + if !strings.HasPrefix(a.deployer.Image, "ami-") { + return fmt.Errorf("invalid AMI id format for %q", a.deployer.Image) + } + + if err = a.ensureInstanceProfileAndRole(sess); err != nil { + return fmt.Errorf("while creating instance profile / roles : %v", err) + } + + a.internalAWSImages, err = a.prepareAWSImages() + if err != nil { + return fmt.Errorf("while preparing AWS images: %v", err) + } + return nil +} + +func (a *AWSRunner) initializeServices() (*session.Session, error) { sess, err := session.NewSession(&aws.Config{Region: &a.deployer.Region}) if err != nil { - klog.Fatalf("Unable to create AWS session, %s", err) + return nil, fmt.Errorf("unable to create AWS session, %w", err) } a.ec2Service = ec2.New(sess) a.ec2icService = ec2instanceconnect.New(sess) a.ssmService = ssm.New(sess) a.iamService = iam.New(sess, &aws.Config{Region: &a.deployer.Region}) - s3Uploader := s3manager.NewUploaderWithClient(s3.New(sess), func(u *s3manager.Uploader) { + a.deployer.BuildOptions.CommonBuildOptions.S3Uploader = s3manager.NewUploaderWithClient(s3.New(sess), func(u *s3manager.Uploader) { u.PartSize = 10 * 1024 * 1024 // 50 mb u.Concurrency = 10 }) - - if err = a.ensureInstanceProfileAndRole(sess, err); err != nil { - klog.Fatalf("While creating instance profile / roles : %v", err) - } - - a.deployer.BuildOptions.CommonBuildOptions.S3Uploader = s3Uploader - if a.internalAWSImages, err = a.prepareAWSImages(); err != nil { - klog.Fatalf("While preparing AWS images: %v", err) - } - return nil + return sess, nil } -func (a *AWSRunner) ensureInstanceProfileAndRole(sess *session.Session, err error) error { - err = utils.EnsureRole(a.iamService, a.deployer.RoleName) +func (a *AWSRunner) ensureInstanceProfileAndRole(sess *session.Session) error { + err := utils.EnsureRole(a.iamService, a.deployer.RoleName) if err != nil { klog.Infof("error with ensure role: %v\n", err) } @@ -401,23 +423,20 @@ func (a *AWSRunner) prepareAWSImages() ([]internalAWSImage, error) { userDataWorkerNode = strings.ReplaceAll(userdata, "{{KUBEADM_CONTROL_PLANE}}", "false") } - if len(a.deployer.Images) > 0 { - for _, imageID := range a.deployer.Images { - ret = append(ret, internalAWSImage{ - amiID: imageID, - userData: userControlPlane, - instanceType: a.deployer.InstanceType, - instanceProfile: a.deployer.InstanceProfile, - }) - for i := 0; i < a.deployer.NumNodes; i++ { - ret = append(ret, internalAWSImage{ - amiID: imageID, - userData: userDataWorkerNode, - instanceType: a.deployer.InstanceType, - instanceProfile: a.deployer.InstanceProfile, - }) - } - } + imageID := a.deployer.Image + ret = append(ret, internalAWSImage{ + amiID: imageID, + userData: userControlPlane, + instanceType: a.deployer.InstanceType, + instanceProfile: a.deployer.InstanceProfile, + }) + for i := 0; i < a.deployer.NumNodes; i++ { + ret = append(ret, internalAWSImage{ + amiID: imageID, + userData: userDataWorkerNode, + instanceType: a.deployer.InstanceType, + instanceProfile: a.deployer.InstanceProfile, + }) } return ret, nil } diff --git a/kubetest2-ec2/pkg/deployer/utils/ssm.go b/kubetest2-ec2/pkg/deployer/utils/ssm.go new file mode 100644 index 000000000..07bef476f --- /dev/null +++ b/kubetest2-ec2/pkg/deployer/utils/ssm.go @@ -0,0 +1,16 @@ +package utils + +import ( + "fmt" + "github.com/aws/aws-sdk-go/service/ssm" +) + +func GetSSMImage(ssmService *ssm.SSM, path string) (string, error) { + rsp, err := ssmService.GetParameter(&ssm.GetParameterInput{ + Name: &path, + }) + if err != nil { + return "", fmt.Errorf("getting AMI ID from SSM path %q, %w", path, err) + } + return *rsp.Parameter.Value, nil +}