in internal/deployers/eksapi/infra.go [94:195]
func (m *InfrastructureManager) createInfrastructureStack(opts *deployerOptions) (*Infrastructure, error) {
// TODO: create a subnet in every AZ
// get two AZs for the subnets
azs, err := m.clients.EC2().DescribeAvailabilityZones(context.TODO(), &ec2.DescribeAvailabilityZonesInput{})
if err != nil {
return nil, err
}
var subnetAzs []string
if opts.CapacityReservation {
subnetAzs, err = m.getAZsWithCapacity(opts)
if err != nil {
return nil, err
}
} else if len(opts.InstanceTypes) > 0 {
azs, err := m.getRankedAZsForInstanceTypes(opts)
if err != nil {
return nil, err
}
if len(azs) == 0 {
return nil, fmt.Errorf("no AZs support any of the provided instance types (%v)", opts.InstanceTypes)
}
subnetAzs = azs[0:int(math.Min(float64(len(azs)), numInfraAZs))]
} else {
for i := range numInfraAZs {
subnetAzs = append(subnetAzs, aws.ToString(azs.AvailabilityZones[i].ZoneName))
}
}
// make sure we always have the number of AZs used in the infra stack. can end up here if using
// a single capacity reservation or the provided instance types are offered in fewer AZs
for _, az := range azs.AvailabilityZones {
if len(subnetAzs) == numInfraAZs {
break
}
if !slices.Contains(subnetAzs, *az.ZoneName) {
az := *az.ZoneName
klog.Infof("padding infra stack with AZ: %v", az)
subnetAzs = append(subnetAzs, az)
}
}
klog.Infof("creating infrastructure stack with AZs: %v", subnetAzs)
input := cloudformation.CreateStackInput{
StackName: aws.String(m.resourceID),
TemplateBody: aws.String(templates.Infrastructure),
Capabilities: []cloudformationtypes.Capability{cloudformationtypes.CapabilityCapabilityIam},
Parameters: []cloudformationtypes.Parameter{
{
ParameterKey: aws.String("ResourceId"),
ParameterValue: aws.String(m.resourceID),
},
{
ParameterKey: aws.String("Subnet01AZ"),
ParameterValue: aws.String(subnetAzs[0]),
},
{
ParameterKey: aws.String("Subnet02AZ"),
ParameterValue: aws.String(subnetAzs[1]),
},
{
ParameterKey: aws.String("AutoMode"),
ParameterValue: aws.String(fmt.Sprintf("%t", opts.AutoMode)),
},
},
}
if opts.ClusterRoleServicePrincipal != "" {
input.Parameters = append(input.Parameters, cloudformationtypes.Parameter{
ParameterKey: aws.String("AdditionalClusterRoleServicePrincipal"),
ParameterValue: aws.String(opts.ClusterRoleServicePrincipal),
})
}
if opts.EKSEndpointURL != "" {
input.Tags = []cloudformationtypes.Tag{
{
Key: aws.String(eksEndpointURLTag),
Value: aws.String(opts.EKSEndpointURL),
},
}
}
klog.Infof("creating infrastructure stack...")
out, err := m.clients.CFN().CreateStack(context.TODO(), &input)
if err != nil {
return nil, err
}
klog.Infof("waiting for infrastructure stack to be created: %s", *out.StackId)
err = cloudformation.NewStackCreateCompleteWaiter(m.clients.CFN()).
Wait(context.TODO(),
&cloudformation.DescribeStacksInput{
StackName: out.StackId,
},
infraStackCreationTimeout)
if err != nil {
return nil, fmt.Errorf("failed to wait for infrastructure stack creation: %w", err)
}
klog.Infof("getting infrastructure stack resources: %s", *out.StackId)
infra, err := m.getInfrastructureStackResources()
infra.availabilityZones = subnetAzs
if err != nil {
return nil, fmt.Errorf("failed to get infrastructure stack resources: %w", err)
}
klog.Infof("created infrastructure: %+v", infra)
return infra, nil
}