Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add bottlerocket ami types #2352

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open

feat: add bottlerocket ami types #2352

wants to merge 26 commits into from

Conversation

jokestax
Copy link
Contributor

@jokestax jokestax commented Dec 30, 2024

Description

Add support for Bottlerocket AMI types in the AWS cloud CLI.

Testing

Provision a cluster using the CLI with the --ami-type <AMI_TYPE> flag.

Example Command:

go run . aws create \
  --alerts-email [email protected] \
  --domain-name kuberfu.com \
  --dns-provider cloudflare \
  --gitops-template-branch main \
  --git-provider github \
  --github-org ar6464 \
  --cluster-name rr18 \
  --ami-type BOTTLEROCKET_ARM_64 

Supported AMI Types

AMI Type
AL2_x86_64
AL2_ARM_64
BOTTLEROCKET_ARM_64
BOTTLEROCKET_x86_64
BOTTLEROCKET_ARM_64_NVIDIA
BOTTLEROCKET_x86_64_NVIDIA

Copy link
Contributor

@nathan-nicholson nathan-nicholson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a lot of functions with in-line defined dependencies (primarily clients to AWS) that will make this almost impossible to properly test logic paths without a lot of effort and real resources.

I may take a stab at refactoring/pairing on this, but I'm not comfortable with merging with its current structure.

cmd/aws/create.go Outdated Show resolved Hide resolved
cmd/aws/create.go Outdated Show resolved Hide resolved
cmd/aws/create.go Outdated Show resolved Hide resolved
cmd/aws/create.go Outdated Show resolved Hide resolved
cmd/aws/create.go Outdated Show resolved Hide resolved
cmd/aws/create.go Outdated Show resolved Hide resolved
cmd/aws/create.go Outdated Show resolved Hide resolved
cmd/aws/create.go Outdated Show resolved Hide resolved
internal/utilities/flags.go Outdated Show resolved Hide resolved
cmd/aws/create.go Show resolved Hide resolved
Copy link
Member

@patrickdappollonio patrickdappollonio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to Nathan's comments as well.

cmd/aws/create.go Outdated Show resolved Hide resolved
cmd/aws/create.go Outdated Show resolved Hide resolved
cmd/aws/create.go Outdated Show resolved Hide resolved
cmd/aws/create.go Outdated Show resolved Hide resolved
cmd/aws/create.go Outdated Show resolved Hide resolved
cmd/aws/create_test.go Outdated Show resolved Hide resolved
cmd/aws/create_test.go Outdated Show resolved Hide resolved
cmd/aws/create_test.go Outdated Show resolved Hide resolved
cmd/aws/create_test.go Outdated Show resolved Hide resolved
cmd/aws/create_test.go Outdated Show resolved Hide resolved
@jokestax jokestax changed the title feat: bottlerocket feat: add bottlerocket AMI types Dec 31, 2024
@jokestax jokestax changed the title feat: add bottlerocket AMI types feat: add bottlerocket ami types Dec 31, 2024
cmd/aws/create.go Outdated Show resolved Hide resolved
Copy link
Contributor

@nathan-nicholson nathan-nicholson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While it may make sense to split out much of this into a struct responsible, we can do that as part of another PR. :shipit:

Comment on lines 34 to 97
type mockInstanceTypesPaginator struct {
instanceTypes []ec2Types.InstanceTypeInfo
err error
called bool
}

func (m *mockInstanceTypesPaginator) HasMorePages() bool {
return !m.called
}

func (m *mockInstanceTypesPaginator) NextPage(ctx context.Context, opts ...func(*ec2.Options)) (*ec2.DescribeInstanceTypesOutput, error) {
if m.err != nil {
return nil, m.err
}
m.called = true
return &ec2.DescribeInstanceTypesOutput{
InstanceTypes: m.instanceTypes,
}, nil
}

type mockSSMClient struct {
ssm.Client
parameterValue string
err error
}

func (m *mockSSMClient) GetParameter(ctx context.Context, input *ssm.GetParameterInput, opts ...func(*ssm.Options)) (*ssm.GetParameterOutput, error) {
if m.err != nil {
return nil, m.err
}
return &ssm.GetParameterOutput{
Parameter: &ssmTypes.Parameter{
Value: &m.parameterValue,
},
}, nil
}

type mockEC2Client struct {
ec2.Client
images []ec2Types.Image
architecture string
err error
}

func (m *mockEC2Client) DescribeImages(ctx context.Context, input *ec2.DescribeImagesInput, opts ...func(*ec2.Options)) (*ec2.DescribeImagesOutput, error) {
if m.err != nil {
return nil, m.err
}
if m.architecture == "x86_64" {
return &ec2.DescribeImagesOutput{
Images: []ec2Types.Image{
{
Architecture: ec2Types.ArchitectureValues("x86_64"),
},
},
}, nil
} else if m.architecture == "" {
return &ec2.DescribeImagesOutput{
Images: m.images,
}, nil
} else {
return nil, errors.New("unexpected architecture")
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are still using the old fashion approach where instead of passing the function, you pass the returned values, making them usable exactly once before you have to reinstantiate them again.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am unclear and would need your help ig 😅

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What Patrick is saying is that you can define a mock implementation of DescribeImages to the mock struct instead of using this single definition. You can see an example of this on the mockCredentialsProvider. It's a function with the same signature as the Method, but that can be dynamically defined for each test case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, sorry, but exactly what Nathan said. I explained it in detail in one of my previous comments but I think because you edited the file either Github or you marked the issue as "resolved", so the comment is collapsed now.

creds, err := getSessionCredentials(context.Background(), mockProvider)
if tt.expectedErr != nil {
require.Nil(t, creds)
require.EqualError(t, err, tt.expectedErr.Error())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mentioned in the previous review but it seems it was marked as resolved without actually resolving it. This is a very weak validation that depends on the fact that a) both haveto be error types, and b) both error string versions have to match. Not sure you want to do that for the reasons I provided before.

The same applies for the rest of the checks in the unit tests below.

cmd/root.go Show resolved Hide resolved
@nathan-nicholson
Copy link
Contributor

I didn't finish completely replacing the mocks, but I'm calling it for today. Spent more time fighting table tests than I'm proud to admit. May have been easier to just do individual test cases for most of these 🤷

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants