mirror of https://github.com/kubernetes/kops.git
hetzner: Use kops-controller for node bootstrap
This commit is contained in:
parent
2c4808c5bd
commit
c9d1eb9761
|
@ -41,6 +41,7 @@ import (
|
|||
nodeidentityos "k8s.io/kops/pkg/nodeidentity/openstack"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/gce/tpm/gcetpmverifier"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/hetzner"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
@ -119,6 +120,12 @@ func main() {
|
|||
setupLog.Error(err, "unable to create verifier")
|
||||
os.Exit(1)
|
||||
}
|
||||
} else if opt.Server.Provider.Hetzner != nil {
|
||||
verifier, err = hetzner.NewHetznerVerifier(opt.Server.Provider.Hetzner)
|
||||
if err != nil {
|
||||
setupLog.Error(err, "unable to create verifier")
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
klog.Fatalf("server cloud provider config not provided")
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package config
|
|||
import (
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
|
||||
gcetpm "k8s.io/kops/upup/pkg/fi/cloudup/gce/tpm"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/hetzner"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
|
@ -61,8 +62,9 @@ type ServerOptions struct {
|
|||
}
|
||||
|
||||
type ServerProviderOptions struct {
|
||||
AWS *awsup.AWSVerifierOptions `json:"aws,omitempty"`
|
||||
GCE *gcetpm.TPMVerifierOptions `json:"gce,omitempty"`
|
||||
AWS *awsup.AWSVerifierOptions `json:"aws,omitempty"`
|
||||
GCE *gcetpm.TPMVerifierOptions `json:"gce,omitempty"`
|
||||
Hetzner *hetzner.HetznerVerifierOptions `json:"hetzner,omitempty"`
|
||||
}
|
||||
|
||||
// DiscoveryOptions configures our support for discovery, particularly gossip DNS (i.e. k8s.local)
|
||||
|
|
|
@ -28,6 +28,7 @@ import (
|
|||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/gce/tpm/gcetpmsigner"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/hetzner"
|
||||
"k8s.io/kops/upup/pkg/fi/nodeup/nodetasks"
|
||||
)
|
||||
|
||||
|
@ -50,6 +51,8 @@ func (b BootstrapClientBuilder) Build(c *fi.ModelBuilderContext) error {
|
|||
authenticator, err = gcetpmsigner.NewTPMAuthenticator()
|
||||
// We don't use the custom resolver here in gossip mode (though we could);
|
||||
// instead we use this as a check that protokube has now started.
|
||||
case kops.CloudProviderHetzner:
|
||||
authenticator, err = hetzner.NewHetznerAuthenticator()
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unsupported cloud provider for authenticator %q", b.CloudProvider)
|
||||
|
|
|
@ -27,6 +27,8 @@ func UseKopsControllerForNodeBootstrap(cluster *kops.Cluster) bool {
|
|||
return true
|
||||
case kops.CloudProviderGCE:
|
||||
return cluster.IsKubernetesGTE("1.22")
|
||||
case kops.CloudProviderHetzner:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package hetzner
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/hetznercloud/hcloud-go/hcloud/metadata"
|
||||
"k8s.io/kops/pkg/bootstrap"
|
||||
)
|
||||
|
||||
const HetznerAuthenticationTokenPrefix = "x-hetzner-id "
|
||||
|
||||
type hetznerAuthenticator struct {
|
||||
}
|
||||
|
||||
var _ bootstrap.Authenticator = &hetznerAuthenticator{}
|
||||
|
||||
func NewHetznerAuthenticator() (bootstrap.Authenticator, error) {
|
||||
return &hetznerAuthenticator{}, nil
|
||||
}
|
||||
|
||||
func (h hetznerAuthenticator) CreateToken(body []byte) (string, error) {
|
||||
serverID, err := metadata.NewClient().InstanceID()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to retrieve server ID: %w", err)
|
||||
}
|
||||
|
||||
return HetznerAuthenticationTokenPrefix + strconv.Itoa(serverID), nil
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
Copyright 2020 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package hetzner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hetznercloud/hcloud-go/hcloud"
|
||||
"k8s.io/kops/pkg/bootstrap"
|
||||
)
|
||||
|
||||
type HetznerVerifierOptions struct {
|
||||
}
|
||||
|
||||
type hetznerVerifier struct {
|
||||
opt HetznerVerifierOptions
|
||||
client *hcloud.Client
|
||||
}
|
||||
|
||||
var _ bootstrap.Verifier = &hetznerVerifier{}
|
||||
|
||||
func NewHetznerVerifier(opt *HetznerVerifierOptions) (bootstrap.Verifier, error) {
|
||||
hcloudToken := os.Getenv("HCLOUD_TOKEN")
|
||||
if hcloudToken == "" {
|
||||
return nil, fmt.Errorf("%s is required", "HCLOUD_TOKEN")
|
||||
}
|
||||
|
||||
opts := []hcloud.ClientOption{
|
||||
hcloud.WithToken(hcloudToken),
|
||||
}
|
||||
hcloudClient := hcloud.NewClient(opts...)
|
||||
|
||||
return &hetznerVerifier{
|
||||
opt: *opt,
|
||||
client: hcloudClient,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h hetznerVerifier) VerifyToken(ctx context.Context, token string, body []byte, useInstanceIDForNodeName bool) (*bootstrap.VerifyResult, error) {
|
||||
if !strings.HasPrefix(token, HetznerAuthenticationTokenPrefix) {
|
||||
return nil, fmt.Errorf("incorrect authorization type")
|
||||
}
|
||||
token = strings.TrimPrefix(token, HetznerAuthenticationTokenPrefix)
|
||||
|
||||
serverID, err := strconv.Atoi(token)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert server ID %q to int: %w", token, err)
|
||||
}
|
||||
server, _, err := h.client.Server.GetByID(ctx, serverID)
|
||||
if err != nil || server == nil {
|
||||
return nil, fmt.Errorf("failed to get info for server %q: %w", token, err)
|
||||
}
|
||||
|
||||
var addrs []string
|
||||
if server.PublicNet.IPv4.IP != nil {
|
||||
addrs = append(addrs, server.PublicNet.IPv4.IP.String())
|
||||
}
|
||||
for _, network := range server.PrivateNet {
|
||||
if network.IP != nil {
|
||||
addrs = append(addrs, network.IP.String())
|
||||
}
|
||||
}
|
||||
|
||||
result := &bootstrap.VerifyResult{
|
||||
NodeName: server.Name,
|
||||
CertificateNames: addrs,
|
||||
}
|
||||
|
||||
for key, value := range server.Labels {
|
||||
if key == TagKubernetesInstanceGroup {
|
||||
result.InstanceGroupName = value
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
|
@ -64,6 +64,7 @@ import (
|
|||
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/gce"
|
||||
gcetpm "k8s.io/kops/upup/pkg/fi/cloudup/gce/tpm"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/hetzner"
|
||||
"k8s.io/kops/util/pkg/env"
|
||||
)
|
||||
|
||||
|
@ -655,6 +656,10 @@ func (tf *TemplateFunctions) KopsControllerConfig() (string, error) {
|
|||
Region: tf.Region,
|
||||
MaxTimeSkew: 300,
|
||||
}
|
||||
|
||||
case kops.CloudProviderHetzner:
|
||||
config.Server.Provider.Hetzner = &hetzner.HetznerVerifierOptions{}
|
||||
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported cloud provider %s", cluster.Spec.GetCloudProvider())
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ import (
|
|||
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/gce/gcediscovery"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/gce/tpm/gcetpmsigner"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/hetzner"
|
||||
"k8s.io/kops/upup/pkg/fi/nodeup/cloudinit"
|
||||
"k8s.io/kops/upup/pkg/fi/nodeup/local"
|
||||
"k8s.io/kops/upup/pkg/fi/nodeup/nodetasks"
|
||||
|
@ -757,6 +758,12 @@ func getNodeConfigFromServer(ctx context.Context, bootConfig *nodeup.BootConfig,
|
|||
return nil, err
|
||||
}
|
||||
resolver = discovery
|
||||
case api.CloudProviderHetzner:
|
||||
a, err := hetzner.NewHetznerAuthenticator()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authenticator = a
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported cloud provider for node configuration %s", bootConfig.CloudProvider)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue