Skip to content

Commit

Permalink
Merge pull request #1290 from randomvariable/lb-name
Browse files Browse the repository at this point in the history
✨ Support cluster names > 22 characters in length
  • Loading branch information
k8s-ci-robot committed Nov 7, 2019
2 parents 3ede0e1 + 0068ee5 commit d2b5087
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 10 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ require (
github.com/spf13/pflag v1.0.5
go.uber.org/atomic v1.4.0 // indirect
go.uber.org/zap v1.10.0 // indirect
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 // indirect
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7
golang.org/x/net v0.0.0-20191021144547-ec77196f6094
golang.org/x/sys v0.0.0-20190911201528-7ad0cfa0b7b5 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
Expand Down
65 changes: 56 additions & 9 deletions pkg/cloud/services/elb/loadbalancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/awserrors"
"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/converters"
"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/wait"
"sigs.k8s.io/cluster-api-provider-aws/pkg/internal/hash"
)

// ResourceGroups are filtered by ARN identifier: https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#arns-syntax
Expand All @@ -42,7 +43,11 @@ func (s *Service) ReconcileLoadbalancers() error {
s.scope.V(2).Info("Reconciling load balancers")

// Get default api server spec.
spec := s.getAPIServerClassicELBSpec()
spec, err := s.getAPIServerClassicELBSpec()

if err != nil {
return err
}

// Describe or create.
apiELB, err := s.describeClassicELB(spec.Name)
Expand Down Expand Up @@ -84,7 +89,11 @@ func (s *Service) ReconcileLoadbalancers() error {

// GetAPIServerDNSName returns the DNS name endpoint for the API server
func (s *Service) GetAPIServerDNSName() (string, error) {
apiELB, err := s.describeClassicELB(GenerateELBName(s.scope.Name(), infrav1.APIServerRoleTagValue))
elbName, err := GenerateELBName(s.scope.Name())
if err != nil {
return "", err
}
apiELB, err := s.describeClassicELB(elbName)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -137,7 +146,10 @@ func (s *Service) RegisterInstanceWithClassicELB(instanceID string, loadBalancer

// RegisterInstanceWithAPIServerELB registers an instance with a classic ELB
func (s *Service) RegisterInstanceWithAPIServerELB(i *infrav1.Instance) error {
name := GenerateELBName(s.scope.Name(), infrav1.APIServerRoleTagValue)
name, err := GenerateELBName(s.scope.Name())
if err != nil {
return err
}
out, err := s.describeClassicELB(name)
if err != nil {
return err
Expand Down Expand Up @@ -169,14 +181,49 @@ func (s *Service) RegisterInstanceWithAPIServerELB(i *infrav1.Instance) error {
return nil
}

// GenerateELBName generates a formatted ELB name
func GenerateELBName(clusterName string, elbName string) string {
return fmt.Sprintf("%s-%s", clusterName, elbName)
// GenerateELBName generates a formatted ELB name via either
// concatenating the cluster name to the "-apiserver" suffix
// or computing a hash for clusters with names above 32 characters.
func GenerateELBName(clusterName string) (string, error) {
standardELBName := generateStandardELBName(clusterName)
if len(standardELBName) <= 32 {
return standardELBName, nil
}

elbName, err := generateHashedELBName(clusterName)
if err != nil {
return "", err
}

return elbName, nil
}

// generateStandardELBName generates a formatted ELB name based on cluster
// and ELB name
func generateStandardELBName(clusterName string) string {
elbCompatibleClusterName := strings.Replace(clusterName, ".", "-", -1)
return fmt.Sprintf("%s-%s", elbCompatibleClusterName, infrav1.APIServerRoleTagValue)
}

// generateHashedELBName generates a 32-character hashed name based on cluster
// and ELB name
func generateHashedELBName(clusterName string) (string, error) {
// hashSize = 32 - length of "k8s" - length of "-" = 28
shortName, err := hash.Base36TruncatedHash(clusterName, 28)
if err != nil {
return "", errors.Wrap(err, "unable to create ELB name")
}

return fmt.Sprintf("%s-%s", shortName, "k8s"), nil
}

func (s *Service) getAPIServerClassicELBSpec() *infrav1.ClassicELB {
func (s *Service) getAPIServerClassicELBSpec() (*infrav1.ClassicELB, error) {
elbName, err := GenerateELBName(s.scope.Name())
if err != nil {
return nil, err
}
res := &infrav1.ClassicELB{
Name: GenerateELBName(s.scope.Name(), infrav1.APIServerRoleTagValue),
Name: elbName,
Scheme: s.scope.ControlPlaneLoadBalancerScheme(),
Listeners: []*infrav1.ClassicELBListener{
{
Expand Down Expand Up @@ -223,7 +270,7 @@ func (s *Service) getAPIServerClassicELBSpec() *infrav1.ClassicELB {
}
}

return res
return res, nil
}

func (s *Service) createClassicELB(spec *infrav1.ClassicELB) (*infrav1.ClassicELB, error) {
Expand Down
68 changes: 68 additions & 0 deletions pkg/cloud/services/elb/loadbalancer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package elb

import (
"testing"
)

func TestGenerateELBName(t *testing.T) {
tests := []struct {
name string
expected string
}{
{
name: "test",
expected: "test-apiserver",
},
{
name: "0123456789012345678901",
expected: "0123456789012345678901-apiserver",
},
{
name: "01234567890123456789012",
expected: "26o3cjil5at5qn27vukn5x09b3ql-k8s",
},
{
name: "anotherverylongtoolongname",
expected: "t8gnrbbifaaf5d0k4xmwui3xwvip-k8s",
},
{
name: "anotherverylongtoolongnameanotherverylongtoolongname",
expected: "tph1huzox1f10z9ow1inrootjws8-k8s",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

elbName, err := GenerateELBName(tt.name)

if err != nil {
t.Error(err)
}

if elbName != tt.expected {
t.Errorf("expected ELB name: %v, got name: %v", tt.expected, elbName)
}

if len(elbName) > 32 {
t.Errorf("ELB name too long: %v vs. %s", len(elbName), "32")
}

})
}
}
50 changes: 50 additions & 0 deletions pkg/internal/hash/base36.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package hash

import (
"github.com/pkg/errors"
"golang.org/x/crypto/blake2b"
)

const base36set = "0123456789abcdefghijklmnopqrstuvwxyz"

// Base36TruncatedHash returns a consistent hash using blake2b
// and truncating the byte values to alphanumeric only
// of a fixed length specified by the consumer.
func Base36TruncatedHash(str string, len int) (string, error) {
hasher, err := blake2b.New(len, nil)
if err != nil {
return "", errors.Wrap(err, "unable to create hash function")
}

hasher.Write([]byte(str))
return base36Truncate(hasher.Sum(nil)), nil
}

// base36Truncate returns a string that is base36 compliant
// It is not an encoding since it returns a same-length string
// for any byte value
func base36Truncate(bytes []byte) string {
var chars string
for _, bite := range bytes {
idx := int(bite) % 36
chars = chars + string(base36set[idx])
}

return chars
}

0 comments on commit d2b5087

Please sign in to comment.