Skip to content

Commit

Permalink
Merge pull request #4273 from vincepri/add-placement-group-name
Browse files Browse the repository at this point in the history
✨ Add support to specify PlacementGroup Name in instances
  • Loading branch information
k8s-ci-robot authored May 22, 2023
2 parents c18c8d3 + 26ef70a commit 7862de6
Show file tree
Hide file tree
Showing 11 changed files with 202 additions and 2 deletions.
1 change: 1 addition & 0 deletions api/v1beta1/awscluster_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func (src *AWSCluster) ConvertTo(dstRaw conversion.Hub) error {
dst.Spec.S3Bucket = restored.Spec.S3Bucket
if restored.Status.Bastion != nil {
dst.Status.Bastion.InstanceMetadataOptions = restored.Status.Bastion.InstanceMetadataOptions
dst.Status.Bastion.PlacementGroupName = restored.Status.Bastion.PlacementGroupName
}
dst.Spec.Partition = restored.Spec.Partition

Expand Down
2 changes: 2 additions & 0 deletions api/v1beta1/awsmachine_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func (src *AWSMachine) ConvertTo(dstRaw conversion.Hub) error {

dst.Spec.Ignition = restored.Spec.Ignition
dst.Spec.InstanceMetadataOptions = restored.Spec.InstanceMetadataOptions
dst.Spec.PlacementGroupName = restored.Spec.PlacementGroupName

return nil
}
Expand Down Expand Up @@ -83,6 +84,7 @@ func (r *AWSMachineTemplate) ConvertTo(dstRaw conversion.Hub) error {
dst.Spec.Template.ObjectMeta = restored.Spec.Template.ObjectMeta
dst.Spec.Template.Spec.Ignition = restored.Spec.Template.Spec.Ignition
dst.Spec.Template.Spec.InstanceMetadataOptions = restored.Spec.Template.Spec.InstanceMetadataOptions
dst.Spec.Template.Spec.PlacementGroupName = restored.Spec.Template.Spec.PlacementGroupName

return nil
}
Expand Down
2 changes: 2 additions & 0 deletions api/v1beta1/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions api/v1beta2/awsmachine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ type AWSMachineSpec struct {
// +optional
SpotMarketOptions *SpotMarketOptions `json:"spotMarketOptions,omitempty"`

// PlacementGroupName specifies the name of the placement group in which to launch the instance.
// +optional
PlacementGroupName string `json:"placementGroupName,omitempty"`

// Tenancy indicates if instance should run on shared or single-tenant hardware.
// +optional
// +kubebuilder:validation:Enum:=default;dedicated;host
Expand Down
4 changes: 4 additions & 0 deletions api/v1beta2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,10 @@ type Instance struct {
// SpotMarketOptions option for configuring instances to be run using AWS Spot instances.
SpotMarketOptions *SpotMarketOptions `json:"spotMarketOptions,omitempty"`

// PlacementGroupName specifies the name of the placement group in which to launch the instance.
// +optional
PlacementGroupName string `json:"placementGroupName,omitempty"`

// Tenancy indicates if instance should run on shared or single-tenant hardware.
// +optional
Tenancy string `json:"tenancy,omitempty"`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,10 @@ spec:
- size
type: object
type: array
placementGroupName:
description: PlacementGroupName specifies the name of the placement
group in which to launch the instance.
type: string
privateIp:
description: The private IPv4 address assigned to the instance.
type: string
Expand Down Expand Up @@ -2371,6 +2375,10 @@ spec:
- size
type: object
type: array
placementGroupName:
description: PlacementGroupName specifies the name of the placement
group in which to launch the instance.
type: string
privateIp:
description: The private IPv4 address assigned to the instance.
type: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1441,6 +1441,10 @@ spec:
- size
type: object
type: array
placementGroupName:
description: PlacementGroupName specifies the name of the placement
group in which to launch the instance.
type: string
privateIp:
description: The private IPv4 address assigned to the instance.
type: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,10 @@ spec:
- size
type: object
type: array
placementGroupName:
description: PlacementGroupName specifies the name of the placement
group in which to launch the instance.
type: string
providerID:
description: ProviderID is the unique identifier as specified by the
cloud provider.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,10 @@ spec:
- size
type: object
type: array
placementGroupName:
description: PlacementGroupName specifies the name of the
placement group in which to launch the instance.
type: string
providerID:
description: ProviderID is the unique identifier as specified
by the cloud provider.
Expand Down
9 changes: 9 additions & 0 deletions pkg/cloud/services/ec2/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ func (s *Service) CreateInstance(scope *scope.MachineScope, userData []byte, use

input.Tenancy = scope.AWSMachine.Spec.Tenancy

input.PlacementGroupName = scope.AWSMachine.Spec.PlacementGroupName

s.scope.Debug("Running instance", "machine-role", scope.Role())
s.scope.Debug("Running instance with instance metadata options", "metadata options", input.InstanceMetadataOptions)
out, err := s.runInstance(scope.Role(), input)
Expand Down Expand Up @@ -588,6 +590,13 @@ func (s *Service) runInstance(role string, i *infrav1.Instance) (*infrav1.Instan
}
}

if i.PlacementGroupName != "" {
if input.Placement == nil {
input.Placement = &ec2.Placement{}
}
input.Placement.GroupName = &i.PlacementGroupName
}

out, err := s.EC2Client.RunInstances(input)
if err != nil {
return nil, errors.Wrap(err, "failed to run instance")
Expand Down
162 changes: 160 additions & 2 deletions pkg/cloud/services/ec2/instances_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2500,7 +2500,163 @@ func TestCreateInstance(t *testing.T) {
},
},
{
name: "with dedicated tenancy ignition",
name: "with custom placement group cloud-config",
machine: clusterv1.Machine{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"set": "node"},
Namespace: "default",
Name: "machine-aws-test1",
},
Spec: clusterv1.MachineSpec{
Bootstrap: clusterv1.Bootstrap{
DataSecretName: pointer.String("bootstrap-data"),
},
},
},
machineConfig: &infrav1.AWSMachineSpec{
AMI: infrav1.AMIReference{
ID: aws.String("abc"),
},
InstanceType: "m5.large",
PlacementGroupName: "placement-group1",
UncompressedUserData: &isUncompressedFalse,
},
awsCluster: &infrav1.AWSCluster{
Spec: infrav1.AWSClusterSpec{
NetworkSpec: infrav1.NetworkSpec{
Subnets: infrav1.Subnets{
infrav1.SubnetSpec{
ID: "subnet-1",
IsPublic: false,
},
infrav1.SubnetSpec{
IsPublic: false,
},
},
},
},
Status: infrav1.AWSClusterStatus{
Network: infrav1.NetworkStatus{
SecurityGroups: map[infrav1.SecurityGroupRole]infrav1.SecurityGroup{
infrav1.SecurityGroupControlPlane: {
ID: "1",
},
infrav1.SecurityGroupNode: {
ID: "2",
},
infrav1.SecurityGroupLB: {
ID: "3",
},
},
APIServerELB: infrav1.LoadBalancer{
DNSName: "test-apiserver.us-east-1.aws",
},
},
},
},
expect: func(m *mocks.MockEC2APIMockRecorder) {
m. // TODO: Restore these parameters, but with the tags as well
RunInstances(gomock.Eq(&ec2.RunInstancesInput{
ImageId: aws.String("abc"),
InstanceType: aws.String("m5.large"),
KeyName: aws.String("default"),
MaxCount: aws.Int64(1),
MinCount: aws.Int64(1),
Placement: &ec2.Placement{
GroupName: aws.String("placement-group1"),
},
SecurityGroupIds: []*string{aws.String("2"), aws.String("3")},
SubnetId: aws.String("subnet-1"),
TagSpecifications: []*ec2.TagSpecification{
{
ResourceType: aws.String("instance"),
Tags: []*ec2.Tag{
{
Key: aws.String("MachineName"),
Value: aws.String("default/machine-aws-test1"),
},
{
Key: aws.String("Name"),
Value: aws.String("aws-test1"),
},
{
Key: aws.String("kubernetes.io/cluster/test1"),
Value: aws.String("owned"),
},
{
Key: aws.String("sigs.k8s.io/cluster-api-provider-aws/cluster/test1"),
Value: aws.String("owned"),
},
{
Key: aws.String("sigs.k8s.io/cluster-api-provider-aws/role"),
Value: aws.String("node"),
},
},
},
},
UserData: aws.String(base64.StdEncoding.EncodeToString(userDataCompressed)),
})).
Return(&ec2.Reservation{
Instances: []*ec2.Instance{
{
State: &ec2.InstanceState{
Name: aws.String(ec2.InstanceStateNamePending),
},
IamInstanceProfile: &ec2.IamInstanceProfile{
Arn: aws.String("arn:aws:iam::123456789012:instance-profile/foo"),
},
InstanceId: aws.String("two"),
InstanceType: aws.String("m5.large"),
SubnetId: aws.String("subnet-1"),
ImageId: aws.String("ami-1"),
RootDeviceName: aws.String("device-1"),
BlockDeviceMappings: []*ec2.InstanceBlockDeviceMapping{
{
DeviceName: aws.String("device-1"),
Ebs: &ec2.EbsInstanceBlockDevice{
VolumeId: aws.String("volume-1"),
},
},
},
Placement: &ec2.Placement{
AvailabilityZone: &az,
GroupName: aws.String("placement-group1"),
},
},
},
}, nil)
m.
DescribeInstanceTypes(gomock.Eq(&ec2.DescribeInstanceTypesInput{
InstanceTypes: []*string{
aws.String("m5.large"),
},
})).
Return(&ec2.DescribeInstanceTypesOutput{
InstanceTypes: []*ec2.InstanceTypeInfo{
{
ProcessorInfo: &ec2.ProcessorInfo{
SupportedArchitectures: []*string{
aws.String("x86_64"),
},
},
},
},
}, nil)
m.
DescribeNetworkInterfaces(gomock.Any()).
Return(&ec2.DescribeNetworkInterfacesOutput{
NetworkInterfaces: []*ec2.NetworkInterface{},
NextToken: nil,
}, nil)
},
check: func(instance *infrav1.Instance, err error) {
if err != nil {
t.Fatalf("did not expect error: %v", err)
}
},
},
{
name: "with dedicated tenancy and placement group ignition",
machine: clusterv1.Machine{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"set": "node"},
Expand All @@ -2519,6 +2675,7 @@ func TestCreateInstance(t *testing.T) {
},
InstanceType: "m5.large",
Tenancy: "dedicated",
PlacementGroupName: "placement-group1",
UncompressedUserData: &isUncompressedTrue,
Ignition: &infrav1.Ignition{},
},
Expand Down Expand Up @@ -2582,7 +2739,8 @@ func TestCreateInstance(t *testing.T) {
MaxCount: aws.Int64(1),
MinCount: aws.Int64(1),
Placement: &ec2.Placement{
Tenancy: &tenancy,
Tenancy: &tenancy,
GroupName: aws.String("placement-group1"),
},
SecurityGroupIds: []*string{aws.String("2"), aws.String("3")},
SubnetId: aws.String("subnet-1"),
Expand Down

0 comments on commit 7862de6

Please sign in to comment.