diff --git a/charts/proxmox-cloud-controller-manager/Chart.yaml b/charts/proxmox-cloud-controller-manager/Chart.yaml index 3c9866d..ff5999a 100644 --- a/charts/proxmox-cloud-controller-manager/Chart.yaml +++ b/charts/proxmox-cloud-controller-manager/Chart.yaml @@ -16,7 +16,7 @@ maintainers: # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.2.9 +version: 0.2.10 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. diff --git a/charts/proxmox-cloud-controller-manager/values.yaml b/charts/proxmox-cloud-controller-manager/values.yaml index 37d38de..af03799 100644 --- a/charts/proxmox-cloud-controller-manager/values.yaml +++ b/charts/proxmox-cloud-controller-manager/values.yaml @@ -40,6 +40,9 @@ existingConfigSecretKey: config.yaml # -- Proxmox cluster config. config: + features: + # specify provider: proxmox if you are using capmox (cluster api provider for proxmox) + provider: 'default' clusters: [] # - url: https://cluster-api-1.exmple.com:8006/api2/json # insecure: false diff --git a/pkg/cluster/cloud_config.go b/pkg/cluster/cloud_config.go index 0704855..e023497 100644 --- a/pkg/cluster/cloud_config.go +++ b/pkg/cluster/cloud_config.go @@ -26,8 +26,20 @@ import ( yaml "gopkg.in/yaml.v3" ) +// Provider specifies the provider. Can be 'default' or 'capmox' +type Provider string + +// ProviderDefault is the default provider +const ProviderDefault Provider = "default" + +// ProviderCapmox is the Provider for capmox +const ProviderCapmox Provider = "capmox" + // ClustersConfig is proxmox multi-cluster cloud config. type ClustersConfig struct { + Features struct { + Provider Provider `yaml:"provider,omitempty"` + } `yaml:"features,omitempty"` Clusters []struct { URL string `yaml:"url"` Insecure bool `yaml:"insecure,omitempty"` @@ -67,6 +79,10 @@ func ReadCloudConfig(config io.Reader) (ClustersConfig, error) { } } + if cfg.Features.Provider == "" { + cfg.Features.Provider = ProviderDefault + } + return cfg, nil } diff --git a/pkg/cluster/cloud_config_test.go b/pkg/cluster/cloud_config_test.go index a71c4f6..225025e 100644 --- a/pkg/cluster/cloud_config_test.go +++ b/pkg/cluster/cloud_config_test.go @@ -69,7 +69,7 @@ clusters: assert.NotNil(t, cfg) assert.Equal(t, 1, len(cfg.Clusters)) - // Valid config with one cluster (username/password) + // Valid config with one cluster (username/password), implicit default provider cfg, err = cluster.ReadCloudConfig(strings.NewReader(` clusters: - url: https://example.com @@ -81,6 +81,39 @@ clusters: assert.Nil(t, err) assert.NotNil(t, cfg) assert.Equal(t, 1, len(cfg.Clusters)) + assert.Equal(t, cluster.ProviderDefault, cfg.Features.Provider) + + // Valid config with one cluster (username/password), explicit provider default + cfg, err = cluster.ReadCloudConfig(strings.NewReader(` +features: + provider: 'default' +clusters: + - url: https://example.com + insecure: false + username: "user@pam" + password: "secret" + region: cluster-1 +`)) + assert.Nil(t, err) + assert.NotNil(t, cfg) + assert.Equal(t, 1, len(cfg.Clusters)) + assert.Equal(t, cluster.ProviderDefault, cfg.Features.Provider) + + // Valid config with one cluster (username/password), explicit provider capmox + cfg, err = cluster.ReadCloudConfig(strings.NewReader(` +features: + provider: 'capmox' +clusters: + - url: https://example.com + insecure: false + username: "user@pam" + password: "secret" + region: cluster-1 +`)) + assert.Nil(t, err) + assert.NotNil(t, cfg) + assert.Equal(t, 1, len(cfg.Clusters)) + assert.Equal(t, cluster.ProviderCapmox, cfg.Features.Provider) } func TestReadCloudConfigFromFile(t *testing.T) { diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index 7603852..429d1a9 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -38,6 +38,11 @@ func GetProviderID(region string, vmr *pxapi.VmRef) string { return fmt.Sprintf("%s://%s/%d", ProviderName, region, vmr.VmId()) } +// GetProviderIDFromUUID returns the magic providerID for kubernetes node. +func GetProviderIDFromUUID(uuid string) string { + return fmt.Sprintf("%s://%s", ProviderName, uuid) +} + // GetVMID returns the VM ID from the providerID. func GetVMID(providerID string) (int, error) { if !strings.HasPrefix(providerID, ProviderName) { diff --git a/pkg/proxmox/cloud.go b/pkg/proxmox/cloud.go index 55265f3..f7d4631 100644 --- a/pkg/proxmox/cloud.go +++ b/pkg/proxmox/cloud.go @@ -65,7 +65,7 @@ func newCloud(config *cluster.ClustersConfig) (cloudprovider.Interface, error) { return nil, err } - instancesInterface := newInstances(client) + instancesInterface := newInstances(client, config.Features.Provider) return &cloud{ client: client, diff --git a/pkg/proxmox/instances.go b/pkg/proxmox/instances.go index c777d90..655cbec 100644 --- a/pkg/proxmox/instances.go +++ b/pkg/proxmox/instances.go @@ -34,12 +34,14 @@ import ( ) type instances struct { - c *cluster.Cluster + c *cluster.Cluster + provider cluster.Provider } -func newInstances(client *cluster.Cluster) *instances { +func newInstances(client *cluster.Cluster, provider cluster.Provider) *instances { return &instances{ - c: client, + c: client, + provider: provider, } } @@ -149,6 +151,12 @@ func (i *instances) InstanceMetadata(_ context.Context, node *v1.Node) (*cloudpr return nil, fmt.Errorf("instances.InstanceMetadata() - failed to find instance by name/uuid %s: %v, skipped", node.Name, err) } } + + if i.provider == cluster.ProviderCapmox { + providerID = provider.GetProviderIDFromUUID(uuid) + } else { + providerID = provider.GetProviderID(region, vmRef) + } } else if !strings.HasPrefix(node.Spec.ProviderID, provider.ProviderName) { klog.V(4).InfoS("instances.InstanceMetadata() omitting unmanaged node", "node", klog.KObj(node), "providerID", node.Spec.ProviderID) @@ -178,7 +186,7 @@ func (i *instances) InstanceMetadata(_ context.Context, node *v1.Node) (*cloudpr } return &cloudprovider.InstanceMetadata{ - ProviderID: provider.GetProviderID(region, vmRef), + ProviderID: providerID, NodeAddresses: addresses, InstanceType: instanceType, Zone: vmRef.Node(), @@ -192,6 +200,17 @@ func (i *instances) InstanceMetadata(_ context.Context, node *v1.Node) (*cloudpr } func (i *instances) getInstance(node *v1.Node) (*pxapi.VmRef, string, error) { + if i.provider == cluster.ProviderCapmox { + uuid := node.Status.NodeInfo.SystemUUID + + vmRef, region, err := i.c.FindVMByUUID(uuid) + if err != nil { + return nil, "", fmt.Errorf("instances.getInstance() error: %v", err) + } + + return vmRef, region, nil + } + vm, region, err := provider.ParseProviderID(node.Spec.ProviderID) if err != nil { return nil, "", fmt.Errorf("instances.getInstance() error: %v", err) diff --git a/pkg/proxmox/instances_test.go b/pkg/proxmox/instances_test.go index 76a8e86..cb78694 100644 --- a/pkg/proxmox/instances_test.go +++ b/pkg/proxmox/instances_test.go @@ -28,8 +28,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" - "github.com/sergelogvinov/proxmox-cloud-controller-manager/pkg/cluster" - provider "github.com/sergelogvinov/proxmox-cloud-controller-manager/pkg/provider" + proxmoxcluster "github.com/sergelogvinov/proxmox-cloud-controller-manager/pkg/cluster" + "github.com/sergelogvinov/proxmox-cloud-controller-manager/pkg/provider" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -44,7 +44,7 @@ type ccmTestSuite struct { } func (ts *ccmTestSuite) SetupTest() { - cfg, err := cluster.ReadCloudConfig(strings.NewReader(` + cfg, err := proxmoxcluster.ReadCloudConfig(strings.NewReader(` clusters: - url: https://127.0.0.1:8006/api2/json insecure: false @@ -123,12 +123,12 @@ clusters: }, ) - cluster, err := cluster.NewCluster(&cfg, &http.Client{}) + cluster, err := proxmoxcluster.NewCluster(&cfg, &http.Client{}) if err != nil { ts.T().Fatalf("failed to create cluster client: %v", err) } - ts.i = newInstances(cluster) + ts.i = newInstances(cluster, proxmoxcluster.ProviderDefault) } func (ts *ccmTestSuite) TearDownTest() {