Merge pull request #16141 from justinsb/pki_bootstrap

Support bootstrapping nodes using Public Key authentication
This commit is contained in:
Kubernetes Prow Robot 2023-12-01 13:41:00 +01:00 committed by GitHub
commit d5818e8971
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 1993 additions and 6 deletions

View File

@ -32,7 +32,9 @@ import (
"k8s.io/kops/cmd/kops-controller/controllers"
"k8s.io/kops/cmd/kops-controller/pkg/config"
"k8s.io/kops/cmd/kops-controller/pkg/server"
"k8s.io/kops/pkg/apis/kops/v1alpha2"
"k8s.io/kops/pkg/bootstrap"
"k8s.io/kops/pkg/bootstrap/pkibootstrap"
"k8s.io/kops/pkg/nodeidentity"
nodeidentityaws "k8s.io/kops/pkg/nodeidentity/aws"
nodeidentityazure "k8s.io/kops/pkg/nodeidentity/azure"
@ -58,7 +60,6 @@ import (
)
var (
scheme = runtime.NewScheme()
setupLog = ctrl.Log.WithName("setup")
)
@ -100,7 +101,8 @@ func main() {
ctrl.SetLogger(klogr.New())
if err := buildScheme(); err != nil {
scheme, err := buildScheme()
if err != nil {
setupLog.Error(err, "error building scheme")
os.Exit(1)
}
@ -108,6 +110,7 @@ func main() {
kubeConfig := ctrl.GetConfigOrDie()
kubeConfig.Burst = 200
kubeConfig.QPS = 100
mgr, err := ctrl.NewManager(kubeConfig, ctrl.Options{
Scheme: scheme,
Metrics: metricsserver.Options{
@ -183,6 +186,15 @@ func main() {
verifiers = append(verifiers, verifier)
}
if opt.Server.PKI != nil {
verifier, err := pkibootstrap.NewVerifier(opt.Server.PKI, mgr.GetClient())
if err != nil {
setupLog.Error(err, "unable to create verifier")
os.Exit(1)
}
verifiers = append(verifiers, verifier)
}
if len(verifiers) == 0 {
klog.Fatalf("server verifiers not provided")
}
@ -233,15 +245,19 @@ func main() {
}
}
func buildScheme() error {
func buildScheme() (*runtime.Scheme, error) {
scheme := runtime.NewScheme()
if err := corev1.AddToScheme(scheme); err != nil {
return fmt.Errorf("error registering corev1: %v", err)
return nil, fmt.Errorf("error registering corev1: %v", err)
}
if err := v1alpha2.AddToScheme(scheme); err != nil {
return nil, fmt.Errorf("error registering kops/v1alpha2 API: %v", err)
}
// Needed so that the leader-election system can post events
if err := coordinationv1.AddToScheme(scheme); err != nil {
return fmt.Errorf("error registering coordinationv1: %v", err)
return nil, fmt.Errorf("error registering coordinationv1: %v", err)
}
return nil
return scheme, nil
}
func addNodeController(mgr manager.Manager, vfsContext *vfs.VFSContext, opt *config.Options) error {

View File

@ -17,6 +17,7 @@ limitations under the License.
package config
import (
"k8s.io/kops/pkg/bootstrap/pkibootstrap"
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
"k8s.io/kops/upup/pkg/fi/cloudup/azure"
"k8s.io/kops/upup/pkg/fi/cloudup/do"
@ -51,6 +52,9 @@ type ServerOptions struct {
// Provider is the cloud provider.
Provider ServerProviderOptions `json:"provider"`
// PKI configures private/public key node authentication.
PKI *pkibootstrap.Options `json:"pki,omitempty"`
// ServerKeyPath is the path to our TLS serving private key.
ServerKeyPath string `json:"serverKeyPath,omitempty"`
// ServerCertificatePath is the path to our TLS serving certificate.

View File

@ -0,0 +1,44 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.13.0
name: hosts.kops.k8s.io
spec:
group: kops.k8s.io
names:
kind: Host
listKind: HostList
plural: hosts
singular: host
scope: Namespaced
versions:
- name: v1alpha2
schema:
openAPIV3Schema:
description: Host represents a bare-metal machine that could be registered
as a Node.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
properties:
instanceGroup:
type: string
publicKey:
type: string
type: object
type: object
served: true
storage: true

View File

@ -24,6 +24,7 @@ import (
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/bootstrap"
"k8s.io/kops/pkg/bootstrap/pkibootstrap"
"k8s.io/kops/pkg/kopscontrollerclient"
"k8s.io/kops/pkg/resolver"
"k8s.io/kops/pkg/wellknownports"
@ -101,6 +102,13 @@ func (b BootstrapClientBuilder) Build(c *fi.NodeupModelBuilderContext) error {
}
authenticator = a
case "metal":
a, err := pkibootstrap.NewAuthenticatorFromFile("/etc/kubernetes/kops/pki/machine/private.pem")
if err != nil {
return err
}
authenticator = a
default:
return fmt.Errorf("unsupported cloud provider for authenticator %q", b.CloudProvider())
}

View File

@ -0,0 +1,46 @@
/*
Copyright 2023 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 v1alpha2
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Host represents a bare-metal machine that could be registered as a Node.
type Host struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec HostSpec `json:"spec,omitempty"`
}
type HostSpec struct {
PublicKey string `json:"publicKey,omitempty"`
InstanceGroup string `json:"instanceGroup,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type HostList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Host `json:"items"`
}

View File

@ -61,6 +61,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
&KeysetList{},
&SSHCredential{},
&SSHCredentialList{},
&Host{},
&HostList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)

View File

@ -2292,6 +2292,82 @@ func (in *HookSpec) DeepCopy() *HookSpec {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Host) DeepCopyInto(out *Host) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Host.
func (in *Host) DeepCopy() *Host {
if in == nil {
return nil
}
out := new(Host)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Host) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HostList) DeepCopyInto(out *HostList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Host, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostList.
func (in *HostList) DeepCopy() *HostList {
if in == nil {
return nil
}
out := new(HostList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *HostList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HostSpec) DeepCopyInto(out *HostSpec) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostSpec.
func (in *HostSpec) DeepCopy() *HostSpec {
if in == nil {
return nil
}
out := new(HostSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HubbleSpec) DeepCopyInto(out *HubbleSpec) {
*out = *in

View File

@ -0,0 +1,46 @@
/*
Copyright 2023 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 v1alpha3
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Host represents a bare-metal machine that could be registered as a Node.
type Host struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec HostSpec `json:"spec,omitempty"`
}
type HostSpec struct {
PublicKey string `json:"publicKey,omitempty"`
InstanceGroup string `json:"instanceGroup,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type HostList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Host `json:"items"`
}

View File

@ -61,6 +61,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
&KeysetList{},
&SSHCredential{},
&SSHCredentialList{},
&Host{},
&HostList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)

View File

@ -2255,6 +2255,82 @@ func (in *HookSpec) DeepCopy() *HookSpec {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Host) DeepCopyInto(out *Host) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Host.
func (in *Host) DeepCopy() *Host {
if in == nil {
return nil
}
out := new(Host)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Host) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HostList) DeepCopyInto(out *HostList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Host, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostList.
func (in *HostList) DeepCopy() *HostList {
if in == nil {
return nil
}
out := new(HostList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *HostList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HostSpec) DeepCopyInto(out *HostSpec) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostSpec.
func (in *HostSpec) DeepCopy() *HostSpec {
if in == nil {
return nil
}
out := new(HostSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HubbleSpec) DeepCopyInto(out *HubbleSpec) {
*out = *in

View File

@ -0,0 +1,26 @@
/*
Copyright 2023 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 pkibootstrap
// Options describes how we authenticate instances with known-public-key authentication.
type Options struct {
// MaxTimeSkew is the maximum time skew to allow (in seconds)
MaxTimeSkew int64 `json:"MaxTimeSkew,omitempty"`
}
// AuthenticationTokenPrefix is the prefix used for authentication using PKI
const AuthenticationTokenPrefix = "x-pki-tpm "

View File

@ -0,0 +1,151 @@
/*
Copyright 2023 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 pkibootstrap
import (
"bytes"
"crypto"
cryptorand "crypto/rand"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"fmt"
"os"
"time"
"k8s.io/klog/v2"
"k8s.io/kops/pkg/bootstrap"
"k8s.io/kops/pkg/pki"
)
type pkiAuthenticator struct {
signer crypto.Signer
keyID string
hostname string
}
// AuthTokenData is the code data that is signed as part of the header.
type AuthTokenData struct {
// Instance is the name/id of the instance we are claiming
Instance string `json:"instance,omitempty"`
// KeyID is the identifier of the public key we are signing with, if we're using a fixed key.
KeyID string `json:"keyID,omitempty"`
// RequestHash is the hash of the request
RequestHash []byte `json:"requestHash,omitempty"`
// Timestamp is the time of this request (to help prevent replay attacks)
Timestamp int64 `json:"timestamp,omitempty"`
// Audience is the audience for this request (to help prevent replay attacks)
Audience string `json:"audience,omitempty"`
}
var _ bootstrap.Authenticator = &pkiAuthenticator{}
func NewAuthenticator(hostname string, signer crypto.Signer) (bootstrap.Authenticator, error) {
keyID, err := computeKeyID(signer)
if err != nil {
return nil, err
}
return &pkiAuthenticator{hostname: hostname, signer: signer, keyID: keyID}, nil
}
func computeKeyID(signer crypto.Signer) (string, error) {
publicKey := signer.Public()
pkData, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
return "", fmt.Errorf("error converting public key to x509: %w", err)
}
var b bytes.Buffer
if err := pem.Encode(&b, &pem.Block{Type: "PUBLIC KEY", Bytes: pkData}); err != nil {
return "", fmt.Errorf("error encoding public key: %w", err)
}
return b.String(), nil
}
func NewAuthenticatorFromFile(p string) (bootstrap.Authenticator, error) {
hostname, err := os.Hostname()
if err != nil {
return nil, fmt.Errorf("couldn't determine hostname: %w", err)
}
keyBytes, err := os.ReadFile(p)
if err != nil {
return nil, fmt.Errorf("error reading %q: %w", p, err)
}
key, err := pki.ParsePEMPrivateKey(keyBytes)
if err != nil {
return nil, fmt.Errorf("error parsing key from %q: %w", p, err)
}
return NewAuthenticator(hostname, key.Key)
}
func (a *pkiAuthenticator) CreateToken(body []byte) (string, error) {
requestHash := sha256.Sum256(body)
data := AuthTokenData{
Timestamp: time.Now().Unix(),
Audience: AudienceNodeAuthentication,
RequestHash: requestHash[:],
KeyID: a.keyID,
Instance: a.hostname,
}
payload, err := json.Marshal(&data)
if err != nil {
return "", fmt.Errorf("failed to marshal token data: %w", err)
}
signature, err := a.sign(payload)
if err != nil {
return "", fmt.Errorf("failed to sign token data: %w", err)
}
token := &AuthToken{
Data: payload,
Signature: signature,
}
b, err := json.Marshal(token)
if err != nil {
return "", fmt.Errorf("failed to marshal token: %w", err)
}
return AuthenticationTokenPrefix + base64.StdEncoding.EncodeToString(b), nil
}
// sign performs a TPM signature with the tpmKey, and sanity checks the result.
func (a *pkiAuthenticator) sign(payload []byte) ([]byte, error) {
beforeSign := time.Now()
digest := sha256.Sum256(payload)
signature, err := a.signer.Sign(cryptorand.Reader, digest[:], crypto.SHA256)
if err != nil {
return nil, fmt.Errorf("failed to sign data: %w", err)
}
klog.Infof("signing took %v", time.Since(beforeSign))
return signature, nil
}

View File

@ -0,0 +1,179 @@
/*
Copyright 2023 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 pkibootstrap
import (
"bytes"
"context"
"crypto"
"crypto/ecdsa"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"math"
"net/http"
"strings"
"time"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
"k8s.io/klog/v2"
kops "k8s.io/kops/pkg/apis/kops/v1alpha2"
"k8s.io/kops/pkg/bootstrap"
"k8s.io/kops/pkg/pki"
"sigs.k8s.io/controller-runtime/pkg/client"
)
type verifier struct {
opt Options
client client.Client
}
// NewVerifier constructs a new verifier.
func NewVerifier(options *Options, client client.Client) (bootstrap.Verifier, error) {
opt := *options
if opt.MaxTimeSkew == 0 {
opt.MaxTimeSkew = 300
}
return &verifier{
opt: opt,
client: client,
}, nil
}
var _ bootstrap.Verifier = &verifier{}
// TODO: Dedup with gce
func (v *verifier) parseTokenData(tokenPrefix string, authToken string, body []byte) (*AuthToken, *AuthTokenData, error) {
if !strings.HasPrefix(authToken, tokenPrefix) {
return nil, nil, fmt.Errorf("incorrect authorization type")
}
authToken = strings.TrimPrefix(authToken, tokenPrefix)
tokenBytes, err := base64.StdEncoding.DecodeString(authToken)
if err != nil {
return nil, nil, fmt.Errorf("decoding authorization token: %w", err)
}
token := &AuthToken{}
if err = json.Unmarshal(tokenBytes, token); err != nil {
return nil, nil, fmt.Errorf("unmarshalling authorization token: %w", err)
}
tokenData := &AuthTokenData{}
if err := json.Unmarshal(token.Data, tokenData); err != nil {
return nil, nil, fmt.Errorf("unmarshalling authorization token data: %w", err)
}
// Guard against replay attacks
if tokenData.Audience != AudienceNodeAuthentication {
return nil, nil, fmt.Errorf("incorrect Audience")
}
timeSkew := math.Abs(time.Since(time.Unix(tokenData.Timestamp, 0)).Seconds())
if timeSkew > float64(v.opt.MaxTimeSkew) {
return nil, nil, fmt.Errorf("incorrect Timestamp %v", tokenData.Timestamp)
}
// Verify the token has signed the body content.
requestHash := sha256.Sum256(body)
if !bytes.Equal(requestHash[:], tokenData.RequestHash) {
return nil, nil, fmt.Errorf("incorrect RequestHash")
}
return token, tokenData, nil
}
// Can generate keys with
// openssl ecparam -name prime256v1 -genkey -noout -out ec-priv-key.pem
// openssl ec -in ec-priv-key.pem -pubout > ec-pub-key.pem
// Note that golang doesn't support secp256k1: https://groups.google.com/g/golang-nuts/c/Mbkug5t3ZYA
func (v *verifier) VerifyToken(ctx context.Context, rawRequest *http.Request, authToken string, body []byte) (*bootstrap.VerifyResult, error) {
// Reminder: we shouldn't trust any data we get from the client until we've checked the signature (and even then...)
// Thankfully the GCE SDK does seem to escape the parameters correctly, for example.
token, tokenData, err := v.parseTokenData(AuthenticationTokenPrefix, authToken, body)
if err != nil {
return nil, err
}
// Verify the token has a valid signature.
result, signingKey, err := v.getSigningKey(ctx, tokenData)
if err != nil {
return nil, err
}
if !verifySignature(signingKey, token.Data, token.Signature) {
return nil, fmt.Errorf("failed to verify claim signature for node")
}
return result, nil
}
func (v *verifier) getSigningKey(ctx context.Context, tokenData *AuthTokenData) (*bootstrap.VerifyResult, crypto.PublicKey, error) {
nodeName := tokenData.Instance
id := types.NamespacedName{
Namespace: "kops-system",
Name: nodeName,
}
var host kops.Host
if err := v.client.Get(ctx, id, &host); err != nil {
if apierrors.IsNotFound(err) {
return nil, nil, fmt.Errorf("host not found for %v", id)
}
return nil, nil, fmt.Errorf("error getting host %v: %w", id, err)
}
// TODO: Check instance-group matches request (does it matter?)
if host.Spec.PublicKey == "" {
return nil, nil, fmt.Errorf("host %v did not have public-key", id)
}
instanceGroup := host.Spec.InstanceGroup
if instanceGroup == "" {
return nil, nil, fmt.Errorf("host %v did not have spec.instanceGroup", id)
}
pubKey, err := pki.ParsePEMPublicKey([]byte(host.Spec.PublicKey))
if err != nil {
return nil, nil, fmt.Errorf("failed to parse public key: %w", err)
}
var sans []string
result := &bootstrap.VerifyResult{
NodeName: nodeName,
InstanceGroupName: instanceGroup,
CertificateNames: sans,
}
return result, pubKey.Key, nil
}
func verifySignature(signingKey crypto.PublicKey, payload []byte, signature []byte) bool {
attestHash := sha256.Sum256(payload)
switch signingKey := signingKey.(type) {
case *ecdsa.PublicKey:
klog.Infof("attestHash %x", attestHash)
klog.Infof("sig %x", signature)
return ecdsa.VerifyASN1(signingKey, attestHash[:], signature)
default:
klog.Warningf("key type %T not supported", signingKey)
return false
}
}

View File

@ -0,0 +1,30 @@
/*
Copyright 2023 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 pkibootstrap
// AuthToken describes the authentication header data when using GCE TPM authentication.
type AuthToken struct {
// Signature is the TPM or PKI signature for data
Signature []byte `json:"signature,omitempty"`
// Data is the data we are signing.
// It is a JSON encoded form of AuthTokenData.
Data []byte `json:"data,omitempty"`
}
// AudienceNodeAuthentication is used in case we have multiple audiences using the TPM in future
const AudienceNodeAuthentication = "kops.k8s.io/node-bootstrap"

View File

@ -0,0 +1,129 @@
/*
Copyright 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
"context"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing"
v1alpha2 "k8s.io/kops/pkg/apis/kops/v1alpha2"
)
// FakeHosts implements HostInterface
type FakeHosts struct {
Fake *FakeKopsV1alpha2
ns string
}
var hostsResource = v1alpha2.SchemeGroupVersion.WithResource("hosts")
var hostsKind = v1alpha2.SchemeGroupVersion.WithKind("Host")
// Get takes name of the host, and returns the corresponding host object, and an error if there is any.
func (c *FakeHosts) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha2.Host, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(hostsResource, c.ns, name), &v1alpha2.Host{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha2.Host), err
}
// List takes label and field selectors, and returns the list of Hosts that match those selectors.
func (c *FakeHosts) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha2.HostList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(hostsResource, hostsKind, c.ns, opts), &v1alpha2.HostList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &v1alpha2.HostList{ListMeta: obj.(*v1alpha2.HostList).ListMeta}
for _, item := range obj.(*v1alpha2.HostList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested hosts.
func (c *FakeHosts) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(hostsResource, c.ns, opts))
}
// Create takes the representation of a host and creates it. Returns the server's representation of the host, and an error, if there is any.
func (c *FakeHosts) Create(ctx context.Context, host *v1alpha2.Host, opts v1.CreateOptions) (result *v1alpha2.Host, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(hostsResource, c.ns, host), &v1alpha2.Host{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha2.Host), err
}
// Update takes the representation of a host and updates it. Returns the server's representation of the host, and an error, if there is any.
func (c *FakeHosts) Update(ctx context.Context, host *v1alpha2.Host, opts v1.UpdateOptions) (result *v1alpha2.Host, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(hostsResource, c.ns, host), &v1alpha2.Host{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha2.Host), err
}
// Delete takes name of the host and deletes it. Returns an error if one occurs.
func (c *FakeHosts) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteActionWithOptions(hostsResource, c.ns, name, opts), &v1alpha2.Host{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakeHosts) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(hostsResource, c.ns, listOpts)
_, err := c.Fake.Invokes(action, &v1alpha2.HostList{})
return err
}
// Patch applies the patch and returns the patched host.
func (c *FakeHosts) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha2.Host, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(hostsResource, c.ns, name, pt, data, subresources...), &v1alpha2.Host{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha2.Host), err
}

View File

@ -32,6 +32,10 @@ func (c *FakeKopsV1alpha2) Clusters(namespace string) v1alpha2.ClusterInterface
return &FakeClusters{c, namespace}
}
func (c *FakeKopsV1alpha2) Hosts(namespace string) v1alpha2.HostInterface {
return &FakeHosts{c, namespace}
}
func (c *FakeKopsV1alpha2) InstanceGroups(namespace string) v1alpha2.InstanceGroupInterface {
return &FakeInstanceGroups{c, namespace}
}

View File

@ -20,6 +20,8 @@ package v1alpha2
type ClusterExpansion interface{}
type HostExpansion interface{}
type InstanceGroupExpansion interface{}
type KeysetExpansion interface{}

View File

@ -0,0 +1,178 @@
/*
Copyright 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1alpha2
import (
"context"
"time"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
v1alpha2 "k8s.io/kops/pkg/apis/kops/v1alpha2"
scheme "k8s.io/kops/pkg/client/clientset_generated/clientset/scheme"
)
// HostsGetter has a method to return a HostInterface.
// A group's client should implement this interface.
type HostsGetter interface {
Hosts(namespace string) HostInterface
}
// HostInterface has methods to work with Host resources.
type HostInterface interface {
Create(ctx context.Context, host *v1alpha2.Host, opts v1.CreateOptions) (*v1alpha2.Host, error)
Update(ctx context.Context, host *v1alpha2.Host, opts v1.UpdateOptions) (*v1alpha2.Host, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha2.Host, error)
List(ctx context.Context, opts v1.ListOptions) (*v1alpha2.HostList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha2.Host, err error)
HostExpansion
}
// hosts implements HostInterface
type hosts struct {
client rest.Interface
ns string
}
// newHosts returns a Hosts
func newHosts(c *KopsV1alpha2Client, namespace string) *hosts {
return &hosts{
client: c.RESTClient(),
ns: namespace,
}
}
// Get takes name of the host, and returns the corresponding host object, and an error if there is any.
func (c *hosts) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha2.Host, err error) {
result = &v1alpha2.Host{}
err = c.client.Get().
Namespace(c.ns).
Resource("hosts").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do(ctx).
Into(result)
return
}
// List takes label and field selectors, and returns the list of Hosts that match those selectors.
func (c *hosts) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha2.HostList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1alpha2.HostList{}
err = c.client.Get().
Namespace(c.ns).
Resource("hosts").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do(ctx).
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested hosts.
func (c *hosts) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.client.Get().
Namespace(c.ns).
Resource("hosts").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch(ctx)
}
// Create takes the representation of a host and creates it. Returns the server's representation of the host, and an error, if there is any.
func (c *hosts) Create(ctx context.Context, host *v1alpha2.Host, opts v1.CreateOptions) (result *v1alpha2.Host, err error) {
result = &v1alpha2.Host{}
err = c.client.Post().
Namespace(c.ns).
Resource("hosts").
VersionedParams(&opts, scheme.ParameterCodec).
Body(host).
Do(ctx).
Into(result)
return
}
// Update takes the representation of a host and updates it. Returns the server's representation of the host, and an error, if there is any.
func (c *hosts) Update(ctx context.Context, host *v1alpha2.Host, opts v1.UpdateOptions) (result *v1alpha2.Host, err error) {
result = &v1alpha2.Host{}
err = c.client.Put().
Namespace(c.ns).
Resource("hosts").
Name(host.Name).
VersionedParams(&opts, scheme.ParameterCodec).
Body(host).
Do(ctx).
Into(result)
return
}
// Delete takes name of the host and deletes it. Returns an error if one occurs.
func (c *hosts) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("hosts").
Name(name).
Body(&opts).
Do(ctx).
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *hosts) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
var timeout time.Duration
if listOpts.TimeoutSeconds != nil {
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Namespace(c.ns).
Resource("hosts").
VersionedParams(&listOpts, scheme.ParameterCodec).
Timeout(timeout).
Body(&opts).
Do(ctx).
Error()
}
// Patch applies the patch and returns the patched host.
func (c *hosts) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha2.Host, err error) {
result = &v1alpha2.Host{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("hosts").
Name(name).
SubResource(subresources...).
VersionedParams(&opts, scheme.ParameterCodec).
Body(data).
Do(ctx).
Into(result)
return
}

View File

@ -29,6 +29,7 @@ import (
type KopsV1alpha2Interface interface {
RESTClient() rest.Interface
ClustersGetter
HostsGetter
InstanceGroupsGetter
KeysetsGetter
SSHCredentialsGetter
@ -43,6 +44,10 @@ func (c *KopsV1alpha2Client) Clusters(namespace string) ClusterInterface {
return newClusters(c, namespace)
}
func (c *KopsV1alpha2Client) Hosts(namespace string) HostInterface {
return newHosts(c, namespace)
}
func (c *KopsV1alpha2Client) InstanceGroups(namespace string) InstanceGroupInterface {
return newInstanceGroups(c, namespace)
}

View File

@ -0,0 +1,129 @@
/*
Copyright 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
"context"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing"
v1alpha3 "k8s.io/kops/pkg/apis/kops/v1alpha3"
)
// FakeHosts implements HostInterface
type FakeHosts struct {
Fake *FakeKopsV1alpha3
ns string
}
var hostsResource = v1alpha3.SchemeGroupVersion.WithResource("hosts")
var hostsKind = v1alpha3.SchemeGroupVersion.WithKind("Host")
// Get takes name of the host, and returns the corresponding host object, and an error if there is any.
func (c *FakeHosts) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha3.Host, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(hostsResource, c.ns, name), &v1alpha3.Host{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha3.Host), err
}
// List takes label and field selectors, and returns the list of Hosts that match those selectors.
func (c *FakeHosts) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha3.HostList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(hostsResource, hostsKind, c.ns, opts), &v1alpha3.HostList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &v1alpha3.HostList{ListMeta: obj.(*v1alpha3.HostList).ListMeta}
for _, item := range obj.(*v1alpha3.HostList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested hosts.
func (c *FakeHosts) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(hostsResource, c.ns, opts))
}
// Create takes the representation of a host and creates it. Returns the server's representation of the host, and an error, if there is any.
func (c *FakeHosts) Create(ctx context.Context, host *v1alpha3.Host, opts v1.CreateOptions) (result *v1alpha3.Host, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(hostsResource, c.ns, host), &v1alpha3.Host{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha3.Host), err
}
// Update takes the representation of a host and updates it. Returns the server's representation of the host, and an error, if there is any.
func (c *FakeHosts) Update(ctx context.Context, host *v1alpha3.Host, opts v1.UpdateOptions) (result *v1alpha3.Host, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(hostsResource, c.ns, host), &v1alpha3.Host{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha3.Host), err
}
// Delete takes name of the host and deletes it. Returns an error if one occurs.
func (c *FakeHosts) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteActionWithOptions(hostsResource, c.ns, name, opts), &v1alpha3.Host{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakeHosts) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(hostsResource, c.ns, listOpts)
_, err := c.Fake.Invokes(action, &v1alpha3.HostList{})
return err
}
// Patch applies the patch and returns the patched host.
func (c *FakeHosts) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha3.Host, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(hostsResource, c.ns, name, pt, data, subresources...), &v1alpha3.Host{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha3.Host), err
}

View File

@ -32,6 +32,10 @@ func (c *FakeKopsV1alpha3) Clusters(namespace string) v1alpha3.ClusterInterface
return &FakeClusters{c, namespace}
}
func (c *FakeKopsV1alpha3) Hosts(namespace string) v1alpha3.HostInterface {
return &FakeHosts{c, namespace}
}
func (c *FakeKopsV1alpha3) InstanceGroups(namespace string) v1alpha3.InstanceGroupInterface {
return &FakeInstanceGroups{c, namespace}
}

View File

@ -20,6 +20,8 @@ package v1alpha3
type ClusterExpansion interface{}
type HostExpansion interface{}
type InstanceGroupExpansion interface{}
type KeysetExpansion interface{}

View File

@ -0,0 +1,178 @@
/*
Copyright 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1alpha3
import (
"context"
"time"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
v1alpha3 "k8s.io/kops/pkg/apis/kops/v1alpha3"
scheme "k8s.io/kops/pkg/client/clientset_generated/clientset/scheme"
)
// HostsGetter has a method to return a HostInterface.
// A group's client should implement this interface.
type HostsGetter interface {
Hosts(namespace string) HostInterface
}
// HostInterface has methods to work with Host resources.
type HostInterface interface {
Create(ctx context.Context, host *v1alpha3.Host, opts v1.CreateOptions) (*v1alpha3.Host, error)
Update(ctx context.Context, host *v1alpha3.Host, opts v1.UpdateOptions) (*v1alpha3.Host, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha3.Host, error)
List(ctx context.Context, opts v1.ListOptions) (*v1alpha3.HostList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha3.Host, err error)
HostExpansion
}
// hosts implements HostInterface
type hosts struct {
client rest.Interface
ns string
}
// newHosts returns a Hosts
func newHosts(c *KopsV1alpha3Client, namespace string) *hosts {
return &hosts{
client: c.RESTClient(),
ns: namespace,
}
}
// Get takes name of the host, and returns the corresponding host object, and an error if there is any.
func (c *hosts) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha3.Host, err error) {
result = &v1alpha3.Host{}
err = c.client.Get().
Namespace(c.ns).
Resource("hosts").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do(ctx).
Into(result)
return
}
// List takes label and field selectors, and returns the list of Hosts that match those selectors.
func (c *hosts) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha3.HostList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1alpha3.HostList{}
err = c.client.Get().
Namespace(c.ns).
Resource("hosts").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do(ctx).
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested hosts.
func (c *hosts) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.client.Get().
Namespace(c.ns).
Resource("hosts").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch(ctx)
}
// Create takes the representation of a host and creates it. Returns the server's representation of the host, and an error, if there is any.
func (c *hosts) Create(ctx context.Context, host *v1alpha3.Host, opts v1.CreateOptions) (result *v1alpha3.Host, err error) {
result = &v1alpha3.Host{}
err = c.client.Post().
Namespace(c.ns).
Resource("hosts").
VersionedParams(&opts, scheme.ParameterCodec).
Body(host).
Do(ctx).
Into(result)
return
}
// Update takes the representation of a host and updates it. Returns the server's representation of the host, and an error, if there is any.
func (c *hosts) Update(ctx context.Context, host *v1alpha3.Host, opts v1.UpdateOptions) (result *v1alpha3.Host, err error) {
result = &v1alpha3.Host{}
err = c.client.Put().
Namespace(c.ns).
Resource("hosts").
Name(host.Name).
VersionedParams(&opts, scheme.ParameterCodec).
Body(host).
Do(ctx).
Into(result)
return
}
// Delete takes name of the host and deletes it. Returns an error if one occurs.
func (c *hosts) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("hosts").
Name(name).
Body(&opts).
Do(ctx).
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *hosts) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
var timeout time.Duration
if listOpts.TimeoutSeconds != nil {
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Namespace(c.ns).
Resource("hosts").
VersionedParams(&listOpts, scheme.ParameterCodec).
Timeout(timeout).
Body(&opts).
Do(ctx).
Error()
}
// Patch applies the patch and returns the patched host.
func (c *hosts) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha3.Host, err error) {
result = &v1alpha3.Host{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("hosts").
Name(name).
SubResource(subresources...).
VersionedParams(&opts, scheme.ParameterCodec).
Body(data).
Do(ctx).
Into(result)
return
}

View File

@ -29,6 +29,7 @@ import (
type KopsV1alpha3Interface interface {
RESTClient() rest.Interface
ClustersGetter
HostsGetter
InstanceGroupsGetter
KeysetsGetter
SSHCredentialsGetter
@ -43,6 +44,10 @@ func (c *KopsV1alpha3Client) Clusters(namespace string) ClusterInterface {
return newClusters(c, namespace)
}
func (c *KopsV1alpha3Client) Hosts(namespace string) HostInterface {
return newHosts(c, namespace)
}
func (c *KopsV1alpha3Client) InstanceGroups(namespace string) InstanceGroupInterface {
return newInstanceGroups(c, namespace)
}

View File

@ -0,0 +1,129 @@
/*
Copyright 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
"context"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing"
v1alpha2 "k8s.io/kops/pkg/apis/kops/v1alpha2"
)
// FakeHosts implements HostInterface
type FakeHosts struct {
Fake *FakeKopsV1alpha2
ns string
}
var hostsResource = v1alpha2.SchemeGroupVersion.WithResource("hosts")
var hostsKind = v1alpha2.SchemeGroupVersion.WithKind("Host")
// Get takes name of the host, and returns the corresponding host object, and an error if there is any.
func (c *FakeHosts) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha2.Host, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(hostsResource, c.ns, name), &v1alpha2.Host{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha2.Host), err
}
// List takes label and field selectors, and returns the list of Hosts that match those selectors.
func (c *FakeHosts) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha2.HostList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(hostsResource, hostsKind, c.ns, opts), &v1alpha2.HostList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &v1alpha2.HostList{ListMeta: obj.(*v1alpha2.HostList).ListMeta}
for _, item := range obj.(*v1alpha2.HostList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested hosts.
func (c *FakeHosts) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(hostsResource, c.ns, opts))
}
// Create takes the representation of a host and creates it. Returns the server's representation of the host, and an error, if there is any.
func (c *FakeHosts) Create(ctx context.Context, host *v1alpha2.Host, opts v1.CreateOptions) (result *v1alpha2.Host, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(hostsResource, c.ns, host), &v1alpha2.Host{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha2.Host), err
}
// Update takes the representation of a host and updates it. Returns the server's representation of the host, and an error, if there is any.
func (c *FakeHosts) Update(ctx context.Context, host *v1alpha2.Host, opts v1.UpdateOptions) (result *v1alpha2.Host, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(hostsResource, c.ns, host), &v1alpha2.Host{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha2.Host), err
}
// Delete takes name of the host and deletes it. Returns an error if one occurs.
func (c *FakeHosts) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteActionWithOptions(hostsResource, c.ns, name, opts), &v1alpha2.Host{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakeHosts) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(hostsResource, c.ns, listOpts)
_, err := c.Fake.Invokes(action, &v1alpha2.HostList{})
return err
}
// Patch applies the patch and returns the patched host.
func (c *FakeHosts) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha2.Host, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(hostsResource, c.ns, name, pt, data, subresources...), &v1alpha2.Host{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha2.Host), err
}

View File

@ -32,6 +32,10 @@ func (c *FakeKopsV1alpha2) Clusters(namespace string) v1alpha2.ClusterInterface
return &FakeClusters{c, namespace}
}
func (c *FakeKopsV1alpha2) Hosts(namespace string) v1alpha2.HostInterface {
return &FakeHosts{c, namespace}
}
func (c *FakeKopsV1alpha2) InstanceGroups(namespace string) v1alpha2.InstanceGroupInterface {
return &FakeInstanceGroups{c, namespace}
}

View File

@ -20,6 +20,8 @@ package v1alpha2
type ClusterExpansion interface{}
type HostExpansion interface{}
type InstanceGroupExpansion interface{}
type KeysetExpansion interface{}

View File

@ -0,0 +1,178 @@
/*
Copyright 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1alpha2
import (
"context"
"time"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
v1alpha2 "k8s.io/kops/pkg/apis/kops/v1alpha2"
scheme "k8s.io/kops/pkg/client/clientset_generated/internalclientset/scheme"
)
// HostsGetter has a method to return a HostInterface.
// A group's client should implement this interface.
type HostsGetter interface {
Hosts(namespace string) HostInterface
}
// HostInterface has methods to work with Host resources.
type HostInterface interface {
Create(ctx context.Context, host *v1alpha2.Host, opts v1.CreateOptions) (*v1alpha2.Host, error)
Update(ctx context.Context, host *v1alpha2.Host, opts v1.UpdateOptions) (*v1alpha2.Host, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha2.Host, error)
List(ctx context.Context, opts v1.ListOptions) (*v1alpha2.HostList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha2.Host, err error)
HostExpansion
}
// hosts implements HostInterface
type hosts struct {
client rest.Interface
ns string
}
// newHosts returns a Hosts
func newHosts(c *KopsV1alpha2Client, namespace string) *hosts {
return &hosts{
client: c.RESTClient(),
ns: namespace,
}
}
// Get takes name of the host, and returns the corresponding host object, and an error if there is any.
func (c *hosts) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha2.Host, err error) {
result = &v1alpha2.Host{}
err = c.client.Get().
Namespace(c.ns).
Resource("hosts").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do(ctx).
Into(result)
return
}
// List takes label and field selectors, and returns the list of Hosts that match those selectors.
func (c *hosts) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha2.HostList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1alpha2.HostList{}
err = c.client.Get().
Namespace(c.ns).
Resource("hosts").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do(ctx).
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested hosts.
func (c *hosts) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.client.Get().
Namespace(c.ns).
Resource("hosts").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch(ctx)
}
// Create takes the representation of a host and creates it. Returns the server's representation of the host, and an error, if there is any.
func (c *hosts) Create(ctx context.Context, host *v1alpha2.Host, opts v1.CreateOptions) (result *v1alpha2.Host, err error) {
result = &v1alpha2.Host{}
err = c.client.Post().
Namespace(c.ns).
Resource("hosts").
VersionedParams(&opts, scheme.ParameterCodec).
Body(host).
Do(ctx).
Into(result)
return
}
// Update takes the representation of a host and updates it. Returns the server's representation of the host, and an error, if there is any.
func (c *hosts) Update(ctx context.Context, host *v1alpha2.Host, opts v1.UpdateOptions) (result *v1alpha2.Host, err error) {
result = &v1alpha2.Host{}
err = c.client.Put().
Namespace(c.ns).
Resource("hosts").
Name(host.Name).
VersionedParams(&opts, scheme.ParameterCodec).
Body(host).
Do(ctx).
Into(result)
return
}
// Delete takes name of the host and deletes it. Returns an error if one occurs.
func (c *hosts) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("hosts").
Name(name).
Body(&opts).
Do(ctx).
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *hosts) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
var timeout time.Duration
if listOpts.TimeoutSeconds != nil {
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Namespace(c.ns).
Resource("hosts").
VersionedParams(&listOpts, scheme.ParameterCodec).
Timeout(timeout).
Body(&opts).
Do(ctx).
Error()
}
// Patch applies the patch and returns the patched host.
func (c *hosts) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha2.Host, err error) {
result = &v1alpha2.Host{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("hosts").
Name(name).
SubResource(subresources...).
VersionedParams(&opts, scheme.ParameterCodec).
Body(data).
Do(ctx).
Into(result)
return
}

View File

@ -29,6 +29,7 @@ import (
type KopsV1alpha2Interface interface {
RESTClient() rest.Interface
ClustersGetter
HostsGetter
InstanceGroupsGetter
KeysetsGetter
SSHCredentialsGetter
@ -43,6 +44,10 @@ func (c *KopsV1alpha2Client) Clusters(namespace string) ClusterInterface {
return newClusters(c, namespace)
}
func (c *KopsV1alpha2Client) Hosts(namespace string) HostInterface {
return newHosts(c, namespace)
}
func (c *KopsV1alpha2Client) InstanceGroups(namespace string) InstanceGroupInterface {
return newInstanceGroups(c, namespace)
}

View File

@ -0,0 +1,129 @@
/*
Copyright 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
"context"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing"
v1alpha3 "k8s.io/kops/pkg/apis/kops/v1alpha3"
)
// FakeHosts implements HostInterface
type FakeHosts struct {
Fake *FakeKopsV1alpha3
ns string
}
var hostsResource = v1alpha3.SchemeGroupVersion.WithResource("hosts")
var hostsKind = v1alpha3.SchemeGroupVersion.WithKind("Host")
// Get takes name of the host, and returns the corresponding host object, and an error if there is any.
func (c *FakeHosts) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha3.Host, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(hostsResource, c.ns, name), &v1alpha3.Host{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha3.Host), err
}
// List takes label and field selectors, and returns the list of Hosts that match those selectors.
func (c *FakeHosts) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha3.HostList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(hostsResource, hostsKind, c.ns, opts), &v1alpha3.HostList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &v1alpha3.HostList{ListMeta: obj.(*v1alpha3.HostList).ListMeta}
for _, item := range obj.(*v1alpha3.HostList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested hosts.
func (c *FakeHosts) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(hostsResource, c.ns, opts))
}
// Create takes the representation of a host and creates it. Returns the server's representation of the host, and an error, if there is any.
func (c *FakeHosts) Create(ctx context.Context, host *v1alpha3.Host, opts v1.CreateOptions) (result *v1alpha3.Host, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(hostsResource, c.ns, host), &v1alpha3.Host{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha3.Host), err
}
// Update takes the representation of a host and updates it. Returns the server's representation of the host, and an error, if there is any.
func (c *FakeHosts) Update(ctx context.Context, host *v1alpha3.Host, opts v1.UpdateOptions) (result *v1alpha3.Host, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(hostsResource, c.ns, host), &v1alpha3.Host{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha3.Host), err
}
// Delete takes name of the host and deletes it. Returns an error if one occurs.
func (c *FakeHosts) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteActionWithOptions(hostsResource, c.ns, name, opts), &v1alpha3.Host{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakeHosts) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(hostsResource, c.ns, listOpts)
_, err := c.Fake.Invokes(action, &v1alpha3.HostList{})
return err
}
// Patch applies the patch and returns the patched host.
func (c *FakeHosts) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha3.Host, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(hostsResource, c.ns, name, pt, data, subresources...), &v1alpha3.Host{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha3.Host), err
}

View File

@ -32,6 +32,10 @@ func (c *FakeKopsV1alpha3) Clusters(namespace string) v1alpha3.ClusterInterface
return &FakeClusters{c, namespace}
}
func (c *FakeKopsV1alpha3) Hosts(namespace string) v1alpha3.HostInterface {
return &FakeHosts{c, namespace}
}
func (c *FakeKopsV1alpha3) InstanceGroups(namespace string) v1alpha3.InstanceGroupInterface {
return &FakeInstanceGroups{c, namespace}
}

View File

@ -20,6 +20,8 @@ package v1alpha3
type ClusterExpansion interface{}
type HostExpansion interface{}
type InstanceGroupExpansion interface{}
type KeysetExpansion interface{}

View File

@ -0,0 +1,178 @@
/*
Copyright 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1alpha3
import (
"context"
"time"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
v1alpha3 "k8s.io/kops/pkg/apis/kops/v1alpha3"
scheme "k8s.io/kops/pkg/client/clientset_generated/internalclientset/scheme"
)
// HostsGetter has a method to return a HostInterface.
// A group's client should implement this interface.
type HostsGetter interface {
Hosts(namespace string) HostInterface
}
// HostInterface has methods to work with Host resources.
type HostInterface interface {
Create(ctx context.Context, host *v1alpha3.Host, opts v1.CreateOptions) (*v1alpha3.Host, error)
Update(ctx context.Context, host *v1alpha3.Host, opts v1.UpdateOptions) (*v1alpha3.Host, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha3.Host, error)
List(ctx context.Context, opts v1.ListOptions) (*v1alpha3.HostList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha3.Host, err error)
HostExpansion
}
// hosts implements HostInterface
type hosts struct {
client rest.Interface
ns string
}
// newHosts returns a Hosts
func newHosts(c *KopsV1alpha3Client, namespace string) *hosts {
return &hosts{
client: c.RESTClient(),
ns: namespace,
}
}
// Get takes name of the host, and returns the corresponding host object, and an error if there is any.
func (c *hosts) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha3.Host, err error) {
result = &v1alpha3.Host{}
err = c.client.Get().
Namespace(c.ns).
Resource("hosts").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do(ctx).
Into(result)
return
}
// List takes label and field selectors, and returns the list of Hosts that match those selectors.
func (c *hosts) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha3.HostList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1alpha3.HostList{}
err = c.client.Get().
Namespace(c.ns).
Resource("hosts").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do(ctx).
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested hosts.
func (c *hosts) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.client.Get().
Namespace(c.ns).
Resource("hosts").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch(ctx)
}
// Create takes the representation of a host and creates it. Returns the server's representation of the host, and an error, if there is any.
func (c *hosts) Create(ctx context.Context, host *v1alpha3.Host, opts v1.CreateOptions) (result *v1alpha3.Host, err error) {
result = &v1alpha3.Host{}
err = c.client.Post().
Namespace(c.ns).
Resource("hosts").
VersionedParams(&opts, scheme.ParameterCodec).
Body(host).
Do(ctx).
Into(result)
return
}
// Update takes the representation of a host and updates it. Returns the server's representation of the host, and an error, if there is any.
func (c *hosts) Update(ctx context.Context, host *v1alpha3.Host, opts v1.UpdateOptions) (result *v1alpha3.Host, err error) {
result = &v1alpha3.Host{}
err = c.client.Put().
Namespace(c.ns).
Resource("hosts").
Name(host.Name).
VersionedParams(&opts, scheme.ParameterCodec).
Body(host).
Do(ctx).
Into(result)
return
}
// Delete takes name of the host and deletes it. Returns an error if one occurs.
func (c *hosts) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("hosts").
Name(name).
Body(&opts).
Do(ctx).
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *hosts) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
var timeout time.Duration
if listOpts.TimeoutSeconds != nil {
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Namespace(c.ns).
Resource("hosts").
VersionedParams(&listOpts, scheme.ParameterCodec).
Timeout(timeout).
Body(&opts).
Do(ctx).
Error()
}
// Patch applies the patch and returns the patched host.
func (c *hosts) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha3.Host, err error) {
result = &v1alpha3.Host{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("hosts").
Name(name).
SubResource(subresources...).
VersionedParams(&opts, scheme.ParameterCodec).
Body(data).
Do(ctx).
Into(result)
return
}

View File

@ -29,6 +29,7 @@ import (
type KopsV1alpha3Interface interface {
RESTClient() rest.Interface
ClustersGetter
HostsGetter
InstanceGroupsGetter
KeysetsGetter
SSHCredentialsGetter
@ -43,6 +44,10 @@ func (c *KopsV1alpha3Client) Clusters(namespace string) ClusterInterface {
return newClusters(c, namespace)
}
func (c *KopsV1alpha3Client) Hosts(namespace string) HostInterface {
return newHosts(c, namespace)
}
func (c *KopsV1alpha3Client) InstanceGroups(namespace string) InstanceGroupInterface {
return newInstanceGroups(c, namespace)
}

View File

@ -45,6 +45,7 @@ import (
"k8s.io/kops/pkg/apis/nodeup"
"k8s.io/kops/pkg/assets"
"k8s.io/kops/pkg/bootstrap"
"k8s.io/kops/pkg/bootstrap/pkibootstrap"
"k8s.io/kops/pkg/configserver"
"k8s.io/kops/pkg/kopscontrollerclient"
"k8s.io/kops/pkg/resolver"
@ -654,6 +655,14 @@ func getNodeConfigFromServers(ctx context.Context, bootConfig *nodeup.BootConfig
return nil, err
}
authenticator = a
case "metal":
a, err := pkibootstrap.NewAuthenticatorFromFile("/etc/kubernetes/kops/pki/machine/private.pem")
if err != nil {
return nil, err
}
authenticator = a
default:
return nil, fmt.Errorf("unsupported cloud provider for node configuration %s", bootConfig.CloudProvider)
}