Skip to content

Commit

Permalink
feat: enable support for capmox
Browse files Browse the repository at this point in the history
This makes ccm compatible with cluster api and cluster api provider proxmox (capmox)

Signed-off-by: Matthias Teich <[email protected]>
  • Loading branch information
Mattes83 authored and sergelogvinov committed Jan 7, 2025
1 parent 63eef87 commit 956a30a
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 12 deletions.
2 changes: 1 addition & 1 deletion charts/proxmox-cloud-controller-manager/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 3 additions & 0 deletions charts/proxmox-cloud-controller-manager/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions pkg/cluster/cloud_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down Expand Up @@ -67,6 +79,10 @@ func ReadCloudConfig(config io.Reader) (ClustersConfig, error) {
}
}

if cfg.Features.Provider == "" {
cfg.Features.Provider = ProviderDefault
}

return cfg, nil
}

Expand Down
35 changes: 34 additions & 1 deletion pkg/cluster/cloud_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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) {
Expand Down
5 changes: 5 additions & 0 deletions pkg/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/proxmox/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
27 changes: 23 additions & 4 deletions pkg/proxmox/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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(),
Expand All @@ -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)
Expand Down
10 changes: 5 additions & 5 deletions pkg/proxmox/instances_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand Down Expand Up @@ -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() {
Expand Down

0 comments on commit 956a30a

Please sign in to comment.