diff --git a/cmd/kubeadm/app/apis/bootstraptoken/doc.go b/cmd/kubeadm/app/apis/bootstraptoken/doc.go new file mode 100644 index 00000000000..b7be16ba469 --- /dev/null +++ b/cmd/kubeadm/app/apis/bootstraptoken/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2021 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. +*/ + +// +groupName=bootstraptoken.kubeadm.k8s.io + +// Package bootstraptoken contains an API and utilities wrapping the +// "bootstrap.kubernetes.io/token" Secret type to ease its usage in kubeadm. +package bootstraptoken // import "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken" diff --git a/cmd/kubeadm/app/apis/bootstraptoken/v1/types.go b/cmd/kubeadm/app/apis/bootstraptoken/v1/types.go new file mode 100644 index 00000000000..8ebaf77f3ba --- /dev/null +++ b/cmd/kubeadm/app/apis/bootstraptoken/v1/types.go @@ -0,0 +1,58 @@ +/* +Copyright 2021 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 v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// BootstrapToken describes one bootstrap token, stored as a Secret in the cluster +// +k8s:deepcopy-gen=true +type BootstrapToken struct { + // Token is used for establishing bidirectional trust between nodes and control-planes. + // Used for joining nodes in the cluster. + Token *BootstrapTokenString `json:"token" datapolicy:"token"` + // Description sets a human-friendly message why this token exists and what it's used + // for, so other administrators can know its purpose. + // +optional + Description string `json:"description,omitempty"` + // TTL defines the time to live for this token. Defaults to 24h. + // Expires and TTL are mutually exclusive. + // +optional + TTL *metav1.Duration `json:"ttl,omitempty"` + // Expires specifies the timestamp when this token expires. Defaults to being set + // dynamically at runtime based on the TTL. Expires and TTL are mutually exclusive. + // +optional + Expires *metav1.Time `json:"expires,omitempty"` + // Usages describes the ways in which this token can be used. Can by default be used + // for establishing bidirectional trust, but that can be changed here. + // +optional + Usages []string `json:"usages,omitempty"` + // Groups specifies the extra groups that this token will authenticate as when/if + // used for authentication + // +optional + Groups []string `json:"groups,omitempty"` +} + +// BootstrapTokenString is a token of the format abcdef.abcdef0123456789 that is used +// for both validation of the practically of the API server from a joining node's point +// of view and as an authentication method for the node in the bootstrap phase of +// "kubeadm join". This token is and should be short-lived +type BootstrapTokenString struct { + ID string `json:"-"` + Secret string `json:"-" datapolicy:"token"` +} diff --git a/cmd/kubeadm/app/apis/kubeadm/bootstraptokenhelpers.go b/cmd/kubeadm/app/apis/bootstraptoken/v1/utils.go similarity index 71% rename from cmd/kubeadm/app/apis/kubeadm/bootstraptokenhelpers.go rename to cmd/kubeadm/app/apis/bootstraptoken/v1/utils.go index d8319865078..83640d03937 100644 --- a/cmd/kubeadm/app/apis/kubeadm/bootstraptokenhelpers.go +++ b/cmd/kubeadm/app/apis/bootstraptoken/v1/utils.go @@ -1,5 +1,5 @@ /* -Copyright 2018 The Kubernetes Authors. +Copyright 2021 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. @@ -14,9 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kubeadm +package v1 import ( + "fmt" "sort" "strings" "time" @@ -30,9 +31,61 @@ import ( bootstrapsecretutil "k8s.io/cluster-bootstrap/util/secrets" ) -// ToSecret converts the given BootstrapToken object to its Secret representation that +// MarshalJSON implements the json.Marshaler interface. +func (bts BootstrapTokenString) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, bts.String())), nil +} + +// UnmarshalJSON implements the json.Unmarshaller interface. +func (bts *BootstrapTokenString) UnmarshalJSON(b []byte) error { + // If the token is represented as "", just return quickly without an error + if len(b) == 0 { + return nil + } + + // Remove unnecessary " characters coming from the JSON parser + token := strings.Replace(string(b), `"`, ``, -1) + // Convert the string Token to a BootstrapTokenString object + newbts, err := NewBootstrapTokenString(token) + if err != nil { + return err + } + bts.ID = newbts.ID + bts.Secret = newbts.Secret + return nil +} + +// String returns the string representation of the BootstrapTokenString +func (bts BootstrapTokenString) String() string { + if len(bts.ID) > 0 && len(bts.Secret) > 0 { + return bootstraputil.TokenFromIDAndSecret(bts.ID, bts.Secret) + } + return "" +} + +// NewBootstrapTokenString converts the given Bootstrap Token as a string +// to the BootstrapTokenString object used for serialization/deserialization +// and internal usage. It also automatically validates that the given token +// is of the right format +func NewBootstrapTokenString(token string) (*BootstrapTokenString, error) { + substrs := bootstraputil.BootstrapTokenRegexp.FindStringSubmatch(token) + // TODO: Add a constant for the 3 value here, and explain better why it's needed (other than because how the regexp parsin works) + if len(substrs) != 3 { + return nil, errors.Errorf("the bootstrap token %q was not of the form %q", token, bootstrapapi.BootstrapTokenPattern) + } + + return &BootstrapTokenString{ID: substrs[1], Secret: substrs[2]}, nil +} + +// NewBootstrapTokenStringFromIDAndSecret is a wrapper around NewBootstrapTokenString +// that allows the caller to specify the ID and Secret separately +func NewBootstrapTokenStringFromIDAndSecret(id, secret string) (*BootstrapTokenString, error) { + return NewBootstrapTokenString(bootstraputil.TokenFromIDAndSecret(id, secret)) +} + +// BootstrapTokenToSecret converts the given BootstrapToken object to its Secret representation that // may be submitted to the API Server in order to be stored. -func (bt *BootstrapToken) ToSecret() *v1.Secret { +func BootstrapTokenToSecret(bt *BootstrapToken) *v1.Secret { return &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: bootstraputil.BootstrapTokenSecretName(bt.Token.ID), diff --git a/cmd/kubeadm/app/apis/kubeadm/bootstraptokenhelpers_test.go b/cmd/kubeadm/app/apis/bootstraptoken/v1/utils_test.go similarity index 58% rename from cmd/kubeadm/app/apis/kubeadm/bootstraptokenhelpers_test.go rename to cmd/kubeadm/app/apis/bootstraptoken/v1/utils_test.go index 58eac205142..9a12ded26c5 100644 --- a/cmd/kubeadm/app/apis/kubeadm/bootstraptokenhelpers_test.go +++ b/cmd/kubeadm/app/apis/bootstraptoken/v1/utils_test.go @@ -1,5 +1,5 @@ /* -Copyright 2018 The Kubernetes Authors. +Copyright 2021 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. @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kubeadm +package v1 import ( "encoding/json" @@ -22,15 +22,239 @@ import ( "testing" "time" - "k8s.io/api/core/v1" + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +func TestMarshalJSON(t *testing.T) { + var tests = []struct { + bts BootstrapTokenString + expected string + }{ + {BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}, `"abcdef.abcdef0123456789"`}, + {BootstrapTokenString{ID: "foo", Secret: "bar"}, `"foo.bar"`}, + {BootstrapTokenString{ID: "h", Secret: "b"}, `"h.b"`}, + } + for _, rt := range tests { + t.Run(rt.bts.ID, func(t *testing.T) { + b, err := json.Marshal(rt.bts) + if err != nil { + t.Fatalf("json.Marshal returned an unexpected error: %v", err) + } + if string(b) != rt.expected { + t.Errorf( + "failed BootstrapTokenString.MarshalJSON:\n\texpected: %s\n\t actual: %s", + rt.expected, + string(b), + ) + } + }) + } +} + +func TestUnmarshalJSON(t *testing.T) { + var tests = []struct { + input string + bts *BootstrapTokenString + expectedError bool + }{ + {`"f.s"`, &BootstrapTokenString{}, true}, + {`"abcdef."`, &BootstrapTokenString{}, true}, + {`"abcdef:abcdef0123456789"`, &BootstrapTokenString{}, true}, + {`abcdef.abcdef0123456789`, &BootstrapTokenString{}, true}, + {`"abcdef.abcdef0123456789`, &BootstrapTokenString{}, true}, + {`"abcdef.ABCDEF0123456789"`, &BootstrapTokenString{}, true}, + {`"abcdef.abcdef0123456789"`, &BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}, false}, + {`"123456.aabbccddeeffgghh"`, &BootstrapTokenString{ID: "123456", Secret: "aabbccddeeffgghh"}, false}, + } + for _, rt := range tests { + t.Run(rt.input, func(t *testing.T) { + newbts := &BootstrapTokenString{} + err := json.Unmarshal([]byte(rt.input), newbts) + if (err != nil) != rt.expectedError { + t.Errorf("failed BootstrapTokenString.UnmarshalJSON:\n\texpected error: %t\n\t actual error: %v", rt.expectedError, err) + } else if !reflect.DeepEqual(rt.bts, newbts) { + t.Errorf( + "failed BootstrapTokenString.UnmarshalJSON:\n\texpected: %v\n\t actual: %v", + rt.bts, + newbts, + ) + } + }) + } +} + +func TestJSONRoundtrip(t *testing.T) { + var tests = []struct { + input string + bts *BootstrapTokenString + }{ + {`"abcdef.abcdef0123456789"`, nil}, + {"", &BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}}, + } + for _, rt := range tests { + t.Run(rt.input, func(t *testing.T) { + if err := roundtrip(rt.input, rt.bts); err != nil { + t.Errorf("failed BootstrapTokenString JSON roundtrip with error: %v", err) + } + }) + } +} + +func roundtrip(input string, bts *BootstrapTokenString) error { + var b []byte + var err error + newbts := &BootstrapTokenString{} + // If string input was specified, roundtrip like this: string -> (unmarshal) -> object -> (marshal) -> string + if len(input) > 0 { + if err := json.Unmarshal([]byte(input), newbts); err != nil { + return errors.Wrap(err, "expected no unmarshal error, got error") + } + if b, err = json.Marshal(newbts); err != nil { + return errors.Wrap(err, "expected no marshal error, got error") + } + if input != string(b) { + return errors.Errorf( + "expected token: %s\n\t actual: %s", + input, + string(b), + ) + } + } else { // Otherwise, roundtrip like this: object -> (marshal) -> string -> (unmarshal) -> object + if b, err = json.Marshal(bts); err != nil { + return errors.Wrap(err, "expected no marshal error, got error") + } + if err := json.Unmarshal(b, newbts); err != nil { + return errors.Wrap(err, "expected no unmarshal error, got error") + } + if !reflect.DeepEqual(bts, newbts) { + return errors.Errorf( + "expected object: %v\n\t actual: %v", + bts, + newbts, + ) + } + } + return nil +} + +func TestTokenFromIDAndSecret(t *testing.T) { + var tests = []struct { + bts BootstrapTokenString + expected string + }{ + {BootstrapTokenString{ID: "foo", Secret: "bar"}, "foo.bar"}, + {BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}, "abcdef.abcdef0123456789"}, + {BootstrapTokenString{ID: "h", Secret: "b"}, "h.b"}, + } + for _, rt := range tests { + t.Run(rt.bts.ID, func(t *testing.T) { + actual := rt.bts.String() + if actual != rt.expected { + t.Errorf( + "failed BootstrapTokenString.String():\n\texpected: %s\n\t actual: %s", + rt.expected, + actual, + ) + } + }) + } +} + +func TestNewBootstrapTokenString(t *testing.T) { + var tests = []struct { + token string + expectedError bool + bts *BootstrapTokenString + }{ + {token: "", expectedError: true, bts: nil}, + {token: ".", expectedError: true, bts: nil}, + {token: "1234567890123456789012", expectedError: true, bts: nil}, // invalid parcel size + {token: "12345.1234567890123456", expectedError: true, bts: nil}, // invalid parcel size + {token: ".1234567890123456", expectedError: true, bts: nil}, // invalid parcel size + {token: "123456.", expectedError: true, bts: nil}, // invalid parcel size + {token: "123456:1234567890.123456", expectedError: true, bts: nil}, // invalid separation + {token: "abcdef:1234567890123456", expectedError: true, bts: nil}, // invalid separation + {token: "Abcdef.1234567890123456", expectedError: true, bts: nil}, // invalid token id + {token: "123456.AABBCCDDEEFFGGHH", expectedError: true, bts: nil}, // invalid token secret + {token: "123456.AABBCCD-EEFFGGHH", expectedError: true, bts: nil}, // invalid character + {token: "abc*ef.1234567890123456", expectedError: true, bts: nil}, // invalid character + {token: "abcdef.1234567890123456", expectedError: false, bts: &BootstrapTokenString{ID: "abcdef", Secret: "1234567890123456"}}, + {token: "123456.aabbccddeeffgghh", expectedError: false, bts: &BootstrapTokenString{ID: "123456", Secret: "aabbccddeeffgghh"}}, + {token: "abcdef.abcdef0123456789", expectedError: false, bts: &BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}}, + {token: "123456.1234560123456789", expectedError: false, bts: &BootstrapTokenString{ID: "123456", Secret: "1234560123456789"}}, + } + for _, rt := range tests { + t.Run(rt.token, func(t *testing.T) { + actual, err := NewBootstrapTokenString(rt.token) + if (err != nil) != rt.expectedError { + t.Errorf( + "failed NewBootstrapTokenString for the token %q\n\texpected error: %t\n\t actual error: %v", + rt.token, + rt.expectedError, + err, + ) + } else if !reflect.DeepEqual(actual, rt.bts) { + t.Errorf( + "failed NewBootstrapTokenString for the token %q\n\texpected: %v\n\t actual: %v", + rt.token, + rt.bts, + actual, + ) + } + }) + } +} + +func TestNewBootstrapTokenStringFromIDAndSecret(t *testing.T) { + var tests = []struct { + id, secret string + expectedError bool + bts *BootstrapTokenString + }{ + {id: "", secret: "", expectedError: true, bts: nil}, + {id: "1234567890123456789012", secret: "", expectedError: true, bts: nil}, // invalid parcel size + {id: "12345", secret: "1234567890123456", expectedError: true, bts: nil}, // invalid parcel size + {id: "", secret: "1234567890123456", expectedError: true, bts: nil}, // invalid parcel size + {id: "123456", secret: "", expectedError: true, bts: nil}, // invalid parcel size + {id: "Abcdef", secret: "1234567890123456", expectedError: true, bts: nil}, // invalid token id + {id: "123456", secret: "AABBCCDDEEFFGGHH", expectedError: true, bts: nil}, // invalid token secret + {id: "123456", secret: "AABBCCD-EEFFGGHH", expectedError: true, bts: nil}, // invalid character + {id: "abc*ef", secret: "1234567890123456", expectedError: true, bts: nil}, // invalid character + {id: "abcdef", secret: "1234567890123456", expectedError: false, bts: &BootstrapTokenString{ID: "abcdef", Secret: "1234567890123456"}}, + {id: "123456", secret: "aabbccddeeffgghh", expectedError: false, bts: &BootstrapTokenString{ID: "123456", Secret: "aabbccddeeffgghh"}}, + {id: "abcdef", secret: "abcdef0123456789", expectedError: false, bts: &BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}}, + {id: "123456", secret: "1234560123456789", expectedError: false, bts: &BootstrapTokenString{ID: "123456", Secret: "1234560123456789"}}, + } + for _, rt := range tests { + t.Run(rt.id, func(t *testing.T) { + actual, err := NewBootstrapTokenStringFromIDAndSecret(rt.id, rt.secret) + if (err != nil) != rt.expectedError { + t.Errorf( + "failed NewBootstrapTokenStringFromIDAndSecret for the token with id %q and secret %q\n\texpected error: %t\n\t actual error: %v", + rt.id, + rt.secret, + rt.expectedError, + err, + ) + } else if !reflect.DeepEqual(actual, rt.bts) { + t.Errorf( + "failed NewBootstrapTokenStringFromIDAndSecret for the token with id %q and secret %q\n\texpected: %v\n\t actual: %v", + rt.id, + rt.secret, + rt.bts, + actual, + ) + } + }) + } +} + // This timestamp is used as the reference value when computing expiration dates based on TTLs in these unit tests var refTime = time.Date(1970, time.January, 1, 1, 1, 1, 0, time.UTC) -func TestToSecret(t *testing.T) { - +func TestBootstrapTokenToSecret(t *testing.T) { var tests = []struct { bt *BootstrapToken secret *v1.Secret @@ -65,10 +289,10 @@ func TestToSecret(t *testing.T) { } for _, rt := range tests { t.Run(rt.bt.Token.ID, func(t *testing.T) { - actual := rt.bt.ToSecret() + actual := BootstrapTokenToSecret(rt.bt) if !reflect.DeepEqual(actual, rt.secret) { t.Errorf( - "failed BootstrapToken.ToSecret():\n\texpected: %v\n\t actual: %v", + "failed BootstrapTokenToSecret():\n\texpected: %v\n\t actual: %v", rt.secret, actual, ) @@ -95,7 +319,7 @@ func TestBootstrapTokenToSecretRoundtrip(t *testing.T) { } for _, rt := range tests { t.Run(rt.bt.Token.ID, func(t *testing.T) { - actual, err := BootstrapTokenFromSecret(rt.bt.ToSecret()) + actual, err := BootstrapTokenFromSecret(BootstrapTokenToSecret(rt.bt)) if err != nil { t.Errorf("failed BootstrapToken to Secret roundtrip with error: %v", err) } diff --git a/cmd/kubeadm/app/apis/bootstraptoken/v1/zz_generated.deepcopy.go b/cmd/kubeadm/app/apis/bootstraptoken/v1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..60e9998c35d --- /dev/null +++ b/cmd/kubeadm/app/apis/bootstraptoken/v1/zz_generated.deepcopy.go @@ -0,0 +1,65 @@ +// +build !ignore_autogenerated + +/* +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 deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BootstrapToken) DeepCopyInto(out *BootstrapToken) { + *out = *in + if in.Token != nil { + in, out := &in.Token, &out.Token + *out = new(BootstrapTokenString) + **out = **in + } + if in.TTL != nil { + in, out := &in.TTL, &out.TTL + *out = new(metav1.Duration) + **out = **in + } + if in.Expires != nil { + in, out := &in.Expires, &out.Expires + *out = (*in).DeepCopy() + } + if in.Usages != nil { + in, out := &in.Usages, &out.Usages + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Groups != nil { + in, out := &in.Groups, &out.Groups + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootstrapToken. +func (in *BootstrapToken) DeepCopy() *BootstrapToken { + if in == nil { + return nil + } + out := new(BootstrapToken) + in.DeepCopyInto(out) + return out +} diff --git a/cmd/kubeadm/app/apis/kubeadm/bootstraptokenstring.go b/cmd/kubeadm/app/apis/kubeadm/bootstraptokenstring.go deleted file mode 100644 index 2c1175b9d8b..00000000000 --- a/cmd/kubeadm/app/apis/kubeadm/bootstraptokenstring.go +++ /dev/null @@ -1,92 +0,0 @@ -/* -Copyright 2018 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 kubeadm holds the internal kubeadm API types -// Note: This file should be kept in sync with the similar one for the external API -// TODO: The BootstrapTokenString object should move out to either k8s.io/client-go or k8s.io/api in the future -// (probably as part of Bootstrap Tokens going GA). It should not be staged under the kubeadm API as it is now. -package kubeadm - -import ( - "fmt" - "strings" - - "github.com/pkg/errors" - - bootstrapapi "k8s.io/cluster-bootstrap/token/api" - bootstraputil "k8s.io/cluster-bootstrap/token/util" -) - -// BootstrapTokenString is a token of the format abcdef.abcdef0123456789 that is used -// for both validation of the practically of the API server from a joining node's point -// of view and as an authentication method for the node in the bootstrap phase of -// "kubeadm join". This token is and should be short-lived -type BootstrapTokenString struct { - ID string - Secret string -} - -// MarshalJSON implements the json.Marshaler interface. -func (bts BootstrapTokenString) MarshalJSON() ([]byte, error) { - return []byte(fmt.Sprintf(`"%s"`, bts.String())), nil -} - -// UnmarshalJSON implements the json.Unmarshaller interface. -func (bts *BootstrapTokenString) UnmarshalJSON(b []byte) error { - // If the token is represented as "", just return quickly without an error - if len(b) == 0 { - return nil - } - - // Remove unnecessary " characters coming from the JSON parser - token := strings.Replace(string(b), `"`, ``, -1) - // Convert the string Token to a BootstrapTokenString object - newbts, err := NewBootstrapTokenString(token) - if err != nil { - return err - } - bts.ID = newbts.ID - bts.Secret = newbts.Secret - return nil -} - -// String returns the string representation of the BootstrapTokenString -func (bts BootstrapTokenString) String() string { - if len(bts.ID) > 0 && len(bts.Secret) > 0 { - return bootstraputil.TokenFromIDAndSecret(bts.ID, bts.Secret) - } - return "" -} - -// NewBootstrapTokenString converts the given Bootstrap Token as a string -// to the BootstrapTokenString object used for serialization/deserialization -// and internal usage. It also automatically validates that the given token -// is of the right format -func NewBootstrapTokenString(token string) (*BootstrapTokenString, error) { - substrs := bootstraputil.BootstrapTokenRegexp.FindStringSubmatch(token) - // TODO: Add a constant for the 3 value here, and explain better why it's needed (other than because how the regexp parsin works) - if len(substrs) != 3 { - return nil, errors.Errorf("the bootstrap token %q was not of the form %q", token, bootstrapapi.BootstrapTokenPattern) - } - - return &BootstrapTokenString{ID: substrs[1], Secret: substrs[2]}, nil -} - -// NewBootstrapTokenStringFromIDAndSecret is a wrapper around NewBootstrapTokenString -// that allows the caller to specify the ID and Secret separately -func NewBootstrapTokenStringFromIDAndSecret(id, secret string) (*BootstrapTokenString, error) { - return NewBootstrapTokenString(bootstraputil.TokenFromIDAndSecret(id, secret)) -} diff --git a/cmd/kubeadm/app/apis/kubeadm/bootstraptokenstring_test.go b/cmd/kubeadm/app/apis/kubeadm/bootstraptokenstring_test.go deleted file mode 100644 index 040a2090508..00000000000 --- a/cmd/kubeadm/app/apis/kubeadm/bootstraptokenstring_test.go +++ /dev/null @@ -1,249 +0,0 @@ -/* -Copyright 2018 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 kubeadm - -import ( - "encoding/json" - "reflect" - "testing" - - "github.com/pkg/errors" -) - -func TestMarshalJSON(t *testing.T) { - var tests = []struct { - bts BootstrapTokenString - expected string - }{ - {BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}, `"abcdef.abcdef0123456789"`}, - {BootstrapTokenString{ID: "foo", Secret: "bar"}, `"foo.bar"`}, - {BootstrapTokenString{ID: "h", Secret: "b"}, `"h.b"`}, - } - for _, rt := range tests { - t.Run(rt.bts.ID, func(t *testing.T) { - b, err := json.Marshal(rt.bts) - if err != nil { - t.Fatalf("json.Marshal returned an unexpected error: %v", err) - } - if string(b) != rt.expected { - t.Errorf( - "failed BootstrapTokenString.MarshalJSON:\n\texpected: %s\n\t actual: %s", - rt.expected, - string(b), - ) - } - }) - } -} - -func TestUnmarshalJSON(t *testing.T) { - var tests = []struct { - input string - bts *BootstrapTokenString - expectedError bool - }{ - {`"f.s"`, &BootstrapTokenString{}, true}, - {`"abcdef."`, &BootstrapTokenString{}, true}, - {`"abcdef:abcdef0123456789"`, &BootstrapTokenString{}, true}, - {`abcdef.abcdef0123456789`, &BootstrapTokenString{}, true}, - {`"abcdef.abcdef0123456789`, &BootstrapTokenString{}, true}, - {`"abcdef.ABCDEF0123456789"`, &BootstrapTokenString{}, true}, - {`"abcdef.abcdef0123456789"`, &BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}, false}, - {`"123456.aabbccddeeffgghh"`, &BootstrapTokenString{ID: "123456", Secret: "aabbccddeeffgghh"}, false}, - } - for _, rt := range tests { - t.Run(rt.input, func(t *testing.T) { - newbts := &BootstrapTokenString{} - err := json.Unmarshal([]byte(rt.input), newbts) - if (err != nil) != rt.expectedError { - t.Errorf("failed BootstrapTokenString.UnmarshalJSON:\n\texpected error: %t\n\t actual error: %v", rt.expectedError, err) - } else if !reflect.DeepEqual(rt.bts, newbts) { - t.Errorf( - "failed BootstrapTokenString.UnmarshalJSON:\n\texpected: %v\n\t actual: %v", - rt.bts, - newbts, - ) - } - }) - } -} - -func TestJSONRoundtrip(t *testing.T) { - var tests = []struct { - input string - bts *BootstrapTokenString - }{ - {`"abcdef.abcdef0123456789"`, nil}, - {"", &BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}}, - } - for _, rt := range tests { - t.Run(rt.input, func(t *testing.T) { - if err := roundtrip(rt.input, rt.bts); err != nil { - t.Errorf("failed BootstrapTokenString JSON roundtrip with error: %v", err) - } - }) - } -} - -func roundtrip(input string, bts *BootstrapTokenString) error { - var b []byte - var err error - newbts := &BootstrapTokenString{} - // If string input was specified, roundtrip like this: string -> (unmarshal) -> object -> (marshal) -> string - if len(input) > 0 { - if err := json.Unmarshal([]byte(input), newbts); err != nil { - return errors.Wrap(err, "expected no unmarshal error, got error") - } - if b, err = json.Marshal(newbts); err != nil { - return errors.Wrap(err, "expected no marshal error, got error") - } - if input != string(b) { - return errors.Errorf( - "expected token: %s\n\t actual: %s", - input, - string(b), - ) - } - } else { // Otherwise, roundtrip like this: object -> (marshal) -> string -> (unmarshal) -> object - if b, err = json.Marshal(bts); err != nil { - return errors.Wrap(err, "expected no marshal error, got error") - } - if err := json.Unmarshal(b, newbts); err != nil { - return errors.Wrap(err, "expected no unmarshal error, got error") - } - if !reflect.DeepEqual(bts, newbts) { - return errors.Errorf( - "expected object: %v\n\t actual: %v", - bts, - newbts, - ) - } - } - return nil -} - -func TestTokenFromIDAndSecret(t *testing.T) { - var tests = []struct { - bts BootstrapTokenString - expected string - }{ - {BootstrapTokenString{ID: "foo", Secret: "bar"}, "foo.bar"}, - {BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}, "abcdef.abcdef0123456789"}, - {BootstrapTokenString{ID: "h", Secret: "b"}, "h.b"}, - } - for _, rt := range tests { - t.Run(rt.bts.ID, func(t *testing.T) { - actual := rt.bts.String() - if actual != rt.expected { - t.Errorf( - "failed BootstrapTokenString.String():\n\texpected: %s\n\t actual: %s", - rt.expected, - actual, - ) - } - }) - } -} - -func TestNewBootstrapTokenString(t *testing.T) { - var tests = []struct { - token string - expectedError bool - bts *BootstrapTokenString - }{ - {token: "", expectedError: true, bts: nil}, - {token: ".", expectedError: true, bts: nil}, - {token: "1234567890123456789012", expectedError: true, bts: nil}, // invalid parcel size - {token: "12345.1234567890123456", expectedError: true, bts: nil}, // invalid parcel size - {token: ".1234567890123456", expectedError: true, bts: nil}, // invalid parcel size - {token: "123456.", expectedError: true, bts: nil}, // invalid parcel size - {token: "123456:1234567890.123456", expectedError: true, bts: nil}, // invalid separation - {token: "abcdef:1234567890123456", expectedError: true, bts: nil}, // invalid separation - {token: "Abcdef.1234567890123456", expectedError: true, bts: nil}, // invalid token id - {token: "123456.AABBCCDDEEFFGGHH", expectedError: true, bts: nil}, // invalid token secret - {token: "123456.AABBCCD-EEFFGGHH", expectedError: true, bts: nil}, // invalid character - {token: "abc*ef.1234567890123456", expectedError: true, bts: nil}, // invalid character - {token: "abcdef.1234567890123456", expectedError: false, bts: &BootstrapTokenString{ID: "abcdef", Secret: "1234567890123456"}}, - {token: "123456.aabbccddeeffgghh", expectedError: false, bts: &BootstrapTokenString{ID: "123456", Secret: "aabbccddeeffgghh"}}, - {token: "abcdef.abcdef0123456789", expectedError: false, bts: &BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}}, - {token: "123456.1234560123456789", expectedError: false, bts: &BootstrapTokenString{ID: "123456", Secret: "1234560123456789"}}, - } - for _, rt := range tests { - t.Run(rt.token, func(t *testing.T) { - actual, err := NewBootstrapTokenString(rt.token) - if (err != nil) != rt.expectedError { - t.Errorf( - "failed NewBootstrapTokenString for the token %q\n\texpected error: %t\n\t actual error: %v", - rt.token, - rt.expectedError, - err, - ) - } else if !reflect.DeepEqual(actual, rt.bts) { - t.Errorf( - "failed NewBootstrapTokenString for the token %q\n\texpected: %v\n\t actual: %v", - rt.token, - rt.bts, - actual, - ) - } - }) - } -} - -func TestNewBootstrapTokenStringFromIDAndSecret(t *testing.T) { - var tests = []struct { - id, secret string - expectedError bool - bts *BootstrapTokenString - }{ - {id: "", secret: "", expectedError: true, bts: nil}, - {id: "1234567890123456789012", secret: "", expectedError: true, bts: nil}, // invalid parcel size - {id: "12345", secret: "1234567890123456", expectedError: true, bts: nil}, // invalid parcel size - {id: "", secret: "1234567890123456", expectedError: true, bts: nil}, // invalid parcel size - {id: "123456", secret: "", expectedError: true, bts: nil}, // invalid parcel size - {id: "Abcdef", secret: "1234567890123456", expectedError: true, bts: nil}, // invalid token id - {id: "123456", secret: "AABBCCDDEEFFGGHH", expectedError: true, bts: nil}, // invalid token secret - {id: "123456", secret: "AABBCCD-EEFFGGHH", expectedError: true, bts: nil}, // invalid character - {id: "abc*ef", secret: "1234567890123456", expectedError: true, bts: nil}, // invalid character - {id: "abcdef", secret: "1234567890123456", expectedError: false, bts: &BootstrapTokenString{ID: "abcdef", Secret: "1234567890123456"}}, - {id: "123456", secret: "aabbccddeeffgghh", expectedError: false, bts: &BootstrapTokenString{ID: "123456", Secret: "aabbccddeeffgghh"}}, - {id: "abcdef", secret: "abcdef0123456789", expectedError: false, bts: &BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}}, - {id: "123456", secret: "1234560123456789", expectedError: false, bts: &BootstrapTokenString{ID: "123456", Secret: "1234560123456789"}}, - } - for _, rt := range tests { - t.Run(rt.id, func(t *testing.T) { - actual, err := NewBootstrapTokenStringFromIDAndSecret(rt.id, rt.secret) - if (err != nil) != rt.expectedError { - t.Errorf( - "failed NewBootstrapTokenStringFromIDAndSecret for the token with id %q and secret %q\n\texpected error: %t\n\t actual error: %v", - rt.id, - rt.secret, - rt.expectedError, - err, - ) - } else if !reflect.DeepEqual(actual, rt.bts) { - t.Errorf( - "failed NewBootstrapTokenStringFromIDAndSecret for the token with id %q and secret %q\n\texpected: %v\n\t actual: %v", - rt.id, - rt.secret, - rt.bts, - actual, - ) - } - }) - } -} diff --git a/cmd/kubeadm/app/apis/kubeadm/fuzzer/fuzzer.go b/cmd/kubeadm/app/apis/kubeadm/fuzzer/fuzzer.go index a42dc09a62f..1bc6dcc3f09 100644 --- a/cmd/kubeadm/app/apis/kubeadm/fuzzer/fuzzer.go +++ b/cmd/kubeadm/app/apis/kubeadm/fuzzer/fuzzer.go @@ -20,6 +20,7 @@ import ( fuzz "github.com/google/gofuzz" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" + bootstraptokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" "k8s.io/kubernetes/cmd/kubeadm/app/constants" ) @@ -49,7 +50,7 @@ func fuzzInitConfiguration(obj *kubeadm.InitConfiguration, c fuzz.Continue) { obj.ClusterConfiguration = kubeadm.ClusterConfiguration{} // Adds the default bootstrap token to get the round trip working - obj.BootstrapTokens = []kubeadm.BootstrapToken{ + obj.BootstrapTokens = []bootstraptokenv1.BootstrapToken{ { Groups: []string{"foo"}, Usages: []string{"foo"}, diff --git a/cmd/kubeadm/app/apis/kubeadm/types.go b/cmd/kubeadm/app/apis/kubeadm/types.go index e947922d984..5c021633e60 100644 --- a/cmd/kubeadm/app/apis/kubeadm/types.go +++ b/cmd/kubeadm/app/apis/kubeadm/types.go @@ -21,9 +21,9 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/kubernetes/cmd/kubeadm/app/features" - "k8s.io/apimachinery/pkg/runtime/schema" + bootstraptokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" + "k8s.io/kubernetes/cmd/kubeadm/app/features" ) // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object @@ -41,7 +41,7 @@ type InitConfiguration struct { ClusterConfiguration `json:"-"` // BootstrapTokens is respected at `kubeadm init` time and describes a set of Bootstrap Tokens to create. - BootstrapTokens []BootstrapToken + BootstrapTokens []bootstraptokenv1.BootstrapToken // NodeRegistration holds fields that relate to registering the new control-plane node to the cluster NodeRegistration NodeRegistrationOptions @@ -242,30 +242,6 @@ type Networking struct { DNSDomain string } -// BootstrapToken describes one bootstrap token, stored as a Secret in the cluster -// TODO: The BootstrapToken object should move out to either k8s.io/client-go or k8s.io/api in the future -// (probably as part of Bootstrap Tokens going GA). It should not be staged under the kubeadm API as it is now. -type BootstrapToken struct { - // Token is used for establishing bidirectional trust between nodes and control-planes. - // Used for joining nodes in the cluster. - Token *BootstrapTokenString - // Description sets a human-friendly message why this token exists and what it's used - // for, so other administrators can know its purpose. - Description string - // TTL defines the time to live for this token. Defaults to 24h. - // Expires and TTL are mutually exclusive. - TTL *metav1.Duration - // Expires specifies the timestamp when this token expires. Defaults to being set - // dynamically at runtime based on the TTL. Expires and TTL are mutually exclusive. - Expires *metav1.Time - // Usages describes the ways in which this token can be used. Can by default be used - // for establishing bidirectional trust, but that can be changed here. - Usages []string - // Groups specifies the extra groups that this token will authenticate as when/if - // used for authentication - Groups []string -} - // Etcd contains elements describing Etcd configuration. type Etcd struct { diff --git a/cmd/kubeadm/app/apis/kubeadm/v1beta2/zz_generated.conversion.go b/cmd/kubeadm/app/apis/kubeadm/v1beta2/zz_generated.conversion.go index c190a242c12..81bdb396e18 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1beta2/zz_generated.conversion.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1beta2/zz_generated.conversion.go @@ -27,6 +27,7 @@ import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" conversion "k8s.io/apimachinery/pkg/conversion" runtime "k8s.io/apimachinery/pkg/runtime" + bootstraptokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" kubeadm "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" ) @@ -57,16 +58,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*BootstrapToken)(nil), (*kubeadm.BootstrapToken)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta2_BootstrapToken_To_kubeadm_BootstrapToken(a.(*BootstrapToken), b.(*kubeadm.BootstrapToken), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*kubeadm.BootstrapToken)(nil), (*BootstrapToken)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_kubeadm_BootstrapToken_To_v1beta2_BootstrapToken(a.(*kubeadm.BootstrapToken), b.(*BootstrapToken), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*BootstrapTokenDiscovery)(nil), (*kubeadm.BootstrapTokenDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta2_BootstrapTokenDiscovery_To_kubeadm_BootstrapTokenDiscovery(a.(*BootstrapTokenDiscovery), b.(*kubeadm.BootstrapTokenDiscovery), scope) }); err != nil { @@ -77,16 +68,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*BootstrapTokenString)(nil), (*kubeadm.BootstrapTokenString)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta2_BootstrapTokenString_To_kubeadm_BootstrapTokenString(a.(*BootstrapTokenString), b.(*kubeadm.BootstrapTokenString), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*kubeadm.BootstrapTokenString)(nil), (*BootstrapTokenString)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_kubeadm_BootstrapTokenString_To_v1beta2_BootstrapTokenString(a.(*kubeadm.BootstrapTokenString), b.(*BootstrapTokenString), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*kubeadm.ClusterConfiguration)(nil), (*ClusterConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_kubeadm_ClusterConfiguration_To_v1beta2_ClusterConfiguration(a.(*kubeadm.ClusterConfiguration), b.(*ClusterConfiguration), scope) }); err != nil { @@ -290,36 +271,6 @@ func Convert_kubeadm_APIServer_To_v1beta2_APIServer(in *kubeadm.APIServer, out * return autoConvert_kubeadm_APIServer_To_v1beta2_APIServer(in, out, s) } -func autoConvert_v1beta2_BootstrapToken_To_kubeadm_BootstrapToken(in *BootstrapToken, out *kubeadm.BootstrapToken, s conversion.Scope) error { - out.Token = (*kubeadm.BootstrapTokenString)(unsafe.Pointer(in.Token)) - out.Description = in.Description - out.TTL = (*v1.Duration)(unsafe.Pointer(in.TTL)) - out.Expires = (*v1.Time)(unsafe.Pointer(in.Expires)) - out.Usages = *(*[]string)(unsafe.Pointer(&in.Usages)) - out.Groups = *(*[]string)(unsafe.Pointer(&in.Groups)) - return nil -} - -// Convert_v1beta2_BootstrapToken_To_kubeadm_BootstrapToken is an autogenerated conversion function. -func Convert_v1beta2_BootstrapToken_To_kubeadm_BootstrapToken(in *BootstrapToken, out *kubeadm.BootstrapToken, s conversion.Scope) error { - return autoConvert_v1beta2_BootstrapToken_To_kubeadm_BootstrapToken(in, out, s) -} - -func autoConvert_kubeadm_BootstrapToken_To_v1beta2_BootstrapToken(in *kubeadm.BootstrapToken, out *BootstrapToken, s conversion.Scope) error { - out.Token = (*BootstrapTokenString)(unsafe.Pointer(in.Token)) - out.Description = in.Description - out.TTL = (*v1.Duration)(unsafe.Pointer(in.TTL)) - out.Expires = (*v1.Time)(unsafe.Pointer(in.Expires)) - out.Usages = *(*[]string)(unsafe.Pointer(&in.Usages)) - out.Groups = *(*[]string)(unsafe.Pointer(&in.Groups)) - return nil -} - -// Convert_kubeadm_BootstrapToken_To_v1beta2_BootstrapToken is an autogenerated conversion function. -func Convert_kubeadm_BootstrapToken_To_v1beta2_BootstrapToken(in *kubeadm.BootstrapToken, out *BootstrapToken, s conversion.Scope) error { - return autoConvert_kubeadm_BootstrapToken_To_v1beta2_BootstrapToken(in, out, s) -} - func autoConvert_v1beta2_BootstrapTokenDiscovery_To_kubeadm_BootstrapTokenDiscovery(in *BootstrapTokenDiscovery, out *kubeadm.BootstrapTokenDiscovery, s conversion.Scope) error { out.Token = in.Token out.APIServerEndpoint = in.APIServerEndpoint @@ -346,28 +297,6 @@ func Convert_kubeadm_BootstrapTokenDiscovery_To_v1beta2_BootstrapTokenDiscovery( return autoConvert_kubeadm_BootstrapTokenDiscovery_To_v1beta2_BootstrapTokenDiscovery(in, out, s) } -func autoConvert_v1beta2_BootstrapTokenString_To_kubeadm_BootstrapTokenString(in *BootstrapTokenString, out *kubeadm.BootstrapTokenString, s conversion.Scope) error { - out.ID = in.ID - out.Secret = in.Secret - return nil -} - -// Convert_v1beta2_BootstrapTokenString_To_kubeadm_BootstrapTokenString is an autogenerated conversion function. -func Convert_v1beta2_BootstrapTokenString_To_kubeadm_BootstrapTokenString(in *BootstrapTokenString, out *kubeadm.BootstrapTokenString, s conversion.Scope) error { - return autoConvert_v1beta2_BootstrapTokenString_To_kubeadm_BootstrapTokenString(in, out, s) -} - -func autoConvert_kubeadm_BootstrapTokenString_To_v1beta2_BootstrapTokenString(in *kubeadm.BootstrapTokenString, out *BootstrapTokenString, s conversion.Scope) error { - out.ID = in.ID - out.Secret = in.Secret - return nil -} - -// Convert_kubeadm_BootstrapTokenString_To_v1beta2_BootstrapTokenString is an autogenerated conversion function. -func Convert_kubeadm_BootstrapTokenString_To_v1beta2_BootstrapTokenString(in *kubeadm.BootstrapTokenString, out *BootstrapTokenString, s conversion.Scope) error { - return autoConvert_kubeadm_BootstrapTokenString_To_v1beta2_BootstrapTokenString(in, out, s) -} - func autoConvert_v1beta2_ClusterConfiguration_To_kubeadm_ClusterConfiguration(in *ClusterConfiguration, out *kubeadm.ClusterConfiguration, s conversion.Scope) error { if err := Convert_v1beta2_Etcd_To_kubeadm_Etcd(&in.Etcd, &out.Etcd, s); err != nil { return err @@ -625,7 +554,7 @@ func Convert_kubeadm_ImageMeta_To_v1beta2_ImageMeta(in *kubeadm.ImageMeta, out * } func autoConvert_v1beta2_InitConfiguration_To_kubeadm_InitConfiguration(in *InitConfiguration, out *kubeadm.InitConfiguration, s conversion.Scope) error { - out.BootstrapTokens = *(*[]kubeadm.BootstrapToken)(unsafe.Pointer(&in.BootstrapTokens)) + out.BootstrapTokens = *(*[]bootstraptokenv1.BootstrapToken)(unsafe.Pointer(&in.BootstrapTokens)) if err := Convert_v1beta2_NodeRegistrationOptions_To_kubeadm_NodeRegistrationOptions(&in.NodeRegistration, &out.NodeRegistration, s); err != nil { return err } diff --git a/cmd/kubeadm/app/apis/kubeadm/v1beta3/bootstraptokenstring.go b/cmd/kubeadm/app/apis/kubeadm/v1beta3/bootstraptokenstring.go deleted file mode 100644 index 49792fdcd03..00000000000 --- a/cmd/kubeadm/app/apis/kubeadm/v1beta3/bootstraptokenstring.go +++ /dev/null @@ -1,88 +0,0 @@ -/* -Copyright 2021 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 v1beta3 - -import ( - "fmt" - "strings" - - "github.com/pkg/errors" - - bootstrapapi "k8s.io/cluster-bootstrap/token/api" - bootstraputil "k8s.io/cluster-bootstrap/token/util" -) - -// BootstrapTokenString is a token of the format abcdef.abcdef0123456789 that is used -// for both validation of the practically of the API server from a joining node's point -// of view and as an authentication method for the node in the bootstrap phase of -// "kubeadm join". This token is and should be short-lived -type BootstrapTokenString struct { - ID string `json:"-"` - Secret string `json:"-" datapolicy:"token"` -} - -// MarshalJSON implements the json.Marshaler interface. -func (bts BootstrapTokenString) MarshalJSON() ([]byte, error) { - return []byte(fmt.Sprintf(`"%s"`, bts.String())), nil -} - -// UnmarshalJSON implements the json.Unmarshaller interface. -func (bts *BootstrapTokenString) UnmarshalJSON(b []byte) error { - // If the token is represented as "", just return quickly without an error - if len(b) == 0 { - return nil - } - - // Remove unnecessary " characters coming from the JSON parser - token := strings.Replace(string(b), `"`, ``, -1) - // Convert the string Token to a BootstrapTokenString object - newbts, err := NewBootstrapTokenString(token) - if err != nil { - return err - } - bts.ID = newbts.ID - bts.Secret = newbts.Secret - return nil -} - -// String returns the string representation of the BootstrapTokenString -func (bts BootstrapTokenString) String() string { - if len(bts.ID) > 0 && len(bts.Secret) > 0 { - return bootstraputil.TokenFromIDAndSecret(bts.ID, bts.Secret) - } - return "" -} - -// NewBootstrapTokenString converts the given Bootstrap Token as a string -// to the BootstrapTokenString object used for serialization/deserialization -// and internal usage. It also automatically validates that the given token -// is of the right format -func NewBootstrapTokenString(token string) (*BootstrapTokenString, error) { - substrs := bootstraputil.BootstrapTokenRegexp.FindStringSubmatch(token) - // TODO: Add a constant for the 3 value here, and explain better why it's needed (other than because how the regexp parsin works) - if len(substrs) != 3 { - return nil, errors.Errorf("the bootstrap token %q was not of the form %q", token, bootstrapapi.BootstrapTokenPattern) - } - - return &BootstrapTokenString{ID: substrs[1], Secret: substrs[2]}, nil -} - -// NewBootstrapTokenStringFromIDAndSecret is a wrapper around NewBootstrapTokenString -// that allows the caller to specify the ID and Secret separately -func NewBootstrapTokenStringFromIDAndSecret(id, secret string) (*BootstrapTokenString, error) { - return NewBootstrapTokenString(bootstraputil.TokenFromIDAndSecret(id, secret)) -} diff --git a/cmd/kubeadm/app/apis/kubeadm/v1beta3/bootstraptokenstring_test.go b/cmd/kubeadm/app/apis/kubeadm/v1beta3/bootstraptokenstring_test.go deleted file mode 100644 index 9426c1922fd..00000000000 --- a/cmd/kubeadm/app/apis/kubeadm/v1beta3/bootstraptokenstring_test.go +++ /dev/null @@ -1,249 +0,0 @@ -/* -Copyright 2021 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 v1beta3 - -import ( - "encoding/json" - "reflect" - "testing" - - "github.com/pkg/errors" -) - -func TestMarshalJSON(t *testing.T) { - var tests = []struct { - bts BootstrapTokenString - expected string - }{ - {BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}, `"abcdef.abcdef0123456789"`}, - {BootstrapTokenString{ID: "foo", Secret: "bar"}, `"foo.bar"`}, - {BootstrapTokenString{ID: "h", Secret: "b"}, `"h.b"`}, - } - for _, rt := range tests { - t.Run(rt.bts.ID, func(t *testing.T) { - b, err := json.Marshal(rt.bts) - if err != nil { - t.Fatalf("json.Marshal returned an unexpected error: %v", err) - } - if string(b) != rt.expected { - t.Errorf( - "failed BootstrapTokenString.MarshalJSON:\n\texpected: %s\n\t actual: %s", - rt.expected, - string(b), - ) - } - }) - } -} - -func TestUnmarshalJSON(t *testing.T) { - var tests = []struct { - input string - bts *BootstrapTokenString - expectedError bool - }{ - {`"f.s"`, &BootstrapTokenString{}, true}, - {`"abcdef."`, &BootstrapTokenString{}, true}, - {`"abcdef:abcdef0123456789"`, &BootstrapTokenString{}, true}, - {`abcdef.abcdef0123456789`, &BootstrapTokenString{}, true}, - {`"abcdef.abcdef0123456789`, &BootstrapTokenString{}, true}, - {`"abcdef.ABCDEF0123456789"`, &BootstrapTokenString{}, true}, - {`"abcdef.abcdef0123456789"`, &BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}, false}, - {`"123456.aabbccddeeffgghh"`, &BootstrapTokenString{ID: "123456", Secret: "aabbccddeeffgghh"}, false}, - } - for _, rt := range tests { - t.Run(rt.input, func(t *testing.T) { - newbts := &BootstrapTokenString{} - err := json.Unmarshal([]byte(rt.input), newbts) - if (err != nil) != rt.expectedError { - t.Errorf("failed BootstrapTokenString.UnmarshalJSON:\n\texpected error: %t\n\t actual error: %v", rt.expectedError, err) - } else if !reflect.DeepEqual(rt.bts, newbts) { - t.Errorf( - "failed BootstrapTokenString.UnmarshalJSON:\n\texpected: %v\n\t actual: %v", - rt.bts, - newbts, - ) - } - }) - } -} - -func TestJSONRoundtrip(t *testing.T) { - var tests = []struct { - input string - bts *BootstrapTokenString - }{ - {`"abcdef.abcdef0123456789"`, nil}, - {"", &BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}}, - } - for _, rt := range tests { - t.Run(rt.input, func(t *testing.T) { - if err := roundtrip(rt.input, rt.bts); err != nil { - t.Errorf("failed BootstrapTokenString JSON roundtrip with error: %v", err) - } - }) - } -} - -func roundtrip(input string, bts *BootstrapTokenString) error { - var b []byte - var err error - newbts := &BootstrapTokenString{} - // If string input was specified, roundtrip like this: string -> (unmarshal) -> object -> (marshal) -> string - if len(input) > 0 { - if err := json.Unmarshal([]byte(input), newbts); err != nil { - return errors.Wrap(err, "expected no unmarshal error, got error") - } - if b, err = json.Marshal(newbts); err != nil { - return errors.Wrap(err, "expected no marshal error, got error") - } - if input != string(b) { - return errors.Errorf( - "expected token: %s\n\t actual: %s", - input, - string(b), - ) - } - } else { // Otherwise, roundtrip like this: object -> (marshal) -> string -> (unmarshal) -> object - if b, err = json.Marshal(bts); err != nil { - return errors.Wrap(err, "expected no marshal error, got error") - } - if err := json.Unmarshal(b, newbts); err != nil { - return errors.Wrap(err, "expected no unmarshal error, got error") - } - if !reflect.DeepEqual(bts, newbts) { - return errors.Errorf( - "expected object: %v\n\t actual: %v", - bts, - newbts, - ) - } - } - return nil -} - -func TestTokenFromIDAndSecret(t *testing.T) { - var tests = []struct { - bts BootstrapTokenString - expected string - }{ - {BootstrapTokenString{ID: "foo", Secret: "bar"}, "foo.bar"}, - {BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}, "abcdef.abcdef0123456789"}, - {BootstrapTokenString{ID: "h", Secret: "b"}, "h.b"}, - } - for _, rt := range tests { - t.Run(rt.bts.ID, func(t *testing.T) { - actual := rt.bts.String() - if actual != rt.expected { - t.Errorf( - "failed BootstrapTokenString.String():\n\texpected: %s\n\t actual: %s", - rt.expected, - actual, - ) - } - }) - } -} - -func TestNewBootstrapTokenString(t *testing.T) { - var tests = []struct { - token string - expectedError bool - bts *BootstrapTokenString - }{ - {token: "", expectedError: true, bts: nil}, - {token: ".", expectedError: true, bts: nil}, - {token: "1234567890123456789012", expectedError: true, bts: nil}, // invalid parcel size - {token: "12345.1234567890123456", expectedError: true, bts: nil}, // invalid parcel size - {token: ".1234567890123456", expectedError: true, bts: nil}, // invalid parcel size - {token: "123456.", expectedError: true, bts: nil}, // invalid parcel size - {token: "123456:1234567890.123456", expectedError: true, bts: nil}, // invalid separation - {token: "abcdef:1234567890123456", expectedError: true, bts: nil}, // invalid separation - {token: "Abcdef.1234567890123456", expectedError: true, bts: nil}, // invalid token id - {token: "123456.AABBCCDDEEFFGGHH", expectedError: true, bts: nil}, // invalid token secret - {token: "123456.AABBCCD-EEFFGGHH", expectedError: true, bts: nil}, // invalid character - {token: "abc*ef.1234567890123456", expectedError: true, bts: nil}, // invalid character - {token: "abcdef.1234567890123456", expectedError: false, bts: &BootstrapTokenString{ID: "abcdef", Secret: "1234567890123456"}}, - {token: "123456.aabbccddeeffgghh", expectedError: false, bts: &BootstrapTokenString{ID: "123456", Secret: "aabbccddeeffgghh"}}, - {token: "abcdef.abcdef0123456789", expectedError: false, bts: &BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}}, - {token: "123456.1234560123456789", expectedError: false, bts: &BootstrapTokenString{ID: "123456", Secret: "1234560123456789"}}, - } - for _, rt := range tests { - t.Run(rt.token, func(t *testing.T) { - actual, err := NewBootstrapTokenString(rt.token) - if (err != nil) != rt.expectedError { - t.Errorf( - "failed NewBootstrapTokenString for the token %q\n\texpected error: %t\n\t actual error: %v", - rt.token, - rt.expectedError, - err, - ) - } else if !reflect.DeepEqual(actual, rt.bts) { - t.Errorf( - "failed NewBootstrapTokenString for the token %q\n\texpected: %v\n\t actual: %v", - rt.token, - rt.bts, - actual, - ) - } - }) - } -} - -func TestNewBootstrapTokenStringFromIDAndSecret(t *testing.T) { - var tests = []struct { - id, secret string - expectedError bool - bts *BootstrapTokenString - }{ - {id: "", secret: "", expectedError: true, bts: nil}, - {id: "1234567890123456789012", secret: "", expectedError: true, bts: nil}, // invalid parcel size - {id: "12345", secret: "1234567890123456", expectedError: true, bts: nil}, // invalid parcel size - {id: "", secret: "1234567890123456", expectedError: true, bts: nil}, // invalid parcel size - {id: "123456", secret: "", expectedError: true, bts: nil}, // invalid parcel size - {id: "Abcdef", secret: "1234567890123456", expectedError: true, bts: nil}, // invalid token id - {id: "123456", secret: "AABBCCDDEEFFGGHH", expectedError: true, bts: nil}, // invalid token secret - {id: "123456", secret: "AABBCCD-EEFFGGHH", expectedError: true, bts: nil}, // invalid character - {id: "abc*ef", secret: "1234567890123456", expectedError: true, bts: nil}, // invalid character - {id: "abcdef", secret: "1234567890123456", expectedError: false, bts: &BootstrapTokenString{ID: "abcdef", Secret: "1234567890123456"}}, - {id: "123456", secret: "aabbccddeeffgghh", expectedError: false, bts: &BootstrapTokenString{ID: "123456", Secret: "aabbccddeeffgghh"}}, - {id: "abcdef", secret: "abcdef0123456789", expectedError: false, bts: &BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}}, - {id: "123456", secret: "1234560123456789", expectedError: false, bts: &BootstrapTokenString{ID: "123456", Secret: "1234560123456789"}}, - } - for _, rt := range tests { - t.Run(rt.id, func(t *testing.T) { - actual, err := NewBootstrapTokenStringFromIDAndSecret(rt.id, rt.secret) - if (err != nil) != rt.expectedError { - t.Errorf( - "failed NewBootstrapTokenStringFromIDAndSecret for the token with id %q and secret %q\n\texpected error: %t\n\t actual error: %v", - rt.id, - rt.secret, - rt.expectedError, - err, - ) - } else if !reflect.DeepEqual(actual, rt.bts) { - t.Errorf( - "failed NewBootstrapTokenStringFromIDAndSecret for the token with id %q and secret %q\n\texpected: %v\n\t actual: %v", - rt.id, - rt.secret, - rt.bts, - actual, - ) - } - }) - } -} diff --git a/cmd/kubeadm/app/apis/kubeadm/v1beta3/defaults.go b/cmd/kubeadm/app/apis/kubeadm/v1beta3/defaults.go index 1539385ef05..dd7b8b85287 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1beta3/defaults.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1beta3/defaults.go @@ -22,6 +22,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + bootstraptokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" "k8s.io/kubernetes/cmd/kubeadm/app/constants" ) @@ -174,7 +175,7 @@ func SetDefaults_FileDiscovery(obj *FileDiscovery) { func SetDefaults_BootstrapTokens(obj *InitConfiguration) { if obj.BootstrapTokens == nil || len(obj.BootstrapTokens) == 0 { - obj.BootstrapTokens = []BootstrapToken{{}} + obj.BootstrapTokens = []bootstraptokenv1.BootstrapToken{{}} } for i := range obj.BootstrapTokens { @@ -183,7 +184,7 @@ func SetDefaults_BootstrapTokens(obj *InitConfiguration) { } // SetDefaults_BootstrapToken sets the defaults for an individual Bootstrap Token -func SetDefaults_BootstrapToken(bt *BootstrapToken) { +func SetDefaults_BootstrapToken(bt *bootstraptokenv1.BootstrapToken) { if bt.TTL == nil { bt.TTL = &metav1.Duration{ Duration: constants.DefaultTokenDuration, diff --git a/cmd/kubeadm/app/apis/kubeadm/v1beta3/doc.go b/cmd/kubeadm/app/apis/kubeadm/v1beta3/doc.go index 50ec9722fff..4e890d279ee 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1beta3/doc.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1beta3/doc.go @@ -36,6 +36,8 @@ limitations under the License. // "IfNotPresent". "IfNotPresent" is the default, which has been the existing behavior prior to this addition. // - Add "InitConfiguration.Patches.Directory", "JoinConfiguration.Patches.Directory" to allow // the user to configure a directory from which to take patches for components deployed by kubeadm. +// - Move the BootstrapToken* API and related utilities out of the "kubeadm" API group to a new group +// "bootstraptoken". The kubeadm API version v1beta3 no longer contains the BootstrapToken* structures. // // Migration from old kubeadm config versions // diff --git a/cmd/kubeadm/app/apis/kubeadm/v1beta3/types.go b/cmd/kubeadm/app/apis/kubeadm/v1beta3/types.go index d50e3cb148f..c3177617ec5 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1beta3/types.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1beta3/types.go @@ -17,8 +17,9 @@ limitations under the License. package v1beta3 import ( - v1 "k8s.io/api/core/v1" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + bootstraptokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" ) // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object @@ -35,7 +36,7 @@ type InitConfiguration struct { // BootstrapTokens is respected at `kubeadm init` time and describes a set of Bootstrap Tokens to create. // This information IS NOT uploaded to the kubeadm cluster configmap, partly because of its sensitive nature // +optional - BootstrapTokens []BootstrapToken `json:"bootstrapTokens,omitempty"` + BootstrapTokens []bootstraptokenv1.BootstrapToken `json:"bootstrapTokens,omitempty"` // NodeRegistration holds fields that relate to registering the new control-plane node to the cluster // +optional @@ -216,7 +217,7 @@ type NodeRegistrationOptions struct { // Taints specifies the taints the Node API object should be registered with. If this field is unset, i.e. nil, in the `kubeadm init` process // it will be defaulted to []v1.Taint{'node-role.kubernetes.io/master=""'}. If you don't want to taint your control-plane node, set this field to an // empty slice, i.e. `taints: []` in the YAML file. This field is solely used for Node registration. - Taints []v1.Taint `json:"taints"` + Taints []corev1.Taint `json:"taints"` // KubeletExtraArgs passes through extra arguments to the kubelet. The arguments here are passed to the kubelet command line via the environment file // kubeadm writes at runtime for the kubelet to source. This overrides the generic base-level configuration in the kubelet-config-1.X ConfigMap @@ -234,7 +235,7 @@ type NodeRegistrationOptions struct { // The value of this field must be one of "Always", "IfNotPresent" or "Never". // If this field is unset kubeadm will default it to "IfNotPresent", or pull the required images if not present on the host. // +optional - ImagePullPolicy v1.PullPolicy `json:"imagePullPolicy,omitempty"` + ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"` } // Networking contains elements describing cluster's networking configuration @@ -250,33 +251,6 @@ type Networking struct { DNSDomain string `json:"dnsDomain,omitempty"` } -// BootstrapToken describes one bootstrap token, stored as a Secret in the cluster -type BootstrapToken struct { - // Token is used for establishing bidirectional trust between nodes and control-planes. - // Used for joining nodes in the cluster. - Token *BootstrapTokenString `json:"token" datapolicy:"token"` - // Description sets a human-friendly message why this token exists and what it's used - // for, so other administrators can know its purpose. - // +optional - Description string `json:"description,omitempty"` - // TTL defines the time to live for this token. Defaults to 24h. - // Expires and TTL are mutually exclusive. - // +optional - TTL *metav1.Duration `json:"ttl,omitempty"` - // Expires specifies the timestamp when this token expires. Defaults to being set - // dynamically at runtime based on the TTL. Expires and TTL are mutually exclusive. - // +optional - Expires *metav1.Time `json:"expires,omitempty"` - // Usages describes the ways in which this token can be used. Can by default be used - // for establishing bidirectional trust, but that can be changed here. - // +optional - Usages []string `json:"usages,omitempty"` - // Groups specifies the extra groups that this token will authenticate as when/if - // used for authentication - // +optional - Groups []string `json:"groups,omitempty"` -} - // Etcd contains elements describing Etcd configuration. type Etcd struct { @@ -453,7 +427,7 @@ type HostPathMount struct { ReadOnly bool `json:"readOnly,omitempty"` // PathType is the type of the HostPath. // +optional - PathType v1.HostPathType `json:"pathType,omitempty"` + PathType corev1.HostPathType `json:"pathType,omitempty"` } // Patches contains options related to applying patches to components deployed by kubeadm. diff --git a/cmd/kubeadm/app/apis/kubeadm/v1beta3/zz_generated.conversion.go b/cmd/kubeadm/app/apis/kubeadm/v1beta3/zz_generated.conversion.go index 46ade900e6c..69d939c57a4 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1beta3/zz_generated.conversion.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1beta3/zz_generated.conversion.go @@ -27,6 +27,7 @@ import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" conversion "k8s.io/apimachinery/pkg/conversion" runtime "k8s.io/apimachinery/pkg/runtime" + bootstraptokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" kubeadm "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" ) @@ -57,16 +58,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*BootstrapToken)(nil), (*kubeadm.BootstrapToken)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta3_BootstrapToken_To_kubeadm_BootstrapToken(a.(*BootstrapToken), b.(*kubeadm.BootstrapToken), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*kubeadm.BootstrapToken)(nil), (*BootstrapToken)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_kubeadm_BootstrapToken_To_v1beta3_BootstrapToken(a.(*kubeadm.BootstrapToken), b.(*BootstrapToken), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*BootstrapTokenDiscovery)(nil), (*kubeadm.BootstrapTokenDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta3_BootstrapTokenDiscovery_To_kubeadm_BootstrapTokenDiscovery(a.(*BootstrapTokenDiscovery), b.(*kubeadm.BootstrapTokenDiscovery), scope) }); err != nil { @@ -77,16 +68,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*BootstrapTokenString)(nil), (*kubeadm.BootstrapTokenString)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta3_BootstrapTokenString_To_kubeadm_BootstrapTokenString(a.(*BootstrapTokenString), b.(*kubeadm.BootstrapTokenString), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*kubeadm.BootstrapTokenString)(nil), (*BootstrapTokenString)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_kubeadm_BootstrapTokenString_To_v1beta3_BootstrapTokenString(a.(*kubeadm.BootstrapTokenString), b.(*BootstrapTokenString), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*kubeadm.ClusterConfiguration)(nil), (*ClusterConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_kubeadm_ClusterConfiguration_To_v1beta3_ClusterConfiguration(a.(*kubeadm.ClusterConfiguration), b.(*ClusterConfiguration), scope) }); err != nil { @@ -300,36 +281,6 @@ func Convert_kubeadm_APIServer_To_v1beta3_APIServer(in *kubeadm.APIServer, out * return autoConvert_kubeadm_APIServer_To_v1beta3_APIServer(in, out, s) } -func autoConvert_v1beta3_BootstrapToken_To_kubeadm_BootstrapToken(in *BootstrapToken, out *kubeadm.BootstrapToken, s conversion.Scope) error { - out.Token = (*kubeadm.BootstrapTokenString)(unsafe.Pointer(in.Token)) - out.Description = in.Description - out.TTL = (*v1.Duration)(unsafe.Pointer(in.TTL)) - out.Expires = (*v1.Time)(unsafe.Pointer(in.Expires)) - out.Usages = *(*[]string)(unsafe.Pointer(&in.Usages)) - out.Groups = *(*[]string)(unsafe.Pointer(&in.Groups)) - return nil -} - -// Convert_v1beta3_BootstrapToken_To_kubeadm_BootstrapToken is an autogenerated conversion function. -func Convert_v1beta3_BootstrapToken_To_kubeadm_BootstrapToken(in *BootstrapToken, out *kubeadm.BootstrapToken, s conversion.Scope) error { - return autoConvert_v1beta3_BootstrapToken_To_kubeadm_BootstrapToken(in, out, s) -} - -func autoConvert_kubeadm_BootstrapToken_To_v1beta3_BootstrapToken(in *kubeadm.BootstrapToken, out *BootstrapToken, s conversion.Scope) error { - out.Token = (*BootstrapTokenString)(unsafe.Pointer(in.Token)) - out.Description = in.Description - out.TTL = (*v1.Duration)(unsafe.Pointer(in.TTL)) - out.Expires = (*v1.Time)(unsafe.Pointer(in.Expires)) - out.Usages = *(*[]string)(unsafe.Pointer(&in.Usages)) - out.Groups = *(*[]string)(unsafe.Pointer(&in.Groups)) - return nil -} - -// Convert_kubeadm_BootstrapToken_To_v1beta3_BootstrapToken is an autogenerated conversion function. -func Convert_kubeadm_BootstrapToken_To_v1beta3_BootstrapToken(in *kubeadm.BootstrapToken, out *BootstrapToken, s conversion.Scope) error { - return autoConvert_kubeadm_BootstrapToken_To_v1beta3_BootstrapToken(in, out, s) -} - func autoConvert_v1beta3_BootstrapTokenDiscovery_To_kubeadm_BootstrapTokenDiscovery(in *BootstrapTokenDiscovery, out *kubeadm.BootstrapTokenDiscovery, s conversion.Scope) error { out.Token = in.Token out.APIServerEndpoint = in.APIServerEndpoint @@ -356,28 +307,6 @@ func Convert_kubeadm_BootstrapTokenDiscovery_To_v1beta3_BootstrapTokenDiscovery( return autoConvert_kubeadm_BootstrapTokenDiscovery_To_v1beta3_BootstrapTokenDiscovery(in, out, s) } -func autoConvert_v1beta3_BootstrapTokenString_To_kubeadm_BootstrapTokenString(in *BootstrapTokenString, out *kubeadm.BootstrapTokenString, s conversion.Scope) error { - out.ID = in.ID - out.Secret = in.Secret - return nil -} - -// Convert_v1beta3_BootstrapTokenString_To_kubeadm_BootstrapTokenString is an autogenerated conversion function. -func Convert_v1beta3_BootstrapTokenString_To_kubeadm_BootstrapTokenString(in *BootstrapTokenString, out *kubeadm.BootstrapTokenString, s conversion.Scope) error { - return autoConvert_v1beta3_BootstrapTokenString_To_kubeadm_BootstrapTokenString(in, out, s) -} - -func autoConvert_kubeadm_BootstrapTokenString_To_v1beta3_BootstrapTokenString(in *kubeadm.BootstrapTokenString, out *BootstrapTokenString, s conversion.Scope) error { - out.ID = in.ID - out.Secret = in.Secret - return nil -} - -// Convert_kubeadm_BootstrapTokenString_To_v1beta3_BootstrapTokenString is an autogenerated conversion function. -func Convert_kubeadm_BootstrapTokenString_To_v1beta3_BootstrapTokenString(in *kubeadm.BootstrapTokenString, out *BootstrapTokenString, s conversion.Scope) error { - return autoConvert_kubeadm_BootstrapTokenString_To_v1beta3_BootstrapTokenString(in, out, s) -} - func autoConvert_v1beta3_ClusterConfiguration_To_kubeadm_ClusterConfiguration(in *ClusterConfiguration, out *kubeadm.ClusterConfiguration, s conversion.Scope) error { if err := Convert_v1beta3_Etcd_To_kubeadm_Etcd(&in.Etcd, &out.Etcd, s); err != nil { return err @@ -628,7 +557,7 @@ func Convert_kubeadm_ImageMeta_To_v1beta3_ImageMeta(in *kubeadm.ImageMeta, out * } func autoConvert_v1beta3_InitConfiguration_To_kubeadm_InitConfiguration(in *InitConfiguration, out *kubeadm.InitConfiguration, s conversion.Scope) error { - out.BootstrapTokens = *(*[]kubeadm.BootstrapToken)(unsafe.Pointer(&in.BootstrapTokens)) + out.BootstrapTokens = *(*[]bootstraptokenv1.BootstrapToken)(unsafe.Pointer(&in.BootstrapTokens)) if err := Convert_v1beta3_NodeRegistrationOptions_To_kubeadm_NodeRegistrationOptions(&in.NodeRegistration, &out.NodeRegistration, s); err != nil { return err } @@ -643,7 +572,7 @@ func autoConvert_v1beta3_InitConfiguration_To_kubeadm_InitConfiguration(in *Init func autoConvert_kubeadm_InitConfiguration_To_v1beta3_InitConfiguration(in *kubeadm.InitConfiguration, out *InitConfiguration, s conversion.Scope) error { // WARNING: in.ClusterConfiguration requires manual conversion: does not exist in peer-type - out.BootstrapTokens = *(*[]BootstrapToken)(unsafe.Pointer(&in.BootstrapTokens)) + out.BootstrapTokens = *(*[]bootstraptokenv1.BootstrapToken)(unsafe.Pointer(&in.BootstrapTokens)) if err := Convert_kubeadm_NodeRegistrationOptions_To_v1beta3_NodeRegistrationOptions(&in.NodeRegistration, &out.NodeRegistration, s); err != nil { return err } diff --git a/cmd/kubeadm/app/apis/kubeadm/v1beta3/zz_generated.deepcopy.go b/cmd/kubeadm/app/apis/kubeadm/v1beta3/zz_generated.deepcopy.go index 2020eff146c..c06ae0bb404 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1beta3/zz_generated.deepcopy.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1beta3/zz_generated.deepcopy.go @@ -24,6 +24,7 @@ import ( corev1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" + bootstraptokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. @@ -69,46 +70,6 @@ func (in *APIServer) DeepCopy() *APIServer { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *BootstrapToken) DeepCopyInto(out *BootstrapToken) { - *out = *in - if in.Token != nil { - in, out := &in.Token, &out.Token - *out = new(BootstrapTokenString) - **out = **in - } - if in.TTL != nil { - in, out := &in.TTL, &out.TTL - *out = new(v1.Duration) - **out = **in - } - if in.Expires != nil { - in, out := &in.Expires, &out.Expires - *out = (*in).DeepCopy() - } - if in.Usages != nil { - in, out := &in.Usages, &out.Usages - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Groups != nil { - in, out := &in.Groups, &out.Groups - *out = make([]string, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootstrapToken. -func (in *BootstrapToken) DeepCopy() *BootstrapToken { - if in == nil { - return nil - } - out := new(BootstrapToken) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BootstrapTokenDiscovery) DeepCopyInto(out *BootstrapTokenDiscovery) { *out = *in @@ -130,22 +91,6 @@ func (in *BootstrapTokenDiscovery) DeepCopy() *BootstrapTokenDiscovery { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *BootstrapTokenString) DeepCopyInto(out *BootstrapTokenString) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootstrapTokenString. -func (in *BootstrapTokenString) DeepCopy() *BootstrapTokenString { - if in == nil { - return nil - } - out := new(BootstrapTokenString) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterConfiguration) DeepCopyInto(out *ClusterConfiguration) { *out = *in @@ -361,7 +306,7 @@ func (in *InitConfiguration) DeepCopyInto(out *InitConfiguration) { out.TypeMeta = in.TypeMeta if in.BootstrapTokens != nil { in, out := &in.BootstrapTokens, &out.BootstrapTokens - *out = make([]BootstrapToken, len(*in)) + *out = make([]bootstraptokenv1.BootstrapToken, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/validation.go b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go index 3ae4462155e..9f0b113ec68 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/validation.go +++ b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go @@ -33,6 +33,7 @@ import ( bootstrapapi "k8s.io/cluster-bootstrap/token/api" bootstraputil "k8s.io/cluster-bootstrap/token/util" "k8s.io/klog/v2" + bootstraptokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3" kubeadmcmdoptions "k8s.io/kubernetes/cmd/kubeadm/app/cmd/options" @@ -203,7 +204,7 @@ func ValidateDiscoveryKubeConfigPath(discoveryFile string, fldPath *field.Path) } // ValidateBootstrapTokens validates a slice of BootstrapToken objects -func ValidateBootstrapTokens(bts []kubeadm.BootstrapToken, fldPath *field.Path) field.ErrorList { +func ValidateBootstrapTokens(bts []bootstraptokenv1.BootstrapToken, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} for i, bt := range bts { btPath := fldPath.Child(fmt.Sprintf("%d", i)) diff --git a/cmd/kubeadm/app/apis/kubeadm/zz_generated.deepcopy.go b/cmd/kubeadm/app/apis/kubeadm/zz_generated.deepcopy.go index 6426ee9b3f1..9f14e11e2ec 100644 --- a/cmd/kubeadm/app/apis/kubeadm/zz_generated.deepcopy.go +++ b/cmd/kubeadm/app/apis/kubeadm/zz_generated.deepcopy.go @@ -24,6 +24,7 @@ import ( corev1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" + bootstraptokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. @@ -69,46 +70,6 @@ func (in *APIServer) DeepCopy() *APIServer { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *BootstrapToken) DeepCopyInto(out *BootstrapToken) { - *out = *in - if in.Token != nil { - in, out := &in.Token, &out.Token - *out = new(BootstrapTokenString) - **out = **in - } - if in.TTL != nil { - in, out := &in.TTL, &out.TTL - *out = new(v1.Duration) - **out = **in - } - if in.Expires != nil { - in, out := &in.Expires, &out.Expires - *out = (*in).DeepCopy() - } - if in.Usages != nil { - in, out := &in.Usages, &out.Usages - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Groups != nil { - in, out := &in.Groups, &out.Groups - *out = make([]string, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootstrapToken. -func (in *BootstrapToken) DeepCopy() *BootstrapToken { - if in == nil { - return nil - } - out := new(BootstrapToken) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BootstrapTokenDiscovery) DeepCopyInto(out *BootstrapTokenDiscovery) { *out = *in @@ -130,22 +91,6 @@ func (in *BootstrapTokenDiscovery) DeepCopy() *BootstrapTokenDiscovery { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *BootstrapTokenString) DeepCopyInto(out *BootstrapTokenString) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BootstrapTokenString. -func (in *BootstrapTokenString) DeepCopy() *BootstrapTokenString { - if in == nil { - return nil - } - out := new(BootstrapTokenString) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterConfiguration) DeepCopyInto(out *ClusterConfiguration) { *out = *in @@ -391,7 +336,7 @@ func (in *InitConfiguration) DeepCopyInto(out *InitConfiguration) { in.ClusterConfiguration.DeepCopyInto(&out.ClusterConfiguration) if in.BootstrapTokens != nil { in, out := &in.BootstrapTokens, &out.BootstrapTokens - *out = make([]BootstrapToken, len(*in)) + *out = make([]bootstraptokenv1.BootstrapToken, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } diff --git a/cmd/kubeadm/app/cmd/options/token.go b/cmd/kubeadm/app/cmd/options/token.go index fbe0e82d0c5..3453a8ab981 100644 --- a/cmd/kubeadm/app/cmd/options/token.go +++ b/cmd/kubeadm/app/cmd/options/token.go @@ -23,13 +23,14 @@ import ( "github.com/spf13/pflag" bootstrapapi "k8s.io/cluster-bootstrap/token/api" + bootstraptokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" ) // NewBootstrapTokenOptions creates a new BootstrapTokenOptions object with the default values func NewBootstrapTokenOptions() *BootstrapTokenOptions { - bto := &BootstrapTokenOptions{&kubeadmapiv1.BootstrapToken{}, ""} + bto := &BootstrapTokenOptions{&bootstraptokenv1.BootstrapToken{}, ""} kubeadmapiv1.SetDefaults_BootstrapToken(bto.BootstrapToken) return bto } @@ -38,7 +39,7 @@ func NewBootstrapTokenOptions() *BootstrapTokenOptions { // and applying the parsed flags to a InitConfiguration object later at runtime // TODO: In the future, we might want to group the flags in a better way than adding them all individually like this type BootstrapTokenOptions struct { - *kubeadmapiv1.BootstrapToken + *bootstraptokenv1.BootstrapToken TokenStr string `datapolicy:"token"` } @@ -92,13 +93,13 @@ func (bto *BootstrapTokenOptions) AddDescriptionFlag(fs *pflag.FlagSet) { func (bto *BootstrapTokenOptions) ApplyTo(cfg *kubeadmapiv1.InitConfiguration) error { if len(bto.TokenStr) > 0 { var err error - bto.Token, err = kubeadmapiv1.NewBootstrapTokenString(bto.TokenStr) + bto.Token, err = bootstraptokenv1.NewBootstrapTokenString(bto.TokenStr) if err != nil { return err } } // Set the token specified by the flags as the first and only token to create in case --config is not specified - cfg.BootstrapTokens = []kubeadmapiv1.BootstrapToken{*bto.BootstrapToken} + cfg.BootstrapTokens = []bootstraptokenv1.BootstrapToken{*bto.BootstrapToken} return nil } diff --git a/cmd/kubeadm/app/cmd/token.go b/cmd/kubeadm/app/cmd/token.go index 5f19d00f007..e45386d4b5b 100644 --- a/cmd/kubeadm/app/cmd/token.go +++ b/cmd/kubeadm/app/cmd/token.go @@ -38,7 +38,7 @@ import ( bootstrapapi "k8s.io/cluster-bootstrap/token/api" bootstraputil "k8s.io/cluster-bootstrap/token/util" "k8s.io/klog/v2" - kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" + bootstraptokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme" kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2" kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3" @@ -383,7 +383,7 @@ func RunListTokens(out io.Writer, errW io.Writer, client clientset.Interface, pr for _, secret := range secrets.Items { // Get the BootstrapToken struct representation from the Secret object - token, err := kubeadmapi.BootstrapTokenFromSecret(&secret) + token, err := bootstraptokenv1.BootstrapTokenFromSecret(&secret) if err != nil { fmt.Fprintf(errW, "%v", err) continue @@ -416,7 +416,7 @@ func RunDeleteTokens(out io.Writer, client clientset.Interface, tokenIDsOrTokens klog.V(1).Info("[token] parsing token") if !bootstraputil.IsValidBootstrapTokenID(tokenIDOrToken) { // Okay, the full token with both id and secret was probably passed. Parse it and extract the ID only - bts, err := kubeadmapiv1.NewBootstrapTokenString(tokenIDOrToken) + bts, err := bootstraptokenv1.NewBootstrapTokenString(tokenIDOrToken) if err != nil { return errors.Errorf("given token didn't match pattern %q or %q", bootstrapapi.BootstrapTokenIDPattern, bootstrapapi.BootstrapTokenIDPattern) diff --git a/cmd/kubeadm/app/cmd/token_test.go b/cmd/kubeadm/app/cmd/token_test.go index 1e4e98d44fc..0dab9ad0ee0 100644 --- a/cmd/kubeadm/app/cmd/token_test.go +++ b/cmd/kubeadm/app/cmd/token_test.go @@ -31,6 +31,7 @@ import ( "k8s.io/client-go/kubernetes/fake" core "k8s.io/client-go/testing" "k8s.io/client-go/tools/clientcmd" + bootstraptokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2" kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3" outputapischeme "k8s.io/kubernetes/cmd/kubeadm/app/apis/output/scheme" @@ -157,13 +158,13 @@ func TestRunCreateToken(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - bts, err := kubeadmapiv1.NewBootstrapTokenString(tc.token) + bts, err := bootstraptokenv1.NewBootstrapTokenString(tc.token) if err != nil && len(tc.token) != 0 { // if tc.token is "" it's okay as it will be generated later at runtime t.Fatalf("token couldn't be parsed for testing: %v", err) } cfg := &kubeadmapiv1.InitConfiguration{ - BootstrapTokens: []kubeadmapiv1.BootstrapToken{ + BootstrapTokens: []bootstraptokenv1.BootstrapToken{ { Token: bts, TTL: &metav1.Duration{Duration: 0}, diff --git a/cmd/kubeadm/app/discovery/token/token.go b/cmd/kubeadm/app/discovery/token/token.go index a9c736a6f87..0032ccd5674 100644 --- a/cmd/kubeadm/app/discovery/token/token.go +++ b/cmd/kubeadm/app/discovery/token/token.go @@ -34,6 +34,7 @@ import ( bootstrapapi "k8s.io/cluster-bootstrap/token/api" bootstrap "k8s.io/cluster-bootstrap/token/jws" "k8s.io/klog/v2" + bootstraptokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3" "k8s.io/kubernetes/cmd/kubeadm/app/constants" @@ -54,7 +55,7 @@ func RetrieveValidatedConfigInfo(cfg *kubeadmapi.Discovery) (*clientcmdapi.Confi // retrieveValidatedConfigInfo is a private implementation of RetrieveValidatedConfigInfo. // It accepts an optional clientset that can be used for testing purposes. func retrieveValidatedConfigInfo(client clientset.Interface, cfg *kubeadmapi.Discovery, interval time.Duration) (*clientcmdapi.Config, error) { - token, err := kubeadmapi.NewBootstrapTokenString(cfg.BootstrapToken.Token) + token, err := bootstraptokenv1.NewBootstrapTokenString(cfg.BootstrapToken.Token) if err != nil { return nil, err } @@ -151,7 +152,7 @@ func buildSecureBootstrapKubeConfig(endpoint string, caCert []byte, clustername } // validateClusterInfoToken validates that the JWS token present in the cluster info ConfigMap is valid -func validateClusterInfoToken(insecureClusterInfo *v1.ConfigMap, token *kubeadmapi.BootstrapTokenString) ([]byte, error) { +func validateClusterInfoToken(insecureClusterInfo *v1.ConfigMap, token *bootstraptokenv1.BootstrapTokenString) ([]byte, error) { insecureKubeconfigString, ok := insecureClusterInfo.Data[bootstrapapi.KubeConfigKey] if !ok || len(insecureKubeconfigString) == 0 { return nil, errors.Errorf("there is no %s key in the %s ConfigMap. This API Server isn't set up for token bootstrapping, can't connect", @@ -194,7 +195,7 @@ func validateClusterCA(insecureConfig *clientcmdapi.Config, pubKeyPins *pubkeypi // getClusterInfo creates a client from the given kubeconfig if the given client is nil, // and requests the cluster info ConfigMap using PollImmediate. // If a client is provided it will be used instead. -func getClusterInfo(client clientset.Interface, kubeconfig *clientcmdapi.Config, token *kubeadmapi.BootstrapTokenString, interval, duration time.Duration) (*v1.ConfigMap, error) { +func getClusterInfo(client clientset.Interface, kubeconfig *clientcmdapi.Config, token *bootstraptokenv1.BootstrapTokenString, interval, duration time.Duration) (*v1.ConfigMap, error) { var cm *v1.ConfigMap var err error diff --git a/cmd/kubeadm/app/phases/bootstraptoken/node/token.go b/cmd/kubeadm/app/phases/bootstraptoken/node/token.go index 9a2dce93bd2..7a163b393ea 100644 --- a/cmd/kubeadm/app/phases/bootstraptoken/node/token.go +++ b/cmd/kubeadm/app/phases/bootstraptoken/node/token.go @@ -18,24 +18,23 @@ package node import ( "context" + "github.com/pkg/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" clientset "k8s.io/client-go/kubernetes" bootstraputil "k8s.io/cluster-bootstrap/token/util" - kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" + bootstraptokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient" ) -// TODO(mattmoyer): Move CreateNewTokens, UpdateOrCreateTokens out of this package to client-go for a generic abstraction and client for a Bootstrap Token - // CreateNewTokens tries to create a token and fails if one with the same ID already exists -func CreateNewTokens(client clientset.Interface, tokens []kubeadmapi.BootstrapToken) error { +func CreateNewTokens(client clientset.Interface, tokens []bootstraptokenv1.BootstrapToken) error { return UpdateOrCreateTokens(client, true, tokens) } // UpdateOrCreateTokens attempts to update a token with the given ID, or create if it does not already exist. -func UpdateOrCreateTokens(client clientset.Interface, failIfExists bool, tokens []kubeadmapi.BootstrapToken) error { +func UpdateOrCreateTokens(client clientset.Interface, failIfExists bool, tokens []bootstraptokenv1.BootstrapToken) error { for _, token := range tokens { @@ -45,7 +44,7 @@ func UpdateOrCreateTokens(client clientset.Interface, failIfExists bool, tokens return errors.Errorf("a token with id %q already exists", token.Token.ID) } - updatedOrNewSecret := token.ToSecret() + updatedOrNewSecret := bootstraptokenv1.BootstrapTokenToSecret(&token) // Try to create or update the token with an exponential backoff err = apiclient.TryRunCommand(func() error { if err := apiclient.CreateOrUpdateSecret(client, updatedOrNewSecret); err != nil { diff --git a/cmd/kubeadm/app/phases/copycerts/copycerts.go b/cmd/kubeadm/app/phases/copycerts/copycerts.go index cdc65918854..5c8957d6837 100644 --- a/cmd/kubeadm/app/phases/copycerts/copycerts.go +++ b/cmd/kubeadm/app/phases/copycerts/copycerts.go @@ -37,6 +37,7 @@ import ( keyutil "k8s.io/client-go/util/keyutil" bootstraputil "k8s.io/cluster-bootstrap/token/util" "k8s.io/klog/v2" + bootstraptokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" nodebootstraptokenphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node" @@ -57,11 +58,11 @@ func createShortLivedBootstrapToken(client clientset.Interface) (string, error) if err != nil { return "", errors.Wrap(err, "error generating token to upload certs") } - token, err := kubeadmapi.NewBootstrapTokenString(tokenStr) + token, err := bootstraptokenv1.NewBootstrapTokenString(tokenStr) if err != nil { return "", errors.Wrap(err, "error creating upload certs token") } - tokens := []kubeadmapi.BootstrapToken{{ + tokens := []bootstraptokenv1.BootstrapToken{{ Token: token, Description: "Proxy for managing TTL for the kubeadm-certs secret", TTL: &metav1.Duration{ diff --git a/cmd/kubeadm/app/util/config/initconfiguration.go b/cmd/kubeadm/app/util/config/initconfiguration.go index 18066744c71..b0db50cf8a8 100644 --- a/cmd/kubeadm/app/util/config/initconfiguration.go +++ b/cmd/kubeadm/app/util/config/initconfiguration.go @@ -31,6 +31,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" netutil "k8s.io/apimachinery/pkg/util/net" bootstraputil "k8s.io/cluster-bootstrap/token/util" + bootstraptokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme" kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3" @@ -44,8 +45,8 @@ import ( var ( // PlaceholderToken is only set statically to make kubeadm not randomize the token on every run - PlaceholderToken = kubeadmapiv1.BootstrapToken{ - Token: &kubeadmapiv1.BootstrapTokenString{ + PlaceholderToken = bootstraptokenv1.BootstrapToken{ + Token: &bootstraptokenv1.BootstrapTokenString{ ID: "abcdef", Secret: "0123456789abcdef", }, @@ -67,7 +68,7 @@ func SetInitDynamicDefaults(cfg *kubeadmapi.InitConfiguration) error { } // SetBootstrapTokensDynamicDefaults checks and sets configuration values for the BootstrapTokens object -func SetBootstrapTokensDynamicDefaults(cfg *[]kubeadmapi.BootstrapToken) error { +func SetBootstrapTokensDynamicDefaults(cfg *[]bootstraptokenv1.BootstrapToken) error { // Populate the .Token field with a random value if unset // We do this at this layer, and not the API defaulting layer // because of possible security concerns, and more practically @@ -82,7 +83,7 @@ func SetBootstrapTokensDynamicDefaults(cfg *[]kubeadmapi.BootstrapToken) error { if err != nil { return errors.Wrap(err, "couldn't generate random token") } - token, err := kubeadmapi.NewBootstrapTokenString(tokenStr) + token, err := bootstraptokenv1.NewBootstrapTokenString(tokenStr) if err != nil { return err } @@ -183,7 +184,7 @@ func SetClusterDynamicDefaults(cfg *kubeadmapi.ClusterConfiguration, localAPIEnd func DefaultedStaticInitConfiguration() (*kubeadmapi.InitConfiguration, error) { versionedInitCfg := &kubeadmapiv1.InitConfiguration{ LocalAPIEndpoint: kubeadmapiv1.APIEndpoint{AdvertiseAddress: "1.2.3.4"}, - BootstrapTokens: []kubeadmapiv1.BootstrapToken{PlaceholderToken}, + BootstrapTokens: []bootstraptokenv1.BootstrapToken{PlaceholderToken}, NodeRegistration: kubeadmapiv1.NodeRegistrationOptions{ CRISocket: kubeadmconstants.DefaultDockerCRISocket, // avoid CRI detection Name: "node", diff --git a/cmd/kubeadm/app/util/marshal_test.go b/cmd/kubeadm/app/util/marshal_test.go index 421405ba225..3053154712e 100644 --- a/cmd/kubeadm/app/util/marshal_test.go +++ b/cmd/kubeadm/app/util/marshal_test.go @@ -27,6 +27,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" + bootstraptokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3" "k8s.io/kubernetes/cmd/kubeadm/app/constants" @@ -119,9 +120,9 @@ func TestMarshalUnmarshalToYamlForCodecs(t *testing.T) { Name: "testNode", CRISocket: "/var/run/cri.sock", }, - BootstrapTokens: []kubeadmapiv1.BootstrapToken{ + BootstrapTokens: []bootstraptokenv1.BootstrapToken{ { - Token: &kubeadmapiv1.BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}, + Token: &bootstraptokenv1.BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}, }, }, // NOTE: Using MarshalToYamlForCodecs and UnmarshalFromYamlForCodecs for ClusterConfiguration fields here won't work