Skip to content
Open
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
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@ The Hetzner Cloud controller manager seamlessly integrates your Kubernetes clust

## About the Fork

In the long run, we (Syself) would like to switch to the [upstream ccm](https://github.com/syself/hetzner-cloud-controller-manager/) again.
We plan to support the [upstream hcloud
ccm](https://github.com/hetznercloud/hcloud-cloud-controller-manager/) in
[CAPH](https://github.com/syself/cluster-api-provider-hetzner/). After that, this fork is no longer
needed.

## About the Fork (old)

In the long run, we (Syself) would like to switch to the [upstream ccm](https://github.com/hetznercloud/hcloud-cloud-controller-manager/) again.

A lot of changes were made in the upstream fork, and we don't plan to merge them into our fork.

Expand Down Expand Up @@ -62,9 +69,12 @@ See [CAPH docs](https://syself.com/docs/caph/topics/baremetal/creating-workload-

## Usage

We recommend to mount the secret `hetzner` as volume and make it avaiable for the container as `/etc/hetzner-secret`.
Then the credentials are automatically reloaded, when the secret changes.
You see an example in the [ccm helm chart](https://github.com/syself/charts/tree/main/charts/ccm-hetzner)
We recommend to mount the secret `hetzner` as volume and make it avaiable for the container as
`/etc/hetzner-secret`. Then the credentials are automatically reloaded, when the secret changes.
When you use the hot-reloading, be sure that the keys in the secret use these names: "hcloud" (for
the HCLOUD_TOKEN), "robot-user" and "robot-password". For compatibility with the upstream hcloud-ccm
we support the key "token" instead of "hcloud". You see an example in the [ccm helm
chart](https://github.com/syself/charts/tree/main/charts/ccm-hetzner)

## Env Variables

Expand Down
3 changes: 3 additions & 0 deletions hcloud/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ func (i *instances) InstanceMetadata(ctx context.Context, node *corev1.Node) (*c
node.Name, errServerNotFound)
}
return &cloudprovider.InstanceMetadata{
// It is ok that this code (syself hetzner-ccm) returns the legacy format
// "hcloud://bm-NNNN". We will use the upstream hcloud-ccm in the future. Related PR for
// caph: https://github.com/syself/cluster-api-provider-hetzner/pull/1703
ProviderID: providerid.LegacyFromRobotServerNumber(bmServer.ServerNumber),
InstanceType: getInstanceTypeOfRobotServer(bmServer),
NodeAddresses: robotNodeAddresses(i.addressFamily, bmServer),
Expand Down
20 changes: 14 additions & 6 deletions internal/credentials/hotreload.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package credentials

import (
"errors"
"fmt"
"os"
"path/filepath"
Expand Down Expand Up @@ -91,7 +92,7 @@ func handleEvent(credentialsDir, baseName string, hcloudClient *hcloud.Client, r
// This case is executed, when the process is running on a local machine.
return loadRobotCredentials(credentialsDir, robotClient)

case "hcloud":
case "hcloud", "token":
// This case is executed, when the process is running on a local machine.
return loadHcloudCredentials(credentialsDir, hcloudClient)

Expand Down Expand Up @@ -228,12 +229,19 @@ func GetInitialHcloudCredentialsFromDirectory(credentialsDir string) (string, er
}

func readHcloudCredentials(credentialsDir string) (string, error) {
hcloudTokenFile := filepath.Join(credentialsDir, "hcloud")
data, err := os.ReadFile(hcloudTokenFile)
if err != nil {
return "", fmt.Errorf("reading hcloud token from %q failed: %w", hcloudTokenFile, err)
var allErrors []error
for _, key := range []string{"hcloud", "token"} {
// upstream hcloud ccm expects by defaul the key "token" in the secret. To ease migration
// (back and forward), we support that, too.
hcloudTokenFile := filepath.Join(credentialsDir, key)
data, err := os.ReadFile(hcloudTokenFile)
if err != nil {
allErrors = append(allErrors, fmt.Errorf("reading hcloud token from %q failed: %w", hcloudTokenFile, err))
continue
}
return strings.TrimSpace(string(data)), nil
}
return strings.TrimSpace(string(data)), nil
return "", errors.Join(allErrors...)
}

// GetDirectory returns the directory where the credentials are stored.
Expand Down
9 changes: 9 additions & 0 deletions internal/providerid/providerid.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const (
//
// It MUST not be changed, otherwise existing nodes will not be recognized anymore.
prefixRobotLegacy = "hcloud://bm-"

prefixRobotNew = "hrobot://"
)

type UnkownPrefixError struct {
Expand All @@ -40,6 +42,13 @@ func (e *UnkownPrefixError) Error() string {
func ToServerID(providerID string) (id int64, isCloudServer bool, err error) {
idString := ""
switch {
case strings.HasPrefix(providerID, prefixRobotNew):
// If a cluster switched from old-syself-ccm to upstream-hcloud-ccm, and then back again to
// old-syself-ccm, then there might be nodes with the new format. Let's support this
// edge-case, but in the long run the upstream-hcloud-ccm should be used. Related:
// https://github.com/syself/cluster-api-provider-hetzner/pull/1703
idString = strings.ReplaceAll(providerID, prefixRobotNew, "")

case strings.HasPrefix(providerID, prefixRobotLegacy):
// This case needs to be before [prefixCloud], as [prefixCloud] is a superset of [prefixRobotLegacy]
idString = strings.ReplaceAll(providerID, prefixRobotLegacy, "")
Expand Down
9 changes: 8 additions & 1 deletion internal/providerid/providerid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,19 @@ func TestToServerID(t *testing.T) {
wantErr: errors.New("providerID is missing a serverID: hcloud://"),
},
{
name: "[robot-syself] simple id",
name: "[robot-syself] simple id (legacy)",
providerID: "hcloud://bm-4321",
wantID: 4321,
wantIsCloudServer: false,
wantErr: nil,
},
{
name: "[robot-syself] simple id (new)",
providerID: "hrobot://4321",
wantID: 4321,
wantIsCloudServer: false,
wantErr: nil,
},
{
name: "[robot-syself] invalid id",
providerID: "hcloud://bm-my-robot",
Expand Down