mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 02:43:36 +00:00
vendor update for CSI 0.3.0
This commit is contained in:
16
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/BUILD
generated
vendored
16
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/BUILD
generated
vendored
@ -10,10 +10,10 @@ go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"arguments.go",
|
||||
"cgroupdriver.go",
|
||||
"copy.go",
|
||||
"endpoint.go",
|
||||
"error.go",
|
||||
"etcd.go",
|
||||
"marshal.go",
|
||||
"template.go",
|
||||
"version.go",
|
||||
@ -21,8 +21,8 @@ go_library(
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/util",
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/preflight:go_default_library",
|
||||
"//vendor/github.com/coreos/etcd/clientv3:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library",
|
||||
"//vendor/gopkg.in/yaml.v2:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
@ -30,6 +30,7 @@ go_library(
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@ -37,15 +38,20 @@ go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"arguments_test.go",
|
||||
"cgroupdriver_test.go",
|
||||
"endpoint_test.go",
|
||||
"error_test.go",
|
||||
"marshal_test.go",
|
||||
"template_test.go",
|
||||
"version_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/preflight:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/scheme:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@ -64,10 +70,10 @@ filegroup(
|
||||
"//cmd/kubeadm/app/util/audit:all-srcs",
|
||||
"//cmd/kubeadm/app/util/config:all-srcs",
|
||||
"//cmd/kubeadm/app/util/dryrun:all-srcs",
|
||||
"//cmd/kubeadm/app/util/etcd:all-srcs",
|
||||
"//cmd/kubeadm/app/util/kubeconfig:all-srcs",
|
||||
"//cmd/kubeadm/app/util/pubkeypin:all-srcs",
|
||||
"//cmd/kubeadm/app/util/staticpod:all-srcs",
|
||||
"//cmd/kubeadm/app/util/token:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
4
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient/BUILD
generated
vendored
4
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient/BUILD
generated
vendored
@ -19,6 +19,8 @@ go_library(
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//pkg/kubelet/apis:go_default_library",
|
||||
"//pkg/kubelet/types:go_default_library",
|
||||
"//pkg/registry/core/service/ipallocator:go_default_library",
|
||||
"//vendor/k8s.io/api/apps/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
@ -27,8 +29,10 @@ go_library(
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
|
68
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient/clientbacked_dryrun.go
generated
vendored
68
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient/clientbacked_dryrun.go
generated
vendored
@ -34,7 +34,7 @@ import (
|
||||
// ClientBackedDryRunGetter implements the DryRunGetter interface for use in NewDryRunClient() and proxies all GET and LIST requests to the backing API server reachable via rest.Config
|
||||
type ClientBackedDryRunGetter struct {
|
||||
client clientset.Interface
|
||||
dynClientPool dynamic.ClientPool
|
||||
dynamicClient dynamic.Interface
|
||||
}
|
||||
|
||||
// InitDryRunGetter should implement the DryRunGetter interface
|
||||
@ -46,10 +46,14 @@ func NewClientBackedDryRunGetter(config *rest.Config) (*ClientBackedDryRunGetter
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dynamicClient, err := dynamic.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ClientBackedDryRunGetter{
|
||||
client: client,
|
||||
dynClientPool: dynamic.NewDynamicClientPool(config),
|
||||
dynamicClient: dynamicClient,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -68,22 +72,15 @@ func NewClientBackedDryRunGetterFromKubeconfig(file string) (*ClientBackedDryRun
|
||||
|
||||
// HandleGetAction handles GET actions to the dryrun clientset this interface supports
|
||||
func (clg *ClientBackedDryRunGetter) HandleGetAction(action core.GetAction) (bool, runtime.Object, error) {
|
||||
rc, err := clg.actionToResourceClient(action)
|
||||
unstructuredObj, err := clg.dynamicClient.Resource(action.GetResource()).Namespace(action.GetNamespace()).Get(action.GetName(), metav1.GetOptions{})
|
||||
// Inform the user that the requested object wasn't found.
|
||||
printIfNotExists(err)
|
||||
if err != nil {
|
||||
return true, nil, err
|
||||
}
|
||||
|
||||
unversionedObj, err := rc.Get(action.GetName(), metav1.GetOptions{})
|
||||
newObj, err := decodeUnstructuredIntoAPIObject(action, unstructuredObj)
|
||||
if err != nil {
|
||||
return true, nil, err
|
||||
}
|
||||
// If the unversioned object does not have .apiVersion; the inner object is probably nil
|
||||
if len(unversionedObj.GetAPIVersion()) == 0 {
|
||||
return true, nil, apierrors.NewNotFound(action.GetResource().GroupResource(), action.GetName())
|
||||
}
|
||||
newObj, err := decodeUnversionedIntoAPIObject(action, unversionedObj)
|
||||
if err != nil {
|
||||
fmt.Printf("error after decode: %v %v\n", unversionedObj, err)
|
||||
fmt.Printf("error after decode: %v %v\n", unstructuredObj, err)
|
||||
return true, nil, err
|
||||
}
|
||||
return true, newObj, err
|
||||
@ -91,27 +88,18 @@ func (clg *ClientBackedDryRunGetter) HandleGetAction(action core.GetAction) (boo
|
||||
|
||||
// HandleListAction handles LIST actions to the dryrun clientset this interface supports
|
||||
func (clg *ClientBackedDryRunGetter) HandleListAction(action core.ListAction) (bool, runtime.Object, error) {
|
||||
rc, err := clg.actionToResourceClient(action)
|
||||
if err != nil {
|
||||
return true, nil, err
|
||||
}
|
||||
|
||||
listOpts := metav1.ListOptions{
|
||||
LabelSelector: action.GetListRestrictions().Labels.String(),
|
||||
FieldSelector: action.GetListRestrictions().Fields.String(),
|
||||
}
|
||||
|
||||
unversionedList, err := rc.List(listOpts)
|
||||
unstructuredList, err := clg.dynamicClient.Resource(action.GetResource()).Namespace(action.GetNamespace()).List(listOpts)
|
||||
if err != nil {
|
||||
return true, nil, err
|
||||
}
|
||||
// If the runtime.Object here is nil, we should return successfully with no result
|
||||
if unversionedList == nil {
|
||||
return true, unversionedList, nil
|
||||
}
|
||||
newObj, err := decodeUnversionedIntoAPIObject(action, unversionedList)
|
||||
newObj, err := decodeUnstructuredIntoAPIObject(action, unstructuredList)
|
||||
if err != nil {
|
||||
fmt.Printf("error after decode: %v %v\n", unversionedList, err)
|
||||
fmt.Printf("error after decode: %v %v\n", unstructuredList, err)
|
||||
return true, nil, err
|
||||
}
|
||||
return true, newObj, err
|
||||
@ -122,28 +110,10 @@ func (clg *ClientBackedDryRunGetter) Client() clientset.Interface {
|
||||
return clg.client
|
||||
}
|
||||
|
||||
// actionToResourceClient returns the ResourceInterface for the given action
|
||||
// First; the function gets the right API group interface from the resource type. The API group struct behind the interface
|
||||
// returned may be cached in the dynamic client pool. Then, an APIResource object is constructed so that it can be passed to
|
||||
// dynamic.Interface's Resource() function, which will give us the final ResourceInterface to query
|
||||
func (clg *ClientBackedDryRunGetter) actionToResourceClient(action core.Action) (dynamic.ResourceInterface, error) {
|
||||
dynIface, err := clg.dynClientPool.ClientForGroupVersionResource(action.GetResource())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
apiResource := &metav1.APIResource{
|
||||
Name: action.GetResource().Resource,
|
||||
Namespaced: action.GetNamespace() != "",
|
||||
}
|
||||
|
||||
return dynIface.Resource(apiResource, action.GetNamespace()), nil
|
||||
}
|
||||
|
||||
// decodeUnversionedIntoAPIObject converts the *unversioned.Unversioned object returned from the dynamic client
|
||||
// to bytes; and then decodes it back _to an external api version (k8s.io/api vs k8s.io/kubernetes/pkg/api*)_ using the normal API machinery
|
||||
func decodeUnversionedIntoAPIObject(action core.Action, unversionedObj runtime.Object) (runtime.Object, error) {
|
||||
objBytes, err := json.Marshal(unversionedObj)
|
||||
func decodeUnstructuredIntoAPIObject(action core.Action, unstructuredObj runtime.Unstructured) (runtime.Object, error) {
|
||||
objBytes, err := json.Marshal(unstructuredObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -153,3 +123,9 @@ func decodeUnversionedIntoAPIObject(action core.Action, unversionedObj runtime.O
|
||||
}
|
||||
return newObj, nil
|
||||
}
|
||||
|
||||
func printIfNotExists(err error) {
|
||||
if apierrors.IsNotFound(err) {
|
||||
fmt.Println("[dryrun] The GET request didn't yield any result, the API Server returned a NotFound error.")
|
||||
}
|
||||
}
|
||||
|
21
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient/dryrunclient.go
generated
vendored
21
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient/dryrunclient.go
generated
vendored
@ -55,6 +55,18 @@ type DryRunClientOptions struct {
|
||||
PrintGETAndLIST bool
|
||||
}
|
||||
|
||||
// GetDefaultDryRunClientOptions returns the default DryRunClientOptions values
|
||||
func GetDefaultDryRunClientOptions(drg DryRunGetter, w io.Writer) DryRunClientOptions {
|
||||
return DryRunClientOptions{
|
||||
Writer: w,
|
||||
Getter: drg,
|
||||
PrependReactors: []core.Reactor{},
|
||||
AppendReactors: []core.Reactor{},
|
||||
MarshalFunc: DefaultMarshalFunc,
|
||||
PrintGETAndLIST: false,
|
||||
}
|
||||
}
|
||||
|
||||
// actionWithName is the generic interface for an action that has a name associated with it
|
||||
// This just makes it easier to catch all actions that has a name; instead of hard-coding all request that has it associated
|
||||
type actionWithName interface {
|
||||
@ -71,14 +83,7 @@ type actionWithObject interface {
|
||||
|
||||
// NewDryRunClient is a wrapper for NewDryRunClientWithOpts using some default values
|
||||
func NewDryRunClient(drg DryRunGetter, w io.Writer) clientset.Interface {
|
||||
return NewDryRunClientWithOpts(DryRunClientOptions{
|
||||
Writer: w,
|
||||
Getter: drg,
|
||||
PrependReactors: []core.Reactor{},
|
||||
AppendReactors: []core.Reactor{},
|
||||
MarshalFunc: DefaultMarshalFunc,
|
||||
PrintGETAndLIST: false,
|
||||
})
|
||||
return NewDryRunClientWithOpts(GetDefaultDryRunClientOptions(drg, w))
|
||||
}
|
||||
|
||||
// NewDryRunClientWithOpts returns a clientset.Interface that can be used normally for talking to the Kubernetes API.
|
||||
|
67
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient/idempotency.go
generated
vendored
67
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient/idempotency.go
generated
vendored
@ -17,6 +17,7 @@ limitations under the License.
|
||||
package apiclient
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
apps "k8s.io/api/apps/v1"
|
||||
@ -24,7 +25,12 @@ import (
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
||||
)
|
||||
|
||||
// TODO: We should invent a dynamic mechanism for this using the dynamic client instead of hard-coding these functions per-type
|
||||
@ -44,6 +50,21 @@ func CreateOrUpdateConfigMap(client clientset.Interface, cm *v1.ConfigMap) error
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateOrRetainConfigMap creates a ConfigMap if the target resource doesn't exist. If the resource exists already, this function will retain the resource instead.
|
||||
func CreateOrRetainConfigMap(client clientset.Interface, cm *v1.ConfigMap, configMapName string) error {
|
||||
if _, err := client.CoreV1().ConfigMaps(cm.ObjectMeta.Namespace).Get(configMapName, metav1.GetOptions{}); err != nil {
|
||||
if !apierrors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
if _, err := client.CoreV1().ConfigMaps(cm.ObjectMeta.Namespace).Create(cm); err != nil {
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("unable to create configmap: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateOrUpdateSecret creates a Secret if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
|
||||
func CreateOrUpdateSecret(client clientset.Interface, secret *v1.Secret) error {
|
||||
if _, err := client.CoreV1().Secrets(secret.ObjectMeta.Namespace).Create(secret); err != nil {
|
||||
@ -171,3 +192,49 @@ func CreateOrUpdateClusterRoleBinding(client clientset.Interface, clusterRoleBin
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PatchNode tries to patch a node using the following client, executing patchFn for the actual mutating logic
|
||||
func PatchNode(client clientset.Interface, nodeName string, patchFn func(*v1.Node)) error {
|
||||
// Loop on every false return. Return with an error if raised. Exit successfully if true is returned.
|
||||
return wait.Poll(constants.APICallRetryInterval, constants.PatchNodeTimeout, func() (bool, error) {
|
||||
// First get the node object
|
||||
n, err := client.CoreV1().Nodes().Get(nodeName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// The node may appear to have no labels at first,
|
||||
// so we wait for it to get hostname label.
|
||||
if _, found := n.ObjectMeta.Labels[kubeletapis.LabelHostname]; !found {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
oldData, err := json.Marshal(n)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Execute the mutating function
|
||||
patchFn(n)
|
||||
|
||||
newData, err := json.Marshal(n)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Node{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if _, err := client.CoreV1().Nodes().Patch(n.Name, types.StrategicMergePatchType, patchBytes); err != nil {
|
||||
if apierrors.IsConflict(err) {
|
||||
fmt.Println("[patchnode] Temporarily unable to update node metadata due to conflict (will retry)")
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
})
|
||||
}
|
||||
|
4
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient/init_dryrun.go
generated
vendored
4
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient/init_dryrun.go
generated
vendored
@ -132,9 +132,7 @@ func (idr *InitDryRunGetter) handleGetNode(action core.GetAction) (bool, runtime
|
||||
Labels: map[string]string{
|
||||
"kubernetes.io/hostname": idr.masterName,
|
||||
},
|
||||
},
|
||||
Spec: v1.NodeSpec{
|
||||
ExternalID: idr.masterName,
|
||||
Annotations: map[string]string{},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
2
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient/init_dryrun_test.go
generated
vendored
2
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient/init_dryrun_test.go
generated
vendored
@ -46,7 +46,7 @@ func TestHandleGetAction(t *testing.T) {
|
||||
{
|
||||
action: core.NewRootGetAction(schema.GroupVersionResource{Version: "v1", Resource: "nodes"}, masterName),
|
||||
expectedHandled: true,
|
||||
expectedObjectJSON: []byte(`{"metadata":{"name":"master-foo","creationTimestamp":null,"labels":{"kubernetes.io/hostname":"master-foo"}},"spec":{"externalID":"master-foo"},"status":{"daemonEndpoints":{"kubeletEndpoint":{"Port":0}},"nodeInfo":{"machineID":"","systemUUID":"","bootID":"","kernelVersion":"","osImage":"","containerRuntimeVersion":"","kubeletVersion":"","kubeProxyVersion":"","operatingSystem":"","architecture":""}}}`),
|
||||
expectedObjectJSON: []byte(`{"metadata":{"name":"master-foo","creationTimestamp":null,"labels":{"kubernetes.io/hostname":"master-foo"}},"spec":{},"status":{"daemonEndpoints":{"kubeletEndpoint":{"Port":0}},"nodeInfo":{"machineID":"","systemUUID":"","bootID":"","kernelVersion":"","osImage":"","containerRuntimeVersion":"","kubeletVersion":"","kubeProxyVersion":"","operatingSystem":"","architecture":""}}}`),
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
|
26
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient/wait.go
generated
vendored
26
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient/wait.go
generated
vendored
@ -17,8 +17,6 @@ limitations under the License.
|
||||
package apiclient
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@ -31,6 +29,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
|
||||
)
|
||||
|
||||
// Waiter is an interface for waiting for criteria in Kubernetes to happen
|
||||
@ -43,11 +42,11 @@ type Waiter interface {
|
||||
WaitForPodToDisappear(staticPodName string) error
|
||||
// WaitForStaticPodSingleHash fetches sha256 hash for the control plane static pod
|
||||
WaitForStaticPodSingleHash(nodeName string, component string) (string, error)
|
||||
// WaitForStaticPodHashChange waits for the given static pod component's static pod hash to get updated.
|
||||
// By doing that we can be sure that the kubelet has restarted the given Static Pod
|
||||
WaitForStaticPodHashChange(nodeName, component, previousHash string) error
|
||||
// WaitForStaticPodControlPlaneHashes fetches sha256 hashes for the control plane static pods
|
||||
WaitForStaticPodControlPlaneHashes(nodeName string) (map[string]string, error)
|
||||
// WaitForStaticPodControlPlaneHashChange waits for the given static pod component's static pod hash to get updated.
|
||||
// By doing that we can be sure that the kubelet has restarted the given Static Pod
|
||||
WaitForStaticPodControlPlaneHashChange(nodeName, component, previousHash string) error
|
||||
// WaitForHealthyKubelet blocks until the kubelet /healthz endpoint returns 'ok'
|
||||
WaitForHealthyKubelet(initalTimeout time.Duration, healthzEndpoint string) error
|
||||
// SetTimeout adjusts the timeout to the specified duration
|
||||
@ -194,17 +193,17 @@ func (w *KubeWaiter) WaitForStaticPodSingleHash(nodeName string, component strin
|
||||
return componentPodHash, err
|
||||
}
|
||||
|
||||
// WaitForStaticPodControlPlaneHashChange blocks until it timeouts or notices that the Mirror Pod (for the Static Pod, respectively) has changed
|
||||
// WaitForStaticPodHashChange blocks until it timeouts or notices that the Mirror Pod (for the Static Pod, respectively) has changed
|
||||
// This implicitly means this function blocks until the kubelet has restarted the Static Pod in question
|
||||
func (w *KubeWaiter) WaitForStaticPodControlPlaneHashChange(nodeName, component, previousHash string) error {
|
||||
func (w *KubeWaiter) WaitForStaticPodHashChange(nodeName, component, previousHash string) error {
|
||||
return wait.PollImmediate(constants.APICallRetryInterval, w.timeout, func() (bool, error) {
|
||||
|
||||
hashes, err := getStaticPodControlPlaneHashes(w.client, nodeName)
|
||||
hash, err := getStaticPodSingleHash(w.client, nodeName, component)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
// We should continue polling until the UID changes
|
||||
if hashes[component] == previousHash {
|
||||
if hash == previousHash {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
@ -235,12 +234,9 @@ func getStaticPodSingleHash(client clientset.Interface, nodeName string, compone
|
||||
return "", err
|
||||
}
|
||||
|
||||
podBytes, err := json.Marshal(staticPod)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%x", sha256.Sum256(podBytes)), nil
|
||||
staticPodHash := staticPod.Annotations[kubetypes.ConfigHashAnnotationKey]
|
||||
fmt.Printf("Static pod: %s hash: %s\n", staticPodName, staticPodHash)
|
||||
return staticPodHash, nil
|
||||
}
|
||||
|
||||
// TryRunCommand runs a function a maximum of failureThreshold times, and retries on error. If failureThreshold is hit; the last error is returned
|
||||
|
21
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/arguments.go
generated
vendored
21
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/arguments.go
generated
vendored
@ -18,17 +18,32 @@ package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// BuildArgumentListFromMap takes two string-string maps, one with the base arguments and one with optional override arguments
|
||||
// BuildArgumentListFromMap takes two string-string maps, one with the base arguments and one
|
||||
// with optional override arguments. In the return list override arguments will precede base
|
||||
// arguments
|
||||
func BuildArgumentListFromMap(baseArguments map[string]string, overrideArguments map[string]string) []string {
|
||||
var command []string
|
||||
for k, v := range overrideArguments {
|
||||
var keys []string
|
||||
for k := range overrideArguments {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
v := overrideArguments[k]
|
||||
// values of "" are allowed as well
|
||||
command = append(command, fmt.Sprintf("--%s=%s", k, v))
|
||||
}
|
||||
for k, v := range baseArguments {
|
||||
keys = []string{}
|
||||
for k := range baseArguments {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
v := baseArguments[k]
|
||||
if _, overrideExists := overrideArguments[k]; !overrideExists {
|
||||
command = append(command, fmt.Sprintf("--%s=%s", k, v))
|
||||
}
|
||||
|
12
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/arguments_test.go
generated
vendored
12
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/arguments_test.go
generated
vendored
@ -39,8 +39,8 @@ func TestBuildArgumentListFromMap(t *testing.T) {
|
||||
},
|
||||
expected: []string{
|
||||
"--admission-control=NamespaceLifecycle,LimitRanger",
|
||||
"--insecure-bind-address=127.0.0.1",
|
||||
"--allow-privileged=true",
|
||||
"--insecure-bind-address=127.0.0.1",
|
||||
},
|
||||
},
|
||||
{ // add an argument that is not in base
|
||||
@ -53,8 +53,8 @@ func TestBuildArgumentListFromMap(t *testing.T) {
|
||||
},
|
||||
expected: []string{
|
||||
"--admission-control=NamespaceLifecycle,LimitRanger",
|
||||
"--insecure-bind-address=127.0.0.1",
|
||||
"--allow-privileged=true",
|
||||
"--insecure-bind-address=127.0.0.1",
|
||||
},
|
||||
},
|
||||
{ // allow empty strings in base
|
||||
@ -68,8 +68,8 @@ func TestBuildArgumentListFromMap(t *testing.T) {
|
||||
},
|
||||
expected: []string{
|
||||
"--admission-control=NamespaceLifecycle,LimitRanger",
|
||||
"--insecure-bind-address=127.0.0.1",
|
||||
"--allow-privileged=true",
|
||||
"--insecure-bind-address=127.0.0.1",
|
||||
"--something-that-allows-empty-string=",
|
||||
},
|
||||
},
|
||||
@ -85,17 +85,15 @@ func TestBuildArgumentListFromMap(t *testing.T) {
|
||||
},
|
||||
expected: []string{
|
||||
"--admission-control=NamespaceLifecycle,LimitRanger",
|
||||
"--insecure-bind-address=127.0.0.1",
|
||||
"--allow-privileged=true",
|
||||
"--something-that-allows-empty-string=",
|
||||
"--allow-privileged=true",
|
||||
"--insecure-bind-address=127.0.0.1",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
actual := BuildArgumentListFromMap(rt.base, rt.overrides)
|
||||
sort.Strings(actual)
|
||||
sort.Strings(rt.expected)
|
||||
if !reflect.DeepEqual(actual, rt.expected) {
|
||||
t.Errorf("failed BuildArgumentListFromMap:\nexpected:\n%v\nsaw:\n%v", rt.expected, actual)
|
||||
}
|
||||
|
7
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/audit/BUILD
generated
vendored
7
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/audit/BUILD
generated
vendored
@ -8,8 +8,10 @@ go_library(
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/install:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@ -18,8 +20,9 @@ go_test(
|
||||
srcs = ["utils_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/kubectl/scheme:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/install:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
16
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/audit/utils.go
generated
vendored
16
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/audit/utils.go
generated
vendored
@ -23,8 +23,10 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apiserver/pkg/apis/audit/install"
|
||||
auditv1beta1 "k8s.io/apiserver/pkg/apis/audit/v1beta1"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
)
|
||||
|
||||
@ -32,7 +34,7 @@ import (
|
||||
func CreateDefaultAuditLogPolicy(policyFile string) error {
|
||||
policy := auditv1beta1.Policy{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "audit.k8s.io/v1beta1",
|
||||
APIVersion: auditv1beta1.SchemeGroupVersion.String(),
|
||||
Kind: "Policy",
|
||||
},
|
||||
Rules: []auditv1beta1.PolicyRule{
|
||||
@ -50,11 +52,15 @@ func writePolicyToDisk(policyFile string, policy *auditv1beta1.Policy) error {
|
||||
return fmt.Errorf("failed to create directory %q: %v", filepath.Dir(policyFile), err)
|
||||
}
|
||||
|
||||
// Registers auditv1beta1 with the runtime Scheme
|
||||
auditv1beta1.AddToScheme(scheme.Scheme)
|
||||
scheme := runtime.NewScheme()
|
||||
// Registers the API group with the scheme and adds types to a scheme
|
||||
install.Install(scheme)
|
||||
|
||||
codecs := serializer.NewCodecFactory(scheme)
|
||||
|
||||
// writes the policy to disk
|
||||
serialized, err := util.MarshalToYaml(policy, auditv1beta1.SchemeGroupVersion)
|
||||
serialized, err := util.MarshalToYamlForCodecs(policy, auditv1beta1.SchemeGroupVersion, codecs)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal audit policy to YAML: %v", err)
|
||||
}
|
||||
|
8
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/audit/utils_test.go
generated
vendored
8
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/audit/utils_test.go
generated
vendored
@ -23,8 +23,9 @@ import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apiserver/pkg/apis/audit/install"
|
||||
auditv1beta1 "k8s.io/apiserver/pkg/apis/audit/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
func cleanup(t *testing.T, path string) {
|
||||
@ -50,8 +51,11 @@ func TestCreateDefaultAuditLogPolicy(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read %v: %v", auditPolicyFile, err)
|
||||
}
|
||||
scheme := runtime.NewScheme()
|
||||
install.Install(scheme)
|
||||
codecs := serializer.NewCodecFactory(scheme)
|
||||
policy := auditv1beta1.Policy{}
|
||||
err = runtime.DecodeInto(scheme.Codecs.UniversalDecoder(), policyBytes, &policy)
|
||||
err = runtime.DecodeInto(codecs.UniversalDecoder(), policyBytes, &policy)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to decode written policy: %v", err)
|
||||
}
|
||||
|
75
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/cgroupdriver.go
generated
vendored
Normal file
75
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/cgroupdriver.go
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
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 util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
utilsexec "k8s.io/utils/exec"
|
||||
)
|
||||
|
||||
// TODO: add support for detecting the cgroup driver for CRI other than
|
||||
// Docker. Currently only Docker driver detection is supported:
|
||||
// Discussion:
|
||||
// https://github.com/kubernetes/kubeadm/issues/844
|
||||
|
||||
// GetCgroupDriverDocker runs 'docker info' to obtain the docker cgroup driver
|
||||
func GetCgroupDriverDocker(execer utilsexec.Interface) (string, error) {
|
||||
info, err := callDockerInfo(execer)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return getCgroupDriverFromDockerInfo(info)
|
||||
}
|
||||
|
||||
func validateCgroupDriver(driver string) error {
|
||||
if driver != "cgroupfs" && driver != "systemd" {
|
||||
return fmt.Errorf("unknown cgroup driver %q", driver)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: Docker 1.13 has a new way to obatain the cgroup driver:
|
||||
// docker info -f "{{.CgroupDriver}}
|
||||
// If the minimum supported Docker version in K8s becomes 1.13, move to
|
||||
// this syntax.
|
||||
func callDockerInfo(execer utilsexec.Interface) (string, error) {
|
||||
out, err := execer.Command("docker", "info").Output()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("cannot execute 'docker info': %v", err)
|
||||
}
|
||||
return string(out), nil
|
||||
}
|
||||
|
||||
func getCgroupDriverFromDockerInfo(info string) (string, error) {
|
||||
lineSeparator := ": "
|
||||
prefix := "Cgroup Driver"
|
||||
for _, line := range strings.Split(info, "\n") {
|
||||
if !strings.Contains(line, prefix+lineSeparator) {
|
||||
continue
|
||||
}
|
||||
lineSplit := strings.Split(line, lineSeparator)
|
||||
// At this point len(lineSplit) is always >= 2
|
||||
driver := lineSplit[1]
|
||||
if err := validateCgroupDriver(driver); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return driver, nil
|
||||
}
|
||||
return "", fmt.Errorf("cgroup driver is not defined in 'docker info'")
|
||||
}
|
68
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/cgroupdriver_test.go
generated
vendored
Normal file
68
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/cgroupdriver_test.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
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 util
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetCgroupDriverDocker(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
info string
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "valid: value is 'cgroupfs'",
|
||||
info: `Cgroup Driver: cgroupfs`,
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "valid: value is 'systemd'",
|
||||
info: `Cgroup Driver: systemd`,
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "invalid: missing 'Cgroup Driver' key and value",
|
||||
info: "",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid: only a 'Cgroup Driver' key is present",
|
||||
info: `Cgroup Driver`,
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid: empty 'Cgroup Driver' value",
|
||||
info: `Cgroup Driver: `,
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid: unknown 'Cgroup Driver' value",
|
||||
info: `Cgroup Driver: invalid-value`,
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if _, err := getCgroupDriverFromDockerInfo(tc.info); (err != nil) != tc.expectedError {
|
||||
t.Fatalf("expected error: %v, saw: %v, error: %v", tc.expectedError, (err != nil), err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
33
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/BUILD
generated
vendored
33
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/BUILD
generated
vendored
@ -8,27 +8,52 @@ load(
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["masterconfig.go"],
|
||||
srcs = [
|
||||
"cluster.go",
|
||||
"masterconfig.go",
|
||||
"nodeconfig.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/util/config",
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/scheme:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha2:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/token:go_default_library",
|
||||
"//pkg/api/legacyscheme:go_default_library",
|
||||
"//pkg/util/node:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/bootstrap/token/util:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["masterconfig_test.go"],
|
||||
srcs = [
|
||||
"masterconfig_test.go",
|
||||
"nodeconfig_test.go",
|
||||
],
|
||||
data = glob(["testdata/**"]),
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/scheme:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha2:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//vendor/github.com/pmezard/go-difflib/difflib:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
|
65
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/cluster.go
generated
vendored
Normal file
65
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/cluster.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
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 config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
)
|
||||
|
||||
// TODO: Add unit tests for this file
|
||||
|
||||
// FetchConfigFromFileOrCluster fetches configuration required for upgrading your cluster from a file (which has precedence) or a ConfigMap in the cluster
|
||||
func FetchConfigFromFileOrCluster(client clientset.Interface, w io.Writer, logPrefix, cfgPath string) (*kubeadmapi.MasterConfiguration, error) {
|
||||
// Load the configuration from a file or the cluster
|
||||
configBytes, err := loadConfigurationBytes(client, w, logPrefix, cfgPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Take the versioned configuration populated from the file or ConfigMap, convert it to internal, default and validate
|
||||
return BytesToInternalConfig(configBytes)
|
||||
}
|
||||
|
||||
// loadConfigurationBytes loads the configuration byte slice from either a file or the cluster ConfigMap
|
||||
func loadConfigurationBytes(client clientset.Interface, w io.Writer, logPrefix, cfgPath string) ([]byte, error) {
|
||||
// The config file has the highest priority
|
||||
if cfgPath != "" {
|
||||
fmt.Fprintf(w, "[%s] Reading configuration options from a file: %s\n", logPrefix, cfgPath)
|
||||
return ioutil.ReadFile(cfgPath)
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "[%s] Reading configuration from the cluster...\n", logPrefix)
|
||||
|
||||
configMap, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(constants.MasterConfigurationConfigMap, metav1.GetOptions{})
|
||||
if apierrors.IsNotFound(err) {
|
||||
// Return the apierror directly so the caller of this function can know what type of error occurred and act based on that
|
||||
return []byte{}, err
|
||||
} else if err != nil {
|
||||
return []byte{}, fmt.Errorf("an unexpected error happened when trying to get the ConfigMap %q in the %s namespace: %v", constants.MasterConfigurationConfigMap, metav1.NamespaceSystem, err)
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "[%s] FYI: You can look at this config file with 'kubectl -n %s get cm %s -oyaml'\n", logPrefix, metav1.NamespaceSystem, constants.MasterConfigurationConfigMap)
|
||||
return []byte(configMap.Data[constants.MasterConfigurationConfigMapKey]), nil
|
||||
}
|
171
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/masterconfig.go
generated
vendored
171
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/masterconfig.go
generated
vendored
@ -14,72 +14,86 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
netutil "k8s.io/apimachinery/pkg/util/net"
|
||||
bootstraputil "k8s.io/client-go/tools/bootstrap/token/util"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
|
||||
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
||||
kubeadmapiv1alpha1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
|
||||
kubeadmapiv1alpha2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha2"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
tokenutil "k8s.io/kubernetes/cmd/kubeadm/app/util/token"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/util/node"
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
)
|
||||
|
||||
// SetInitDynamicDefaults checks and sets configuration values for Master node
|
||||
// SetInitDynamicDefaults checks and sets configuration values for the MasterConfiguration object
|
||||
func SetInitDynamicDefaults(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
|
||||
// validate cfg.API.AdvertiseAddress.
|
||||
addressIP := net.ParseIP(cfg.API.AdvertiseAddress)
|
||||
if addressIP == nil && cfg.API.AdvertiseAddress != "" {
|
||||
return fmt.Errorf("couldn't use \"%s\" as \"apiserver-advertise-address\", must be ipv4 or ipv6 address", cfg.API.AdvertiseAddress)
|
||||
}
|
||||
// Choose the right address for the API Server to advertise. If the advertise address is localhost or 0.0.0.0, the default interface's IP address is used
|
||||
// This is the same logic as the API Server uses
|
||||
ip, err := netutil.ChooseBindAddress(net.ParseIP(cfg.API.AdvertiseAddress))
|
||||
ip, err := netutil.ChooseBindAddress(addressIP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.API.AdvertiseAddress = ip.String()
|
||||
ip = net.ParseIP(cfg.API.AdvertiseAddress)
|
||||
if ip.To4() != nil {
|
||||
cfg.KubeProxy.Config.BindAddress = kubeadmapiext.DefaultProxyBindAddressv4
|
||||
cfg.KubeProxy.Config.BindAddress = kubeadmapiv1alpha2.DefaultProxyBindAddressv4
|
||||
} else {
|
||||
cfg.KubeProxy.Config.BindAddress = kubeadmapiext.DefaultProxyBindAddressv6
|
||||
cfg.KubeProxy.Config.BindAddress = kubeadmapiv1alpha2.DefaultProxyBindAddressv6
|
||||
}
|
||||
// Resolve possible version labels and validate version string
|
||||
err = NormalizeKubernetesVersion(cfg)
|
||||
if err != nil {
|
||||
if err := NormalizeKubernetesVersion(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cfg.Token == "" {
|
||||
var err error
|
||||
cfg.Token, err = tokenutil.GenerateToken()
|
||||
// Downcase SANs. Some domain names (like ELBs) have capitals in them.
|
||||
LowercaseSANs(cfg.APIServerCertSANs)
|
||||
|
||||
// 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
|
||||
// because we can't return errors in the API object defaulting
|
||||
// process but here we can.
|
||||
for i, bt := range cfg.BootstrapTokens {
|
||||
if bt.Token != nil && len(bt.Token.String()) > 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
tokenStr, err := bootstraputil.GenerateBootstrapToken()
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't generate random token: %v", err)
|
||||
}
|
||||
token, err := kubeadmapi.NewBootstrapTokenString(tokenStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.BootstrapTokens[i].Token = token
|
||||
}
|
||||
|
||||
cfg.NodeName = node.GetHostname(cfg.NodeName)
|
||||
cfg.NodeRegistration.Name = node.GetHostname(cfg.NodeRegistration.Name)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TryLoadMasterConfiguration tries to loads a Master configuration from the given file (if defined)
|
||||
func TryLoadMasterConfiguration(cfgPath string, cfg *kubeadmapiext.MasterConfiguration) error {
|
||||
|
||||
if cfgPath != "" {
|
||||
b, err := ioutil.ReadFile(cfgPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read config from %q [%v]", cfgPath, err)
|
||||
}
|
||||
if err := runtime.DecodeInto(legacyscheme.Codecs.UniversalDecoder(), b, cfg); err != nil {
|
||||
return fmt.Errorf("unable to decode config from %q [%v]", cfgPath, err)
|
||||
}
|
||||
// Only if the slice is nil, we should append the master taint. This allows the user to specify an empty slice for no default master taint
|
||||
if cfg.NodeRegistration.Taints == nil {
|
||||
cfg.NodeRegistration.Taints = []v1.Taint{kubeadmconstants.MasterTaint}
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -90,29 +104,93 @@ func TryLoadMasterConfiguration(cfgPath string, cfg *kubeadmapiext.MasterConfigu
|
||||
// Then the external, versioned configuration is defaulted and converted to the internal type.
|
||||
// Right thereafter, the configuration is defaulted again with dynamic values (like IP addresses of a machine, etc)
|
||||
// Lastly, the internal config is validated and returned.
|
||||
func ConfigFileAndDefaultsToInternalConfig(cfgPath string, defaultversionedcfg *kubeadmapiext.MasterConfiguration) (*kubeadmapi.MasterConfiguration, error) {
|
||||
func ConfigFileAndDefaultsToInternalConfig(cfgPath string, defaultversionedcfg *kubeadmapiv1alpha2.MasterConfiguration) (*kubeadmapi.MasterConfiguration, error) {
|
||||
internalcfg := &kubeadmapi.MasterConfiguration{}
|
||||
|
||||
// Loads configuration from config file, if provided
|
||||
// Nb. --config overrides command line flags
|
||||
if err := TryLoadMasterConfiguration(cfgPath, defaultversionedcfg); err != nil {
|
||||
return nil, err
|
||||
if cfgPath != "" {
|
||||
// Loads configuration from config file, if provided
|
||||
// Nb. --config overrides command line flags
|
||||
glog.V(1).Infoln("loading configuration from the given file")
|
||||
|
||||
b, err := ioutil.ReadFile(cfgPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read config from %q [%v]", cfgPath, err)
|
||||
}
|
||||
return BytesToInternalConfig(b)
|
||||
}
|
||||
|
||||
// Takes passed flags into account; the defaulting is executed once again enforcing assignement of
|
||||
// static default values to cfg only for values not provided with flags
|
||||
legacyscheme.Scheme.Default(defaultversionedcfg)
|
||||
legacyscheme.Scheme.Convert(defaultversionedcfg, internalcfg, nil)
|
||||
// Applies dynamic defaults to settings not provided with flags
|
||||
if err := SetInitDynamicDefaults(internalcfg); err != nil {
|
||||
return nil, err
|
||||
kubeadmscheme.Scheme.Default(defaultversionedcfg)
|
||||
kubeadmscheme.Scheme.Convert(defaultversionedcfg, internalcfg, nil)
|
||||
|
||||
return defaultAndValidate(internalcfg)
|
||||
}
|
||||
|
||||
// BytesToInternalConfig converts a byte array to an internal, defaulted and validated configuration object
|
||||
func BytesToInternalConfig(b []byte) (*kubeadmapi.MasterConfiguration, error) {
|
||||
internalcfg := &kubeadmapi.MasterConfiguration{}
|
||||
|
||||
decoded, err := kubeadmutil.LoadYAML(b)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to decode config from bytes: %v", err)
|
||||
}
|
||||
|
||||
// Validates cfg (flags/configs + defaults + dynamic defaults)
|
||||
if err := validation.ValidateMasterConfiguration(internalcfg).ToAggregate(); err != nil {
|
||||
// As there was a bug in kubeadm v1.10 and earlier that made the YAML uploaded to the cluster configmap NOT have metav1.TypeMeta information
|
||||
// we need to populate this here manually. If kind or apiVersion is empty, we know the apiVersion is v1alpha1, as by the time kubeadm had this bug,
|
||||
// it could only write
|
||||
// TODO: Remove this "hack" in v1.12 when we know the ConfigMap always contains v1alpha2 content written by kubeadm v1.11. Also, we will drop support for
|
||||
// v1alpha1 in v1.12
|
||||
kind := decoded["kind"]
|
||||
apiVersion := decoded["apiVersion"]
|
||||
if kind == nil || len(kind.(string)) == 0 {
|
||||
decoded["kind"] = "MasterConfiguration"
|
||||
}
|
||||
if apiVersion == nil || len(apiVersion.(string)) == 0 {
|
||||
decoded["apiVersion"] = kubeadmapiv1alpha1.SchemeGroupVersion.String()
|
||||
}
|
||||
|
||||
// Between v1.9 and v1.10 the proxy componentconfig in the v1alpha1 MasterConfiguration changed unexpectedly, which broke unmarshalling out-of-the-box
|
||||
// Hence, we need to workaround this bug in the v1alpha1 API
|
||||
if decoded["apiVersion"] == kubeadmapiv1alpha1.SchemeGroupVersion.String() {
|
||||
v1alpha1cfg := &kubeadmapiv1alpha1.MasterConfiguration{}
|
||||
if err := kubeadmapiv1alpha1.Migrate(decoded, v1alpha1cfg, kubeadmscheme.Codecs); err != nil {
|
||||
return nil, fmt.Errorf("unable to migrate config from previous version: %v", err)
|
||||
}
|
||||
|
||||
// Default and convert to the internal version
|
||||
kubeadmscheme.Scheme.Default(v1alpha1cfg)
|
||||
kubeadmscheme.Scheme.Convert(v1alpha1cfg, internalcfg, nil)
|
||||
} else if decoded["apiVersion"] == kubeadmapiv1alpha2.SchemeGroupVersion.String() {
|
||||
v1alpha2cfg := &kubeadmapiv1alpha2.MasterConfiguration{}
|
||||
if err := runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(), b, v1alpha2cfg); err != nil {
|
||||
return nil, fmt.Errorf("unable to decode config: %v", err)
|
||||
}
|
||||
|
||||
// Default and convert to the internal version
|
||||
kubeadmscheme.Scheme.Default(v1alpha2cfg)
|
||||
kubeadmscheme.Scheme.Convert(v1alpha2cfg, internalcfg, nil)
|
||||
} else {
|
||||
// TODO: Add support for an upcoming v1alpha2 API
|
||||
// TODO: In the future, we can unmarshal any two or more external types into the internal object directly using the following syntax.
|
||||
// Long-term we don't need this if/else clause. In the future this will do
|
||||
// runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(kubeadmapiv1alpha2.SchemeGroupVersion, kubeadmapiv2alpha3.SchemeGroupVersion), b, internalcfg)
|
||||
return nil, fmt.Errorf("unknown API version for kubeadm configuration")
|
||||
}
|
||||
|
||||
return defaultAndValidate(internalcfg)
|
||||
}
|
||||
|
||||
func defaultAndValidate(cfg *kubeadmapi.MasterConfiguration) (*kubeadmapi.MasterConfiguration, error) {
|
||||
// Applies dynamic defaults to settings not provided with flags
|
||||
if err := SetInitDynamicDefaults(cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return internalcfg, nil
|
||||
// Validates cfg (flags/configs + defaults + dynamic defaults)
|
||||
if err := validation.ValidateMasterConfiguration(cfg).ToAggregate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// NormalizeKubernetesVersion resolves version labels, sets alternative
|
||||
@ -141,3 +219,14 @@ func NormalizeKubernetesVersion(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LowercaseSANs can be used to force all SANs to be lowercase so it passes IsDNS1123Subdomain
|
||||
func LowercaseSANs(sans []string) {
|
||||
for i, san := range sans {
|
||||
lowercase := strings.ToLower(san)
|
||||
if lowercase != san {
|
||||
glog.V(1).Infof("lowercasing SAN %q to %q", san, lowercase)
|
||||
sans[i] = lowercase
|
||||
}
|
||||
}
|
||||
}
|
||||
|
212
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/masterconfig_test.go
generated
vendored
212
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/masterconfig_test.go
generated
vendored
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
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.
|
||||
@ -14,4 +14,212 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/pmezard/go-difflib/difflib"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha2"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
)
|
||||
|
||||
const (
|
||||
master_v1alpha1YAML = "testdata/conversion/master/v1alpha1.yaml"
|
||||
master_v1alpha1WithoutTypeMetaYAML = "testdata/conversion/master/v1alpha1_without_TypeMeta.yaml"
|
||||
master_v1alpha2YAML = "testdata/conversion/master/v1alpha2.yaml"
|
||||
master_internalYAML = "testdata/conversion/master/internal.yaml"
|
||||
master_incompleteYAML = "testdata/defaulting/master/incomplete.yaml"
|
||||
master_defaultedYAML = "testdata/defaulting/master/defaulted.yaml"
|
||||
master_invalidYAML = "testdata/validation/invalid_mastercfg.yaml"
|
||||
master_beforeUpgradeYAML = "testdata/v1alpha1_upgrade/before.yaml"
|
||||
master_afterUpgradeYAML = "testdata/v1alpha1_upgrade/after.yaml"
|
||||
)
|
||||
|
||||
func diff(expected, actual []byte) string {
|
||||
// Write out the diff
|
||||
var diffBytes bytes.Buffer
|
||||
difflib.WriteUnifiedDiff(&diffBytes, difflib.UnifiedDiff{
|
||||
A: difflib.SplitLines(string(expected)),
|
||||
B: difflib.SplitLines(string(actual)),
|
||||
FromFile: "expected",
|
||||
ToFile: "actual",
|
||||
Context: 3,
|
||||
})
|
||||
return diffBytes.String()
|
||||
}
|
||||
|
||||
func TestConfigFileAndDefaultsToInternalConfig(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name, in, out string
|
||||
groupVersion schema.GroupVersion
|
||||
expectedErr bool
|
||||
}{
|
||||
// These tests are reading one file, loading it using ConfigFileAndDefaultsToInternalConfig that all of kubeadm is using for unmarshal of our API types,
|
||||
// and then marshals the internal object to the expected groupVersion
|
||||
{ // v1alpha1 (faulty) -> internal
|
||||
name: "v1alpha1WithoutTypeMetaToInternal",
|
||||
in: master_v1alpha1WithoutTypeMetaYAML,
|
||||
out: master_internalYAML,
|
||||
groupVersion: kubeadm.SchemeGroupVersion,
|
||||
},
|
||||
{ // v1alpha1 -> internal
|
||||
name: "v1alpha1ToInternal",
|
||||
in: master_v1alpha1YAML,
|
||||
out: master_internalYAML,
|
||||
groupVersion: kubeadm.SchemeGroupVersion,
|
||||
},
|
||||
{ // v1alpha2 -> internal
|
||||
name: "v1alpha2ToInternal",
|
||||
in: master_v1alpha2YAML,
|
||||
out: master_internalYAML,
|
||||
groupVersion: kubeadm.SchemeGroupVersion,
|
||||
},
|
||||
{ // v1alpha1 (faulty) -> internal -> v1alpha2
|
||||
name: "v1alpha1WithoutTypeMetaTov1alpha2",
|
||||
in: master_v1alpha1WithoutTypeMetaYAML,
|
||||
out: master_v1alpha2YAML,
|
||||
groupVersion: v1alpha2.SchemeGroupVersion,
|
||||
},
|
||||
{ // v1alpha1 -> internal -> v1alpha2
|
||||
name: "v1alpha1Tov1alpha2",
|
||||
in: master_v1alpha1YAML,
|
||||
out: master_v1alpha2YAML,
|
||||
groupVersion: v1alpha2.SchemeGroupVersion,
|
||||
},
|
||||
// These tests are reading one file that has only a subset of the fields populated, loading it using ConfigFileAndDefaultsToInternalConfig,
|
||||
// and then marshals the internal object to the expected groupVersion
|
||||
{ // v1alpha1 (faulty) -> default -> validate -> internal -> v1alpha2
|
||||
name: "incompleteYAMLToDefaultedv1alpha2",
|
||||
in: master_incompleteYAML,
|
||||
out: master_defaultedYAML,
|
||||
groupVersion: v1alpha2.SchemeGroupVersion,
|
||||
},
|
||||
{ // v1alpha1 (faulty) -> validation should fail
|
||||
name: "invalidYAMLShouldFail",
|
||||
in: master_invalidYAML,
|
||||
expectedErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t2 *testing.T) {
|
||||
|
||||
internalcfg, err := ConfigFileAndDefaultsToInternalConfig(rt.in, &v1alpha2.MasterConfiguration{})
|
||||
if err != nil {
|
||||
if rt.expectedErr {
|
||||
return
|
||||
}
|
||||
t2.Fatalf("couldn't unmarshal test data: %v", err)
|
||||
}
|
||||
|
||||
actual, err := kubeadmutil.MarshalToYamlForCodecs(internalcfg, rt.groupVersion, scheme.Codecs)
|
||||
if err != nil {
|
||||
t2.Fatalf("couldn't marshal internal object: %v", err)
|
||||
}
|
||||
|
||||
expected, err := ioutil.ReadFile(rt.out)
|
||||
if err != nil {
|
||||
t2.Fatalf("couldn't read test data: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(expected, actual) {
|
||||
t2.Errorf("the expected and actual output differs.\n\tin: %s\n\tout: %s\n\tgroupversion: %s\n\tdiff: \n%s\n",
|
||||
rt.in, rt.out, rt.groupVersion.String(), diff(expected, actual))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestUpgrade tests reading a faulty YAML representation of the MasterConfiguration object (as found in kubeadm clusters <= v1.9.x),
|
||||
// fixes the problems internally and verifies the marshalled output is the expected output
|
||||
func TestUpgrade(t *testing.T) {
|
||||
before, err := ioutil.ReadFile(master_beforeUpgradeYAML)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't read test data: %v", err)
|
||||
}
|
||||
|
||||
afterExpected, err := ioutil.ReadFile(master_afterUpgradeYAML)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't read test data: %v", err)
|
||||
}
|
||||
|
||||
decoded, err := kubeadmutil.LoadYAML(before)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't unmarshal test yaml: %v", err)
|
||||
}
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
v1alpha1.AddToScheme(scheme)
|
||||
codecs := serializer.NewCodecFactory(scheme)
|
||||
|
||||
obj := &v1alpha1.MasterConfiguration{}
|
||||
if err := v1alpha1.Migrate(decoded, obj, codecs); err != nil {
|
||||
t.Fatalf("couldn't decode migrated object: %v", err)
|
||||
}
|
||||
|
||||
afterActual, err := kubeadmutil.MarshalToYamlForCodecs(obj, v1alpha1.SchemeGroupVersion, codecs)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't marshal object: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(afterExpected, afterActual) {
|
||||
t.Errorf("v1alpha1 object after unmarshal, conversion and marshal didn't match expected value.\n\tdiff: \n%s\n", diff(afterExpected, afterActual))
|
||||
}
|
||||
}
|
||||
|
||||
func TestLowercaseSANs(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
in []string
|
||||
out []string
|
||||
}{
|
||||
{
|
||||
name: "empty struct",
|
||||
},
|
||||
{
|
||||
name: "already lowercase",
|
||||
in: []string{"example.k8s.io"},
|
||||
out: []string{"example.k8s.io"},
|
||||
},
|
||||
{
|
||||
name: "ip addresses and uppercase",
|
||||
in: []string{"EXAMPLE.k8s.io", "10.100.0.1"},
|
||||
out: []string{"example.k8s.io", "10.100.0.1"},
|
||||
},
|
||||
{
|
||||
name: "punycode and uppercase",
|
||||
in: []string{"xn--7gq663byk9a.xn--fiqz9s", "ANOTHEREXAMPLE.k8s.io"},
|
||||
out: []string{"xn--7gq663byk9a.xn--fiqz9s", "anotherexample.k8s.io"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
cfg := &v1alpha2.MasterConfiguration{
|
||||
APIServerCertSANs: test.in,
|
||||
}
|
||||
|
||||
LowercaseSANs(cfg.APIServerCertSANs)
|
||||
|
||||
if len(cfg.APIServerCertSANs) != len(test.out) {
|
||||
t.Fatalf("expected %d elements, got %d", len(test.out), len(cfg.APIServerCertSANs))
|
||||
}
|
||||
|
||||
for i, expected := range test.out {
|
||||
if cfg.APIServerCertSANs[i] != expected {
|
||||
t.Errorf("expected element %d to be %q, got %q", i, expected, cfg.APIServerCertSANs[i])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
71
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/nodeconfig.go
generated
vendored
Normal file
71
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/nodeconfig.go
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
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 config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
||||
kubeadmapiv1alpha1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
|
||||
kubeadmapiv1alpha2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha2"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
|
||||
"k8s.io/kubernetes/pkg/util/node"
|
||||
)
|
||||
|
||||
// SetJoinDynamicDefaults checks and sets configuration values for the NodeConfiguration object
|
||||
func SetJoinDynamicDefaults(cfg *kubeadmapi.NodeConfiguration) error {
|
||||
cfg.NodeRegistration.Name = node.GetHostname(cfg.NodeRegistration.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// NodeConfigFileAndDefaultsToInternalConfig
|
||||
func NodeConfigFileAndDefaultsToInternalConfig(cfgPath string, defaultversionedcfg *kubeadmapiv1alpha2.NodeConfiguration) (*kubeadmapi.NodeConfiguration, error) {
|
||||
internalcfg := &kubeadmapi.NodeConfiguration{}
|
||||
|
||||
if cfgPath != "" {
|
||||
// Loads configuration from config file, if provided
|
||||
// Nb. --config overrides command line flags
|
||||
glog.V(1).Infoln("loading configuration from the given file")
|
||||
|
||||
b, err := ioutil.ReadFile(cfgPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read config from %q [%v]", cfgPath, err)
|
||||
}
|
||||
runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(kubeadmapiv1alpha1.SchemeGroupVersion, kubeadmapiv1alpha2.SchemeGroupVersion), b, internalcfg)
|
||||
} else {
|
||||
// Takes passed flags into account; the defaulting is executed once again enforcing assignement of
|
||||
// static default values to cfg only for values not provided with flags
|
||||
kubeadmscheme.Scheme.Default(defaultversionedcfg)
|
||||
kubeadmscheme.Scheme.Convert(defaultversionedcfg, internalcfg, nil)
|
||||
}
|
||||
|
||||
// Applies dynamic defaults to settings not provided with flags
|
||||
if err := SetJoinDynamicDefaults(internalcfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Validates cfg (flags/configs + defaults)
|
||||
if err := validation.ValidateNodeConfiguration(internalcfg).ToAggregate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return internalcfg, nil
|
||||
}
|
108
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/nodeconfig_test.go
generated
vendored
Normal file
108
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/nodeconfig_test.go
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
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 config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha2"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
)
|
||||
|
||||
const (
|
||||
node_v1alpha1YAML = "testdata/conversion/node/v1alpha1.yaml"
|
||||
node_v1alpha2YAML = "testdata/conversion/node/v1alpha2.yaml"
|
||||
node_internalYAML = "testdata/conversion/node/internal.yaml"
|
||||
node_incompleteYAML = "testdata/defaulting/node/incomplete.yaml"
|
||||
node_defaultedYAML = "testdata/defaulting/node/defaulted.yaml"
|
||||
node_invalidYAML = "testdata/validation/invalid_nodecfg.yaml"
|
||||
)
|
||||
|
||||
func TestNodeConfigFileAndDefaultsToInternalConfig(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name, in, out string
|
||||
groupVersion schema.GroupVersion
|
||||
expectedErr bool
|
||||
}{
|
||||
// These tests are reading one file, loading it using NodeConfigFileAndDefaultsToInternalConfig that all of kubeadm is using for unmarshal of our API types,
|
||||
// and then marshals the internal object to the expected groupVersion
|
||||
{ // v1alpha1 -> internal
|
||||
name: "v1alpha1ToInternal",
|
||||
in: node_v1alpha1YAML,
|
||||
out: node_internalYAML,
|
||||
groupVersion: kubeadm.SchemeGroupVersion,
|
||||
},
|
||||
{ // v1alpha2 -> internal
|
||||
name: "v1alpha2ToInternal",
|
||||
in: node_v1alpha2YAML,
|
||||
out: node_internalYAML,
|
||||
groupVersion: kubeadm.SchemeGroupVersion,
|
||||
},
|
||||
{ // v1alpha1 -> internal -> v1alpha2
|
||||
name: "v1alpha1WithoutTypeMetaTov1alpha2",
|
||||
in: node_v1alpha1YAML,
|
||||
out: node_v1alpha2YAML,
|
||||
groupVersion: v1alpha2.SchemeGroupVersion,
|
||||
},
|
||||
// These tests are reading one file that has only a subset of the fields populated, loading it using NodeConfigFileAndDefaultsToInternalConfig,
|
||||
// and then marshals the internal object to the expected groupVersion
|
||||
{ // v1alpha1 -> default -> validate -> internal -> v1alpha2
|
||||
name: "incompleteYAMLToDefaulted",
|
||||
in: node_incompleteYAML,
|
||||
out: node_defaultedYAML,
|
||||
groupVersion: v1alpha2.SchemeGroupVersion,
|
||||
},
|
||||
{ // v1alpha1 (faulty) -> validation should fail
|
||||
name: "invalidYAMLShouldFail",
|
||||
in: node_invalidYAML,
|
||||
expectedErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t2 *testing.T) {
|
||||
|
||||
internalcfg, err := NodeConfigFileAndDefaultsToInternalConfig(rt.in, &v1alpha2.NodeConfiguration{})
|
||||
if err != nil {
|
||||
if rt.expectedErr {
|
||||
return
|
||||
}
|
||||
t2.Fatalf("couldn't unmarshal test data: %v", err)
|
||||
}
|
||||
|
||||
actual, err := kubeadmutil.MarshalToYamlForCodecs(internalcfg, rt.groupVersion, scheme.Codecs)
|
||||
if err != nil {
|
||||
t2.Fatalf("couldn't marshal internal object: %v", err)
|
||||
}
|
||||
|
||||
expected, err := ioutil.ReadFile(rt.out)
|
||||
if err != nil {
|
||||
t2.Fatalf("couldn't read test data: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(expected, actual) {
|
||||
t2.Errorf("the expected and actual output differs.\n\tin: %s\n\tout: %s\n\tgroupversion: %s\n\tdiff: \n%s\n",
|
||||
rt.in, rt.out, rt.groupVersion.String(), diff(expected, actual))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
161
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/conversion/master/internal.yaml
generated
vendored
Normal file
161
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/conversion/master/internal.yaml
generated
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
API:
|
||||
AdvertiseAddress: 192.168.2.2
|
||||
BindPort: 6443
|
||||
ControlPlaneEndpoint: ""
|
||||
APIServerCertSANs: null
|
||||
APIServerExtraArgs:
|
||||
authorization-mode: Node,RBAC,Webhook
|
||||
APIServerExtraVolumes: null
|
||||
AuditPolicyConfiguration:
|
||||
LogDir: /var/log/kubernetes/audit
|
||||
LogMaxAge: 2
|
||||
Path: ""
|
||||
BootstrapTokens:
|
||||
- Description: ""
|
||||
Expires: null
|
||||
Groups:
|
||||
- system:bootstrappers:kubeadm:default-node-token
|
||||
TTL: 24h0m0s
|
||||
Token: s73ybu.6tw6wnqgp5z0wb77
|
||||
Usages:
|
||||
- signing
|
||||
- authentication
|
||||
CIImageRepository: ""
|
||||
CertificatesDir: /etc/kubernetes/pki
|
||||
ClusterName: kubernetes
|
||||
ControllerManagerExtraArgs: null
|
||||
ControllerManagerExtraVolumes: null
|
||||
Etcd:
|
||||
External: null
|
||||
Local:
|
||||
DataDir: /var/lib/etcd
|
||||
ExtraArgs: null
|
||||
Image: ""
|
||||
PeerCertSANs: null
|
||||
ServerCertSANs: null
|
||||
FeatureGates: null
|
||||
ImageRepository: k8s.gcr.io
|
||||
KubeProxy:
|
||||
Config:
|
||||
bindAddress: 0.0.0.0
|
||||
clientConnection:
|
||||
acceptContentTypes: ""
|
||||
burst: 10
|
||||
contentType: application/vnd.kubernetes.protobuf
|
||||
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
|
||||
qps: 5
|
||||
clusterCIDR: ""
|
||||
configSyncPeriod: 15m0s
|
||||
conntrack:
|
||||
max: null
|
||||
maxPerCore: 32768
|
||||
min: 131072
|
||||
tcpCloseWaitTimeout: 1h0m0s
|
||||
tcpEstablishedTimeout: 24h0m0s
|
||||
enableProfiling: false
|
||||
featureGates:
|
||||
ServiceNodeExclusion: true
|
||||
SupportIPVSProxyMode: true
|
||||
healthzBindAddress: 0.0.0.0:10256
|
||||
hostnameOverride: ""
|
||||
iptables:
|
||||
masqueradeAll: false
|
||||
masqueradeBit: 14
|
||||
minSyncPeriod: 0s
|
||||
syncPeriod: 30s
|
||||
ipvs:
|
||||
excludeCIDRs: null
|
||||
minSyncPeriod: 0s
|
||||
scheduler: ""
|
||||
syncPeriod: 30s
|
||||
metricsBindAddress: 127.0.0.1:10249
|
||||
mode: ""
|
||||
nodePortAddresses: null
|
||||
oomScoreAdj: -999
|
||||
portRange: ""
|
||||
resourceContainer: /kube-proxy
|
||||
udpIdleTimeout: 250ms
|
||||
KubeletConfiguration:
|
||||
BaseConfig:
|
||||
address: 0.0.0.0
|
||||
authentication:
|
||||
anonymous:
|
||||
enabled: false
|
||||
webhook:
|
||||
cacheTTL: 2m0s
|
||||
enabled: true
|
||||
x509:
|
||||
clientCAFile: /etc/kubernetes/pki/ca.crt
|
||||
authorization:
|
||||
mode: Webhook
|
||||
webhook:
|
||||
cacheAuthorizedTTL: 5m0s
|
||||
cacheUnauthorizedTTL: 30s
|
||||
cgroupDriver: cgroupfs
|
||||
cgroupsPerQOS: true
|
||||
clusterDNS:
|
||||
- 10.96.0.10
|
||||
clusterDomain: cluster.local
|
||||
containerLogMaxFiles: 5
|
||||
containerLogMaxSize: 10Mi
|
||||
contentType: application/vnd.kubernetes.protobuf
|
||||
cpuCFSQuota: true
|
||||
cpuManagerPolicy: none
|
||||
cpuManagerReconcilePeriod: 10s
|
||||
enableControllerAttachDetach: true
|
||||
enableDebuggingHandlers: true
|
||||
enforceNodeAllocatable:
|
||||
- pods
|
||||
eventBurst: 10
|
||||
eventRecordQPS: 5
|
||||
evictionHard:
|
||||
imagefs.available: 15%
|
||||
memory.available: 100Mi
|
||||
nodefs.available: 10%
|
||||
nodefs.inodesFree: 5%
|
||||
evictionPressureTransitionPeriod: 5m0s
|
||||
failSwapOn: true
|
||||
fileCheckFrequency: 20s
|
||||
hairpinMode: promiscuous-bridge
|
||||
healthzBindAddress: 127.0.0.1
|
||||
healthzPort: 10248
|
||||
httpCheckFrequency: 20s
|
||||
imageGCHighThresholdPercent: 85
|
||||
imageGCLowThresholdPercent: 80
|
||||
imageMinimumGCAge: 2m0s
|
||||
iptablesDropBit: 15
|
||||
iptablesMasqueradeBit: 14
|
||||
kubeAPIBurst: 10
|
||||
kubeAPIQPS: 5
|
||||
makeIPTablesUtilChains: true
|
||||
maxOpenFiles: 1000000
|
||||
maxPods: 110
|
||||
nodeStatusUpdateFrequency: 10s
|
||||
oomScoreAdj: -999
|
||||
podPidsLimit: -1
|
||||
port: 10250
|
||||
registryBurst: 10
|
||||
registryPullQPS: 5
|
||||
resolvConf: /etc/resolv.conf
|
||||
rotateCertificates: true
|
||||
runtimeRequestTimeout: 2m0s
|
||||
serializeImagePulls: true
|
||||
staticPodPath: /etc/kubernetes/manifests
|
||||
streamingConnectionIdleTimeout: 4h0m0s
|
||||
syncFrequency: 1m0s
|
||||
volumeStatsAggPeriod: 1m0s
|
||||
KubernetesVersion: v1.10.2
|
||||
Networking:
|
||||
DNSDomain: cluster.local
|
||||
PodSubnet: ""
|
||||
ServiceSubnet: 10.96.0.0/12
|
||||
NodeRegistration:
|
||||
CRISocket: /var/run/dockershim.sock
|
||||
KubeletExtraArgs: null
|
||||
Name: master-1
|
||||
Taints:
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/master
|
||||
SchedulerExtraArgs: null
|
||||
SchedulerExtraVolumes: null
|
||||
UnifiedControlPlaneImage: ""
|
149
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/conversion/master/v1alpha1.yaml
generated
vendored
Normal file
149
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/conversion/master/v1alpha1.yaml
generated
vendored
Normal file
@ -0,0 +1,149 @@
|
||||
api:
|
||||
advertiseAddress: 192.168.2.2
|
||||
bindPort: 6443
|
||||
controlPlaneEndpoint: ""
|
||||
apiVersion: kubeadm.k8s.io/v1alpha1
|
||||
auditPolicy:
|
||||
logDir: /var/log/kubernetes/audit
|
||||
logMaxAge: 2
|
||||
path: ""
|
||||
authorizationModes:
|
||||
- Node
|
||||
- RBAC
|
||||
- Webhook
|
||||
certificatesDir: /etc/kubernetes/pki
|
||||
cloudProvider: ""
|
||||
clusterName: kubernetes
|
||||
criSocket: /var/run/dockershim.sock
|
||||
etcd:
|
||||
caFile: ""
|
||||
certFile: ""
|
||||
dataDir: /var/lib/etcd
|
||||
endpoints: null
|
||||
image: ""
|
||||
keyFile: ""
|
||||
imageRepository: k8s.gcr.io
|
||||
kind: MasterConfiguration
|
||||
kubeProxy:
|
||||
config:
|
||||
bindAddress: 0.0.0.0
|
||||
clientConnection:
|
||||
acceptContentTypes: ""
|
||||
burst: 10
|
||||
contentType: application/vnd.kubernetes.protobuf
|
||||
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
|
||||
qps: 5
|
||||
clusterCIDR: ""
|
||||
configSyncPeriod: 15m0s
|
||||
conntrack:
|
||||
max: null
|
||||
maxPerCore: 32768
|
||||
min: 131072
|
||||
tcpCloseWaitTimeout: 1h0m0s
|
||||
tcpEstablishedTimeout: 24h0m0s
|
||||
enableProfiling: false
|
||||
featureGates:
|
||||
ServiceNodeExclusion: true
|
||||
SupportIPVSProxyMode: true
|
||||
healthzBindAddress: 0.0.0.0:10256
|
||||
hostnameOverride: ""
|
||||
iptables:
|
||||
masqueradeAll: false
|
||||
masqueradeBit: 14
|
||||
minSyncPeriod: 0s
|
||||
syncPeriod: 30s
|
||||
ipvs:
|
||||
excludeCIDRs: null
|
||||
minSyncPeriod: 0s
|
||||
scheduler: ""
|
||||
syncPeriod: 30s
|
||||
metricsBindAddress: 127.0.0.1:10249
|
||||
mode: ""
|
||||
nodePortAddresses: null
|
||||
oomScoreAdj: -999
|
||||
portRange: ""
|
||||
resourceContainer: /kube-proxy
|
||||
udpIdleTimeout: 250ms
|
||||
kubeletConfiguration:
|
||||
baseConfig:
|
||||
address: 0.0.0.0
|
||||
authentication:
|
||||
anonymous:
|
||||
enabled: false
|
||||
webhook:
|
||||
cacheTTL: 2m0s
|
||||
enabled: true
|
||||
x509:
|
||||
clientCAFile: /etc/kubernetes/pki/ca.crt
|
||||
authorization:
|
||||
mode: Webhook
|
||||
webhook:
|
||||
cacheAuthorizedTTL: 5m0s
|
||||
cacheUnauthorizedTTL: 30s
|
||||
cgroupDriver: cgroupfs
|
||||
cgroupsPerQOS: true
|
||||
clusterDNS:
|
||||
- 10.96.0.10
|
||||
clusterDomain: cluster.local
|
||||
containerLogMaxFiles: 5
|
||||
containerLogMaxSize: 10Mi
|
||||
contentType: application/vnd.kubernetes.protobuf
|
||||
cpuCFSQuota: true
|
||||
cpuManagerPolicy: none
|
||||
cpuManagerReconcilePeriod: 10s
|
||||
enableControllerAttachDetach: true
|
||||
enableDebuggingHandlers: true
|
||||
enforceNodeAllocatable:
|
||||
- pods
|
||||
eventBurst: 10
|
||||
eventRecordQPS: 5
|
||||
evictionHard:
|
||||
imagefs.available: 15%
|
||||
memory.available: 100Mi
|
||||
nodefs.available: 10%
|
||||
nodefs.inodesFree: 5%
|
||||
evictionPressureTransitionPeriod: 5m0s
|
||||
failSwapOn: true
|
||||
fileCheckFrequency: 20s
|
||||
hairpinMode: promiscuous-bridge
|
||||
healthzBindAddress: 127.0.0.1
|
||||
healthzPort: 10248
|
||||
httpCheckFrequency: 20s
|
||||
imageGCHighThresholdPercent: 85
|
||||
imageGCLowThresholdPercent: 80
|
||||
imageMinimumGCAge: 2m0s
|
||||
iptablesDropBit: 15
|
||||
iptablesMasqueradeBit: 14
|
||||
kubeAPIBurst: 10
|
||||
kubeAPIQPS: 5
|
||||
makeIPTablesUtilChains: true
|
||||
maxOpenFiles: 1000000
|
||||
maxPods: 110
|
||||
nodeStatusUpdateFrequency: 10s
|
||||
oomScoreAdj: -999
|
||||
podPidsLimit: -1
|
||||
port: 10250
|
||||
registryBurst: 10
|
||||
registryPullQPS: 5
|
||||
resolvConf: /etc/resolv.conf
|
||||
runtimeRequestTimeout: 2m0s
|
||||
serializeImagePulls: true
|
||||
staticPodPath: /etc/kubernetes/manifests
|
||||
streamingConnectionIdleTimeout: 4h0m0s
|
||||
syncFrequency: 1m0s
|
||||
volumeStatsAggPeriod: 1m0s
|
||||
kubernetesVersion: v1.10.2
|
||||
networking:
|
||||
dnsDomain: cluster.local
|
||||
podSubnet: ""
|
||||
serviceSubnet: 10.96.0.0/12
|
||||
nodeName: master-1
|
||||
privilegedPods: false
|
||||
token: s73ybu.6tw6wnqgp5z0wb77
|
||||
tokenGroups:
|
||||
- system:bootstrappers:kubeadm:default-node-token
|
||||
tokenTTL: 24h0m0s
|
||||
tokenUsages:
|
||||
- signing
|
||||
- authentication
|
||||
unifiedControlPlaneImage: ""
|
146
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/conversion/master/v1alpha1_without_TypeMeta.yaml
generated
vendored
Normal file
146
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/conversion/master/v1alpha1_without_TypeMeta.yaml
generated
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
# This file don't have TypeMeta set. kubeadm should then unmarshal it as a apiVersion=kubeadm.k8s.io/v1alpha1 and kind=MasterConfiguration
|
||||
api:
|
||||
advertiseAddress: 192.168.2.2
|
||||
bindPort: 6443
|
||||
controlPlaneEndpoint: ""
|
||||
auditPolicy:
|
||||
logDir: /var/log/kubernetes/audit
|
||||
logMaxAge: 2
|
||||
path: ""
|
||||
authorizationModes:
|
||||
- Node
|
||||
- RBAC
|
||||
- Webhook
|
||||
certificatesDir: /etc/kubernetes/pki
|
||||
cloudProvider: ""
|
||||
clusterName: kubernetes
|
||||
criSocket: /var/run/dockershim.sock
|
||||
etcd:
|
||||
caFile: ""
|
||||
certFile: ""
|
||||
dataDir: /var/lib/etcd
|
||||
endpoints: null
|
||||
image: ""
|
||||
keyFile: ""
|
||||
imageRepository: k8s.gcr.io
|
||||
kubeProxy:
|
||||
config:
|
||||
bindAddress: 0.0.0.0
|
||||
clientConnection:
|
||||
acceptContentTypes: ""
|
||||
burst: 10
|
||||
contentType: application/vnd.kubernetes.protobuf
|
||||
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
|
||||
qps: 5
|
||||
clusterCIDR: ""
|
||||
configSyncPeriod: 15m0s
|
||||
conntrack:
|
||||
max: null
|
||||
maxPerCore: 32768
|
||||
min: 131072
|
||||
tcpCloseWaitTimeout: 1h0m0s
|
||||
tcpEstablishedTimeout: 24h0m0s
|
||||
enableProfiling: false
|
||||
featureGates: "SupportIPVSProxyMode=true,ServiceNodeExclusion=true"
|
||||
healthzBindAddress: 0.0.0.0:10256
|
||||
hostnameOverride: ""
|
||||
iptables:
|
||||
masqueradeAll: false
|
||||
masqueradeBit: 14
|
||||
minSyncPeriod: 0s
|
||||
syncPeriod: 30s
|
||||
ipvs:
|
||||
excludeCIDRs: null
|
||||
minSyncPeriod: 0s
|
||||
scheduler: ""
|
||||
syncPeriod: 30s
|
||||
metricsBindAddress: 127.0.0.1:10249
|
||||
mode: ""
|
||||
nodePortAddresses: null
|
||||
oomScoreAdj: -999
|
||||
portRange: ""
|
||||
resourceContainer: /kube-proxy
|
||||
udpIdleTimeout: 250ms
|
||||
kubeletConfiguration:
|
||||
baseConfig:
|
||||
address: 0.0.0.0
|
||||
authentication:
|
||||
anonymous:
|
||||
enabled: false
|
||||
webhook:
|
||||
cacheTTL: 2m0s
|
||||
enabled: true
|
||||
x509:
|
||||
clientCAFile: /etc/kubernetes/pki/ca.crt
|
||||
authorization:
|
||||
mode: Webhook
|
||||
webhook:
|
||||
cacheAuthorizedTTL: 5m0s
|
||||
cacheUnauthorizedTTL: 30s
|
||||
cgroupDriver: cgroupfs
|
||||
cgroupsPerQOS: true
|
||||
clusterDNS:
|
||||
- 10.96.0.10
|
||||
clusterDomain: cluster.local
|
||||
containerLogMaxFiles: 5
|
||||
containerLogMaxSize: 10Mi
|
||||
contentType: application/vnd.kubernetes.protobuf
|
||||
cpuCFSQuota: true
|
||||
cpuManagerPolicy: none
|
||||
cpuManagerReconcilePeriod: 10s
|
||||
enableControllerAttachDetach: true
|
||||
enableDebuggingHandlers: true
|
||||
enforceNodeAllocatable:
|
||||
- pods
|
||||
eventBurst: 10
|
||||
eventRecordQPS: 5
|
||||
evictionHard:
|
||||
imagefs.available: 15%
|
||||
memory.available: 100Mi
|
||||
nodefs.available: 10%
|
||||
nodefs.inodesFree: 5%
|
||||
evictionPressureTransitionPeriod: 5m0s
|
||||
failSwapOn: true
|
||||
fileCheckFrequency: 20s
|
||||
hairpinMode: promiscuous-bridge
|
||||
healthzBindAddress: 127.0.0.1
|
||||
healthzPort: 10248
|
||||
httpCheckFrequency: 20s
|
||||
imageGCHighThresholdPercent: 85
|
||||
imageGCLowThresholdPercent: 80
|
||||
imageMinimumGCAge: 2m0s
|
||||
iptablesDropBit: 15
|
||||
iptablesMasqueradeBit: 14
|
||||
kubeAPIBurst: 10
|
||||
kubeAPIQPS: 5
|
||||
makeIPTablesUtilChains: true
|
||||
maxOpenFiles: 1000000
|
||||
maxPods: 110
|
||||
nodeStatusUpdateFrequency: 10s
|
||||
oomScoreAdj: -999
|
||||
podPidsLimit: -1
|
||||
port: 10250
|
||||
registryBurst: 10
|
||||
registryPullQPS: 5
|
||||
resolvConf: /etc/resolv.conf
|
||||
runtimeRequestTimeout: 2m0s
|
||||
serializeImagePulls: true
|
||||
staticPodPath: /etc/kubernetes/manifests
|
||||
streamingConnectionIdleTimeout: 4h0m0s
|
||||
syncFrequency: 1m0s
|
||||
volumeStatsAggPeriod: 1m0s
|
||||
kubernetesVersion: v1.10.2
|
||||
networking:
|
||||
dnsDomain: cluster.local
|
||||
podSubnet: ""
|
||||
serviceSubnet: 10.96.0.0/12
|
||||
nodeName: master-1
|
||||
privilegedPods: false
|
||||
token: s73ybu.6tw6wnqgp5z0wb77
|
||||
tokenGroups:
|
||||
- system:bootstrappers:kubeadm:default-node-token
|
||||
tokenTTL: 24h0m0s
|
||||
tokenUsages:
|
||||
- signing
|
||||
- authentication
|
||||
unifiedControlPlaneImage: ""
|
148
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/conversion/master/v1alpha2.yaml
generated
vendored
Normal file
148
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/conversion/master/v1alpha2.yaml
generated
vendored
Normal file
@ -0,0 +1,148 @@
|
||||
api:
|
||||
advertiseAddress: 192.168.2.2
|
||||
bindPort: 6443
|
||||
controlPlaneEndpoint: ""
|
||||
apiServerExtraArgs:
|
||||
authorization-mode: Node,RBAC,Webhook
|
||||
apiVersion: kubeadm.k8s.io/v1alpha2
|
||||
auditPolicy:
|
||||
logDir: /var/log/kubernetes/audit
|
||||
logMaxAge: 2
|
||||
path: ""
|
||||
bootstrapTokens:
|
||||
- groups:
|
||||
- system:bootstrappers:kubeadm:default-node-token
|
||||
token: s73ybu.6tw6wnqgp5z0wb77
|
||||
ttl: 24h0m0s
|
||||
usages:
|
||||
- signing
|
||||
- authentication
|
||||
certificatesDir: /etc/kubernetes/pki
|
||||
clusterName: kubernetes
|
||||
etcd:
|
||||
local:
|
||||
dataDir: /var/lib/etcd
|
||||
image: ""
|
||||
imageRepository: k8s.gcr.io
|
||||
kind: MasterConfiguration
|
||||
kubeProxy:
|
||||
config:
|
||||
bindAddress: 0.0.0.0
|
||||
clientConnection:
|
||||
acceptContentTypes: ""
|
||||
burst: 10
|
||||
contentType: application/vnd.kubernetes.protobuf
|
||||
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
|
||||
qps: 5
|
||||
clusterCIDR: ""
|
||||
configSyncPeriod: 15m0s
|
||||
conntrack:
|
||||
max: null
|
||||
maxPerCore: 32768
|
||||
min: 131072
|
||||
tcpCloseWaitTimeout: 1h0m0s
|
||||
tcpEstablishedTimeout: 24h0m0s
|
||||
enableProfiling: false
|
||||
featureGates:
|
||||
ServiceNodeExclusion: true
|
||||
SupportIPVSProxyMode: true
|
||||
healthzBindAddress: 0.0.0.0:10256
|
||||
hostnameOverride: ""
|
||||
iptables:
|
||||
masqueradeAll: false
|
||||
masqueradeBit: 14
|
||||
minSyncPeriod: 0s
|
||||
syncPeriod: 30s
|
||||
ipvs:
|
||||
excludeCIDRs: null
|
||||
minSyncPeriod: 0s
|
||||
scheduler: ""
|
||||
syncPeriod: 30s
|
||||
metricsBindAddress: 127.0.0.1:10249
|
||||
mode: ""
|
||||
nodePortAddresses: null
|
||||
oomScoreAdj: -999
|
||||
portRange: ""
|
||||
resourceContainer: /kube-proxy
|
||||
udpIdleTimeout: 250ms
|
||||
kubeletConfiguration:
|
||||
baseConfig:
|
||||
address: 0.0.0.0
|
||||
authentication:
|
||||
anonymous:
|
||||
enabled: false
|
||||
webhook:
|
||||
cacheTTL: 2m0s
|
||||
enabled: true
|
||||
x509:
|
||||
clientCAFile: /etc/kubernetes/pki/ca.crt
|
||||
authorization:
|
||||
mode: Webhook
|
||||
webhook:
|
||||
cacheAuthorizedTTL: 5m0s
|
||||
cacheUnauthorizedTTL: 30s
|
||||
cgroupDriver: cgroupfs
|
||||
cgroupsPerQOS: true
|
||||
clusterDNS:
|
||||
- 10.96.0.10
|
||||
clusterDomain: cluster.local
|
||||
containerLogMaxFiles: 5
|
||||
containerLogMaxSize: 10Mi
|
||||
contentType: application/vnd.kubernetes.protobuf
|
||||
cpuCFSQuota: true
|
||||
cpuManagerPolicy: none
|
||||
cpuManagerReconcilePeriod: 10s
|
||||
enableControllerAttachDetach: true
|
||||
enableDebuggingHandlers: true
|
||||
enforceNodeAllocatable:
|
||||
- pods
|
||||
eventBurst: 10
|
||||
eventRecordQPS: 5
|
||||
evictionHard:
|
||||
imagefs.available: 15%
|
||||
memory.available: 100Mi
|
||||
nodefs.available: 10%
|
||||
nodefs.inodesFree: 5%
|
||||
evictionPressureTransitionPeriod: 5m0s
|
||||
failSwapOn: true
|
||||
fileCheckFrequency: 20s
|
||||
hairpinMode: promiscuous-bridge
|
||||
healthzBindAddress: 127.0.0.1
|
||||
healthzPort: 10248
|
||||
httpCheckFrequency: 20s
|
||||
imageGCHighThresholdPercent: 85
|
||||
imageGCLowThresholdPercent: 80
|
||||
imageMinimumGCAge: 2m0s
|
||||
iptablesDropBit: 15
|
||||
iptablesMasqueradeBit: 14
|
||||
kubeAPIBurst: 10
|
||||
kubeAPIQPS: 5
|
||||
makeIPTablesUtilChains: true
|
||||
maxOpenFiles: 1000000
|
||||
maxPods: 110
|
||||
nodeStatusUpdateFrequency: 10s
|
||||
oomScoreAdj: -999
|
||||
podPidsLimit: -1
|
||||
port: 10250
|
||||
registryBurst: 10
|
||||
registryPullQPS: 5
|
||||
resolvConf: /etc/resolv.conf
|
||||
rotateCertificates: true
|
||||
runtimeRequestTimeout: 2m0s
|
||||
serializeImagePulls: true
|
||||
staticPodPath: /etc/kubernetes/manifests
|
||||
streamingConnectionIdleTimeout: 4h0m0s
|
||||
syncFrequency: 1m0s
|
||||
volumeStatsAggPeriod: 1m0s
|
||||
kubernetesVersion: v1.10.2
|
||||
networking:
|
||||
dnsDomain: cluster.local
|
||||
podSubnet: ""
|
||||
serviceSubnet: 10.96.0.0/12
|
||||
nodeRegistration:
|
||||
criSocket: /var/run/dockershim.sock
|
||||
name: master-1
|
||||
taints:
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/master
|
||||
unifiedControlPlaneImage: ""
|
17
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/conversion/node/internal.yaml
generated
vendored
Normal file
17
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/conversion/node/internal.yaml
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
CACertPath: /etc/kubernetes/pki/ca.crt
|
||||
ClusterName: kubernetes
|
||||
DiscoveryFile: ""
|
||||
DiscoveryTimeout: 5m0s
|
||||
DiscoveryToken: abcdef.0123456789abcdef
|
||||
DiscoveryTokenAPIServers:
|
||||
- kube-apiserver:6443
|
||||
DiscoveryTokenCACertHashes: null
|
||||
DiscoveryTokenUnsafeSkipCAVerification: true
|
||||
FeatureGates: null
|
||||
NodeRegistration:
|
||||
CRISocket: /var/run/dockershim.sock
|
||||
KubeletExtraArgs: null
|
||||
Name: master-1
|
||||
Taints: null
|
||||
TLSBootstrapToken: abcdef.0123456789abcdef
|
||||
Token: abcdef.0123456789abcdef
|
14
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/conversion/node/v1alpha1.yaml
generated
vendored
Normal file
14
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/conversion/node/v1alpha1.yaml
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
apiVersion: kubeadm.k8s.io/v1alpha1
|
||||
kind: NodeConfiguration
|
||||
caCertPath: /etc/kubernetes/pki/ca.crt
|
||||
clusterName: kubernetes
|
||||
criSocket: /var/run/dockershim.sock
|
||||
discoveryFile: ""
|
||||
discoveryTimeout: 5m0s
|
||||
discoveryToken: abcdef.0123456789abcdef
|
||||
discoveryTokenAPIServers:
|
||||
- kube-apiserver:6443
|
||||
discoveryTokenUnsafeSkipCAVerification: true
|
||||
nodeName: master-1
|
||||
tlsBootstrapToken: abcdef.0123456789abcdef
|
||||
token: abcdef.0123456789abcdef
|
15
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/conversion/node/v1alpha2.yaml
generated
vendored
Normal file
15
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/conversion/node/v1alpha2.yaml
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
apiVersion: kubeadm.k8s.io/v1alpha2
|
||||
caCertPath: /etc/kubernetes/pki/ca.crt
|
||||
clusterName: kubernetes
|
||||
discoveryFile: ""
|
||||
discoveryTimeout: 5m0s
|
||||
discoveryToken: abcdef.0123456789abcdef
|
||||
discoveryTokenAPIServers:
|
||||
- kube-apiserver:6443
|
||||
discoveryTokenUnsafeSkipCAVerification: true
|
||||
kind: NodeConfiguration
|
||||
nodeRegistration:
|
||||
criSocket: /var/run/dockershim.sock
|
||||
name: master-1
|
||||
tlsBootstrapToken: abcdef.0123456789abcdef
|
||||
token: abcdef.0123456789abcdef
|
143
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/defaulting/master/defaulted.yaml
generated
vendored
Normal file
143
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/defaulting/master/defaulted.yaml
generated
vendored
Normal file
@ -0,0 +1,143 @@
|
||||
api:
|
||||
advertiseAddress: 192.168.2.2
|
||||
bindPort: 6443
|
||||
controlPlaneEndpoint: ""
|
||||
apiVersion: kubeadm.k8s.io/v1alpha2
|
||||
auditPolicy:
|
||||
logDir: /var/log/kubernetes/audit
|
||||
logMaxAge: 2
|
||||
path: ""
|
||||
bootstrapTokens:
|
||||
- groups:
|
||||
- system:bootstrappers:kubeadm:default-node-token
|
||||
token: s73ybu.6tw6wnqgp5z0wb77
|
||||
ttl: 24h0m0s
|
||||
usages:
|
||||
- signing
|
||||
- authentication
|
||||
certificatesDir: /var/lib/kubernetes/pki
|
||||
clusterName: kubernetes
|
||||
etcd:
|
||||
local:
|
||||
dataDir: /var/lib/etcd
|
||||
image: ""
|
||||
imageRepository: my-company.com
|
||||
kind: MasterConfiguration
|
||||
kubeProxy:
|
||||
config:
|
||||
bindAddress: 0.0.0.0
|
||||
clientConnection:
|
||||
acceptContentTypes: ""
|
||||
burst: 10
|
||||
contentType: application/vnd.kubernetes.protobuf
|
||||
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
|
||||
qps: 5
|
||||
clusterCIDR: ""
|
||||
configSyncPeriod: 15m0s
|
||||
conntrack:
|
||||
max: null
|
||||
maxPerCore: 32768
|
||||
min: 131072
|
||||
tcpCloseWaitTimeout: 1h0m0s
|
||||
tcpEstablishedTimeout: 24h0m0s
|
||||
enableProfiling: false
|
||||
healthzBindAddress: 0.0.0.0:10256
|
||||
hostnameOverride: ""
|
||||
iptables:
|
||||
masqueradeAll: false
|
||||
masqueradeBit: 14
|
||||
minSyncPeriod: 0s
|
||||
syncPeriod: 30s
|
||||
ipvs:
|
||||
excludeCIDRs: null
|
||||
minSyncPeriod: 0s
|
||||
scheduler: ""
|
||||
syncPeriod: 30s
|
||||
metricsBindAddress: 127.0.0.1:10249
|
||||
mode: ""
|
||||
nodePortAddresses: null
|
||||
oomScoreAdj: -999
|
||||
portRange: ""
|
||||
resourceContainer: /kube-proxy
|
||||
udpIdleTimeout: 250ms
|
||||
kubeletConfiguration:
|
||||
baseConfig:
|
||||
address: 0.0.0.0
|
||||
authentication:
|
||||
anonymous:
|
||||
enabled: false
|
||||
webhook:
|
||||
cacheTTL: 2m0s
|
||||
enabled: true
|
||||
x509:
|
||||
clientCAFile: /etc/kubernetes/pki/ca.crt
|
||||
authorization:
|
||||
mode: Webhook
|
||||
webhook:
|
||||
cacheAuthorizedTTL: 5m0s
|
||||
cacheUnauthorizedTTL: 30s
|
||||
cgroupDriver: cgroupfs
|
||||
cgroupsPerQOS: true
|
||||
clusterDNS:
|
||||
- 10.192.0.10
|
||||
clusterDomain: cluster.global
|
||||
containerLogMaxFiles: 5
|
||||
containerLogMaxSize: 10Mi
|
||||
contentType: application/vnd.kubernetes.protobuf
|
||||
cpuCFSQuota: true
|
||||
cpuManagerPolicy: none
|
||||
cpuManagerReconcilePeriod: 10s
|
||||
enableControllerAttachDetach: true
|
||||
enableDebuggingHandlers: true
|
||||
enforceNodeAllocatable:
|
||||
- pods
|
||||
eventBurst: 10
|
||||
eventRecordQPS: 5
|
||||
evictionHard:
|
||||
imagefs.available: 15%
|
||||
memory.available: 100Mi
|
||||
nodefs.available: 10%
|
||||
nodefs.inodesFree: 5%
|
||||
evictionPressureTransitionPeriod: 5m0s
|
||||
failSwapOn: true
|
||||
fileCheckFrequency: 20s
|
||||
hairpinMode: promiscuous-bridge
|
||||
healthzBindAddress: 127.0.0.1
|
||||
healthzPort: 10248
|
||||
httpCheckFrequency: 20s
|
||||
imageGCHighThresholdPercent: 85
|
||||
imageGCLowThresholdPercent: 80
|
||||
imageMinimumGCAge: 2m0s
|
||||
iptablesDropBit: 15
|
||||
iptablesMasqueradeBit: 14
|
||||
kubeAPIBurst: 10
|
||||
kubeAPIQPS: 5
|
||||
makeIPTablesUtilChains: true
|
||||
maxOpenFiles: 1000000
|
||||
maxPods: 110
|
||||
nodeStatusUpdateFrequency: 10s
|
||||
oomScoreAdj: -999
|
||||
podPidsLimit: -1
|
||||
port: 10250
|
||||
registryBurst: 10
|
||||
registryPullQPS: 5
|
||||
resolvConf: /etc/resolv.conf
|
||||
rotateCertificates: true
|
||||
runtimeRequestTimeout: 2m0s
|
||||
serializeImagePulls: true
|
||||
staticPodPath: /etc/kubernetes/manifests
|
||||
streamingConnectionIdleTimeout: 4h0m0s
|
||||
syncFrequency: 1m0s
|
||||
volumeStatsAggPeriod: 1m0s
|
||||
kubernetesVersion: v1.10.2
|
||||
networking:
|
||||
dnsDomain: cluster.global
|
||||
podSubnet: ""
|
||||
serviceSubnet: 10.196.0.0/12
|
||||
nodeRegistration:
|
||||
criSocket: /var/run/criruntime.sock
|
||||
name: master-1
|
||||
taints:
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/master
|
||||
unifiedControlPlaneImage: ""
|
15
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/defaulting/master/incomplete.yaml
generated
vendored
Normal file
15
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/defaulting/master/incomplete.yaml
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
# This file _should_ set TypeMeta, but at some point earlier we supported deserializing MasterConfigurations without TypeMeta, so we need to support that as long as we
|
||||
# support the v1alpha1 API. In the meantime kubeadm will treat this as v1alpha1 automatically when unmarshalling.
|
||||
api:
|
||||
advertiseAddress: 192.168.2.2
|
||||
bindPort: 6443
|
||||
certificatesDir: /var/lib/kubernetes/pki
|
||||
clusterName: kubernetes
|
||||
criSocket: /var/run/criruntime.sock
|
||||
imageRepository: my-company.com
|
||||
kubernetesVersion: v1.10.2
|
||||
networking:
|
||||
dnsDomain: cluster.global
|
||||
serviceSubnet: 10.196.0.0/12
|
||||
nodeName: master-1
|
||||
token: s73ybu.6tw6wnqgp5z0wb77
|
15
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/defaulting/node/defaulted.yaml
generated
vendored
Normal file
15
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/defaulting/node/defaulted.yaml
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
apiVersion: kubeadm.k8s.io/v1alpha2
|
||||
caCertPath: /etc/kubernetes/pki/ca.crt
|
||||
clusterName: kubernetes
|
||||
discoveryFile: ""
|
||||
discoveryTimeout: 5m0s
|
||||
discoveryToken: abcdef.0123456789abcdef
|
||||
discoveryTokenAPIServers:
|
||||
- kube-apiserver:6443
|
||||
discoveryTokenUnsafeSkipCAVerification: true
|
||||
kind: NodeConfiguration
|
||||
nodeRegistration:
|
||||
criSocket: /var/run/dockershim.sock
|
||||
name: thegopher
|
||||
tlsBootstrapToken: abcdef.0123456789abcdef
|
||||
token: abcdef.0123456789abcdef
|
7
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/defaulting/node/incomplete.yaml
generated
vendored
Normal file
7
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/defaulting/node/incomplete.yaml
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
apiVersion: kubeadm.k8s.io/v1alpha1
|
||||
kind: NodeConfiguration
|
||||
discoveryTokenAPIServers:
|
||||
- kube-apiserver:6443
|
||||
discoveryTokenUnsafeSkipCAVerification: true
|
||||
nodeName: thegopher
|
||||
token: abcdef.0123456789abcdef
|
73
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/v1alpha1_upgrade/after.yaml
generated
vendored
Normal file
73
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/v1alpha1_upgrade/after.yaml
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
api:
|
||||
advertiseAddress: 172.31.93.180
|
||||
bindPort: 6443
|
||||
controlPlaneEndpoint: ""
|
||||
apiVersion: kubeadm.k8s.io/v1alpha1
|
||||
auditPolicy:
|
||||
logDir: ""
|
||||
path: ""
|
||||
authorizationModes:
|
||||
- Node
|
||||
- RBAC
|
||||
certificatesDir: /etc/kubernetes/pki
|
||||
cloudProvider: aws
|
||||
etcd:
|
||||
caFile: ""
|
||||
certFile: ""
|
||||
dataDir: /var/lib/etcd
|
||||
endpoints: null
|
||||
image: ""
|
||||
keyFile: ""
|
||||
imageRepository: gcr.io/google_containers
|
||||
kind: MasterConfiguration
|
||||
kubeProxy:
|
||||
config:
|
||||
bindAddress: 0.0.0.0
|
||||
clientConnection:
|
||||
acceptContentTypes: ""
|
||||
burst: 10
|
||||
contentType: application/vnd.kubernetes.protobuf
|
||||
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
|
||||
qps: 5
|
||||
clusterCIDR: 192.168.0.0/16
|
||||
configSyncPeriod: 15m0s
|
||||
conntrack:
|
||||
max: null
|
||||
maxPerCore: 32768
|
||||
min: 131072
|
||||
tcpCloseWaitTimeout: 1h0m0s
|
||||
tcpEstablishedTimeout: 24h0m0s
|
||||
enableProfiling: false
|
||||
featureGates:
|
||||
ServiceNodeExclusion: true
|
||||
SupportIPVSProxyMode: true
|
||||
healthzBindAddress: 0.0.0.0:10256
|
||||
hostnameOverride: ""
|
||||
iptables:
|
||||
masqueradeAll: false
|
||||
masqueradeBit: 14
|
||||
minSyncPeriod: 0s
|
||||
syncPeriod: 30s
|
||||
ipvs:
|
||||
excludeCIDRs: null
|
||||
minSyncPeriod: 0s
|
||||
scheduler: ""
|
||||
syncPeriod: 30s
|
||||
metricsBindAddress: 127.0.0.1:10249
|
||||
mode: ""
|
||||
nodePortAddresses: null
|
||||
oomScoreAdj: -999
|
||||
portRange: ""
|
||||
resourceContainer: /kube-proxy
|
||||
udpIdleTimeout: 0s
|
||||
kubeletConfiguration: {}
|
||||
kubernetesVersion: v1.9.6
|
||||
networking:
|
||||
dnsDomain: cluster.local
|
||||
podSubnet: 192.168.0.0/16
|
||||
serviceSubnet: 10.96.0.0/12
|
||||
nodeName: ip-172-31-93-180.ec2.internal
|
||||
privilegedPods: false
|
||||
token: 8d69af.cd3e1c58f6228dfc
|
||||
tokenTTL: 24h0m0s
|
||||
unifiedControlPlaneImage: ""
|
64
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/v1alpha1_upgrade/before.yaml
generated
vendored
Normal file
64
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/v1alpha1_upgrade/before.yaml
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
# This MasterConfiguration object is wrong in two ways: it hasn't TypeMeta set, and .kubeProxy.config.featureGates is a string as it was in v1.9
|
||||
# In v1.10 however, it changed in an inbackwards-compatible way to a map[string]string, so we have to workaround that to unmarshal this object
|
||||
api:
|
||||
advertiseAddress: 172.31.93.180
|
||||
bindPort: 6443
|
||||
authorizationModes:
|
||||
- Node
|
||||
- RBAC
|
||||
certificatesDir: /etc/kubernetes/pki
|
||||
cloudProvider: aws
|
||||
etcd:
|
||||
caFile: ""
|
||||
certFile: ""
|
||||
dataDir: /var/lib/etcd
|
||||
endpoints: null
|
||||
image: ""
|
||||
keyFile: ""
|
||||
imageRepository: gcr.io/google_containers
|
||||
kubeProxy:
|
||||
config:
|
||||
bindAddress: 0.0.0.0
|
||||
clientConnection:
|
||||
acceptContentTypes: ""
|
||||
burst: 10
|
||||
contentType: application/vnd.kubernetes.protobuf
|
||||
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
|
||||
qps: 5
|
||||
clusterCIDR: 192.168.0.0/16
|
||||
configSyncPeriod: 15m0s
|
||||
conntrack:
|
||||
max: null
|
||||
maxPerCore: 32768
|
||||
min: 131072
|
||||
tcpCloseWaitTimeout: 1h0m0s
|
||||
tcpEstablishedTimeout: 24h0m0s
|
||||
enableProfiling: false
|
||||
featureGates: "SupportIPVSProxyMode=true,ServiceNodeExclusion=true"
|
||||
healthzBindAddress: 0.0.0.0:10256
|
||||
hostnameOverride: ""
|
||||
iptables:
|
||||
masqueradeAll: false
|
||||
masqueradeBit: 14
|
||||
minSyncPeriod: 0s
|
||||
syncPeriod: 30s
|
||||
ipvs:
|
||||
minSyncPeriod: 0s
|
||||
scheduler: ""
|
||||
syncPeriod: 30s
|
||||
metricsBindAddress: 127.0.0.1:10249
|
||||
mode: ""
|
||||
oomScoreAdj: -999
|
||||
portRange: ""
|
||||
resourceContainer: /kube-proxy
|
||||
udpTimeoutMilliseconds: 250ms
|
||||
kubeletConfiguration: {}
|
||||
kubernetesVersion: v1.9.6
|
||||
networking:
|
||||
dnsDomain: cluster.local
|
||||
podSubnet: 192.168.0.0/16
|
||||
serviceSubnet: 10.96.0.0/12
|
||||
nodeName: ip-172-31-93-180.ec2.internal
|
||||
token: 8d69af.cd3e1c58f6228dfc
|
||||
tokenTTL: 24h0m0s
|
||||
unifiedControlPlaneImage: ""
|
12
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/validation/invalid_mastercfg.yaml
generated
vendored
Normal file
12
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/validation/invalid_mastercfg.yaml
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
api:
|
||||
bindPort: 0
|
||||
certificatesDir: relativepath
|
||||
clusterName: kubernetes
|
||||
criSocket: relativepath
|
||||
imageRepository: my-company.com
|
||||
kubernetesVersion: v1.10.2
|
||||
networking:
|
||||
dnsDomain: cluster.GLOBAL
|
||||
serviceSubnet: 10.196.1000.0/100
|
||||
nodeName: MASTER
|
||||
token: s7bu.6tw6wn
|
11
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/validation/invalid_nodecfg.yaml
generated
vendored
Normal file
11
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/validation/invalid_nodecfg.yaml
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
apiVersion: kubeadm.k8s.io/v1alpha1
|
||||
kind: NodeConfiguration
|
||||
caCertPath: relativepath
|
||||
criSocket: relativepath
|
||||
discoveryFile: relativepath
|
||||
discoveryTimeout: not-a-time
|
||||
discoveryTokenAPIServers:
|
||||
- INVALID_URL
|
||||
discoveryTokenUnsafeSkipCAVerification: false
|
||||
nodeName: NODE-1
|
||||
token: invalidtoken
|
19
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/dryrun/dryrun.go
generated
vendored
19
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/dryrun/dryrun.go
generated
vendored
@ -20,6 +20,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@ -43,6 +44,13 @@ func NewFileToPrint(realPath, printPath string) FileToPrint {
|
||||
}
|
||||
}
|
||||
|
||||
// PrintDryRunFile is a helper method around PrintDryRunFiles
|
||||
func PrintDryRunFile(fileName, realDir, printDir string, w io.Writer) error {
|
||||
return PrintDryRunFiles([]FileToPrint{
|
||||
NewFileToPrint(filepath.Join(realDir, fileName), filepath.Join(printDir, fileName)),
|
||||
}, w)
|
||||
}
|
||||
|
||||
// PrintDryRunFiles prints the contents of the FileToPrints given to it to the writer w
|
||||
func PrintDryRunFiles(files []FileToPrint, w io.Writer) error {
|
||||
errs := []error{}
|
||||
@ -81,7 +89,7 @@ func NewWaiter() apiclient.Waiter {
|
||||
|
||||
// WaitForAPI just returns a dummy nil, to indicate that the program should just proceed
|
||||
func (w *Waiter) WaitForAPI() error {
|
||||
fmt.Println("[dryrun] Would wait for the API Server's /healthz endpoint to return 'ok'")
|
||||
fmt.Println("[dryrun] Would wait for the API Server's /healthz endpoint to return 'ok'")
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -99,15 +107,14 @@ func (w *Waiter) WaitForPodToDisappear(podName string) error {
|
||||
|
||||
// WaitForHealthyKubelet blocks until the kubelet /healthz endpoint returns 'ok'
|
||||
func (w *Waiter) WaitForHealthyKubelet(_ time.Duration, healthzEndpoint string) error {
|
||||
fmt.Printf("[dryrun] Would make sure the kubelet %q endpoint is healthy\n", healthzEndpoint)
|
||||
fmt.Printf("[dryrun] Would make sure the kubelet %q endpoint is healthy\n", healthzEndpoint)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetTimeout is a no-op; we don't wait in this implementation
|
||||
func (w *Waiter) SetTimeout(_ time.Duration) {}
|
||||
|
||||
// WaitForStaticPodControlPlaneHashes returns an empty hash for all control plane images; WaitForStaticPodControlPlaneHashChange won't block in any case
|
||||
// but the empty strings there are needed
|
||||
// WaitForStaticPodControlPlaneHashes returns an empty hash for all control plane images;
|
||||
func (w *Waiter) WaitForStaticPodControlPlaneHashes(_ string) (map[string]string, error) {
|
||||
return map[string]string{
|
||||
constants.KubeAPIServer: "",
|
||||
@ -122,7 +129,7 @@ func (w *Waiter) WaitForStaticPodSingleHash(_ string, _ string) (string, error)
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// WaitForStaticPodControlPlaneHashChange returns a dummy nil error in order for the flow to just continue as we're dryrunning
|
||||
func (w *Waiter) WaitForStaticPodControlPlaneHashChange(_, _, _ string) error {
|
||||
// WaitForStaticPodHashChange returns a dummy nil error in order for the flow to just continue as we're dryrunning
|
||||
func (w *Waiter) WaitForStaticPodHashChange(_, _, _ string) error {
|
||||
return nil
|
||||
}
|
||||
|
112
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/endpoint.go
generated
vendored
112
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/endpoint.go
generated
vendored
@ -19,45 +19,101 @@ package util
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
)
|
||||
|
||||
// GetMasterEndpoint returns a properly formatted Master Endpoint
|
||||
// or passes the error from GetMasterHostPort.
|
||||
func GetMasterEndpoint(cfg *kubeadmapi.MasterConfiguration) (string, error) {
|
||||
|
||||
hostPort, err := GetMasterHostPort(cfg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
// GetMasterEndpoint returns a properly formatted endpoint for the control plane built according following rules:
|
||||
// - If the api.ControlPlaneEndpoint is defined, use it.
|
||||
// - if the api.ControlPlaneEndpoint is defined but without a port number, use the api.ControlPlaneEndpoint + api.BindPort is used.
|
||||
// - Otherwise, in case the api.ControlPlaneEndpoint is not defined, use the api.AdvertiseAddress + the api.BindPort.
|
||||
func GetMasterEndpoint(api *kubeadmapi.API) (string, error) {
|
||||
// parse the bind port
|
||||
var bindPort = strconv.Itoa(int(api.BindPort))
|
||||
if _, err := parsePort(bindPort); err != nil {
|
||||
return "", fmt.Errorf("invalid value %q given for api.bindPort: %s", api.BindPort, err)
|
||||
}
|
||||
return fmt.Sprintf("https://%s", hostPort), nil
|
||||
|
||||
// parse the AdvertiseAddress
|
||||
var ip = net.ParseIP(api.AdvertiseAddress)
|
||||
if ip == nil {
|
||||
return "", fmt.Errorf("invalid value `%s` given for api.advertiseAddress", api.AdvertiseAddress)
|
||||
}
|
||||
|
||||
// set the master url using cfg.API.AdvertiseAddress + the cfg.API.BindPort
|
||||
masterURL := &url.URL{
|
||||
Scheme: "https",
|
||||
Host: net.JoinHostPort(ip.String(), bindPort),
|
||||
}
|
||||
|
||||
// if the controlplane endpoint is defined
|
||||
if len(api.ControlPlaneEndpoint) > 0 {
|
||||
// parse the controlplane endpoint
|
||||
var host, port string
|
||||
var err error
|
||||
if host, port, err = ParseHostPort(api.ControlPlaneEndpoint); err != nil {
|
||||
return "", fmt.Errorf("invalid value %q given for api.controlPlaneEndpoint: %s", api.ControlPlaneEndpoint, err)
|
||||
}
|
||||
|
||||
// if a port is provided within the controlPlaneAddress warn the users we are using it, else use the bindport
|
||||
if port != "" {
|
||||
fmt.Println("[endpoint] WARNING: port specified in api.controlPlaneEndpoint overrides api.bindPort in the controlplane address")
|
||||
} else {
|
||||
port = bindPort
|
||||
}
|
||||
|
||||
// overrides the master url using the controlPlaneAddress (and eventually the bindport)
|
||||
masterURL = &url.URL{
|
||||
Scheme: "https",
|
||||
Host: net.JoinHostPort(host, port),
|
||||
}
|
||||
}
|
||||
|
||||
return masterURL.String(), nil
|
||||
}
|
||||
|
||||
// GetMasterHostPort returns a properly formatted Master IP/port pair or error
|
||||
// if the IP address can not be parsed or port is outside the valid TCP range.
|
||||
func GetMasterHostPort(cfg *kubeadmapi.MasterConfiguration) (string, error) {
|
||||
var masterIP string
|
||||
if len(cfg.API.ControlPlaneEndpoint) > 0 {
|
||||
errs := validation.IsDNS1123Subdomain(cfg.API.ControlPlaneEndpoint)
|
||||
if len(errs) > 0 {
|
||||
return "", fmt.Errorf("error parsing `ControlPlaneEndpoint` to valid dns subdomain with errors: %s", errs)
|
||||
}
|
||||
masterIP = cfg.API.ControlPlaneEndpoint
|
||||
} else {
|
||||
ip := net.ParseIP(cfg.API.AdvertiseAddress)
|
||||
if ip == nil {
|
||||
return "", fmt.Errorf("error parsing address %s", cfg.API.AdvertiseAddress)
|
||||
}
|
||||
masterIP = ip.String()
|
||||
// ParseHostPort parses a network address of the form "host:port", "ipv4:port", "[ipv6]:port" into host and port;
|
||||
// ":port" can be eventually omitted.
|
||||
// If the string is not a valid representation of network address, ParseHostPort returns an error.
|
||||
func ParseHostPort(hostport string) (string, string, error) {
|
||||
var host, port string
|
||||
var err error
|
||||
|
||||
// try to split host and port
|
||||
if host, port, err = net.SplitHostPort(hostport); err != nil {
|
||||
// if SplitHostPort returns an error, the entire hostport is considered as host
|
||||
host = hostport
|
||||
}
|
||||
|
||||
if cfg.API.BindPort < 0 || cfg.API.BindPort > 65535 {
|
||||
return "", fmt.Errorf("api server port must be between 0 and 65535")
|
||||
// if port is defined, parse and validate it
|
||||
if port != "" {
|
||||
if _, err := parsePort(port); err != nil {
|
||||
return "", "", fmt.Errorf("port must be a valid number between 1 and 65535, inclusive")
|
||||
}
|
||||
}
|
||||
|
||||
hostPort := net.JoinHostPort(masterIP, strconv.Itoa(int(cfg.API.BindPort)))
|
||||
return hostPort, nil
|
||||
// if host is a valid IP, returns it
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
return host, port, nil
|
||||
}
|
||||
|
||||
// if host is a validate RFC-1123 subdomain, returns it
|
||||
if errs := validation.IsDNS1123Subdomain(host); len(errs) == 0 {
|
||||
return host, port, nil
|
||||
}
|
||||
|
||||
return "", "", fmt.Errorf("host must be a valid IP address or a valid RFC-1123 DNS subdomain")
|
||||
}
|
||||
|
||||
// ParsePort parses a string representing a TCP port.
|
||||
// If the string is not a valid representation of a TCP port, ParsePort returns an error.
|
||||
func parsePort(port string) (int, error) {
|
||||
if portInt, err := strconv.Atoi(port); err == nil && (1 <= portInt && portInt <= 65535) {
|
||||
return portInt, nil
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("port must be a valid number between 1 and 65535, inclusive")
|
||||
}
|
||||
|
432
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/endpoint_test.go
generated
vendored
432
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/endpoint_test.go
generated
vendored
@ -24,234 +24,322 @@ import (
|
||||
|
||||
func TestGetMasterEndpoint(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
endpoint string
|
||||
expected bool
|
||||
name string
|
||||
api *kubeadmapi.API
|
||||
expectedEndpoint string
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "bad controlplane endpooint dns",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "bad!!cp.k8s.io",
|
||||
BindPort: 1234,
|
||||
},
|
||||
name: "use ControlPlaneEndpoint (dns) if fully defined",
|
||||
api: &kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "cp.k8s.io:1234",
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
},
|
||||
endpoint: "https://cp.k8s.io:1234",
|
||||
expected: false,
|
||||
expectedEndpoint: "https://cp.k8s.io:1234",
|
||||
},
|
||||
{
|
||||
name: "both DNS and IP passed",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
AdvertiseAddress: "1.2.3.4",
|
||||
ControlPlaneEndpoint: "cp.k8s.io",
|
||||
BindPort: 1234,
|
||||
},
|
||||
name: "use ControlPlaneEndpoint (ipv4) if fully defined",
|
||||
api: &kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "1.2.3.4:1234",
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
},
|
||||
endpoint: "https://cp.k8s.io:1234",
|
||||
expected: true,
|
||||
expectedEndpoint: "https://1.2.3.4:1234",
|
||||
},
|
||||
{
|
||||
name: "valid DNS endpoint",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "cp.k8s.io",
|
||||
BindPort: 1234,
|
||||
},
|
||||
name: "use ControlPlaneEndpoint (ipv6) if fully defined",
|
||||
api: &kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "[2001:db8::1]:1234",
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
},
|
||||
endpoint: "https://cp.k8s.io:1234",
|
||||
expected: true,
|
||||
expectedEndpoint: "https://[2001:db8::1]:1234",
|
||||
},
|
||||
{
|
||||
name: "valid IPv4 endpoint",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
AdvertiseAddress: "1.2.3.4",
|
||||
BindPort: 1234,
|
||||
},
|
||||
name: "use ControlPlaneEndpoint (dns) + BindPort if ControlPlaneEndpoint defined without port",
|
||||
api: &kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "cp.k8s.io",
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
},
|
||||
endpoint: "https://1.2.3.4:1234",
|
||||
expected: true,
|
||||
expectedEndpoint: "https://cp.k8s.io:4567",
|
||||
},
|
||||
{
|
||||
name: "valid IPv6 endpoint",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
AdvertiseAddress: "2001:db8::1",
|
||||
BindPort: 4321,
|
||||
},
|
||||
name: "use ControlPlaneEndpoint (ipv4) + BindPort if ControlPlaneEndpoint defined without port",
|
||||
api: &kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "1.2.3.4",
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
},
|
||||
endpoint: "https://[2001:db8::1]:4321",
|
||||
expected: true,
|
||||
expectedEndpoint: "https://1.2.3.4:4567",
|
||||
},
|
||||
{
|
||||
name: "invalid IPv4 endpoint",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
AdvertiseAddress: "1.2.3.4",
|
||||
BindPort: 1234,
|
||||
},
|
||||
name: "use ControlPlaneEndpoint (ipv6) + BindPort if ControlPlaneEndpoint defined without port",
|
||||
api: &kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "2001:db8::1",
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
},
|
||||
endpoint: "https://[1.2.3.4]:1234",
|
||||
expected: false,
|
||||
expectedEndpoint: "https://[2001:db8::1]:4567",
|
||||
},
|
||||
{
|
||||
name: "invalid IPv6 endpoint",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
AdvertiseAddress: "2001:db8::1",
|
||||
BindPort: 4321,
|
||||
},
|
||||
name: "use AdvertiseAddress (ipv4) + BindPort if ControlPlaneEndpoint is not defined",
|
||||
api: &kubeadmapi.API{
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
},
|
||||
endpoint: "https://2001:db8::1:4321",
|
||||
expected: false,
|
||||
expectedEndpoint: "https://4.5.6.7:4567",
|
||||
},
|
||||
{
|
||||
name: "invalid IPv4 AdvertiseAddress",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
AdvertiseAddress: "1.2.34",
|
||||
BindPort: 1234,
|
||||
},
|
||||
name: "use AdvertiseAddress (ipv6) + BindPort if ControlPlaneEndpoint is not defined",
|
||||
api: &kubeadmapi.API{
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "2001:db8::1",
|
||||
},
|
||||
endpoint: "https://1.2.3.4:1234",
|
||||
expected: false,
|
||||
expectedEndpoint: "https://[2001:db8::1]:4567",
|
||||
},
|
||||
{
|
||||
name: "invalid IPv6 AdvertiseAddress",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
AdvertiseAddress: "2001::db8::1",
|
||||
BindPort: 4321,
|
||||
},
|
||||
name: "fail if invalid BindPort",
|
||||
api: &kubeadmapi.API{
|
||||
BindPort: 0,
|
||||
},
|
||||
endpoint: "https://[2001:db8::1]:4321",
|
||||
expected: false,
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "fail if invalid ControlPlaneEndpoint (dns)",
|
||||
api: &kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "bad!!.cp.k8s.io",
|
||||
BindPort: 4567,
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "fail if invalid ControlPlaneEndpoint (ip4)",
|
||||
api: &kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "1..0",
|
||||
BindPort: 4567,
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "fail if invalid ControlPlaneEndpoint (ip6)",
|
||||
api: &kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "1200::AB00:1234::2552:7777:1313",
|
||||
BindPort: 4567,
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "fail if invalid ControlPlaneEndpoint (port)",
|
||||
api: &kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "cp.k8s.io:0",
|
||||
BindPort: 4567,
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "fail if invalid AdvertiseAddress (ip4)",
|
||||
api: &kubeadmapi.API{
|
||||
AdvertiseAddress: "1..0",
|
||||
BindPort: 4567,
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "fail if invalid AdvertiseAddress (ip6)",
|
||||
api: &kubeadmapi.API{
|
||||
AdvertiseAddress: "1200::AB00:1234::2552:7777:1313",
|
||||
BindPort: 4567,
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
actual, err := GetMasterEndpoint(rt.cfg)
|
||||
if err != nil && rt.expected {
|
||||
t.Error(err)
|
||||
actualEndpoint, actualError := GetMasterEndpoint(rt.api)
|
||||
|
||||
if (actualError != nil) && !rt.expectedError {
|
||||
t.Errorf("%s unexpected failure: %v", rt.name, actualError)
|
||||
continue
|
||||
} else if (actualError == nil) && rt.expectedError {
|
||||
t.Errorf("%s passed when expected to fail", rt.name)
|
||||
continue
|
||||
}
|
||||
if actual != rt.endpoint && rt.expected {
|
||||
t.Errorf(
|
||||
"%s test case failed:\n\texpected: %s\n\t actual: %s",
|
||||
rt.name,
|
||||
rt.endpoint,
|
||||
(actual),
|
||||
)
|
||||
|
||||
if actualEndpoint != rt.expectedEndpoint {
|
||||
t.Errorf("%s returned invalid endpoint %s, expected %s", rt.name, actualEndpoint, rt.expectedEndpoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMasterHostPort(t *testing.T) {
|
||||
func TestParseHostPort(t *testing.T) {
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
hostPort string
|
||||
expected bool
|
||||
name string
|
||||
hostport string
|
||||
expectedHost string
|
||||
expectedPort string
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "valid IPv4 master host and port",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
AdvertiseAddress: "1.2.3.4",
|
||||
BindPort: 1234,
|
||||
},
|
||||
},
|
||||
hostPort: "1.2.3.4:1234",
|
||||
expected: true,
|
||||
name: "valid dns",
|
||||
hostport: "cp.k8s.io",
|
||||
expectedHost: "cp.k8s.io",
|
||||
expectedPort: "",
|
||||
},
|
||||
{
|
||||
name: "valid IPv6 master host port",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
AdvertiseAddress: "2001:db8::1",
|
||||
BindPort: 4321,
|
||||
},
|
||||
},
|
||||
hostPort: "[2001:db8::1]:4321",
|
||||
expected: true,
|
||||
name: "valid dns:port",
|
||||
hostport: "cp.k8s.io:1234",
|
||||
expectedHost: "cp.k8s.io",
|
||||
expectedPort: "1234",
|
||||
},
|
||||
{
|
||||
name: "invalid IPv4 address",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
AdvertiseAddress: "1.2.34",
|
||||
BindPort: 1234,
|
||||
},
|
||||
},
|
||||
hostPort: "1.2.3.4:1234",
|
||||
expected: false,
|
||||
name: "valid ip4",
|
||||
hostport: "1.2.3.4",
|
||||
expectedHost: "1.2.3.4",
|
||||
expectedPort: "",
|
||||
},
|
||||
{
|
||||
name: "invalid IPv6 address",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
AdvertiseAddress: "2001::db8::1",
|
||||
BindPort: 4321,
|
||||
},
|
||||
},
|
||||
hostPort: "[2001:db8::1]:4321",
|
||||
expected: false,
|
||||
name: "valid ipv4:port",
|
||||
hostport: "1.2.3.4:1234",
|
||||
expectedHost: "1.2.3.4",
|
||||
expectedPort: "1234",
|
||||
},
|
||||
{
|
||||
name: "invalid TCP port number",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
AdvertiseAddress: "1.2.3.4",
|
||||
BindPort: 987654321,
|
||||
},
|
||||
},
|
||||
hostPort: "1.2.3.4:987654321",
|
||||
expected: false,
|
||||
name: "valid ipv6",
|
||||
hostport: "2001:db8::1",
|
||||
expectedHost: "2001:db8::1",
|
||||
expectedPort: "",
|
||||
},
|
||||
{
|
||||
name: "invalid negative TCP port number",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
AdvertiseAddress: "1.2.3.4",
|
||||
BindPort: -987654321,
|
||||
},
|
||||
},
|
||||
hostPort: "1.2.3.4:-987654321",
|
||||
expected: false,
|
||||
name: "valid ipv6:port",
|
||||
hostport: "[2001:db8::1]:1234",
|
||||
expectedHost: "2001:db8::1",
|
||||
expectedPort: "1234",
|
||||
},
|
||||
{
|
||||
name: "unspecified IPv4 TCP port",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
AdvertiseAddress: "1.2.3.4",
|
||||
},
|
||||
},
|
||||
hostPort: "1.2.3.4:0",
|
||||
expected: true,
|
||||
name: "invalid port(not a number)",
|
||||
hostport: "cp.k8s.io:aaa",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "unspecified IPv6 TCP port",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
AdvertiseAddress: "1:2:3::4",
|
||||
},
|
||||
},
|
||||
hostPort: "[1:2:3::4]:0",
|
||||
expected: true,
|
||||
name: "invalid port(out of range, positive port number)",
|
||||
hostport: "cp.k8s.io:987654321",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid port(out of range, negative port number)",
|
||||
hostport: "cp.k8s.io:-987654321",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid port(out of range, negative port number)",
|
||||
hostport: "cp.k8s.io:123:123",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid dns",
|
||||
hostport: "bad!!cp.k8s.io",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid valid dns:port",
|
||||
hostport: "bad!!cp.k8s.io:1234",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid ip4, but valid DNS",
|
||||
hostport: "259.2.3.4",
|
||||
expectedHost: "259.2.3.4",
|
||||
},
|
||||
{
|
||||
name: "invalid ip4",
|
||||
hostport: "1..3.4",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid ip4(2):port",
|
||||
hostport: "1..3.4:1234",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid ipv6",
|
||||
hostport: "1200::AB00:1234::2552:7777:1313",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid ipv6:port",
|
||||
hostport: "[1200::AB00:1234::2552:7777:1313]:1234",
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
actual, err := GetMasterHostPort(rt.cfg)
|
||||
if err != nil && rt.expected {
|
||||
t.Error(err)
|
||||
actualHost, actualPort, actualError := ParseHostPort(rt.hostport)
|
||||
|
||||
if (actualError != nil) && !rt.expectedError {
|
||||
t.Errorf("%s unexpected failure: %v", rt.name, actualError)
|
||||
continue
|
||||
} else if (actualError == nil) && rt.expectedError {
|
||||
t.Errorf("%s passed when expected to fail", rt.name)
|
||||
continue
|
||||
}
|
||||
if actual != rt.hostPort && rt.expected {
|
||||
t.Errorf(
|
||||
"%s test case failed:\n\texpected: %s\n\t actual: %s",
|
||||
rt.name,
|
||||
rt.hostPort,
|
||||
(actual),
|
||||
)
|
||||
|
||||
if actualHost != rt.expectedHost {
|
||||
t.Errorf("%s returned invalid host %s, expected %s", rt.name, actualHost, rt.expectedHost)
|
||||
continue
|
||||
}
|
||||
|
||||
if actualPort != rt.expectedPort {
|
||||
t.Errorf("%s returned invalid port %s, expected %s", rt.name, actualPort, rt.expectedPort)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePort(t *testing.T) {
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
port string
|
||||
expectedPort int
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "valid port",
|
||||
port: "1234",
|
||||
expectedPort: 1234,
|
||||
},
|
||||
{
|
||||
name: "invalid port (not a number)",
|
||||
port: "a",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid port (<1)",
|
||||
port: "-10",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid port (>65535)",
|
||||
port: "66535",
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
actualPort, actualError := parsePort(rt.port)
|
||||
|
||||
if (actualError != nil) && !rt.expectedError {
|
||||
t.Errorf("%s unexpected failure: %v", rt.name, actualError)
|
||||
continue
|
||||
} else if (actualError == nil) && rt.expectedError {
|
||||
t.Errorf("%s passed when expected to fail", rt.name)
|
||||
continue
|
||||
}
|
||||
|
||||
if actualPort != rt.expectedPort {
|
||||
t.Errorf("%s returned invalid port %d, expected %d", rt.name, actualPort, rt.expectedPort)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
19
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/error.go
generated
vendored
19
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/error.go
generated
vendored
@ -22,7 +22,6 @@ import (
|
||||
"strings"
|
||||
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -34,10 +33,6 @@ const (
|
||||
ValidationExitCode = 3
|
||||
)
|
||||
|
||||
type debugError interface {
|
||||
DebugError() (msg string, args []interface{})
|
||||
}
|
||||
|
||||
// fatal prints the message if set and then exits.
|
||||
func fatal(msg string, code int) {
|
||||
if len(msg) > 0 {
|
||||
@ -57,16 +52,22 @@ func fatal(msg string, code int) {
|
||||
// This method is generic to the command in use and may be used by non-Kubectl
|
||||
// commands.
|
||||
func CheckErr(err error) {
|
||||
checkErr("", err, fatal)
|
||||
checkErr(err, fatal)
|
||||
}
|
||||
|
||||
// preflightError allows us to know if the error is a preflight error or not
|
||||
// defining the interface here avoids an import cycle of pulling in preflight into the util package
|
||||
type preflightError interface {
|
||||
Preflight() bool
|
||||
}
|
||||
|
||||
// checkErr formats a given error as a string and calls the passed handleErr
|
||||
// func with that string and an kubectl exit code.
|
||||
func checkErr(prefix string, err error, handleErr func(string, int)) {
|
||||
// func with that string and an exit code.
|
||||
func checkErr(err error, handleErr func(string, int)) {
|
||||
switch err.(type) {
|
||||
case nil:
|
||||
return
|
||||
case *preflight.Error:
|
||||
case preflightError:
|
||||
handleErr(err.Error(), PreFlightExitCode)
|
||||
case utilerrors.Aggregate:
|
||||
handleErr(err.Error(), ValidationExitCode)
|
||||
|
10
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/error_test.go
generated
vendored
10
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/error_test.go
generated
vendored
@ -19,10 +19,12 @@ package util
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
|
||||
)
|
||||
|
||||
type pferror struct{}
|
||||
|
||||
func (p *pferror) Preflight() bool { return true }
|
||||
func (p *pferror) Error() string { return "" }
|
||||
func TestCheckErr(t *testing.T) {
|
||||
var codeReturned int
|
||||
errHandle := func(err string, code int) {
|
||||
@ -35,12 +37,12 @@ func TestCheckErr(t *testing.T) {
|
||||
}{
|
||||
{nil, 0},
|
||||
{fmt.Errorf(""), DefaultErrorExitCode},
|
||||
{&preflight.Error{}, PreFlightExitCode},
|
||||
{&pferror{}, PreFlightExitCode},
|
||||
}
|
||||
|
||||
for _, rt := range tokenTest {
|
||||
codeReturned = 0
|
||||
checkErr("", rt.e, errHandle)
|
||||
checkErr(rt.e, errHandle)
|
||||
if codeReturned != rt.expected {
|
||||
t.Errorf(
|
||||
"failed checkErr:\n\texpected: %d\n\t actual: %d",
|
||||
|
51
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/etcd.go
generated
vendored
51
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/etcd.go
generated
vendored
@ -1,51 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 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 util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
"time"
|
||||
)
|
||||
|
||||
// EtcdCluster is an interface to get etcd cluster related information
|
||||
type EtcdCluster interface {
|
||||
GetEtcdClusterStatus() (*clientv3.StatusResponse, error)
|
||||
}
|
||||
|
||||
// LocalEtcdCluster represents an instance of a local etcd cluster
|
||||
type LocalEtcdCluster struct{}
|
||||
|
||||
// GetEtcdClusterStatus returns nil for status Up or error for status Down
|
||||
func (cluster LocalEtcdCluster) GetEtcdClusterStatus() (*clientv3.StatusResponse, error) {
|
||||
ep := []string{"localhost:2379"}
|
||||
cli, err := clientv3.New(clientv3.Config{
|
||||
Endpoints: ep,
|
||||
DialTimeout: 5 * time.Second,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
resp, err := cli.Status(context.Background(), ep[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
39
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/etcd/BUILD
generated
vendored
Normal file
39
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/etcd/BUILD
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["etcd.go"],
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/util/etcd",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util/staticpod:go_default_library",
|
||||
"//vendor/github.com/coreos/etcd/clientv3:go_default_library",
|
||||
"//vendor/github.com/coreos/etcd/pkg/transport:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["etcd_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/test:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
224
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/etcd/etcd.go
generated
vendored
Normal file
224
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/etcd/etcd.go
generated
vendored
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
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 etcd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
"github.com/coreos/etcd/pkg/transport"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod"
|
||||
)
|
||||
|
||||
// ClusterInterrogator is an interface to get etcd cluster related information
|
||||
type ClusterInterrogator interface {
|
||||
ClusterAvailable() (bool, error)
|
||||
GetClusterStatus() (map[string]*clientv3.StatusResponse, error)
|
||||
GetClusterVersions() (map[string]string, error)
|
||||
GetVersion() (string, error)
|
||||
HasTLS() bool
|
||||
WaitForClusterAvailable(delay time.Duration, retries int, retryInterval time.Duration) (bool, error)
|
||||
}
|
||||
|
||||
// Client provides connection parameters for an etcd cluster
|
||||
type Client struct {
|
||||
Endpoints []string
|
||||
TLS *tls.Config
|
||||
}
|
||||
|
||||
// HasTLS returns true if etcd is configured for TLS
|
||||
func (c Client) HasTLS() bool {
|
||||
return c.TLS != nil
|
||||
}
|
||||
|
||||
// PodManifestsHaveTLS reads the etcd staticpod manifest from disk and returns false if the TLS flags
|
||||
// are missing from the command list. If all the flags are present it returns true.
|
||||
func PodManifestsHaveTLS(ManifestDir string) (bool, error) {
|
||||
etcdPodPath := constants.GetStaticPodFilepath(constants.Etcd, ManifestDir)
|
||||
etcdPod, err := staticpod.ReadStaticPodFromDisk(etcdPodPath)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to check if etcd pod implements TLS: %v", err)
|
||||
}
|
||||
|
||||
tlsFlags := []string{
|
||||
"--cert-file=",
|
||||
"--key-file=",
|
||||
"--trusted-ca-file=",
|
||||
"--client-cert-auth=",
|
||||
"--peer-cert-file=",
|
||||
"--peer-key-file=",
|
||||
"--peer-trusted-ca-file=",
|
||||
"--peer-client-cert-auth=",
|
||||
}
|
||||
FlagLoop:
|
||||
for _, flag := range tlsFlags {
|
||||
for _, container := range etcdPod.Spec.Containers {
|
||||
for _, arg := range container.Command {
|
||||
if strings.Contains(arg, flag) {
|
||||
continue FlagLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
// flag not found in any container
|
||||
return false, nil
|
||||
}
|
||||
// all flags were found in container args; pod fully implements TLS
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// New creates a new EtcdCluster client
|
||||
func New(endpoints []string, ca, cert, key string) (*Client, error) {
|
||||
client := Client{Endpoints: endpoints}
|
||||
|
||||
if ca != "" || cert != "" || key != "" {
|
||||
tlsInfo := transport.TLSInfo{
|
||||
CertFile: cert,
|
||||
KeyFile: key,
|
||||
TrustedCAFile: ca,
|
||||
}
|
||||
tlsConfig, err := tlsInfo.ClientConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client.TLS = tlsConfig
|
||||
}
|
||||
|
||||
return &client, nil
|
||||
}
|
||||
|
||||
// NewFromStaticPod creates a GenericClient from the given endpoints, manifestDir, and certificatesDir
|
||||
func NewFromStaticPod(endpoints []string, manifestDir string, certificatesDir string) (*Client, error) {
|
||||
hasTLS, err := PodManifestsHaveTLS(manifestDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read manifests from: %s, error: %v", manifestDir, err)
|
||||
}
|
||||
if hasTLS {
|
||||
return New(
|
||||
endpoints,
|
||||
filepath.Join(certificatesDir, constants.EtcdCACertName),
|
||||
filepath.Join(certificatesDir, constants.EtcdHealthcheckClientCertName),
|
||||
filepath.Join(certificatesDir, constants.EtcdHealthcheckClientKeyName),
|
||||
)
|
||||
}
|
||||
return New(endpoints, "", "", "")
|
||||
}
|
||||
|
||||
// GetVersion returns the etcd version of the cluster.
|
||||
// An error is returned if the version of all endpoints do not match
|
||||
func (c Client) GetVersion() (string, error) {
|
||||
var clusterVersion string
|
||||
|
||||
versions, err := c.GetClusterVersions()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, v := range versions {
|
||||
if clusterVersion != "" && clusterVersion != v {
|
||||
return "", fmt.Errorf("etcd cluster contains endpoints with mismatched versions: %v", versions)
|
||||
}
|
||||
clusterVersion = v
|
||||
}
|
||||
if clusterVersion == "" {
|
||||
return "", fmt.Errorf("could not determine cluster etcd version")
|
||||
}
|
||||
return clusterVersion, nil
|
||||
}
|
||||
|
||||
// GetClusterVersions returns a map of the endpoints and their associated versions
|
||||
func (c Client) GetClusterVersions() (map[string]string, error) {
|
||||
versions := make(map[string]string)
|
||||
statuses, err := c.GetClusterStatus()
|
||||
if err != nil {
|
||||
return versions, err
|
||||
}
|
||||
|
||||
for ep, status := range statuses {
|
||||
versions[ep] = status.Version
|
||||
}
|
||||
return versions, nil
|
||||
}
|
||||
|
||||
// ClusterAvailable returns true if the cluster status indicates the cluster is available.
|
||||
func (c Client) ClusterAvailable() (bool, error) {
|
||||
_, err := c.GetClusterStatus()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// GetClusterStatus returns nil for status Up or error for status Down
|
||||
func (c Client) GetClusterStatus() (map[string]*clientv3.StatusResponse, error) {
|
||||
cli, err := clientv3.New(clientv3.Config{
|
||||
Endpoints: c.Endpoints,
|
||||
DialTimeout: 5 * time.Second,
|
||||
TLS: c.TLS,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
clusterStatus := make(map[string]*clientv3.StatusResponse)
|
||||
for _, ep := range c.Endpoints {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
resp, err := cli.Status(ctx, ep)
|
||||
cancel()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clusterStatus[ep] = resp
|
||||
}
|
||||
return clusterStatus, nil
|
||||
}
|
||||
|
||||
// WaitForClusterAvailable returns true if all endpoints in the cluster are available after an initial delay and retry attempts, an error is returned otherwise
|
||||
func (c Client) WaitForClusterAvailable(delay time.Duration, retries int, retryInterval time.Duration) (bool, error) {
|
||||
fmt.Printf("[util/etcd] Waiting %v for initial delay\n", delay)
|
||||
time.Sleep(delay)
|
||||
for i := 0; i < retries; i++ {
|
||||
if i > 0 {
|
||||
fmt.Printf("[util/etcd] Waiting %v until next retry\n", retryInterval)
|
||||
time.Sleep(retryInterval)
|
||||
}
|
||||
fmt.Printf("[util/etcd] Attempting to see if all cluster endpoints are available %d/%d\n", i+1, retries)
|
||||
resp, err := c.ClusterAvailable()
|
||||
if err != nil {
|
||||
switch err {
|
||||
case context.DeadlineExceeded:
|
||||
fmt.Println("[util/etcd] Attempt timed out")
|
||||
default:
|
||||
fmt.Printf("[util/etcd] Attempt failed with error: %v\n", err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
return false, fmt.Errorf("timeout waiting for etcd cluster to be available")
|
||||
}
|
||||
|
||||
// CheckConfigurationIsHA returns true if the given MasterConfiguration etcd block appears to be an HA configuration.
|
||||
func CheckConfigurationIsHA(cfg *kubeadmapi.Etcd) bool {
|
||||
return cfg.External != nil && len(cfg.External.Endpoints) > 1
|
||||
}
|
310
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/etcd/etcd_test.go
generated
vendored
Normal file
310
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/etcd/etcd_test.go
generated
vendored
Normal file
@ -0,0 +1,310 @@
|
||||
/*
|
||||
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 etcd
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
testutil "k8s.io/kubernetes/cmd/kubeadm/test"
|
||||
)
|
||||
|
||||
const (
|
||||
secureEtcdPod = `# generated by kubeadm v1.10.0
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
annotations:
|
||||
scheduler.alpha.kubernetes.io/critical-pod: ""
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
component: etcd
|
||||
tier: control-plane
|
||||
name: etcd
|
||||
namespace: kube-system
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- etcd
|
||||
- --advertise-client-urls=https://127.0.0.1:2379
|
||||
- --data-dir=/var/lib/etcd
|
||||
- --peer-key-file=/etc/kubernetes/pki/etcd/peer.key
|
||||
- --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
|
||||
- --listen-client-urls=https://127.0.0.1:2379
|
||||
- --peer-client-cert-auth=true
|
||||
- --cert-file=/etc/kubernetes/pki/etcd/server.crt
|
||||
- --key-file=/etc/kubernetes/pki/etcd/server.key
|
||||
- --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
|
||||
- --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt
|
||||
- --client-cert-auth=true
|
||||
image: k8s.gcr.io/etcd-amd64:3.1.12
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -ec
|
||||
- ETCDCTL_API=3 etcdctl --endpoints=127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt
|
||||
--cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key
|
||||
get foo
|
||||
failureThreshold: 8
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 15
|
||||
name: etcd
|
||||
resources: {}
|
||||
volumeMounts:
|
||||
- mountPath: /var/lib/etcd
|
||||
name: etcd-data
|
||||
- mountPath: /etc/kubernetes/pki/etcd
|
||||
name: etcd-certs
|
||||
hostNetwork: true
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /var/lib/etcd
|
||||
type: DirectoryOrCreate
|
||||
name: etcd-data
|
||||
- hostPath:
|
||||
path: /etc/kubernetes/pki/etcd
|
||||
type: DirectoryOrCreate
|
||||
name: etcd-certs
|
||||
status: {}
|
||||
`
|
||||
secureExposedEtcdPod = `
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
annotations:
|
||||
scheduler.alpha.kubernetes.io/critical-pod: ""
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
component: etcd
|
||||
tier: control-plane
|
||||
name: etcd
|
||||
namespace: kube-system
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- etcd
|
||||
- --advertise-client-urls=https://10.0.5.5:2379
|
||||
- --data-dir=/var/lib/etcd
|
||||
- --peer-key-file=/etc/kubernetes/pki/etcd/peer.key
|
||||
- --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
|
||||
- --listen-client-urls=https://[::0:0]:2379
|
||||
- --peer-client-cert-auth=true
|
||||
- --cert-file=/etc/kubernetes/pki/etcd/server.crt
|
||||
- --key-file=/etc/kubernetes/pki/etcd/server.key
|
||||
- --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
|
||||
- --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt
|
||||
- --client-cert-auth=true
|
||||
image: k8s.gcr.io/etcd-amd64:3.1.12
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -ec
|
||||
- ETCDCTL_API=3 etcdctl --endpoints=https://[::1]:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt
|
||||
--cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key
|
||||
get foo
|
||||
failureThreshold: 8
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 15
|
||||
name: etcd
|
||||
resources: {}
|
||||
volumeMounts:
|
||||
- mountPath: /var/lib/etcd
|
||||
name: etcd-data
|
||||
- mountPath: /etc/kubernetes/pki/etcd
|
||||
name: etcd-certs
|
||||
hostNetwork: true
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /var/lib/etcd
|
||||
type: DirectoryOrCreate
|
||||
name: etcd-data
|
||||
- hostPath:
|
||||
path: /etc/kubernetes/pki/etcd
|
||||
type: DirectoryOrCreate
|
||||
name: etcd-certs
|
||||
status: {}
|
||||
`
|
||||
insecureEtcdPod = `# generated by kubeadm v1.9.6
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
annotations:
|
||||
scheduler.alpha.kubernetes.io/critical-pod: ""
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
component: etcd
|
||||
tier: control-plane
|
||||
name: etcd
|
||||
namespace: kube-system
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- etcd
|
||||
- --listen-client-urls=http://127.0.0.1:2379
|
||||
- --advertise-client-urls=http://127.0.0.1:2379
|
||||
- --data-dir=/var/lib/etcd
|
||||
image: gcr.io/google_containers/etcd-amd64:3.1.11
|
||||
livenessProbe:
|
||||
failureThreshold: 8
|
||||
httpGet:
|
||||
host: 127.0.0.1
|
||||
path: /health
|
||||
port: 2379
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 15
|
||||
name: etcd
|
||||
resources: {}
|
||||
volumeMounts:
|
||||
- mountPath: /var/lib/etcd
|
||||
name: etcd
|
||||
hostNetwork: true
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /var/lib/etcd
|
||||
type: DirectoryOrCreate
|
||||
name: etcd
|
||||
status: {}
|
||||
`
|
||||
invalidPod = `---{ broken yaml @@@`
|
||||
)
|
||||
|
||||
func TestPodManifestHasTLS(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
podYaml string
|
||||
hasTLS bool
|
||||
expectErr bool
|
||||
writeManifest bool
|
||||
}{
|
||||
{
|
||||
description: "secure etcd returns true",
|
||||
podYaml: secureEtcdPod,
|
||||
hasTLS: true,
|
||||
writeManifest: true,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
description: "secure exposed etcd returns true",
|
||||
podYaml: secureExposedEtcdPod,
|
||||
hasTLS: true,
|
||||
writeManifest: true,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
description: "insecure etcd returns false",
|
||||
podYaml: insecureEtcdPod,
|
||||
hasTLS: false,
|
||||
writeManifest: true,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
description: "invalid pod fails to unmarshal",
|
||||
podYaml: invalidPod,
|
||||
hasTLS: false,
|
||||
writeManifest: true,
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
description: "non-existent file returns error",
|
||||
podYaml: ``,
|
||||
hasTLS: false,
|
||||
writeManifest: false,
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
tmpdir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
manifestPath := filepath.Join(tmpdir, "etcd.yaml")
|
||||
if rt.writeManifest {
|
||||
err := ioutil.WriteFile(manifestPath, []byte(rt.podYaml), 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to write pod manifest\n%s\n\tfatal error: %v", rt.description, err)
|
||||
}
|
||||
}
|
||||
|
||||
hasTLS, actualErr := PodManifestsHaveTLS(tmpdir)
|
||||
if (actualErr != nil) != rt.expectErr {
|
||||
t.Errorf(
|
||||
"PodManifestHasTLS failed\n%s\n\texpected error: %t\n\tgot: %t\n\tactual error: %v",
|
||||
rt.description,
|
||||
rt.expectErr,
|
||||
(actualErr != nil),
|
||||
actualErr,
|
||||
)
|
||||
}
|
||||
|
||||
if hasTLS != rt.hasTLS {
|
||||
t.Errorf("PodManifestHasTLS failed\n%s\n\texpected hasTLS: %t\n\tgot: %t", rt.description, rt.hasTLS, hasTLS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckConfigurationIsHA(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
cfg *kubeadmapi.Etcd
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "HA etcd",
|
||||
cfg: &kubeadmapi.Etcd{
|
||||
External: &kubeadmapi.ExternalEtcd{
|
||||
Endpoints: []string{"10.100.0.1:2379", "10.100.0.2:2379", "10.100.0.3:2379"},
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "single External etcd",
|
||||
cfg: &kubeadmapi.Etcd{
|
||||
External: &kubeadmapi.ExternalEtcd{
|
||||
Endpoints: []string{"10.100.0.1:2379"},
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "local etcd",
|
||||
cfg: &kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "empty etcd struct",
|
||||
cfg: &kubeadmapi.Etcd{},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if isHA := CheckConfigurationIsHA(test.cfg); isHA != test.expected {
|
||||
t.Errorf("expected isHA to be %v, got %v", test.expected, isHA)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
91
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/marshal.go
generated
vendored
91
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/marshal.go
generated
vendored
@ -17,12 +17,16 @@ limitations under the License.
|
||||
package util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
kubeadmapiv1alpha1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
|
||||
)
|
||||
|
||||
// MarshalToYaml marshals an object into yaml.
|
||||
@ -31,6 +35,8 @@ func MarshalToYaml(obj runtime.Object, gv schema.GroupVersion) ([]byte, error) {
|
||||
}
|
||||
|
||||
// MarshalToYamlForCodecs marshals an object into yaml using the specified codec
|
||||
// TODO: Is specifying the gv really needed here?
|
||||
// TODO: Can we support json out of the box easily here?
|
||||
func MarshalToYamlForCodecs(obj runtime.Object, gv schema.GroupVersion, codecs serializer.CodecFactory) ([]byte, error) {
|
||||
mediaType := "application/yaml"
|
||||
info, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), mediaType)
|
||||
@ -41,3 +47,88 @@ func MarshalToYamlForCodecs(obj runtime.Object, gv schema.GroupVersion, codecs s
|
||||
encoder := codecs.EncoderForVersion(info.Serializer, gv)
|
||||
return runtime.Encode(encoder, obj)
|
||||
}
|
||||
|
||||
// UnmarshalFromYaml unmarshals yaml into an object.
|
||||
func UnmarshalFromYaml(buffer []byte, gv schema.GroupVersion) (runtime.Object, error) {
|
||||
return UnmarshalFromYamlForCodecs(buffer, gv, clientsetscheme.Codecs)
|
||||
}
|
||||
|
||||
// UnmarshalFromYamlForCodecs unmarshals yaml into an object using the specified codec
|
||||
// TODO: Is specifying the gv really needed here?
|
||||
// TODO: Can we support json out of the box easily here?
|
||||
func UnmarshalFromYamlForCodecs(buffer []byte, gv schema.GroupVersion, codecs serializer.CodecFactory) (runtime.Object, error) {
|
||||
mediaType := "application/yaml"
|
||||
info, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), mediaType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unsupported media type %q", mediaType)
|
||||
}
|
||||
|
||||
decoder := codecs.DecoderToVersion(info.Serializer, gv)
|
||||
return runtime.Decode(decoder, buffer)
|
||||
}
|
||||
|
||||
// GroupVersionKindFromBytes parses the bytes and returns the gvk
|
||||
func GroupVersionKindFromBytes(buffer []byte, codecs serializer.CodecFactory) (schema.GroupVersionKind, error) {
|
||||
|
||||
decoded, err := LoadYAML(buffer)
|
||||
if err != nil {
|
||||
return schema.EmptyObjectKind.GroupVersionKind(), fmt.Errorf("unable to decode config from bytes: %v", err)
|
||||
}
|
||||
kindStr, apiVersionStr := "", ""
|
||||
|
||||
// As there was a bug in kubeadm v1.10 and earlier that made the YAML uploaded to the cluster configmap NOT have metav1.TypeMeta information
|
||||
// we need to populate this here manually. If kind or apiVersion is empty, we know the apiVersion is v1alpha1, as by the time kubeadm had this bug,
|
||||
// it could only write
|
||||
// TODO: Remove this "hack" in v1.12 when we know the ConfigMap always contains v1alpha2 content written by kubeadm v1.11. Also, we will drop support for
|
||||
// v1alpha1 in v1.12
|
||||
kind := decoded["kind"]
|
||||
apiVersion := decoded["apiVersion"]
|
||||
if kind == nil || len(kind.(string)) == 0 {
|
||||
kindStr = "MasterConfiguration"
|
||||
} else {
|
||||
kindStr = kind.(string)
|
||||
}
|
||||
if apiVersion == nil || len(apiVersion.(string)) == 0 {
|
||||
apiVersionStr = kubeadmapiv1alpha1.SchemeGroupVersion.String()
|
||||
} else {
|
||||
apiVersionStr = apiVersion.(string)
|
||||
}
|
||||
gv, err := schema.ParseGroupVersion(apiVersionStr)
|
||||
if err != nil {
|
||||
return schema.EmptyObjectKind.GroupVersionKind(), fmt.Errorf("unable to parse apiVersion: %v", err)
|
||||
}
|
||||
|
||||
return gv.WithKind(kindStr), nil
|
||||
}
|
||||
|
||||
// LoadYAML is a small wrapper around go-yaml that ensures all nested structs are map[string]interface{} instead of map[interface{}]interface{}.
|
||||
func LoadYAML(bytes []byte) (map[string]interface{}, error) {
|
||||
var decoded map[interface{}]interface{}
|
||||
if err := yaml.Unmarshal(bytes, &decoded); err != nil {
|
||||
return map[string]interface{}{}, fmt.Errorf("couldn't unmarshal YAML: %v", err)
|
||||
}
|
||||
|
||||
converted, ok := convert(decoded).(map[string]interface{})
|
||||
if !ok {
|
||||
return map[string]interface{}{}, errors.New("yaml is not a map")
|
||||
}
|
||||
|
||||
return converted, nil
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/40737122/convert-yaml-to-json-without-struct-golang
|
||||
func convert(i interface{}) interface{} {
|
||||
switch x := i.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
m2 := map[string]interface{}{}
|
||||
for k, v := range x {
|
||||
m2[k.(string)] = convert(v)
|
||||
}
|
||||
return m2
|
||||
case []interface{}:
|
||||
for i, v := range x {
|
||||
x[i] = convert(v)
|
||||
}
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
125
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/marshal_test.go
generated
vendored
Normal file
125
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/marshal_test.go
generated
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
Copyright 2017 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 util
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
||||
kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
|
||||
)
|
||||
|
||||
func TestMarshalUnmarshalYaml(t *testing.T) {
|
||||
pod := &corev1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "someName",
|
||||
Namespace: "testNamespace",
|
||||
Labels: map[string]string{
|
||||
"test": "yes",
|
||||
},
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
RestartPolicy: corev1.RestartPolicyAlways,
|
||||
},
|
||||
}
|
||||
|
||||
bytes, err := MarshalToYaml(pod, corev1.SchemeGroupVersion)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error marshalling: %v", err)
|
||||
}
|
||||
|
||||
t.Logf("\n%s", bytes)
|
||||
|
||||
obj2, err := UnmarshalFromYaml(bytes, corev1.SchemeGroupVersion)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error marshalling: %v", err)
|
||||
}
|
||||
|
||||
pod2, ok := obj2.(*corev1.Pod)
|
||||
if !ok {
|
||||
t.Fatal("did not get a Pod")
|
||||
}
|
||||
|
||||
if pod2.Name != pod.Name {
|
||||
t.Errorf("expected %q, got %q", pod.Name, pod2.Name)
|
||||
}
|
||||
|
||||
if pod2.Namespace != pod.Namespace {
|
||||
t.Errorf("expected %q, got %q", pod.Namespace, pod2.Namespace)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(pod2.Labels, pod.Labels) {
|
||||
t.Errorf("expected %v, got %v", pod.Labels, pod2.Labels)
|
||||
}
|
||||
|
||||
if pod2.Spec.RestartPolicy != pod.Spec.RestartPolicy {
|
||||
t.Errorf("expected %q, got %q", pod.Spec.RestartPolicy, pod2.Spec.RestartPolicy)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalUnmarshalToYamlForCodecs(t *testing.T) {
|
||||
cfg := &kubeadmapiext.MasterConfiguration{
|
||||
API: kubeadmapiext.API{
|
||||
AdvertiseAddress: "10.100.0.1",
|
||||
BindPort: 4332,
|
||||
},
|
||||
NodeName: "testNode",
|
||||
NoTaintMaster: true,
|
||||
Networking: kubeadmapiext.Networking{
|
||||
ServiceSubnet: "10.100.0.0/24",
|
||||
PodSubnet: "10.100.1.0/24",
|
||||
},
|
||||
}
|
||||
|
||||
bytes, err := MarshalToYamlForCodecs(cfg, kubeadmapiext.SchemeGroupVersion, scheme.Codecs)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error marshalling MasterConfiguration: %v", err)
|
||||
}
|
||||
t.Logf("\n%s", bytes)
|
||||
|
||||
obj, err := UnmarshalFromYamlForCodecs(bytes, kubeadmapiext.SchemeGroupVersion, scheme.Codecs)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error unmarshalling MasterConfiguration: %v", err)
|
||||
}
|
||||
|
||||
cfg2, ok := obj.(*kubeadmapiext.MasterConfiguration)
|
||||
if !ok {
|
||||
t.Fatal("did not get MasterConfiguration back")
|
||||
}
|
||||
|
||||
if cfg2.API.AdvertiseAddress != cfg.API.AdvertiseAddress {
|
||||
t.Errorf("expected %q, got %q", cfg.API.AdvertiseAddress, cfg2.API.AdvertiseAddress)
|
||||
}
|
||||
if cfg2.API.BindPort != cfg.API.BindPort {
|
||||
t.Errorf("expected %d, got %d", cfg.API.BindPort, cfg2.API.BindPort)
|
||||
}
|
||||
if cfg2.NodeName != cfg.NodeName {
|
||||
t.Errorf("expected %q, got %q", cfg.NodeName, cfg2.NodeName)
|
||||
}
|
||||
if cfg2.NoTaintMaster != cfg.NoTaintMaster {
|
||||
t.Errorf("expected %v, got %v", cfg.NoTaintMaster, cfg2.NoTaintMaster)
|
||||
}
|
||||
if cfg2.Networking.ServiceSubnet != cfg.Networking.ServiceSubnet {
|
||||
t.Errorf("expected %v, got %v", cfg.Networking.ServiceSubnet, cfg2.Networking.ServiceSubnet)
|
||||
}
|
||||
if cfg2.Networking.PodSubnet != cfg.Networking.PodSubnet {
|
||||
t.Errorf("expected %v, got %v", cfg.Networking.PodSubnet, cfg2.Networking.PodSubnet)
|
||||
}
|
||||
}
|
1
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod/BUILD
generated
vendored
1
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod/BUILD
generated
vendored
@ -14,6 +14,7 @@ go_test(
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/features:go_default_library",
|
||||
"//cmd/kubeadm/test:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
|
53
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod/utils.go
generated
vendored
53
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod/utils.go
generated
vendored
@ -64,9 +64,10 @@ func ComponentPod(container v1.Container, volumes map[string]v1.Volume) v1.Pod {
|
||||
Labels: map[string]string{"component": container.Name, "tier": "control-plane"},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{container},
|
||||
HostNetwork: true,
|
||||
Volumes: VolumeMapToSlice(volumes),
|
||||
Containers: []v1.Container{container},
|
||||
PriorityClassName: "system-cluster-critical",
|
||||
HostNetwork: true,
|
||||
Volumes: VolumeMapToSlice(volumes),
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -97,6 +98,24 @@ func ComponentProbe(cfg *kubeadmapi.MasterConfiguration, componentName string, p
|
||||
}
|
||||
}
|
||||
|
||||
// EtcdProbe is a helper function for building a shell-based, etcdctl v1.Probe object to healthcheck etcd
|
||||
func EtcdProbe(cfg *kubeadmapi.MasterConfiguration, componentName string, port int, certsDir string, CACertName string, CertName string, KeyName string) *v1.Probe {
|
||||
tlsFlags := fmt.Sprintf("--cacert=%[1]s/%[2]s --cert=%[1]s/%[3]s --key=%[1]s/%[4]s", certsDir, CACertName, CertName, KeyName)
|
||||
// etcd pod is alive if a linearizable get succeeds.
|
||||
cmd := fmt.Sprintf("ETCDCTL_API=3 etcdctl --endpoints=https://[%s]:%d %s get foo", GetProbeAddress(cfg, componentName), port, tlsFlags)
|
||||
|
||||
return &v1.Probe{
|
||||
Handler: v1.Handler{
|
||||
Exec: &v1.ExecAction{
|
||||
Command: []string{"/bin/sh", "-ec", cmd},
|
||||
},
|
||||
},
|
||||
InitialDelaySeconds: 15,
|
||||
TimeoutSeconds: 15,
|
||||
FailureThreshold: 8,
|
||||
}
|
||||
}
|
||||
|
||||
// NewVolume creates a v1.Volume with a hostPath mount to the specified location
|
||||
func NewVolume(name, path string, pathType *v1.HostPathType) v1.Volume {
|
||||
return v1.Volume{
|
||||
@ -180,6 +199,23 @@ func WriteStaticPodToDisk(componentName, manifestDir string, pod v1.Pod) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadStaticPodFromDisk reads a static pod file from disk
|
||||
func ReadStaticPodFromDisk(manifestPath string) (*v1.Pod, error) {
|
||||
buf, err := ioutil.ReadFile(manifestPath)
|
||||
if err != nil {
|
||||
return &v1.Pod{}, fmt.Errorf("failed to read manifest for %q: %v", manifestPath, err)
|
||||
}
|
||||
|
||||
obj, err := util.UnmarshalFromYaml(buf, v1.SchemeGroupVersion)
|
||||
if err != nil {
|
||||
return &v1.Pod{}, fmt.Errorf("failed to unmarshal manifest for %q from YAML: %v", manifestPath, err)
|
||||
}
|
||||
|
||||
pod := obj.(*v1.Pod)
|
||||
|
||||
return pod, nil
|
||||
}
|
||||
|
||||
// GetProbeAddress returns an IP address or 127.0.0.1 to use for liveness probes
|
||||
// in static pod manifests.
|
||||
func GetProbeAddress(cfg *kubeadmapi.MasterConfiguration, componentName string) string {
|
||||
@ -206,8 +242,8 @@ func GetProbeAddress(cfg *kubeadmapi.MasterConfiguration, componentName string)
|
||||
return addr
|
||||
}
|
||||
case componentName == kubeadmconstants.Etcd:
|
||||
if cfg.Etcd.ExtraArgs != nil {
|
||||
if arg, exists := cfg.Etcd.ExtraArgs[etcdListenClientURLsArg]; exists {
|
||||
if cfg.Etcd.Local != nil && cfg.Etcd.Local.ExtraArgs != nil {
|
||||
if arg, exists := cfg.Etcd.Local.ExtraArgs[etcdListenClientURLsArg]; exists {
|
||||
// Use the first url in the listen-client-urls if multiple url's are specified.
|
||||
if strings.ContainsAny(arg, ",") {
|
||||
arg = strings.Split(arg, ",")[0]
|
||||
@ -218,6 +254,13 @@ func GetProbeAddress(cfg *kubeadmapi.MasterConfiguration, componentName string)
|
||||
}
|
||||
// Return the IP if the URL contains an address instead of a name.
|
||||
if ip := net.ParseIP(parsedURL.Hostname()); ip != nil {
|
||||
// etcdctl doesn't support auto-converting zero addresses into loopback addresses
|
||||
if ip.Equal(net.IPv4zero) {
|
||||
return "127.0.0.1"
|
||||
}
|
||||
if ip.Equal(net.IPv6zero) {
|
||||
return net.IPv6loopback.String()
|
||||
}
|
||||
return ip.String()
|
||||
}
|
||||
// Use the local resolver to try resolving the name within the URL.
|
||||
|
270
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod/utils_test.go
generated
vendored
270
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod/utils_test.go
generated
vendored
@ -17,6 +17,9 @@ limitations under the License.
|
||||
package staticpod
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
@ -28,6 +31,7 @@ import (
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
testutil "k8s.io/kubernetes/cmd/kubeadm/test"
|
||||
)
|
||||
|
||||
func TestComponentResources(t *testing.T) {
|
||||
@ -161,48 +165,6 @@ func TestComponentProbe(t *testing.T) {
|
||||
scheme: v1.URISchemeHTTP,
|
||||
expected: "2001:db8::1",
|
||||
},
|
||||
{
|
||||
name: "valid etcd probe using listen-client-urls IPv4 addresses",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
ExtraArgs: map[string]string{
|
||||
"listen-client-urls": "http://1.2.3.4:2379,http://4.3.2.1:2379"},
|
||||
},
|
||||
},
|
||||
component: kubeadmconstants.Etcd,
|
||||
port: 1,
|
||||
path: "foo",
|
||||
scheme: v1.URISchemeHTTP,
|
||||
expected: "1.2.3.4",
|
||||
},
|
||||
{
|
||||
name: "valid etcd probe using listen-client-urls IPv6 addresses",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
ExtraArgs: map[string]string{
|
||||
"listen-client-urls": "http://[2001:db8::1]:2379,http://[2001:db8::2]:2379"},
|
||||
},
|
||||
},
|
||||
component: kubeadmconstants.Etcd,
|
||||
port: 1,
|
||||
path: "foo",
|
||||
scheme: v1.URISchemeHTTP,
|
||||
expected: "2001:db8::1",
|
||||
},
|
||||
{
|
||||
name: "valid IPv4 etcd probe using hostname for listen-client-urls",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
ExtraArgs: map[string]string{
|
||||
"listen-client-urls": "http://localhost:2379"},
|
||||
},
|
||||
},
|
||||
component: kubeadmconstants.Etcd,
|
||||
port: 1,
|
||||
path: "foo",
|
||||
scheme: v1.URISchemeHTTP,
|
||||
expected: "127.0.0.1",
|
||||
},
|
||||
}
|
||||
for _, rt := range tests {
|
||||
actual := ComponentProbe(rt.cfg, rt.component, rt.port, rt.path, rt.scheme)
|
||||
@ -229,6 +191,155 @@ func TestComponentProbe(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEtcdProbe(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
component string
|
||||
port int
|
||||
certsDir string
|
||||
cacert string
|
||||
cert string
|
||||
key string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "valid etcd probe using listen-client-urls IPv4 addresses",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
ExtraArgs: map[string]string{
|
||||
"listen-client-urls": "http://1.2.3.4:2379,http://4.3.2.1:2379"},
|
||||
},
|
||||
},
|
||||
},
|
||||
component: kubeadmconstants.Etcd,
|
||||
port: 1,
|
||||
certsDir: "secretsA",
|
||||
cacert: "ca1",
|
||||
cert: "cert1",
|
||||
key: "key1",
|
||||
expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[1.2.3.4]:1 --cacert=secretsA/ca1 --cert=secretsA/cert1 --key=secretsA/key1 get foo",
|
||||
},
|
||||
{
|
||||
name: "valid etcd probe using listen-client-urls unspecified IPv6 address",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
ExtraArgs: map[string]string{
|
||||
"listen-client-urls": "http://[0:0:0:0:0:0:0:0]:2379"},
|
||||
},
|
||||
},
|
||||
},
|
||||
component: kubeadmconstants.Etcd,
|
||||
port: 1,
|
||||
certsDir: "secretsB",
|
||||
cacert: "ca2",
|
||||
cert: "cert2",
|
||||
key: "key2",
|
||||
expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[::1]:1 --cacert=secretsB/ca2 --cert=secretsB/cert2 --key=secretsB/key2 get foo",
|
||||
},
|
||||
{
|
||||
name: "valid etcd probe using listen-client-urls unspecified IPv6 address 2",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
ExtraArgs: map[string]string{
|
||||
"listen-client-urls": "http://[::0:0]:2379"},
|
||||
},
|
||||
},
|
||||
},
|
||||
component: kubeadmconstants.Etcd,
|
||||
port: 1,
|
||||
certsDir: "secretsB",
|
||||
cacert: "ca2",
|
||||
cert: "cert2",
|
||||
key: "key2",
|
||||
expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[::1]:1 --cacert=secretsB/ca2 --cert=secretsB/cert2 --key=secretsB/key2 get foo",
|
||||
},
|
||||
{
|
||||
name: "valid etcd probe using listen-client-urls unspecified IPv6 address 3",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
ExtraArgs: map[string]string{
|
||||
"listen-client-urls": "http://[::]:2379"},
|
||||
},
|
||||
},
|
||||
},
|
||||
component: kubeadmconstants.Etcd,
|
||||
port: 1,
|
||||
certsDir: "secretsB",
|
||||
cacert: "ca2",
|
||||
cert: "cert2",
|
||||
key: "key2",
|
||||
expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[::1]:1 --cacert=secretsB/ca2 --cert=secretsB/cert2 --key=secretsB/key2 get foo",
|
||||
},
|
||||
{
|
||||
name: "valid etcd probe using listen-client-urls unspecified IPv4 address",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
ExtraArgs: map[string]string{
|
||||
"listen-client-urls": "http://1.2.3.4:2379,http://4.3.2.1:2379"},
|
||||
},
|
||||
},
|
||||
},
|
||||
component: kubeadmconstants.Etcd,
|
||||
port: 1,
|
||||
certsDir: "secretsA",
|
||||
cacert: "ca1",
|
||||
cert: "cert1",
|
||||
key: "key1",
|
||||
expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[1.2.3.4]:1 --cacert=secretsA/ca1 --cert=secretsA/cert1 --key=secretsA/key1 get foo",
|
||||
},
|
||||
{
|
||||
name: "valid etcd probe using listen-client-urls IPv6 addresses",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
ExtraArgs: map[string]string{
|
||||
"listen-client-urls": "http://[2001:db8::1]:2379,http://[2001:db8::2]:2379"},
|
||||
},
|
||||
},
|
||||
},
|
||||
component: kubeadmconstants.Etcd,
|
||||
port: 1,
|
||||
certsDir: "secretsB",
|
||||
cacert: "ca2",
|
||||
cert: "cert2",
|
||||
key: "key2",
|
||||
expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[2001:db8::1]:1 --cacert=secretsB/ca2 --cert=secretsB/cert2 --key=secretsB/key2 get foo",
|
||||
},
|
||||
{
|
||||
name: "valid IPv4 etcd probe using hostname for listen-client-urls",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
ExtraArgs: map[string]string{
|
||||
"listen-client-urls": "http://localhost:2379"},
|
||||
},
|
||||
},
|
||||
},
|
||||
component: kubeadmconstants.Etcd,
|
||||
port: 1,
|
||||
certsDir: "secretsC",
|
||||
cacert: "ca3",
|
||||
cert: "cert3",
|
||||
key: "key3",
|
||||
expected: "ETCDCTL_API=3 etcdctl --endpoints=https://[127.0.0.1]:1 --cacert=secretsC/ca3 --cert=secretsC/cert3 --key=secretsC/key3 get foo",
|
||||
},
|
||||
}
|
||||
for _, rt := range tests {
|
||||
actual := EtcdProbe(rt.cfg, rt.component, rt.port, rt.certsDir, rt.cacert, rt.cert, rt.key)
|
||||
if actual.Handler.Exec.Command[2] != rt.expected {
|
||||
t.Errorf("%s test case failed:\n\texpected: %s\n\t actual: %s",
|
||||
rt.name, rt.expected,
|
||||
actual.Handler.Exec.Command[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestComponentPod(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
@ -253,8 +364,9 @@ func TestComponentPod(t *testing.T) {
|
||||
Name: "foo",
|
||||
},
|
||||
},
|
||||
HostNetwork: true,
|
||||
Volumes: []v1.Volume{},
|
||||
PriorityClassName: "system-cluster-critical",
|
||||
HostNetwork: true,
|
||||
Volumes: []v1.Volume{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -425,3 +537,73 @@ func TestGetExtraParameters(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
validPod = `
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
labels:
|
||||
component: etcd
|
||||
tier: control-plane
|
||||
name: etcd
|
||||
namespace: kube-system
|
||||
spec:
|
||||
containers:
|
||||
- image: gcr.io/google_containers/etcd-amd64:3.1.11
|
||||
status: {}
|
||||
`
|
||||
invalidPod = `---{ broken yaml @@@`
|
||||
)
|
||||
|
||||
func TestReadStaticPodFromDisk(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
podYaml string
|
||||
expectErr bool
|
||||
writeManifest bool
|
||||
}{
|
||||
{
|
||||
description: "valid pod is marshaled",
|
||||
podYaml: validPod,
|
||||
writeManifest: true,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
description: "invalid pod fails to unmarshal",
|
||||
podYaml: invalidPod,
|
||||
writeManifest: true,
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
description: "non-existent file returns error",
|
||||
podYaml: ``,
|
||||
writeManifest: false,
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
tmpdir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
manifestPath := filepath.Join(tmpdir, "pod.yaml")
|
||||
if rt.writeManifest {
|
||||
err := ioutil.WriteFile(manifestPath, []byte(rt.podYaml), 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to write pod manifest\n%s\n\tfatal error: %v", rt.description, err)
|
||||
}
|
||||
}
|
||||
|
||||
_, actualErr := ReadStaticPodFromDisk(manifestPath)
|
||||
if (actualErr != nil) != rt.expectErr {
|
||||
t.Errorf(
|
||||
"ReadStaticPodFromDisk failed\n%s\n\texpected error: %t\n\tgot: %t\n\tactual error: %v",
|
||||
rt.description,
|
||||
rt.expectErr,
|
||||
(actualErr != nil),
|
||||
actualErr,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
34
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/token/BUILD
generated
vendored
34
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/token/BUILD
generated
vendored
@ -1,34 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["tokens_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = ["//cmd/kubeadm/app/apis/kubeadm:go_default_library"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["tokens.go"],
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/util/token",
|
||||
deps = ["//cmd/kubeadm/app/apis/kubeadm:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
125
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/token/tokens.go
generated
vendored
125
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/token/tokens.go
generated
vendored
@ -1,125 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 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 token
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
)
|
||||
|
||||
const (
|
||||
// TokenIDBytes defines a number of bytes used for a token id
|
||||
TokenIDBytes = 6
|
||||
// TokenSecretBytes defines a number of bytes used for a secret
|
||||
TokenSecretBytes = 16
|
||||
)
|
||||
|
||||
var (
|
||||
// TokenIDRegexpString defines token's id regular expression pattern
|
||||
TokenIDRegexpString = "^([a-z0-9]{6})$"
|
||||
// TokenIDRegexp is a compiled regular expression of TokenIDRegexpString
|
||||
TokenIDRegexp = regexp.MustCompile(TokenIDRegexpString)
|
||||
// TokenRegexpString defines id.secret regular expression pattern
|
||||
TokenRegexpString = "^([a-z0-9]{6})\\.([a-z0-9]{16})$"
|
||||
// TokenRegexp is a compiled regular expression of TokenRegexpString
|
||||
TokenRegexp = regexp.MustCompile(TokenRegexpString)
|
||||
)
|
||||
|
||||
const validBootstrapTokenChars = "0123456789abcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
func randBytes(length int) (string, error) {
|
||||
// len("0123456789abcdefghijklmnopqrstuvwxyz") = 36 which doesn't evenly divide
|
||||
// the possible values of a byte: 256 mod 36 = 4. Discard any random bytes we
|
||||
// read that are >= 252 so the bytes we evenly divide the character set.
|
||||
const maxByteValue = 252
|
||||
|
||||
var (
|
||||
b byte
|
||||
err error
|
||||
token = make([]byte, length)
|
||||
)
|
||||
|
||||
reader := bufio.NewReaderSize(rand.Reader, length*2)
|
||||
for i := range token {
|
||||
for {
|
||||
if b, err = reader.ReadByte(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if b < maxByteValue {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
token[i] = validBootstrapTokenChars[int(b)%len(validBootstrapTokenChars)]
|
||||
}
|
||||
|
||||
return string(token), nil
|
||||
}
|
||||
|
||||
// GenerateToken generates a new token with a token ID that is valid as a
|
||||
// Kubernetes DNS label.
|
||||
// For more info, see kubernetes/pkg/util/validation/validation.go.
|
||||
func GenerateToken() (string, error) {
|
||||
tokenID, err := randBytes(TokenIDBytes)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tokenSecret, err := randBytes(TokenSecretBytes)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s.%s", tokenID, tokenSecret), nil
|
||||
}
|
||||
|
||||
// ParseTokenID tries and parse a valid token ID from a string.
|
||||
// An error is returned in case of failure.
|
||||
func ParseTokenID(s string) error {
|
||||
if !TokenIDRegexp.MatchString(s) {
|
||||
return fmt.Errorf("token ID [%q] was not of form [%q]", s, TokenIDRegexpString)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseToken tries and parse a valid token from a string.
|
||||
// A token ID and token secret are returned in case of success, an error otherwise.
|
||||
func ParseToken(s string) (string, string, error) {
|
||||
split := TokenRegexp.FindStringSubmatch(s)
|
||||
if len(split) != 3 {
|
||||
return "", "", fmt.Errorf("token [%q] was not of form [%q]", s, TokenRegexpString)
|
||||
}
|
||||
return split[1], split[2], nil
|
||||
}
|
||||
|
||||
// BearerToken returns a string representation of the passed token.
|
||||
func BearerToken(d *kubeadmapi.TokenDiscovery) string {
|
||||
return fmt.Sprintf("%s.%s", d.ID, d.Secret)
|
||||
}
|
||||
|
||||
// ValidateToken validates whether a token is well-formed.
|
||||
// In case it's not, the corresponding error is returned as well.
|
||||
func ValidateToken(d *kubeadmapi.TokenDiscovery) (bool, error) {
|
||||
if _, _, err := ParseToken(d.ID + "." + d.Secret); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
173
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/token/tokens_test.go
generated
vendored
173
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/token/tokens_test.go
generated
vendored
@ -1,173 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 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 token
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
)
|
||||
|
||||
func TestTokenParse(t *testing.T) {
|
||||
var tests = []struct {
|
||||
token string
|
||||
expected bool
|
||||
}{
|
||||
{token: "1234567890123456789012", expected: false}, // invalid parcel size
|
||||
{token: "12345.1234567890123456", expected: false}, // invalid parcel size
|
||||
{token: ".1234567890123456", expected: false}, // invalid parcel size
|
||||
{token: "123456:1234567890.123456", expected: false}, // invalid separation
|
||||
{token: "abcdef:1234567890123456", expected: false}, // invalid separation
|
||||
{token: "Abcdef.1234567890123456", expected: false}, // invalid token id
|
||||
{token: "123456.AABBCCDDEEFFGGHH", expected: false}, // invalid token secret
|
||||
{token: "abcdef.1234567890123456", expected: true},
|
||||
{token: "123456.aabbccddeeffgghh", expected: true},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
_, _, actual := ParseToken(rt.token)
|
||||
if (actual == nil) != rt.expected {
|
||||
t.Errorf(
|
||||
"failed ParseToken for this token: [%s]\n\texpected: %t\n\t actual: %t",
|
||||
rt.token,
|
||||
rt.expected,
|
||||
(actual == nil),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestParseTokenID(t *testing.T) {
|
||||
var tests = []struct {
|
||||
tokenID string
|
||||
expected bool
|
||||
}{
|
||||
{tokenID: "", expected: false},
|
||||
{tokenID: "1234567890123456789012", expected: false},
|
||||
{tokenID: "12345", expected: false},
|
||||
{tokenID: "Abcdef", expected: false},
|
||||
{tokenID: "abcdef", expected: true},
|
||||
{tokenID: "123456", expected: true},
|
||||
}
|
||||
for _, rt := range tests {
|
||||
actual := ParseTokenID(rt.tokenID)
|
||||
if (actual == nil) != rt.expected {
|
||||
t.Errorf(
|
||||
"failed ParseTokenID for this token ID: [%s]\n\texpected: %t\n\t actual: %t",
|
||||
rt.tokenID,
|
||||
rt.expected,
|
||||
(actual == nil),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateToken(t *testing.T) {
|
||||
var tests = []struct {
|
||||
token *kubeadmapi.TokenDiscovery
|
||||
expected bool
|
||||
}{
|
||||
{token: &kubeadmapi.TokenDiscovery{ID: "", Secret: ""}, expected: false},
|
||||
{token: &kubeadmapi.TokenDiscovery{ID: "1234567890123456789012", Secret: ""}, expected: false},
|
||||
{token: &kubeadmapi.TokenDiscovery{ID: "", Secret: "1234567890123456789012"}, expected: false},
|
||||
{token: &kubeadmapi.TokenDiscovery{ID: "12345", Secret: "1234567890123456"}, expected: false},
|
||||
{token: &kubeadmapi.TokenDiscovery{ID: "Abcdef", Secret: "1234567890123456"}, expected: false},
|
||||
{token: &kubeadmapi.TokenDiscovery{ID: "123456", Secret: "AABBCCDDEEFFGGHH"}, expected: false},
|
||||
{token: &kubeadmapi.TokenDiscovery{ID: "abc*ef", Secret: "1234567890123456"}, expected: false},
|
||||
{token: &kubeadmapi.TokenDiscovery{ID: "abcdef", Secret: "123456789*123456"}, expected: false},
|
||||
{token: &kubeadmapi.TokenDiscovery{ID: "abcdef", Secret: "1234567890123456"}, expected: true},
|
||||
{token: &kubeadmapi.TokenDiscovery{ID: "123456", Secret: "aabbccddeeffgghh"}, expected: true},
|
||||
{token: &kubeadmapi.TokenDiscovery{ID: "abc456", Secret: "1234567890123456"}, expected: true},
|
||||
{token: &kubeadmapi.TokenDiscovery{ID: "abcdef", Secret: "123456ddeeffgghh"}, expected: true},
|
||||
}
|
||||
for _, rt := range tests {
|
||||
valid, actual := ValidateToken(rt.token)
|
||||
if (actual == nil) != rt.expected {
|
||||
t.Errorf(
|
||||
"failed ValidateToken for this token ID: [%s]\n\texpected: %t\n\t actual: %t",
|
||||
rt.token,
|
||||
rt.expected,
|
||||
(actual == nil),
|
||||
)
|
||||
}
|
||||
if (valid == true) != rt.expected {
|
||||
t.Errorf(
|
||||
"failed ValidateToken for this token ID: [%s]\n\texpected: %t\n\t actual: %t",
|
||||
rt.token,
|
||||
rt.expected,
|
||||
(actual == nil),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateToken(t *testing.T) {
|
||||
token, err := GenerateToken()
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateToken returned an unexpected error: %+v", err)
|
||||
}
|
||||
tokenID, tokenSecret, err := ParseToken(token)
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateToken returned an unexpected error: %+v", err)
|
||||
}
|
||||
if len(tokenID) != 6 {
|
||||
t.Errorf("failed GenerateToken first part length:\n\texpected: 6\n\t actual: %d", len(tokenID))
|
||||
}
|
||||
if len(tokenSecret) != 16 {
|
||||
t.Errorf("failed GenerateToken second part length:\n\texpected: 16\n\t actual: %d", len(tokenSecret))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandBytes(t *testing.T) {
|
||||
var randTest = []int{
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
100,
|
||||
}
|
||||
|
||||
for _, rt := range randTest {
|
||||
actual, err := randBytes(rt)
|
||||
if err != nil {
|
||||
t.Errorf("failed randBytes: %v", err)
|
||||
}
|
||||
if len(actual) != rt {
|
||||
t.Errorf("failed randBytes:\n\texpected: %d\n\t actual: %d\n", rt, len(actual))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBearerToken(t *testing.T) {
|
||||
var tests = []struct {
|
||||
token *kubeadmapi.TokenDiscovery
|
||||
expected string
|
||||
}{
|
||||
{token: &kubeadmapi.TokenDiscovery{ID: "foo", Secret: "bar"}, expected: "foo.bar"}, // should use default
|
||||
}
|
||||
for _, rt := range tests {
|
||||
actual := BearerToken(rt.token)
|
||||
if actual != rt.expected {
|
||||
t.Errorf(
|
||||
"failed BearerToken:\n\texpected: %s\n\t actual: %s",
|
||||
rt.expected,
|
||||
actual,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
4
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/version.go
generated
vendored
4
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/version.go
generated
vendored
@ -122,8 +122,8 @@ func splitVersion(version string) (string, string, error) {
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(subs[0][2], "ci"):
|
||||
// Special case. CI images populated only by ci-cross area
|
||||
urlSuffix = "ci-cross"
|
||||
// Just use whichever the user specified
|
||||
urlSuffix = subs[0][2]
|
||||
default:
|
||||
urlSuffix = "release"
|
||||
}
|
||||
|
4
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/version_test.go
generated
vendored
4
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/version_test.go
generated
vendored
@ -180,8 +180,10 @@ func TestSplitVersion(t *testing.T) {
|
||||
{"release/v1.7.0", "https://dl.k8s.io/release", "v1.7.0", true},
|
||||
{"release/latest-1.7", "https://dl.k8s.io/release", "latest-1.7", true},
|
||||
// CI builds area, lookup actual builds at ci-cross/*.txt
|
||||
{"ci/latest", "https://dl.k8s.io/ci", "latest", true},
|
||||
{"ci-cross/latest", "https://dl.k8s.io/ci-cross", "latest", true},
|
||||
{"ci/latest-1.7", "https://dl.k8s.io/ci-cross", "latest-1.7", true},
|
||||
{"ci/latest-1.7", "https://dl.k8s.io/ci", "latest-1.7", true},
|
||||
{"ci-cross/latest-1.7", "https://dl.k8s.io/ci-cross", "latest-1.7", true},
|
||||
// unknown label in default (release) area: splitVersion validate only areas.
|
||||
{"unknown-1", "https://dl.k8s.io/release", "unknown-1", true},
|
||||
// unknown area, not valid input.
|
||||
|
Reference in New Issue
Block a user