Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions cloud/linode/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"os"
"strconv"
"time"
"regexp"

"github.com/spf13/pflag"
"golang.org/x/exp/slices"
Expand Down Expand Up @@ -58,6 +59,7 @@ var Options struct {
ClusterCIDRIPv4 string
NodeCIDRMaskSizeIPv4 int
NodeCIDRMaskSizeIPv6 int
NodeBalancerPrefix string
}

type linodeCloud struct {
Expand All @@ -69,8 +71,9 @@ type linodeCloud struct {
}

var (
instanceCache *instances
ipHolderCharLimit int = 23
instanceCache *instances
ipHolderCharLimit int = 23
NodeBalancerPrefixCharLimit int = 19
)

func init() {
Expand Down Expand Up @@ -193,6 +196,19 @@ func newCloud() (cloudprovider.Interface, error) {
return nil, fmt.Errorf("%s", msg)
}

if len(Options.NodeBalancerPrefix) > NodeBalancerPrefixCharLimit {
msg := fmt.Sprintf("nodebalancer-prefix must be %d characters or less: %s is %d characters\n", NodeBalancerPrefixCharLimit, Options.NodeBalancerPrefix, len(Options.NodeBalancerPrefix))
klog.Error(msg)
return nil, fmt.Errorf("%s", msg)
}

validPrefix := regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)
if !validPrefix.MatchString(Options.NodeBalancerPrefix) {
msg := fmt.Sprintf("nodebalancer-prefix must be no empty and use only letters, numbers, underscores, and dashes: %s\n", Options.NodeBalancerPrefix)
klog.Error(msg)
return nil, fmt.Errorf("%s", msg)
}

// create struct that satisfies cloudprovider.Interface
lcloud := &linodeCloud{
client: linodeClient,
Expand Down
53 changes: 53 additions & 0 deletions cloud/linode/cloud_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func TestNewCloudRouteControllerDisabled(t *testing.T) {
t.Setenv("LINODE_API_TOKEN", "dummyapitoken")
t.Setenv("LINODE_REGION", "us-east")
t.Setenv("LINODE_REQUEST_TIMEOUT_SECONDS", "10")
Options.NodeBalancerPrefix = "ccm"

t.Run("should not fail if vpc is empty and routecontroller is disabled", func(t *testing.T) {
Options.VPCName = ""
Expand All @@ -45,6 +46,7 @@ func TestNewCloud(t *testing.T) {
t.Setenv("LINODE_REQUEST_TIMEOUT_SECONDS", "10")
t.Setenv("LINODE_ROUTES_CACHE_TTL_SECONDS", "60")
Options.LinodeGoDebug = true
Options.NodeBalancerPrefix = "ccm"

t.Run("should fail if api token is empty", func(t *testing.T) {
t.Setenv("LINODE_API_TOKEN", "")
Expand Down Expand Up @@ -126,6 +128,57 @@ func TestNewCloud(t *testing.T) {
_, err := newCloud()
assert.Error(t, err, "expected error if ipholdersuffix is longer than 23 chars")
})

t.Run("should fail if nodebalancer-prefix is longer than 19 chars", func(t *testing.T) {
prefix := Options.NodeBalancerPrefix
rtEnabled := Options.EnableRouteController
Options.EnableRouteController = false
Options.LoadBalancerType = "nodebalancer"
Options.NodeBalancerPrefix = strings.Repeat("a", 21)
defer func() {
Options.NodeBalancerPrefix = prefix
Options.LoadBalancerType = ""
Options.EnableRouteController = rtEnabled
}()
_, err := newCloud()
t.Log(err)
require.Error(t, err, "expected error if nodebalancer-prefix is longer than 19 chars")
require.ErrorContains(t, err, "nodebalancer-prefix")
})

t.Run("should fail if nodebalancer-prefix is empty", func(t *testing.T) {
prefix := Options.NodeBalancerPrefix
rtEnabled := Options.EnableRouteController
Options.EnableRouteController = false
Options.LoadBalancerType = "nodebalancer"
Options.NodeBalancerPrefix = ""
defer func() {
Options.NodeBalancerPrefix = prefix
Options.LoadBalancerType = ""
Options.EnableRouteController = rtEnabled
}()
_, err := newCloud()
t.Log(err)
require.Error(t, err, "expected error if nodebalancer-prefix is empty")
require.ErrorContains(t, err, "nodebalancer-prefix must be no empty")
})

t.Run("should fail if not validated nodebalancer-prefix", func(t *testing.T) {
prefix := Options.NodeBalancerPrefix
rtEnabled := Options.EnableRouteController
Options.EnableRouteController = false
Options.LoadBalancerType = "nodebalancer"
Options.NodeBalancerPrefix = "\\+x"
defer func() {
Options.NodeBalancerPrefix = prefix
Options.LoadBalancerType = ""
Options.EnableRouteController = rtEnabled
}()
_, err := newCloud()
t.Log(err)
require.Error(t, err, "expected error if not validated nodebalancer-prefix")
require.ErrorContains(t, err, "nodebalancer-prefix must be no empty and use only letters, numbers, underscores, and dashes")
})
}

func Test_linodeCloud_LoadBalancer(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion cloud/linode/loadbalancers.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ func (l *loadbalancers) cleanupOldNodeBalancer(ctx context.Context, service *v1.
// GetLoadBalancer will not modify service.
func (l *loadbalancers) GetLoadBalancerName(_ context.Context, _ string, _ *v1.Service) string {
unixNano := strconv.FormatInt(time.Now().UnixNano(), 16)
return fmt.Sprintf("ccm-%s", unixNano[len(unixNano)-12:])
return fmt.Sprintf("%s-%s", Options.NodeBalancerPrefix, unixNano[len(unixNano)-12:])
}

// GetLoadBalancer returns the *v1.LoadBalancerStatus of service.
Expand Down
3 changes: 3 additions & 0 deletions deploy/chart/templates/daemonset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ spec:
{{- if .Values.nodeBalancerBackendIPv4Subnet }}
- --nodebalancer-backend-ipv4-subnet={{ .Values.nodeBalancerBackendIPv4Subnet }}
{{- end }}
{{- if .Values.nodeBalancerPrefix }}
- --nodebalancer-prefix={{ .Values.nodeBalancerPrefix }}
{{- end }}
{{- if .Values.extraArgs }}
{{- toYaml .Values.extraArgs | nindent 12 }}
{{- end }}
Expand Down
3 changes: 3 additions & 0 deletions deploy/chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ tolerations:
# nodeBalancerBackendIPv4SubnetName is the subnet name to use for the backend ips of the NodeBalancer
# nodeBalancerBackendIPv4SubnetName: ""

# nodeBalancerPrefix is used to add prefix for nodeBalancer name. Default is "ccm"
# nodeBalancerPrefix: ""

# This section adds the ability to pass environment variables to adjust CCM defaults
# https://github.com/linode/linode-cloud-controller-manager/blob/master/cloud/linode/loadbalancers.go
# LINODE_HOSTNAME_ONLY_INGRESS type bool is supported
Expand Down
1 change: 1 addition & 0 deletions docs/configuration/environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ The CCM supports the following flags:
| `--enable-ipv6-for-loadbalancers` | `false` | Set both IPv4 and IPv6 addresses for all LoadBalancer services (when disabled, only IPv4 is used). This can also be configured per-service using the `service.beta.kubernetes.io/linode-loadbalancer-enable-ipv6-ingress` annotation. |
| `--node-cidr-mask-size-ipv4` | `24` | ipv4 cidr mask size for pod cidrs allocated to nodes |
| `--node-cidr-mask-size-ipv6` | `64` | ipv6 cidr mask size for pod cidrs allocated to nodes |
| `--nodebalancer-prefix` | `ccm` | Name prefix for NoadBalancers. |

## Configuration Methods

Expand Down
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func main() {
command.Flags().IntVar(&linode.Options.NodeBalancerBackendIPv4SubnetID, "nodebalancer-backend-ipv4-subnet-id", 0, "ipv4 subnet id to use for NodeBalancer backends")
command.Flags().StringVar(&linode.Options.NodeBalancerBackendIPv4SubnetName, "nodebalancer-backend-ipv4-subnet-name", "", "ipv4 subnet name to use for NodeBalancer backends")
command.Flags().BoolVar(&linode.Options.DisableNodeBalancerVPCBackends, "disable-nodebalancer-vpc-backends", false, "disables nodebalancer backends in VPCs (when enabled, nodebalancers will only have private IPs as backends for backward compatibility)")
command.Flags().StringVar(&linode.Options.NodeBalancerPrefix, "nodebalancer-prefix", "ccm", fmt.Sprintf("Name prefix for NoadBalancers. (max. %v char.)", linode.NodeBalancerPrefixCharLimit))

// Set static flags
command.Flags().VisitAll(func(fl *pflag.Flag) {
Expand Down
Loading