Skip to content

Commit

Permalink
add validation for aws ami type
Browse files Browse the repository at this point in the history
  • Loading branch information
jokestax committed Dec 8, 2024
1 parent 536d8e1 commit 1327659
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 40 deletions.
11 changes: 11 additions & 0 deletions cmd/aws/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package aws
import (
"fmt"


"github.com/konstructio/kubefirst-api/pkg/constants"
"github.com/konstructio/kubefirst/internal/common"
"github.com/konstructio/kubefirst/internal/progress"
Expand Down Expand Up @@ -37,11 +38,20 @@ var (
nodeCountFlag string
installCatalogApps string
installKubefirstProFlag bool
amiType string

// Supported argument arrays
supportedDNSProviders = []string{"aws", "cloudflare"}
supportedGitProviders = []string{"github", "gitlab"}
supportedGitProtocolOverride = []string{"https", "ssh"}
supportedAMITypes = []string{
"AL2_x86_64",
"AL2_ARM_64",
"BOTTLEROCKET_ARM_64",
"BOTTLEROCKET_x86_64",
"BOTTLEROCKET_ARM_64_NVIDIA",
"BOTTLEROCKET_x86_64_NVIDIA",
}
)

func NewCommand() *cobra.Command {
Expand Down Expand Up @@ -99,6 +109,7 @@ func Create() *cobra.Command {
createCmd.Flags().BoolVar(&useTelemetryFlag, "use-telemetry", true, "whether to emit telemetry")
createCmd.Flags().BoolVar(&ecrFlag, "ecr", false, "whether or not to use ecr vs the git provider")
createCmd.Flags().BoolVar(&installKubefirstProFlag, "install-kubefirst-pro", true, "whether or not to install kubefirst pro")
createCmd.Flags().StringVar(&amiType, "ami-type", "AL2_x86_64", fmt.Sprintf("the ami type for node group - one of: %q", supportedAMITypes))

return createCmd
}
Expand Down
158 changes: 139 additions & 19 deletions cmd/aws/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@ See the LICENSE file for more details.
package aws

import (
"context"
"fmt"
"os"
"strings"

"github.com/aws/aws-sdk-go/aws"
awsinternal "github.com/konstructio/kubefirst-api/pkg/aws"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/ec2"
"github.com/aws/aws-sdk-go-v2/service/ssm"
"github.com/aws/aws-sdk-go-v2/service/sts"
bl "github.com/charmbracelet/log"
internalssh "github.com/konstructio/kubefirst-api/pkg/ssh"
pkg "github.com/konstructio/kubefirst-api/pkg/utils"
"github.com/konstructio/kubefirst/internal/catalog"
Expand Down Expand Up @@ -41,7 +46,7 @@ func createAws(cmd *cobra.Command, _ []string) error {
return fmt.Errorf("invalid catalog apps: %w", err)
}

err = ValidateProvidedFlags(cliFlags.GitProvider)
err = ValidateProvidedFlags(cliFlags.GitProvider, cliFlags.AmiType, cliFlags.CloudRegion)
if err != nil {
progress.Error(err.Error())
return fmt.Errorf("failed to validate provided flags: %w", err)
Expand All @@ -57,15 +62,7 @@ func createAws(cmd *cobra.Command, _ []string) error {
return nil
}

// Validate aws region
config, err := awsinternal.NewAwsV2(cloudRegionFlag)
if err != nil {
progress.Error(err.Error())
return fmt.Errorf("failed to validate AWS region: %w", err)
}

awsClient := &awsinternal.Configuration{Config: config}
creds, err := awsClient.Config.Credentials.Retrieve(aws.BackgroundContext())
creds, err := ValidateAWSRegionAndRetrieveCredentials(cloudRegionFlag)
if err != nil {
progress.Error(err.Error())
return fmt.Errorf("failed to retrieve AWS credentials: %w", err)
Expand All @@ -78,12 +75,6 @@ func createAws(cmd *cobra.Command, _ []string) error {
return fmt.Errorf("failed to write config: %w", err)
}

_, err = awsClient.CheckAvailabilityZones(cliFlags.CloudRegion)
if err != nil {
progress.Error(err.Error())
return fmt.Errorf("failed to check availability zones: %w", err)
}

gitAuth, err := gitShim.ValidateGitCredentials(cliFlags.GitProvider, cliFlags.GithubOrg, cliFlags.GitlabGroup)
if err != nil {
progress.Error(err.Error())
Expand Down Expand Up @@ -136,7 +127,7 @@ func createAws(cmd *cobra.Command, _ []string) error {
return nil
}

func ValidateProvidedFlags(gitProvider string) error {
func ValidateProvidedFlags(gitProvider, amiType, cloudRegion string) error {
progress.AddStep("Validate provided flags")

// Validate required environment variables for dns provider
Expand All @@ -161,7 +152,136 @@ func ValidateProvidedFlags(gitProvider string) error {
log.Info().Msgf("%q %s", "gitlab.com", key.Type())
}

if err := ValidateAMIType(amiType, cloudRegion); err != nil {
progress.Error(err.Error())
return fmt.Errorf("failed to validte ami type for node group: %w", err)
}

progress.CompleteStep("Validate provided flags")

return nil
}

func ValidateAWSRegionAndRetrieveCredentials(cloudRegion string) (*aws.Credentials, error) {
// Load AWS configuration
cfg, err := config.LoadDefaultConfig(context.TODO(),
config.WithRegion(cloudRegion),
)
if err != nil {
return nil, fmt.Errorf("failed to load AWS configuration: %w", err)
}

// Validate region by creating a client
stsClient := sts.NewFromConfig(cfg)
_, err = stsClient.GetCallerIdentity(context.TODO(), &sts.GetCallerIdentityInput{})
if err != nil {
return nil, fmt.Errorf("failed to validate AWS region: %w", err)
}

// Retrieve credentials
creds, err := cfg.Credentials.Retrieve(context.TODO())
if err != nil {
return nil, fmt.Errorf("failed to retrieve AWS credentials: %w", err)
}

return &creds, nil
}

func ValidateAMIType(amiType, region string) error {
ssm_types := map[string]string{

Check failure on line 191 in cmd/aws/create.go

View workflow job for this annotation

GitHub Actions / build

var-naming: don't use underscores in Go names; var ssm_types should be ssmTypes (revive)
"AL2_x86_64": "/aws/service/eks/optimized-ami/1.29/amazon-linux-2/recommended/image_id",
"AL2_ARM_64": "/aws/service/eks/optimized-ami/1.29/amazon-linux-2-arm64/recommended/image_id",
"BOTTLEROCKET_ARM_64": "/aws/service/bottlerocket/aws-k8s-1.29/arm64/latest/image_id",
"BOTTLEROCKET_x86_64": "/aws/service/bottlerocket/aws-k8s-1.29/x86_64/latest/image_id",
"BOTTLEROCKET_ARM_64_NVIDIA": "/aws/service/bottlerocket/aws-k8s-1.29-nvidia/arm64/latest/image_id",
"BOTTLEROCKET_x86_64_NVIDIA": "/aws/service/bottlerocket/aws-k8s-1.29-nvidia/x86_64/latest/image_id",
}

_, ok := ssm_types[amiType]
if !ok {
return fmt.Errorf("not a valid ami type")
}
cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion(region))
if err != nil {
return fmt.Errorf("unable to load AWS SDK config: %w", err)
}
ec2Client := ec2.NewFromConfig(cfg)
ssmClient := ssm.NewFromConfig(cfg)
ssmParameterName := ssm_types["BOTTLEROCKET_x86_64_NVIDIA"]

amiID, err := GetLatestAMIFromSSM(ssmClient, ssmParameterName)
if err != nil {
return fmt.Errorf("failed to get AMI ID from SSM: %w", err)
}
bl.Info("Retrieved AMI ID: %s\n", amiID)

architecture, err := GetAMIArchitecture(ec2Client, amiID)
if err != nil {
return fmt.Errorf("failed to get AMI architecture: %w", err)
}
fmt.Printf("AMI Architecture: %s\n", architecture)

instanceTypes, err := GetSupportedInstanceTypes(ec2Client, architecture)
if err != nil {
return fmt.Errorf("failed to get supported instance types: %w", err)
}

fmt.Println("Supported Instance Types:")
for _, instanceType := range instanceTypes {
fmt.Println(instanceType)
}

return nil
}

func GetLatestAMIFromSSM(ssmClient *ssm.Client, parameterName string) (string, error) {

Check failure on line 237 in cmd/aws/create.go

View workflow job for this annotation

GitHub Actions / build

unnecessary leading newline (whitespace)

input := &ssm.GetParameterInput{
Name: aws.String(parameterName),
}
output, err := ssmClient.GetParameter(context.TODO(), input)
if err != nil {
return "", err

Check failure on line 244 in cmd/aws/create.go

View workflow job for this annotation

GitHub Actions / build

error returned from external package is unwrapped: sig: func (*github.com/aws/aws-sdk-go-v2/service/ssm.Client).GetParameter(ctx context.Context, params *github.com/aws/aws-sdk-go-v2/service/ssm.GetParameterInput, optFns ...func(*github.com/aws/aws-sdk-go-v2/service/ssm.Options)) (*github.com/aws/aws-sdk-go-v2/service/ssm.GetParameterOutput, error) (wrapcheck)
}

return *output.Parameter.Value, nil
}

func GetAMIArchitecture(ec2Client *ec2.Client, amiID string) (string, error) {
input := &ec2.DescribeImagesInput{
ImageIds: []string{amiID},
}
output, err := ec2Client.DescribeImages(context.TODO(), input)
if err != nil {
return "", err

Check failure on line 256 in cmd/aws/create.go

View workflow job for this annotation

GitHub Actions / build

error returned from external package is unwrapped: sig: func (*github.com/aws/aws-sdk-go-v2/service/ec2.Client).DescribeImages(ctx context.Context, params *github.com/aws/aws-sdk-go-v2/service/ec2.DescribeImagesInput, optFns ...func(*github.com/aws/aws-sdk-go-v2/service/ec2.Options)) (*github.com/aws/aws-sdk-go-v2/service/ec2.DescribeImagesOutput, error) (wrapcheck)
}

if len(output.Images) == 0 {
return "", fmt.Errorf("no images found for AMI ID: %s", amiID)
}

val := output.Images[0]
return string(val.Architecture), nil
}

func GetSupportedInstanceTypes(ec2Client *ec2.Client, architecture string) ([]string, error) {
input := &ec2.DescribeInstanceTypesInput{}

var instanceTypes []string
paginator := ec2.NewDescribeInstanceTypesPaginator(ec2Client, input)

for paginator.HasMorePages() {
page, err := paginator.NextPage(context.TODO())
if err != nil {
return nil, err

Check failure on line 276 in cmd/aws/create.go

View workflow job for this annotation

GitHub Actions / build

error returned from external package is unwrapped: sig: func (*github.com/aws/aws-sdk-go-v2/service/ec2.DescribeInstanceTypesPaginator).NextPage(ctx context.Context, optFns ...func(*github.com/aws/aws-sdk-go-v2/service/ec2.Options)) (*github.com/aws/aws-sdk-go-v2/service/ec2.DescribeInstanceTypesOutput, error) (wrapcheck)
}

for _, instanceType := range page.InstanceTypes {
if string(instanceType.ProcessorInfo.SupportedArchitectures[0]) == architecture {
instanceTypes = append(instanceTypes, string(instanceType.InstanceType))
}
}
}

return instanceTypes, nil
}
36 changes: 21 additions & 15 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ go 1.23.0
require (
github.com/argoproj/argo-cd/v2 v2.9.3
github.com/atotto/clipboard v0.1.4
github.com/aws/aws-sdk-go v1.55.5
github.com/aws/aws-sdk-go-v2/config v1.28.6
github.com/aws/aws-sdk-go-v2/service/ec2 v1.91.0
github.com/aws/aws-sdk-go-v2/service/ssm v1.56.1
github.com/charmbracelet/bubbles v0.16.1
github.com/charmbracelet/bubbletea v0.24.2
github.com/charmbracelet/glamour v0.8.0
Expand Down Expand Up @@ -34,6 +36,11 @@ require (
k8s.io/client-go v11.0.1-0.20190816222228-6d55c1b1f1ca+incompatible
)

require (
github.com/aws/aws-sdk-go v1.44.317 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
)

require (
cloud.google.com/go v0.112.1 // indirect
cloud.google.com/go/compute v1.24.0 // indirect
Expand Down Expand Up @@ -65,32 +72,30 @@ require (
github.com/alecthomas/chroma/v2 v2.14.0 // indirect
github.com/argoproj/gitops-engine v0.7.3 // indirect
github.com/argoproj/pkg v0.13.7-0.20230627120311-a4dd357b057e // indirect
github.com/aws/aws-sdk-go-v2 v1.17.8 // indirect
github.com/aws/aws-sdk-go-v2 v1.32.6
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
github.com/aws/aws-sdk-go-v2/config v1.18.19 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.13.18 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.32 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.47
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.25 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.25 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.23 // indirect
github.com/aws/aws-sdk-go-v2/service/ec2 v1.91.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ecr v1.18.7 // indirect
github.com/aws/aws-sdk-go-v2/service/eks v1.27.10 // indirect
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.15.6 // indirect
github.com/aws/aws-sdk-go-v2/service/iam v1.19.8 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.26 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.6 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.0 // indirect
github.com/aws/aws-sdk-go-v2/service/kms v1.20.8 // indirect
github.com/aws/aws-sdk-go-v2/service/route53 v1.27.5 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.31.0 // indirect
github.com/aws/aws-sdk-go-v2/service/servicequotas v1.14.7 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.12.6 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.18.7 // indirect
github.com/aws/smithy-go v1.13.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.24.7 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.33.2
github.com/aws/smithy-go v1.22.1 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
Expand All @@ -102,6 +107,7 @@ require (
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chai2010/gettext-go v0.1.0 // indirect
github.com/charmbracelet/log v0.4.0
github.com/charmbracelet/x/ansi v0.4.5 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/cloudflare/cloudflare-go v0.73.0 // indirect
Expand Down
Loading

0 comments on commit 1327659

Please sign in to comment.