Skip to content

Commit

Permalink
WIP: Implemented API loadbalancer class, allowing NLB and ELB support…
Browse files Browse the repository at this point in the history
… on AWS.
  • Loading branch information
christianjoun committed Sep 19, 2020
1 parent 509e693 commit d77b10a
Show file tree
Hide file tree
Showing 23 changed files with 2,464 additions and 62 deletions.
15 changes: 15 additions & 0 deletions cmd/kops/create_cluster.go
Expand Up @@ -80,6 +80,9 @@ type CreateClusterOptions struct {
MasterTenancy string
NodeTenancy string

// Specify API loadbalancer class as classic or nlb
APILoadBalancerClass string

// Allow custom public master name
MasterPublicName string

Expand Down Expand Up @@ -280,6 +283,7 @@ func NewCmdCreateCluster(f *util.Factory, out io.Writer) *cobra.Command {
cmd.Flags().StringVar(&options.MasterTenancy, "master-tenancy", options.MasterTenancy, "The tenancy of the master group on AWS. Can either be default or dedicated.")
cmd.Flags().StringVar(&options.NodeTenancy, "node-tenancy", options.NodeTenancy, "The tenancy of the node group on AWS. Can be either default or dedicated.")

cmd.Flags().StringVar(&options.APILoadBalancerClass, "api-loadbalancer-class", options.APILoadBalancerClass, "Currently only supported in AWS. Sets the API loadbalancer class to eiether 'classic' or 'network'")
cmd.Flags().StringVar(&options.APILoadBalancerType, "api-loadbalancer-type", options.APILoadBalancerType, "Sets the API loadbalancer type to either 'public' or 'internal'")
cmd.Flags().StringVar(&options.APISSLCertificate, "api-ssl-certificate", options.APISSLCertificate, "Currently only supported in AWS. Sets the ARN of the SSL Certificate to use for the API server loadbalancer.")

Expand Down Expand Up @@ -489,6 +493,17 @@ func RunCreateCluster(ctx context.Context, f *util.Factory, out io.Writer, c *Cr
cluster.Spec.MasterPublicName = c.MasterPublicName
}

if cluster.Spec.API.LoadBalancer != nil && cluster.Spec.API.LoadBalancer.Class == "" {
switch c.APILoadBalancerClass {
case "", "classic":
cluster.Spec.API.LoadBalancer.Class = api.LoadBalancerClassClassic
case "network":
cluster.Spec.API.LoadBalancer.Class = api.LoadBalancerClassNetwork
default:
return fmt.Errorf("unknown api-loadbalancer-class: %q", c.APILoadBalancerClass)
}
}

if err := commands.SetClusterFields(c.Overrides, cluster, instanceGroups); err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion docs/cluster_spec.md
Expand Up @@ -82,7 +82,7 @@ spec:

*AWS only*
You can choose to have a Network Load Balancer instead of a Classsic Load Balancer. The `class`
field should be either `Network` or `Classic` (default). Note: Note: changing the class of load balancer in an existing
field should be either `Network` or `Classic` (default). Note: changing the class of load balancer in an existing
cluster is a disruptive operation. Until the masters have gone through a rolling update, new connections to the apiserver will fail due to the old master's TLS certificates containing the old load balancer's IP address.
```yaml
spec:
Expand Down
56 changes: 48 additions & 8 deletions pkg/commands/status_discovery.go
Expand Up @@ -18,6 +18,10 @@ package commands

import (
"fmt"
"reflect"

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

"github.com/aws/aws-sdk-go/aws"
"k8s.io/kops/pkg/apis/kops"
Expand All @@ -37,6 +41,10 @@ type CloudDiscoveryStatusStore struct {

var _ kops.StatusStore = &CloudDiscoveryStatusStore{}

func isNil(v interface{}) bool {
return v == nil || (reflect.ValueOf(v).Kind() == reflect.Ptr && reflect.ValueOf(v).IsNil())
}

func (s *CloudDiscoveryStatusStore) GetApiIngressStatus(cluster *kops.Cluster) ([]kops.ApiIngressStatus, error) {
cloud, err := cloudup.BuildCloud(cluster)
if err != nil {
Expand All @@ -53,19 +61,51 @@ func (s *CloudDiscoveryStatusStore) GetApiIngressStatus(cluster *kops.Cluster) (

if awsCloud, ok := cloud.(awsup.AWSCloud); ok {
name := "api." + cluster.Name
lb, err := awstasks.FindLoadBalancerByNameTag(awsCloud, name)
if lb == nil {
return nil, nil

ELB, NLB := false, false

lbSpec := cluster.Spec.API.LoadBalancer
switch lbSpec.Class {
case kops.LoadBalancerClassClassic, "":
ELB = true
case kops.LoadBalancerClassNetwork:
NLB = true
default:
return nil, fmt.Errorf("Unknown Cluster.Spec.API.LoadBalancer.Class : %v", lbSpec.Class)
}
if err != nil {
return nil, fmt.Errorf("error looking for AWS ELB: %v", err)

var lb interface{}

if ELB {
lb, err = awstasks.FindLoadBalancerByNameTag(awsCloud, name)
if isNil(lb) {
return nil, nil
}
if err != nil {
return nil, fmt.Errorf("error looking for AWS ELB: %v", err)
}
} else if NLB {
lb, err = awstasks.FindNetworkLoadBalancerByNameTag(awsCloud, name)
if isNil(lb) {
return nil, nil
}
if err != nil {
return nil, fmt.Errorf("error looking for AWS ELB: %v", err)
}

}
var ingresses []kops.ApiIngressStatus

if lb != nil {
lbDnsName := aws.StringValue(lb.DNSName)
if !isNil(lb) {
var lbDnsName string
if ELB {
lbDnsName = aws.StringValue(lb.(*elb.LoadBalancerDescription).DNSName)
} else if NLB {
lbDnsName = aws.StringValue(lb.(*elbv2.LoadBalancer).DNSName)
}
//lbDnsName := aws.StringValue(lb.DNSName)
if lbDnsName == "" {
return nil, fmt.Errorf("found ELB %q, but it did not have a DNSName", name)
return nil, fmt.Errorf("found api LB %q, but it did not have a DNSName", name)
}

ingresses = append(ingresses, kops.ApiIngressStatus{Hostname: lbDnsName})
Expand Down

0 comments on commit d77b10a

Please sign in to comment.