mirror of
https://github.com/outbackdingo/talos-cloud-controller-manager.git
synced 2026-01-27 18:20:23 +00:00
feat: node transformer feature flags
Introduce feature flags: * PublicIPDiscovery enables the Cloud Controller Manager (CCM) to identify global/public IPs on the node. Signed-off-by: Serge Logvinov <serge.logvinov@sinextra.dev>
This commit is contained in:
2
.github/workflows/build-test.yaml
vendored
2
.github/workflows/build-test.yaml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
- name: Lint
|
||||
uses: golangci/golangci-lint-action@v5
|
||||
with:
|
||||
version: v1.57.1
|
||||
version: v1.58.0
|
||||
args: --timeout=5m --config=.golangci.yml
|
||||
- name: Build
|
||||
timeout-minutes: 10
|
||||
|
||||
@@ -143,16 +143,17 @@ linters:
|
||||
- errorlint
|
||||
- exhaustruct
|
||||
- exhaustivestruct
|
||||
- err113
|
||||
- forbidigo
|
||||
- forcetypeassert
|
||||
- funlen
|
||||
- gas
|
||||
- gochecknoglobals
|
||||
- gochecknoinits
|
||||
- gocognit
|
||||
- godox
|
||||
- goerr113
|
||||
- gomnd
|
||||
- gosec
|
||||
- mnd
|
||||
- ifshort
|
||||
- ireturn # we return interfaces
|
||||
- maintidx
|
||||
@@ -175,7 +176,6 @@ linters:
|
||||
|
||||
# temporarily disabled linters
|
||||
- copyloopvar
|
||||
# https://github.com/golangci/golangci-lint/issues/4606
|
||||
- intrange
|
||||
|
||||
# abandoned linters for which golangci shows the warning that the repo is archived by the owner
|
||||
@@ -188,6 +188,7 @@ linters:
|
||||
- deadcode
|
||||
- ifshort
|
||||
- perfsprint
|
||||
- execinquery
|
||||
|
||||
disable-all: false
|
||||
fast: false
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/siderolabs/talos-cloud-controller-manager/pkg/transformer"
|
||||
utilsnet "github.com/siderolabs/talos-cloud-controller-manager/pkg/utils/net"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/network"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/runtime"
|
||||
@@ -21,29 +22,36 @@ import (
|
||||
"k8s.io/utils/strings/slices"
|
||||
)
|
||||
|
||||
func getNodeAddresses(config *cloudConfig, platform string, nodeIPs []string, ifaces []network.AddressStatusSpec) []v1.NodeAddress {
|
||||
var publicIPv4s, publicIPv6s, publicIPs []string
|
||||
func ipDescovery(nodeIPs []string, ifaces []network.AddressStatusSpec) (publicIPv4s, publicIPv6s []string) {
|
||||
for _, iface := range ifaces {
|
||||
if iface.LinkName == "kubespan" || iface.LinkName == "lo" {
|
||||
continue
|
||||
}
|
||||
|
||||
switch platform {
|
||||
case "nocloud", "metal", "openstack":
|
||||
for _, iface := range ifaces {
|
||||
if iface.LinkName == "kubespan" {
|
||||
ip := iface.Address.Addr()
|
||||
if ip.IsGlobalUnicast() && !ip.IsPrivate() {
|
||||
if slices.Contains(nodeIPs, ip.String()) {
|
||||
continue
|
||||
}
|
||||
|
||||
ip := iface.Address.Addr()
|
||||
if ip.IsGlobalUnicast() && !ip.IsPrivate() {
|
||||
if slices.Contains(nodeIPs, ip.String()) {
|
||||
continue
|
||||
}
|
||||
|
||||
if ip.Is6() {
|
||||
publicIPv6s = append(publicIPv6s, ip.String())
|
||||
} else {
|
||||
publicIPv4s = append(publicIPv4s, ip.String())
|
||||
}
|
||||
if ip.Is6() {
|
||||
publicIPv6s = append(publicIPv6s, ip.String())
|
||||
} else {
|
||||
publicIPv4s = append(publicIPv4s, ip.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return publicIPv4s, publicIPv6s
|
||||
}
|
||||
|
||||
func getNodeAddresses(config *cloudConfig, platform string, features *transformer.NodeFeaturesFlagSpec, nodeIPs []string, ifaces []network.AddressStatusSpec) []v1.NodeAddress {
|
||||
var publicIPv4s, publicIPv6s, publicIPs []string
|
||||
|
||||
switch platform {
|
||||
// Those platforms don't expose public IPs information in metadata
|
||||
case "nocloud", "metal", "openstack", "oracle":
|
||||
publicIPv4s, publicIPv6s = ipDescovery(nodeIPs, ifaces)
|
||||
default:
|
||||
for _, iface := range ifaces {
|
||||
if iface.LinkName == "external" {
|
||||
@@ -62,6 +70,12 @@ func getNodeAddresses(config *cloudConfig, platform string, nodeIPs []string, if
|
||||
}
|
||||
}
|
||||
|
||||
if features != nil && features.PublicIPDiscovery {
|
||||
ipv4, ipv6 := ipDescovery(nodeIPs, ifaces)
|
||||
publicIPv4s = append(publicIPv4s, ipv4...)
|
||||
publicIPv6s = append(publicIPv6s, ipv6...)
|
||||
}
|
||||
|
||||
addresses := []v1.NodeAddress{}
|
||||
for _, ip := range utilsnet.PreferedDualStackNodeIPs(config.Global.PreferIPv6, nodeIPs) {
|
||||
addresses = append(addresses, v1.NodeAddress{Type: v1.NodeInternalIP, Address: ip})
|
||||
|
||||
@@ -30,6 +30,7 @@ func TestGetNodeAddresses(t *testing.T) {
|
||||
name string
|
||||
cfg cloudConfig
|
||||
platform string
|
||||
features *transformer.NodeFeaturesFlagSpec
|
||||
providedIP string
|
||||
ifaces []network.AddressStatusSpec
|
||||
expected []v1.NodeAddress
|
||||
@@ -142,9 +143,45 @@ func TestGetNodeAddresses(t *testing.T) {
|
||||
{Type: v1.NodeExternalIP, Address: "2001:1234::1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "gcp dualstack with public IPs",
|
||||
cfg: cfg,
|
||||
platform: "gcp",
|
||||
providedIP: "192.168.0.1,fd15:1:2::192:168:0:1",
|
||||
ifaces: []network.AddressStatusSpec{
|
||||
{Address: netip.MustParsePrefix("192.168.0.1/24")},
|
||||
{Address: netip.MustParsePrefix("fe80::e0b5:71ff:fe24:7e60/64")},
|
||||
{Address: netip.MustParsePrefix("1.2.3.4/24"), LinkName: "external"},
|
||||
{Address: netip.MustParsePrefix("2001:1234::123/64")},
|
||||
},
|
||||
expected: []v1.NodeAddress{
|
||||
{Type: v1.NodeInternalIP, Address: "192.168.0.1"},
|
||||
{Type: v1.NodeInternalIP, Address: "fd15:1:2:0:192:168:0:1"},
|
||||
{Type: v1.NodeExternalIP, Address: "1.2.3.4"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "gcp dualstack with public IPs and featureflag",
|
||||
cfg: cfg,
|
||||
platform: "gcp",
|
||||
features: &transformer.NodeFeaturesFlagSpec{PublicIPDiscovery: true},
|
||||
providedIP: "192.168.0.1,fd15:1:2::192:168:0:1",
|
||||
ifaces: []network.AddressStatusSpec{
|
||||
{Address: netip.MustParsePrefix("192.168.0.1/24")},
|
||||
{Address: netip.MustParsePrefix("fe80::e0b5:71ff:fe24:7e60/64")},
|
||||
{Address: netip.MustParsePrefix("1.2.3.4/24"), LinkName: "external"},
|
||||
{Address: netip.MustParsePrefix("2001:1234::123/64")},
|
||||
},
|
||||
expected: []v1.NodeAddress{
|
||||
{Type: v1.NodeInternalIP, Address: "192.168.0.1"},
|
||||
{Type: v1.NodeInternalIP, Address: "fd15:1:2:0:192:168:0:1"},
|
||||
{Type: v1.NodeExternalIP, Address: "1.2.3.4"},
|
||||
{Type: v1.NodeExternalIP, Address: "2001:1234::123"},
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
addresses := getNodeAddresses(&tt.cfg, tt.platform, strings.Split(tt.providedIP, ","), tt.ifaces)
|
||||
addresses := getNodeAddresses(&tt.cfg, tt.platform, tt.features, strings.Split(tt.providedIP, ","), tt.ifaces)
|
||||
|
||||
assert.Equal(t, tt.expected, addresses)
|
||||
})
|
||||
|
||||
@@ -104,7 +104,7 @@ func (i *instances) InstanceMetadata(ctx context.Context, node *v1.Node) (*cloud
|
||||
return nil, fmt.Errorf("error getting interfaces list from the node %s: %w", node.Name, err)
|
||||
}
|
||||
|
||||
addresses := getNodeAddresses(i.c.config, meta.Platform, nodeIPs, ifaces)
|
||||
addresses := getNodeAddresses(i.c.config, meta.Platform, &nodeSpec.Features, nodeIPs, ifaces)
|
||||
|
||||
addresses = append(addresses, v1.NodeAddress{Type: v1.NodeHostName, Address: node.Name})
|
||||
|
||||
|
||||
@@ -20,12 +20,20 @@ type NodeTerm struct {
|
||||
Annotations map[string]string `yaml:"annotations,omitempty"`
|
||||
Labels map[string]string `yaml:"labels,omitempty"`
|
||||
PlatformMetadata map[string]string `yaml:"platformMetadata,omitempty"`
|
||||
Features NodeFeaturesFlagSpec `yaml:"features,omitempty"`
|
||||
}
|
||||
|
||||
// NodeSpec represents the transformed node specifcations.
|
||||
type NodeSpec struct {
|
||||
Annotations map[string]string
|
||||
Labels map[string]string
|
||||
Features NodeFeaturesFlagSpec
|
||||
}
|
||||
|
||||
// NodeFeaturesFlagSpec represents the node features flags.
|
||||
type NodeFeaturesFlagSpec struct {
|
||||
// PublicIPDiscovery try to find public IP on the node
|
||||
PublicIPDiscovery bool `yaml:"publicIPDiscovery,omitempty"`
|
||||
}
|
||||
|
||||
var prohibitedPlatformMetadataKeys = []string{"hostname", "platform"}
|
||||
@@ -36,6 +44,11 @@ func TransformNode(terms []NodeTerm, platformMetadata *runtime.PlatformMetadataS
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
node := &NodeSpec{
|
||||
Annotations: make(map[string]string),
|
||||
Labels: make(map[string]string),
|
||||
}
|
||||
|
||||
metadata := metadataFromStruct(platformMetadata)
|
||||
|
||||
for _, term := range terms {
|
||||
@@ -45,11 +58,6 @@ func TransformNode(terms []NodeTerm, platformMetadata *runtime.PlatformMetadataS
|
||||
}
|
||||
|
||||
if match {
|
||||
node := &NodeSpec{
|
||||
Annotations: make(map[string]string),
|
||||
Labels: make(map[string]string),
|
||||
}
|
||||
|
||||
if term.Annotations != nil {
|
||||
for k, v := range term.Annotations {
|
||||
t, err := executeTemplate(v, platformMetadata)
|
||||
@@ -107,7 +115,7 @@ func TransformNode(terms []NodeTerm, platformMetadata *runtime.PlatformMetadataS
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func executeTemplate(tmpl string, data interface{}) (string, error) {
|
||||
|
||||
Reference in New Issue
Block a user