Skip to content

Commit

Permalink
Add machines to specified ELBs when creating/updating them
Browse files Browse the repository at this point in the history
Changes the type/name of the LoadBalancers field in ProviderConfig. AWS
only allows identifying load balancers by name, and their Describe call
doesn't allow Filters.
  • Loading branch information
csrwng committed Oct 24, 2018
1 parent 63ef3ac commit 312f2e7
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,9 @@ type AWSMachineProviderConfig struct {
// Placement specifies where to create the instance in AWS
Placement Placement

// LoadBalancerIDs is the IDs of the load balancers to which the new instance
// LoadBalancerNames is the names of the load balancers to which the new instance
// should be added once it is created.
LoadBalancerIDs []AWSResourceReference
LoadBalancerNames []string
}

// AWSResourceReference is a reference to a specific AWS resource by ID, ARN, or filters.
Expand Down
10 changes: 4 additions & 6 deletions pkg/apis/awsproviderconfig/v1alpha1/zz_generated.deepcopy.go

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

49 changes: 35 additions & 14 deletions pkg/cloud/aws/actuators/machine/actuator.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/elb"

"k8s.io/apimachinery/pkg/runtime"
awsclient "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/aws/client"
Expand Down Expand Up @@ -121,12 +122,6 @@ func (a *Actuator) Create(cluster *clusterv1.Cluster, machine *clusterv1.Machine
}
return err
}

// TODO(csrwng):
// Part of the status that gets updated when the machine gets created is the PublicIP.
// However, after a call to runInstance, most of the time a PublicIP is not yet allocated.
// If we don't yet have complete status (ie. the instance state is Pending, instead of Running),
// maybe we should return an error so the machine controller keeps retrying until we have complete status we can set.
return a.updateStatus(machine, instance, mLog)
}

Expand Down Expand Up @@ -433,14 +428,11 @@ func (a *Actuator) CreateMachine(cluster *clusterv1.Cluster, machine *clusterv1.
return nil, fmt.Errorf("unexpected reservation creating instance")
}

// TOOD(csrwng):
// One issue we have right now with how this works, is that usually at the end of the RunInstances call,
// the instance state is not yet 'Running'. Rather it is 'Pending'. Therefore the status
// is not yet complete (like PublicIP). One possible fix would be to wait and poll here
// until the instance is in the Running state. The other approach is to return an error
// so that the machine is requeued and in the exists function return false if the status doesn't match.
// That would require making the create re-entrant so we can just update the status.
return runResult.Instances[0], nil
instance := runResult.Instances[0]

err = a.UpdateLoadBalancers(client, machineProviderConfig, instance, mLog)

return instance, err
}

// Delete deletes a machine and updates its finalizer
Expand Down Expand Up @@ -547,6 +539,11 @@ func (a *Actuator) Update(cluster *clusterv1.Cluster, machine *clusterv1.Machine

}

err = a.UpdateLoadBalancers(client, machineProviderConfig, newestInstance, mLog)
if err != nil {
return err
}

// We do not support making changes to pre-existing instances, just update status.
return a.updateStatus(machine, newestInstance, mLog)
}
Expand Down Expand Up @@ -613,6 +610,30 @@ func (a *Actuator) getMachineInstances(cluster *clusterv1.Cluster, machine *clus
return GetRunningInstances(machine, client)
}

// UpdateLoadBalancers adds a given machine instance to the load balancers specified in its provider config
func (a *Actuator) UpdateLoadBalancers(client awsclient.Client, providerConfig *providerconfigv1.AWSMachineProviderConfig, instance *ec2.Instance, mLog log.FieldLogger) error {
if len(providerConfig.LoadBalancerNames) == 0 {
return nil
}
elbInstance := &elb.Instance{InstanceId: instance.InstanceId}
var errs []error
for _, elbName := range providerConfig.LoadBalancerNames {
req := &elb.RegisterInstancesWithLoadBalancerInput{
Instances: []*elb.Instance{elbInstance},
LoadBalancerName: aws.String(elbName),
}
_, err := client.RegisterInstancesWithLoadBalancer(req)
if err != nil {
errs = append(errs, fmt.Errorf("%s: %v", elbName, err))
}
}

if len(errs) > 0 {
return fmt.Errorf("failed to register instances with elbs: %v", errs)
}
return nil
}

// updateStatus calculates the new machine status, checks if anything has changed, and updates if so.
func (a *Actuator) updateStatus(machine *clusterv1.Machine, instance *ec2.Instance, mLog log.FieldLogger) error {

Expand Down
17 changes: 17 additions & 0 deletions pkg/cloud/aws/actuators/machine/actuator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ func testMachineAPIResources(clusterID string) (*clusterv1.Machine, *clusterv1.C
{ID: aws.String("sg-08b1ffd32874d59a2")}, // aws-actuator_infra_k8s
},
PublicIP: aws.Bool(true),
LoadBalancerNames: []string{
"cluster-con",
"cluster-ext",
"cluster-int",
},
}

codec, err := providerconfigv1.NewCodec()
Expand Down Expand Up @@ -207,6 +212,7 @@ func TestCreateAndDeleteMachine(t *testing.T) {
mockRunInstances(mockAWSClient, tc.createErrorExpected)
mockDescribeInstances(mockAWSClient, tc.createErrorExpected)
mockTerminateInstances(mockAWSClient)
mockRegisterInstancesWithLoadBalancer(mockAWSClient, tc.createErrorExpected)

// Create the machine
createErr := actuator.Create(cluster, machine)
Expand Down Expand Up @@ -369,3 +375,14 @@ func TestRemoveDuplicatedTags(t *testing.T) {
}
}
}

func mockRegisterInstancesWithLoadBalancer(mockAWSClient *mockaws.MockClient, createError bool) {
if createError {
return
}
// RegisterInstancesWithLoadBalancer should be called for every load balancer name in the machine
// spec for create and for update (3 * 2 = 6)
for i := 0; i < 6; i++ {
mockAWSClient.EXPECT().RegisterInstancesWithLoadBalancer(gomock.Any())
}
}

0 comments on commit 312f2e7

Please sign in to comment.