Bumping k8s dependencies to 1.13
This commit is contained in:
38
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/BUILD
generated
vendored
38
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/BUILD
generated
vendored
@@ -11,6 +11,8 @@ go_library(
|
||||
srcs = [
|
||||
"arguments.go",
|
||||
"cgroupdriver.go",
|
||||
"chroot_unix.go",
|
||||
"chroot_windows.go",
|
||||
"copy.go",
|
||||
"endpoint.go",
|
||||
"error.go",
|
||||
@@ -21,15 +23,19 @@ go_library(
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/util",
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm: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",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_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",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//pkg/version:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||
"//vendor/github.com/ghodss/yaml:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -39,6 +45,7 @@ go_test(
|
||||
srcs = [
|
||||
"arguments_test.go",
|
||||
"cgroupdriver_test.go",
|
||||
"chroot_test.go",
|
||||
"endpoint_test.go",
|
||||
"error_test.go",
|
||||
"marshal_test.go",
|
||||
@@ -48,10 +55,13 @@ go_test(
|
||||
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",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha3:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -73,7 +83,9 @@ filegroup(
|
||||
"//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/runtime:all-srcs",
|
||||
"//cmd/kubeadm/app/util/staticpod:all-srcs",
|
||||
"//cmd/kubeadm/app/util/system:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
48
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient/BUILD
generated
vendored
48
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient/BUILD
generated
vendored
@@ -22,25 +22,25 @@ go_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",
|
||||
"//vendor/k8s.io/api/rbac/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/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",
|
||||
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/testing:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
"//staging/src/k8s.io/api/apps/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/dynamic:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/testing:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -65,10 +65,10 @@ go_test(
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/client-go/testing:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/testing:go_default_library",
|
||||
],
|
||||
)
|
||||
|
14
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient/wait.go
generated
vendored
14
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient/wait.go
generated
vendored
@@ -211,20 +211,6 @@ func (w *KubeWaiter) WaitForStaticPodHashChange(nodeName, component, previousHas
|
||||
})
|
||||
}
|
||||
|
||||
// getStaticPodControlPlaneHashes computes hashes for all the control plane's Static Pod resources
|
||||
func getStaticPodControlPlaneHashes(client clientset.Interface, nodeName string) (map[string]string, error) {
|
||||
|
||||
mirrorPodHashes := map[string]string{}
|
||||
for _, component := range constants.MasterComponents {
|
||||
hash, err := getStaticPodSingleHash(client, nodeName, component)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mirrorPodHashes[component] = hash
|
||||
}
|
||||
return mirrorPodHashes, nil
|
||||
}
|
||||
|
||||
// getStaticSinglePodHash computes hashes for a single Static Pod resource
|
||||
func getStaticPodSingleHash(client clientset.Interface, nodeName string, component string) (string, error) {
|
||||
|
||||
|
18
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/audit/BUILD
generated
vendored
18
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/audit/BUILD
generated
vendored
@@ -7,11 +7,11 @@ go_library(
|
||||
visibility = ["//visibility:public"],
|
||||
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",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/apis/audit/install:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/apis/audit/v1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -20,10 +20,10 @@ go_test(
|
||||
srcs = ["utils_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//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",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/apis/audit/install:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/apis/audit/v1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
14
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/audit/utils.go
generated
vendored
14
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/audit/utils.go
generated
vendored
@@ -26,27 +26,27 @@ import (
|
||||
"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"
|
||||
auditv1 "k8s.io/apiserver/pkg/apis/audit/v1"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
)
|
||||
|
||||
// CreateDefaultAuditLogPolicy writes the default audit log policy to disk.
|
||||
func CreateDefaultAuditLogPolicy(policyFile string) error {
|
||||
policy := auditv1beta1.Policy{
|
||||
policy := auditv1.Policy{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: auditv1beta1.SchemeGroupVersion.String(),
|
||||
APIVersion: auditv1.SchemeGroupVersion.String(),
|
||||
Kind: "Policy",
|
||||
},
|
||||
Rules: []auditv1beta1.PolicyRule{
|
||||
Rules: []auditv1.PolicyRule{
|
||||
{
|
||||
Level: auditv1beta1.LevelMetadata,
|
||||
Level: auditv1.LevelMetadata,
|
||||
},
|
||||
},
|
||||
}
|
||||
return writePolicyToDisk(policyFile, &policy)
|
||||
}
|
||||
|
||||
func writePolicyToDisk(policyFile string, policy *auditv1beta1.Policy) error {
|
||||
func writePolicyToDisk(policyFile string, policy *auditv1.Policy) error {
|
||||
// creates target folder if not already exists
|
||||
if err := os.MkdirAll(filepath.Dir(policyFile), 0700); err != nil {
|
||||
return fmt.Errorf("failed to create directory %q: %v", filepath.Dir(policyFile), err)
|
||||
@@ -59,7 +59,7 @@ func writePolicyToDisk(policyFile string, policy *auditv1beta1.Policy) error {
|
||||
codecs := serializer.NewCodecFactory(scheme)
|
||||
|
||||
// writes the policy to disk
|
||||
serialized, err := util.MarshalToYamlForCodecs(policy, auditv1beta1.SchemeGroupVersion, codecs)
|
||||
serialized, err := util.MarshalToYamlForCodecs(policy, auditv1.SchemeGroupVersion, codecs)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal audit policy to YAML: %v", err)
|
||||
|
4
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/audit/utils_test.go
generated
vendored
4
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/audit/utils_test.go
generated
vendored
@@ -25,7 +25,7 @@ import (
|
||||
"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"
|
||||
auditv1 "k8s.io/apiserver/pkg/apis/audit/v1"
|
||||
)
|
||||
|
||||
func cleanup(t *testing.T, path string) {
|
||||
@@ -54,7 +54,7 @@ func TestCreateDefaultAuditLogPolicy(t *testing.T) {
|
||||
scheme := runtime.NewScheme()
|
||||
install.Install(scheme)
|
||||
codecs := serializer.NewCodecFactory(scheme)
|
||||
policy := auditv1beta1.Policy{}
|
||||
policy := auditv1.Policy{}
|
||||
err = runtime.DecodeInto(codecs.UniversalDecoder(), policyBytes, &policy)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to decode written policy: %v", err)
|
||||
|
66
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/chroot_test.go
generated
vendored
Normal file
66
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/chroot_test.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
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 (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Can't just call Chroot() because it will affect other tests in the
|
||||
// same process. Golang makes it hard to just call fork(), so instead
|
||||
// we exec ourselves again, and run the test in the new subprocess.
|
||||
|
||||
func testChrootReal(t *testing.T) {
|
||||
testfile := filepath.FromSlash("/" + filepath.Base(os.Args[0]))
|
||||
dir := filepath.Dir(os.Args[0])
|
||||
if dir == "." {
|
||||
t.Skip("skipping: running test at root somehow")
|
||||
}
|
||||
if err := Chroot(dir); err != nil {
|
||||
if strings.Contains(err.Error(), "operation not permitted") {
|
||||
t.Skip("skipping: insufficient permissions to chroot")
|
||||
}
|
||||
t.Fatalf("chroot error: %v", err)
|
||||
}
|
||||
|
||||
// All file access should now be relative to `dir`
|
||||
if _, err := os.Stat(testfile); err != nil {
|
||||
t.Errorf("Expected file %q to exist, but got %v", testfile, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChroot(t *testing.T) {
|
||||
if os.Getenv("GO_TEST_CHROOT_FOR_REALZ") == "1" {
|
||||
testChrootReal(t)
|
||||
return
|
||||
}
|
||||
|
||||
cmd := exec.Command(os.Args[0], "-test.v", "-test.run=TestChroot")
|
||||
cmd.Env = []string{"GO_TEST_CHROOT_FOR_REALZ=1"}
|
||||
|
||||
out, err := cmd.Output()
|
||||
t.Logf("subprocess output:\n%s", out)
|
||||
if err != nil {
|
||||
t.Errorf("subprocess error: %v", err)
|
||||
}
|
||||
}
|
40
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/chroot_unix.go
generated
vendored
Normal file
40
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/chroot_unix.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
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"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Chroot chroot()s to the new path.
|
||||
// NB: All file paths after this call are effectively relative to
|
||||
// `rootfs`
|
||||
func Chroot(rootfs string) error {
|
||||
if err := syscall.Chroot(rootfs); err != nil {
|
||||
return fmt.Errorf("unable to chroot to %s: %v", rootfs, err)
|
||||
}
|
||||
root := filepath.FromSlash("/")
|
||||
if err := os.Chdir(root); err != nil {
|
||||
return fmt.Errorf("unable to chdir to %s: %v", root, err)
|
||||
}
|
||||
return nil
|
||||
}
|
30
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/chroot_windows.go
generated
vendored
Normal file
30
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/chroot_windows.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
// +build windows
|
||||
|
||||
/*
|
||||
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"
|
||||
)
|
||||
|
||||
// Chroot chroot()s to the new path.
|
||||
// NB: All file paths after this call are effectively relative to
|
||||
// `rootfs`
|
||||
func Chroot(rootfs string) error {
|
||||
return fmt.Errorf("chroot is not implemented on Windows")
|
||||
}
|
37
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/BUILD
generated
vendored
37
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/BUILD
generated
vendored
@@ -10,6 +10,7 @@ go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"cluster.go",
|
||||
"common.go",
|
||||
"masterconfig.go",
|
||||
"nodeconfig.go",
|
||||
],
|
||||
@@ -17,27 +18,31 @@ go_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/apis/kubeadm/v1alpha3:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library",
|
||||
"//cmd/kubeadm/app/componentconfigs:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//pkg/util/node:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/bootstrap/token/util:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/cert: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 = [
|
||||
"cluster_test.go",
|
||||
"common_test.go",
|
||||
"masterconfig_test.go",
|
||||
"nodeconfig_test.go",
|
||||
],
|
||||
@@ -46,13 +51,17 @@ go_test(
|
||||
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/v1alpha3:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/fake: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",
|
||||
],
|
||||
)
|
||||
|
||||
|
231
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/cluster.go
generated
vendored
231
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/cluster.go
generated
vendored
@@ -17,49 +17,244 @@ limitations under the License.
|
||||
package config
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
)
|
||||
|
||||
// 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) {
|
||||
func FetchConfigFromFileOrCluster(client clientset.Interface, w io.Writer, logPrefix, cfgPath string, newControlPlane bool) (*kubeadmapi.InitConfiguration, error) {
|
||||
// Load the configuration from a file or the cluster
|
||||
configBytes, err := loadConfigurationBytes(client, w, logPrefix, cfgPath)
|
||||
initcfg, err := loadConfiguration(client, w, logPrefix, cfgPath, newControlPlane)
|
||||
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)
|
||||
// Apply dynamic defaults
|
||||
if err := SetInitDynamicDefaults(initcfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return initcfg, err
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// loadConfiguration loads the configuration byte slice from either a file or the cluster ConfigMap
|
||||
func loadConfiguration(client clientset.Interface, w io.Writer, logPrefix, cfgPath string, newControlPlane bool) (*kubeadmapi.InitConfiguration, 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)
|
||||
return loadInitConfigurationFromFile(cfgPath)
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "[%s] Reading configuration from the cluster...\n", logPrefix)
|
||||
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.InitConfigurationConfigMap)
|
||||
return getInitConfigurationFromCluster(constants.KubernetesDir, client, newControlPlane)
|
||||
}
|
||||
|
||||
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)
|
||||
func loadInitConfigurationFromFile(cfgPath string) (*kubeadmapi.InitConfiguration, error) {
|
||||
configBytes, err := ioutil.ReadFile(cfgPath)
|
||||
if err != nil {
|
||||
return nil, 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
|
||||
// Unmarshal the versioned configuration populated from the file,
|
||||
// convert it to the internal API types, then default and validate
|
||||
// NB the file can be one of
|
||||
// - a single YAML, with a v1alpha2.MasterConfiguration object (with embedded component configs)
|
||||
// - multiple YAML, with a combination of
|
||||
// - a YAML with a v1alpha3.InitConfiguration object
|
||||
// - a YAML with a v1alpha3.ClusterConfiguration object (without embedded component configs)
|
||||
// - separated YAML for components configs
|
||||
initcfg, err := BytesToInternalConfig(configBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return initcfg, nil
|
||||
}
|
||||
|
||||
func getInitConfigurationFromCluster(kubeconfigDir string, client clientset.Interface, newControlPlane bool) (*kubeadmapi.InitConfiguration, error) {
|
||||
// TODO: This code should support reading the MasterConfiguration key as well for backwards-compat
|
||||
// Also, the config map really should be KubeadmConfigConfigMap...
|
||||
configMap, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(constants.InitConfigurationConfigMap, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: remove in V1.13
|
||||
// If InitConfigurationConfigMapKey exist, the kubeadm-config was created with v1.11
|
||||
if _, ok := configMap.Data[constants.InitConfigurationConfigMapKey]; ok {
|
||||
return getInitConfigurationFromConfigMapV11(configMap.Data)
|
||||
}
|
||||
|
||||
return getInitConfigurationFromConfigMaps(kubeconfigDir, client, configMap.Data, newControlPlane)
|
||||
}
|
||||
|
||||
func getInitConfigurationFromConfigMapV11(data map[string]string) (*kubeadmapi.InitConfiguration, error) {
|
||||
configBytes := []byte(data[constants.InitConfigurationConfigMapKey])
|
||||
|
||||
// Unmarshal the versioned configuration populated from the file,
|
||||
// convert it to the internal API types, then default and validate
|
||||
// NB the config map created with v11 is a single YAML, with a v1alpha2.MasterConfiguration object (with embedded component configs)
|
||||
initcfg, err := BytesToInternalConfig(configBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return initcfg, nil
|
||||
}
|
||||
|
||||
func getInitConfigurationFromConfigMaps(kubeconfigDir string, client clientset.Interface, data map[string]string, newControlPlane bool) (*kubeadmapi.InitConfiguration, error) {
|
||||
// In case of cluster crated with v1.12 InitConfiguration is composed with data from different places
|
||||
initcfg := &kubeadmapi.InitConfiguration{}
|
||||
|
||||
// gets ClusterConfiguration from kubeadm-config
|
||||
clusterConfigurationData, ok := data[constants.ClusterConfigurationConfigMapKey]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected error when reading kubeadm-config ConfigMap: %s key value pair missing", constants.ClusterConfigurationConfigMapKey)
|
||||
}
|
||||
if err := runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(), []byte(clusterConfigurationData), &initcfg.ClusterConfiguration); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// gets the component configs from the corresponding config maps
|
||||
if err := getComponentConfigs(client, &initcfg.ClusterConfiguration); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if this isn't a new controlplane instance (e.g. in case of kubeadm upgrades)
|
||||
// get nodes specific information as well
|
||||
if !newControlPlane {
|
||||
// gets the nodeRegistration for the current from the node object
|
||||
if err := getNodeRegistration(kubeconfigDir, client, &initcfg.NodeRegistration); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// gets the APIEndpoint for the current node from then ClusterStatus in the kubeadm-config ConfigMap
|
||||
if err := getAPIEndpoint(data, initcfg.NodeRegistration.Name, &initcfg.APIEndpoint); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return initcfg, nil
|
||||
}
|
||||
|
||||
// getNodeRegistration returns the nodeRegistration for the current node
|
||||
func getNodeRegistration(kubeconfigDir string, client clientset.Interface, nodeRegistration *kubeadmapi.NodeRegistrationOptions) error {
|
||||
// gets the name of the current node
|
||||
nodeName, err := getNodeNameFromKubeletConfig(kubeconfigDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// gets the corresponding node and retrives attributes stored there.
|
||||
node, err := client.CoreV1().Nodes().Get(nodeName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
criSocket, ok := node.ObjectMeta.Annotations[constants.AnnotationKubeadmCRISocket]
|
||||
if !ok {
|
||||
return fmt.Errorf("Node %s doesn't have %s annotation", nodeName, constants.AnnotationKubeadmCRISocket)
|
||||
}
|
||||
|
||||
// returns the nodeRegistration attributes
|
||||
nodeRegistration.Name = nodeName
|
||||
nodeRegistration.CRISocket = criSocket
|
||||
nodeRegistration.Taints = node.Spec.Taints
|
||||
// NB. currently nodeRegistration.KubeletExtraArgs isn't stored at node level but only in the kubeadm-flags.env
|
||||
// that isn't modified during upgrades
|
||||
// in future we might reconsider this thus enabling changes to the kubeadm-flags.env during upgrades as well
|
||||
return nil
|
||||
}
|
||||
|
||||
// getNodeNameFromConfig gets the node name from a kubelet config file
|
||||
// TODO: in future we want to switch to a more canonical way for doing this e.g. by having this
|
||||
// information in the local kubelet config.yaml
|
||||
func getNodeNameFromKubeletConfig(kubeconfigDir string) (string, error) {
|
||||
// loads the kubelet.conf file
|
||||
fileName := filepath.Join(kubeconfigDir, constants.KubeletKubeConfigFileName)
|
||||
config, err := clientcmd.LoadFromFile(fileName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// gets the info about the current user
|
||||
authInfo := config.AuthInfos[config.Contexts[config.CurrentContext].AuthInfo]
|
||||
|
||||
// gets the X509 certificate with current user credentials
|
||||
var certs []*x509.Certificate
|
||||
if len(authInfo.ClientCertificateData) > 0 {
|
||||
// if the config file uses an embedded x509 certificate (e.g. kubelet.conf created by kubeadm), parse it
|
||||
if certs, err = certutil.ParseCertsPEM(authInfo.ClientCertificateData); err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else if len(authInfo.ClientCertificate) > 0 {
|
||||
// if the config file links an external x509 certificate (e.g. kubelet.conf created by TLS bootstrap), load it
|
||||
if certs, err = certutil.CertsFromFile(authInfo.ClientCertificate); err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
return "", errors.New("Invalid kubelet.conf. X509 certificate expected")
|
||||
}
|
||||
|
||||
// We are only putting one certificate in the certificate pem file, so it's safe to just pick the first one
|
||||
// TODO: Support multiple certs here in order to be able to rotate certs
|
||||
cert := certs[0]
|
||||
|
||||
// gets the node name from the certificate common name
|
||||
return strings.TrimPrefix(cert.Subject.CommonName, constants.NodesUserPrefix), nil
|
||||
}
|
||||
|
||||
// getAPIEndpoint returns the APIEndpoint for the current node
|
||||
func getAPIEndpoint(data map[string]string, nodeName string, apiEndpoint *kubeadmapi.APIEndpoint) error {
|
||||
// gets the ClusterStatus from kubeadm-config
|
||||
clusterStatusData, ok := data[constants.ClusterStatusConfigMapKey]
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected error when reading kubeadm-config ConfigMap: %s key value pair missing", constants.ClusterStatusConfigMapKey)
|
||||
}
|
||||
clusterStatus := &kubeadmapi.ClusterStatus{}
|
||||
if err := runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(), []byte(clusterStatusData), clusterStatus); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// gets the APIEndpoint for the current machine from the ClusterStatus
|
||||
e, ok := clusterStatus.APIEndpoints[nodeName]
|
||||
if !ok {
|
||||
return errors.New("failed to get APIEndpoint information for this node")
|
||||
}
|
||||
|
||||
apiEndpoint.AdvertiseAddress = e.AdvertiseAddress
|
||||
apiEndpoint.BindPort = e.BindPort
|
||||
return nil
|
||||
}
|
||||
|
||||
// getComponentConfigs gets the component configs from the corresponding config maps
|
||||
func getComponentConfigs(client clientset.Interface, clusterConfiguration *kubeadmapi.ClusterConfiguration) error {
|
||||
// some config maps is versioned, so we need the KubernetesVersion for getting the right config map
|
||||
k8sVersion := version.MustParseGeneric(clusterConfiguration.KubernetesVersion)
|
||||
for kind, registration := range componentconfigs.Known {
|
||||
obj, err := registration.GetFromConfigMap(client, k8sVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ok := registration.SetToInternalConfig(obj, clusterConfiguration); !ok {
|
||||
return fmt.Errorf("couldn't save componentconfig value for kind %q", string(kind))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
684
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/cluster_test.go
generated
vendored
Normal file
684
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/cluster_test.go
generated
vendored
Normal file
@@ -0,0 +1,684 @@
|
||||
/*
|
||||
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"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
clientsetfake "k8s.io/client-go/kubernetes/fake"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
)
|
||||
|
||||
var k8sVersionString = "v1.12.0"
|
||||
var k8sVersion = version.MustParseGeneric(k8sVersionString)
|
||||
var nodeName = "mynode"
|
||||
var cfgFiles = map[string][]byte{
|
||||
"MasterConfiguration_v1alpha2": []byte(`
|
||||
apiVersion: kubeadm.k8s.io/v1alpha2
|
||||
kind: MasterConfiguration
|
||||
kubernetesVersion: ` + k8sVersionString + `
|
||||
api:
|
||||
advertiseAddress: 1.2.3.4
|
||||
bindPort: 1234
|
||||
`),
|
||||
"InitConfiguration_v1alpha3": []byte(`
|
||||
apiVersion: kubeadm.k8s.io/v1alpha3
|
||||
kind: InitConfiguration
|
||||
`),
|
||||
"ClusterConfiguration_v1alpha3": []byte(`
|
||||
apiVersion: kubeadm.k8s.io/v1alpha3
|
||||
kind: ClusterConfiguration
|
||||
kubernetesVersion: ` + k8sVersionString + `
|
||||
`),
|
||||
"ClusterStatus_v1alpha3": []byte(`
|
||||
apiVersion: kubeadm.k8s.io/v1alpha3
|
||||
kind: ClusterStatus
|
||||
apiEndpoints:
|
||||
` + nodeName + `:
|
||||
advertiseAddress: 1.2.3.4
|
||||
bindPort: 1234
|
||||
`),
|
||||
"ClusterStatus_v1alpha3_Without_APIEndpoints": []byte(`
|
||||
apiVersion: kubeadm.k8s.io/v1alpha3
|
||||
kind: ClusterStatus
|
||||
`),
|
||||
"Kube-proxy_componentconfig": []byte(`
|
||||
apiVersion: kubeproxy.config.k8s.io/v1alpha1
|
||||
kind: KubeProxyConfiguration
|
||||
`),
|
||||
"Kubelet_componentconfig": []byte(`
|
||||
apiVersion: kubelet.config.k8s.io/v1beta1
|
||||
kind: KubeletConfiguration
|
||||
`),
|
||||
}
|
||||
|
||||
var kubeletConfFiles = map[string][]byte{
|
||||
"withoutX509Cert": []byte(`
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server: https://10.0.2.15:6443
|
||||
name: kubernetes
|
||||
contexts:
|
||||
- context:
|
||||
cluster: kubernetes
|
||||
user: system:node:mynode
|
||||
name: system:node:mynode@kubernetes
|
||||
current-context: system:node:mynode@kubernetes
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: system:node:mynode
|
||||
user:
|
||||
`),
|
||||
"configWithEmbeddedCert": []byte(`
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server: https://10.0.2.15:6443
|
||||
name: kubernetes
|
||||
contexts:
|
||||
- context:
|
||||
cluster: kubernetes
|
||||
user: system:node:mynode
|
||||
name: system:node:mynode@kubernetes
|
||||
current-context: system:node:mynode@kubernetes
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: system:node:mynode
|
||||
user:
|
||||
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4akNDQWRxZ0F3SUJBZ0lJQWl3VURhYk5vZ1F3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB4T0RBNU1ERXhOVE14TWpaYUZ3MHhPVEE1TURFeE5qQXhOVGxhTURReApGVEFUQmdOVkJBb1RESE41YzNSbGJUcHViMlJsY3pFYk1Ca0dBMVVFQXhNU2MzbHpkR1Z0T201dlpHVTZiWGx1CmIyUmxNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQWs2UXUzeStyNEZYUzZ4VkoKWU1vNE9kSkt3R1d1MHY4TEJIUnhhOUhvVHo1RXZLQnB1OVJoemt5dStUaFczb0xta2ZTRmNJcitHa0M5MW0zOApFelRmVE5JY2dsL0V5YkpmR1QvdGdUazZYd1kxY1UrUUdmSEFNNTBCVzFXTFVHc25CSllJZjA5eENnZTVoTkxLCnREeUJOWWNQZzg1bUJpOU9CNFJ2UlgyQVFRMjJwZ0xrQUpJWklOU0FEdUFrODN2b051SXM2YVY2bHBkR2Vva3YKdDlpTFdNR3p3a3ZTZUZQTlNGeWZ3Q055eENjb1FDQUNtSnJRS3NoeUE2bWNzdVhORWVXdlRQdVVFSWZPVFl4dwpxdkszRVBOK0xUYlA2anhUMWtTcFJUOSt4Z29uSlFhU0RsbUNBd20zRGJkSVppWUt3R2ppMkxKL0kvYWc0cTlzCjNLb0J2UUlEQVFBQm95Y3dKVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFLcVVrU21jdW85OG5EK015b005VFdEV0pyTndySXpQTUNqRQpCSkdyREhVaHIwcEZlRjc0RHViODNzRXlaNjFxNUVQd2Y0enNLSzdzdDRUTzZhcE9pZWJYVmN3dnZoa09HQ2dFCmFVdGNOMjFhUGxtU0tOd0c4ai8yK3ZhbU80bGplK1NnZzRUUVB0eDZWejh5VXN2RFhxSUZycjNNd1gzSDA1RW4KWXAzN05JYkhKbGxHUW5LVHA5aTg5aXF4WXVhSERqZldiVHlEY3B5NldNVjdVaFYvY1plc3lGL0NBamNHd1V6YgowRlo5bW5tMnFONlBGWHZ4RmdMSGFWZzN2SVVCbkNmVVVyY1BDNE94VFNPK21aUmUxazh3eUFpVWovSk0rZllvCkcrMi9sbThUYVZqb1U3Rmk1S2E1RzVIWTJHTGFSN1ArSXhZY3JNSENsNjJZN1JxY3JuYz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||
`),
|
||||
"configWithLinkedCert": []byte(`
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server: https://10.0.2.15:6443
|
||||
name: kubernetes
|
||||
contexts:
|
||||
- context:
|
||||
cluster: kubernetes
|
||||
user: system:node:mynode
|
||||
name: system:node:mynode@kubernetes
|
||||
current-context: system:node:mynode@kubernetes
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: system:node:mynode
|
||||
user:
|
||||
client-certificate: kubelet.pem
|
||||
`),
|
||||
}
|
||||
|
||||
var pemFiles = map[string][]byte{
|
||||
"mynode.pem": []byte(`
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC8jCCAdqgAwIBAgIIAiwUDabNogQwDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
|
||||
AxMKa3ViZXJuZXRlczAeFw0xODA5MDExNTMxMjZaFw0xOTA5MDExNjAxNTlaMDQx
|
||||
FTATBgNVBAoTDHN5c3RlbTpub2RlczEbMBkGA1UEAxMSc3lzdGVtOm5vZGU6bXlu
|
||||
b2RlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk6Qu3y+r4FXS6xVJ
|
||||
YMo4OdJKwGWu0v8LBHRxa9HoTz5EvKBpu9Rhzkyu+ThW3oLmkfSFcIr+GkC91m38
|
||||
EzTfTNIcgl/EybJfGT/tgTk6XwY1cU+QGfHAM50BW1WLUGsnBJYIf09xCge5hNLK
|
||||
tDyBNYcPg85mBi9OB4RvRX2AQQ22pgLkAJIZINSADuAk83voNuIs6aV6lpdGeokv
|
||||
t9iLWMGzwkvSeFPNSFyfwCNyxCcoQCACmJrQKshyA6mcsuXNEeWvTPuUEIfOTYxw
|
||||
qvK3EPN+LTbP6jxT1kSpRT9+xgonJQaSDlmCAwm3DbdIZiYKwGji2LJ/I/ag4q9s
|
||||
3KoBvQIDAQABoycwJTAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUH
|
||||
AwIwDQYJKoZIhvcNAQELBQADggEBAKqUkSmcuo98nD+MyoM9TWDWJrNwrIzPMCjE
|
||||
BJGrDHUhr0pFeF74Dub83sEyZ61q5EPwf4zsKK7st4TO6apOiebXVcwvvhkOGCgE
|
||||
aUtcN21aPlmSKNwG8j/2+vamO4lje+Sgg4TQPtx6Vz8yUsvDXqIFrr3MwX3H05En
|
||||
Yp37NIbHJllGQnKTp9i89iqxYuaHDjfWbTyDcpy6WMV7UhV/cZesyF/CAjcGwUzb
|
||||
0FZ9mnm2qN6PFXvxFgLHaVg3vIUBnCfUUrcPC4OxTSO+mZRe1k8wyAiUj/JM+fYo
|
||||
G+2/lm8TaVjoU7Fi5Ka5G5HY2GLaR7P+IxYcrMHCl62Y7Rqcrnc=
|
||||
-----END CERTIFICATE-----
|
||||
`),
|
||||
}
|
||||
|
||||
func TestLoadInitConfigurationFromFile(t *testing.T) {
|
||||
// Create temp folder for the test case
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create tmpdir")
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
fileContents []byte
|
||||
}{
|
||||
{
|
||||
name: "v1alpha2.MasterConfiguration",
|
||||
fileContents: cfgFiles["MasterConfiguration_v1alpha2"],
|
||||
},
|
||||
{
|
||||
name: "v1alpha3.partial1",
|
||||
fileContents: cfgFiles["InitConfiguration_v1alpha3"],
|
||||
},
|
||||
{
|
||||
name: "v1alpha3.partial2",
|
||||
fileContents: cfgFiles["ClusterConfiguration_v1alpha3"],
|
||||
},
|
||||
{
|
||||
name: "v1alpha3.full",
|
||||
fileContents: bytes.Join([][]byte{
|
||||
cfgFiles["InitConfiguration_v1alpha3"],
|
||||
cfgFiles["ClusterConfiguration_v1alpha3"],
|
||||
cfgFiles["Kube-proxy_componentconfig"],
|
||||
cfgFiles["Kubelet_componentconfig"],
|
||||
}, []byte(kubeadmconstants.YAMLDocumentSeparator)),
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t2 *testing.T) {
|
||||
cfgPath := filepath.Join(tmpdir, rt.name)
|
||||
err := ioutil.WriteFile(cfgPath, rt.fileContents, 0644)
|
||||
if err != nil {
|
||||
t.Errorf("Couldn't create file")
|
||||
return
|
||||
}
|
||||
|
||||
obj, err := loadInitConfigurationFromFile(cfgPath)
|
||||
if err != nil {
|
||||
t.Errorf("Error reading file: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if obj == nil {
|
||||
t.Errorf("Unexpected nil return value")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetNodeNameFromKubeletConfig(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create tmpdir")
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
kubeconfigContent []byte
|
||||
pemContent []byte
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "valid - with embedded cert",
|
||||
kubeconfigContent: kubeletConfFiles["configWithEmbeddedCert"],
|
||||
},
|
||||
{
|
||||
name: "invalid - linked cert missing",
|
||||
kubeconfigContent: kubeletConfFiles["configWithLinkedCert"],
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "valid - with linked cert",
|
||||
kubeconfigContent: kubeletConfFiles["configWithLinkedCert"],
|
||||
pemContent: pemFiles["mynode.pem"],
|
||||
},
|
||||
{
|
||||
name: "invalid - without embedded or linked X509Cert",
|
||||
kubeconfigContent: kubeletConfFiles["withoutX509Cert"],
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t2 *testing.T) {
|
||||
if len(rt.pemContent) > 0 {
|
||||
pemPath := filepath.Join(tmpdir, "kubelet.pem")
|
||||
err := ioutil.WriteFile(pemPath, rt.pemContent, 0644)
|
||||
if err != nil {
|
||||
t.Errorf("Couldn't create pem file: %v", err)
|
||||
return
|
||||
}
|
||||
rt.kubeconfigContent = []byte(strings.Replace(string(rt.kubeconfigContent), "kubelet.pem", pemPath, -1))
|
||||
}
|
||||
|
||||
kubeconfigPath := filepath.Join(tmpdir, kubeadmconstants.KubeletKubeConfigFileName)
|
||||
err := ioutil.WriteFile(kubeconfigPath, rt.kubeconfigContent, 0644)
|
||||
if err != nil {
|
||||
t.Errorf("Couldn't create kubeconfig: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
name, err := getNodeNameFromKubeletConfig(tmpdir)
|
||||
if rt.expectedError != (err != nil) {
|
||||
t.Errorf("unexpected return err from getNodeRegistration: %v", err)
|
||||
return
|
||||
}
|
||||
if rt.expectedError {
|
||||
return
|
||||
}
|
||||
|
||||
if name != nodeName {
|
||||
t.Errorf("invalid name")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetNodeRegistration(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create tmpdir")
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
fileContents []byte
|
||||
node *v1.Node
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "invalid - no kubelet.conf",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
fileContents: kubeletConfFiles["configWithEmbeddedCert"],
|
||||
node: &v1.Node{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: nodeName,
|
||||
Annotations: map[string]string{
|
||||
kubeadmconstants.AnnotationKubeadmCRISocket: "myCRIsocket",
|
||||
},
|
||||
},
|
||||
Spec: v1.NodeSpec{
|
||||
Taints: []v1.Taint{kubeadmconstants.MasterTaint},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid - no node",
|
||||
fileContents: kubeletConfFiles["configWithEmbeddedCert"],
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t2 *testing.T) {
|
||||
cfgPath := filepath.Join(tmpdir, kubeadmconstants.KubeletKubeConfigFileName)
|
||||
if len(rt.fileContents) > 0 {
|
||||
err := ioutil.WriteFile(cfgPath, rt.fileContents, 0644)
|
||||
if err != nil {
|
||||
t.Errorf("Couldn't create file")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
client := clientsetfake.NewSimpleClientset()
|
||||
|
||||
if rt.node != nil {
|
||||
_, err := client.CoreV1().Nodes().Create(rt.node)
|
||||
if err != nil {
|
||||
t.Errorf("couldn't create Node")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
cfg := &kubeadmapi.InitConfiguration{}
|
||||
err = getNodeRegistration(tmpdir, client, &cfg.NodeRegistration)
|
||||
if rt.expectedError != (err != nil) {
|
||||
t.Errorf("unexpected return err from getNodeRegistration: %v", err)
|
||||
return
|
||||
}
|
||||
if rt.expectedError {
|
||||
return
|
||||
}
|
||||
|
||||
if cfg.NodeRegistration.Name != nodeName {
|
||||
t.Errorf("invalid cfg.NodeRegistration.Name")
|
||||
}
|
||||
if cfg.NodeRegistration.CRISocket != "myCRIsocket" {
|
||||
t.Errorf("invalid cfg.NodeRegistration.CRISocket")
|
||||
}
|
||||
if len(cfg.NodeRegistration.Taints) != 1 {
|
||||
t.Errorf("invalid cfg.NodeRegistration.Taints")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAPIEndpoint(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
configMap fakeConfigMap
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
configMap: fakeConfigMap{
|
||||
name: kubeadmconstants.InitConfigurationConfigMap, // ClusterConfiguration from kubeadm-config.
|
||||
data: map[string]string{
|
||||
kubeadmconstants.ClusterStatusConfigMapKey: string(cfgFiles["ClusterStatus_v1alpha3"]),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid - No CLusterStatus in kubeadm-config ConfigMap",
|
||||
configMap: fakeConfigMap{
|
||||
name: kubeadmconstants.InitConfigurationConfigMap, // ClusterConfiguration from kubeadm-config.
|
||||
data: map[string]string{},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid - CLusterStatus without APIEndopoints",
|
||||
configMap: fakeConfigMap{
|
||||
name: kubeadmconstants.InitConfigurationConfigMap, // ClusterConfiguration from kubeadm-config.
|
||||
data: map[string]string{
|
||||
kubeadmconstants.ClusterStatusConfigMapKey: string(cfgFiles["ClusterStatus_v1alpha3_Without_APIEndpoints"]),
|
||||
},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t *testing.T) {
|
||||
cfg := &kubeadmapi.InitConfiguration{}
|
||||
err := getAPIEndpoint(rt.configMap.data, nodeName, &cfg.APIEndpoint)
|
||||
if rt.expectedError != (err != nil) {
|
||||
t.Errorf("unexpected return err from getInitConfigurationFromCluster: %v", err)
|
||||
return
|
||||
}
|
||||
if rt.expectedError {
|
||||
return
|
||||
}
|
||||
|
||||
if cfg.APIEndpoint.AdvertiseAddress != "1.2.3.4" || cfg.APIEndpoint.BindPort != 1234 {
|
||||
t.Errorf("invalid cfg.APIEndpoint")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetComponentConfigs(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
configMaps []fakeConfigMap
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
configMaps: []fakeConfigMap{
|
||||
{
|
||||
name: kubeadmconstants.KubeProxyConfigMap, // Kube-proxy component config from corresponding ConfigMap.
|
||||
data: map[string]string{
|
||||
kubeadmconstants.KubeProxyConfigMapKey: string(cfgFiles["Kube-proxy_componentconfig"]),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: kubeadmconstants.GetKubeletConfigMapName(k8sVersion), // Kubelet component config from corresponding ConfigMap.
|
||||
data: map[string]string{
|
||||
kubeadmconstants.KubeletBaseConfigurationConfigMapKey: string(cfgFiles["Kubelet_componentconfig"]),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid - No kubelet component config ConfigMap",
|
||||
configMaps: []fakeConfigMap{
|
||||
{
|
||||
name: kubeadmconstants.KubeProxyConfigMap,
|
||||
data: map[string]string{
|
||||
kubeadmconstants.KubeProxyConfigMapKey: string(cfgFiles["Kube-proxy_componentconfig"]),
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid - No kube-proxy component config ConfigMap",
|
||||
configMaps: []fakeConfigMap{
|
||||
{
|
||||
name: kubeadmconstants.GetKubeletConfigMapName(k8sVersion),
|
||||
data: map[string]string{
|
||||
kubeadmconstants.KubeletBaseConfigurationConfigMapKey: string(cfgFiles["Kubelet_componentconfig"]),
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t *testing.T) {
|
||||
client := clientsetfake.NewSimpleClientset()
|
||||
|
||||
for _, c := range rt.configMaps {
|
||||
err := c.create(client)
|
||||
if err != nil {
|
||||
t.Errorf("couldn't create ConfigMap %s", c.name)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
cfg := &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
KubernetesVersion: k8sVersionString,
|
||||
},
|
||||
}
|
||||
err := getComponentConfigs(client, &cfg.ClusterConfiguration)
|
||||
if rt.expectedError != (err != nil) {
|
||||
t.Errorf("unexpected return err from getInitConfigurationFromCluster: %v", err)
|
||||
return
|
||||
}
|
||||
if rt.expectedError {
|
||||
return
|
||||
}
|
||||
|
||||
// Test expected values in InitConfiguration
|
||||
if cfg.ComponentConfigs.Kubelet == nil {
|
||||
t.Errorf("invalid cfg.ComponentConfigs.Kubelet")
|
||||
}
|
||||
if cfg.ComponentConfigs.KubeProxy == nil {
|
||||
t.Errorf("invalid cfg.ComponentConfigs.KubeProxy")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetInitConfigurationFromCluster(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create tmpdir")
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
fileContents []byte
|
||||
node *v1.Node
|
||||
configMaps []fakeConfigMap
|
||||
newControlPlane bool
|
||||
expectedError bool
|
||||
}{
|
||||
{ //TODO: remove in V1.13
|
||||
name: "before v1.11", // single YAML, with a v1alpha2.MasterConfiguration object (with embedded component configs)
|
||||
configMaps: []fakeConfigMap{
|
||||
{
|
||||
name: kubeadmconstants.InitConfigurationConfigMap,
|
||||
data: map[string]string{
|
||||
kubeadmconstants.InitConfigurationConfigMapKey: string(cfgFiles["MasterConfiguration_v1alpha2"]),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid - No kubeadm-config ConfigMap",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid - No CLusterConfiguration in kubeadm-config ConfigMap",
|
||||
configMaps: []fakeConfigMap{
|
||||
{
|
||||
name: kubeadmconstants.InitConfigurationConfigMap, // ClusterConfiguration from kubeadm-config.
|
||||
data: map[string]string{},
|
||||
},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "valid - new control plane == false", // InitConfiguration composed with data from different places, with also node specific information from ClusterStatus and node
|
||||
configMaps: []fakeConfigMap{
|
||||
{
|
||||
name: kubeadmconstants.InitConfigurationConfigMap, // ClusterConfiguration from kubeadm-config.
|
||||
data: map[string]string{
|
||||
kubeadmconstants.ClusterConfigurationConfigMapKey: string(cfgFiles["ClusterConfiguration_v1alpha3"]),
|
||||
kubeadmconstants.ClusterStatusConfigMapKey: string(cfgFiles["ClusterStatus_v1alpha3"]),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: kubeadmconstants.KubeProxyConfigMap, // Kube-proxy component config from corresponding ConfigMap.
|
||||
data: map[string]string{
|
||||
kubeadmconstants.KubeProxyConfigMapKey: string(cfgFiles["Kube-proxy_componentconfig"]),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: kubeadmconstants.GetKubeletConfigMapName(k8sVersion), // Kubelet component config from corresponding ConfigMap.
|
||||
data: map[string]string{
|
||||
kubeadmconstants.KubeletBaseConfigurationConfigMapKey: string(cfgFiles["Kubelet_componentconfig"]),
|
||||
},
|
||||
},
|
||||
},
|
||||
fileContents: kubeletConfFiles["configWithEmbeddedCert"],
|
||||
node: &v1.Node{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: nodeName,
|
||||
Annotations: map[string]string{
|
||||
kubeadmconstants.AnnotationKubeadmCRISocket: "myCRIsocket",
|
||||
},
|
||||
},
|
||||
Spec: v1.NodeSpec{
|
||||
Taints: []v1.Taint{kubeadmconstants.MasterTaint},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid - new control plane == true", // InitConfiguration composed with data from different places, without node specific information
|
||||
configMaps: []fakeConfigMap{
|
||||
{
|
||||
name: kubeadmconstants.InitConfigurationConfigMap, // ClusterConfiguration from kubeadm-config.
|
||||
data: map[string]string{
|
||||
kubeadmconstants.ClusterConfigurationConfigMapKey: string(cfgFiles["ClusterConfiguration_v1alpha3"]),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: kubeadmconstants.KubeProxyConfigMap, // Kube-proxy component config from corresponding ConfigMap.
|
||||
data: map[string]string{
|
||||
kubeadmconstants.KubeProxyConfigMapKey: string(cfgFiles["Kube-proxy_componentconfig"]),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: kubeadmconstants.GetKubeletConfigMapName(k8sVersion), // Kubelet component config from corresponding ConfigMap.
|
||||
data: map[string]string{
|
||||
kubeadmconstants.KubeletBaseConfigurationConfigMapKey: string(cfgFiles["Kubelet_componentconfig"]),
|
||||
},
|
||||
},
|
||||
},
|
||||
newControlPlane: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t *testing.T) {
|
||||
cfgPath := filepath.Join(tmpdir, kubeadmconstants.KubeletKubeConfigFileName)
|
||||
if len(rt.fileContents) > 0 {
|
||||
err := ioutil.WriteFile(cfgPath, rt.fileContents, 0644)
|
||||
if err != nil {
|
||||
t.Errorf("Couldn't create file")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
client := clientsetfake.NewSimpleClientset()
|
||||
|
||||
if rt.node != nil {
|
||||
_, err := client.CoreV1().Nodes().Create(rt.node)
|
||||
if err != nil {
|
||||
t.Errorf("couldn't create Node")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range rt.configMaps {
|
||||
err := c.create(client)
|
||||
if err != nil {
|
||||
t.Errorf("couldn't create ConfigMap %s", c.name)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
cfg, err := getInitConfigurationFromCluster(tmpdir, client, rt.newControlPlane)
|
||||
if rt.expectedError != (err != nil) {
|
||||
t.Errorf("unexpected return err from getInitConfigurationFromCluster: %v", err)
|
||||
return
|
||||
}
|
||||
if rt.expectedError {
|
||||
return
|
||||
}
|
||||
|
||||
// Test expected values in InitConfiguration
|
||||
if cfg == nil {
|
||||
t.Errorf("unexpected nil return value")
|
||||
}
|
||||
if cfg.ClusterConfiguration.KubernetesVersion != k8sVersionString {
|
||||
t.Errorf("invalid ClusterConfiguration.KubernetesVersion")
|
||||
}
|
||||
if !rt.newControlPlane && (cfg.APIEndpoint.AdvertiseAddress != "1.2.3.4" || cfg.APIEndpoint.BindPort != 1234) {
|
||||
t.Errorf("invalid cfg.APIEndpoint")
|
||||
}
|
||||
if cfg.ComponentConfigs.Kubelet == nil {
|
||||
t.Errorf("invalid cfg.ComponentConfigs.Kubelet")
|
||||
}
|
||||
if cfg.ComponentConfigs.KubeProxy == nil {
|
||||
t.Errorf("invalid cfg.ComponentConfigs.KubeProxy")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type fakeConfigMap struct {
|
||||
name string
|
||||
data map[string]string
|
||||
}
|
||||
|
||||
func (c *fakeConfigMap) create(client clientset.Interface) error {
|
||||
return apiclient.CreateOrUpdateConfigMap(client, &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: c.name,
|
||||
Namespace: metav1.NamespaceSystem,
|
||||
},
|
||||
Data: c.data,
|
||||
})
|
||||
}
|
178
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/common.go
generated
vendored
Normal file
178
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/common.go
generated
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
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"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
netutil "k8s.io/apimachinery/pkg/util/net"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
||||
kubeadmapiv1alpha3 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha3"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
)
|
||||
|
||||
// AnyConfigFileAndDefaultsToInternal reads either a InitConfiguration or JoinConfiguration and unmarshals it
|
||||
func AnyConfigFileAndDefaultsToInternal(cfgPath string) (runtime.Object, error) {
|
||||
b, err := ioutil.ReadFile(cfgPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gvks, err := kubeadmutil.GroupVersionKindsFromBytes(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// First, check if the gvk list has InitConfiguration and in that case try to unmarshal it
|
||||
if kubeadmutil.GroupVersionKindsHasInitConfiguration(gvks...) {
|
||||
return ConfigFileAndDefaultsToInternalConfig(cfgPath, &kubeadmapiv1alpha3.InitConfiguration{})
|
||||
}
|
||||
if kubeadmutil.GroupVersionKindsHasJoinConfiguration(gvks...) {
|
||||
return NodeConfigFileAndDefaultsToInternalConfig(cfgPath, &kubeadmapiv1alpha3.JoinConfiguration{})
|
||||
}
|
||||
return nil, fmt.Errorf("didn't recognize types with GroupVersionKind: %v", gvks)
|
||||
}
|
||||
|
||||
// MarshalKubeadmConfigObject marshals an Object registered in the kubeadm scheme. If the object is a InitConfiguration or ClusterConfiguration, some extra logic is run
|
||||
func MarshalKubeadmConfigObject(obj runtime.Object) ([]byte, error) {
|
||||
switch internalcfg := obj.(type) {
|
||||
case *kubeadmapi.InitConfiguration:
|
||||
return MarshalInitConfigurationToBytes(internalcfg, kubeadmapiv1alpha3.SchemeGroupVersion)
|
||||
case *kubeadmapi.ClusterConfiguration:
|
||||
return MarshalClusterConfigurationToBytes(internalcfg, kubeadmapiv1alpha3.SchemeGroupVersion)
|
||||
default:
|
||||
return kubeadmutil.MarshalToYamlForCodecs(obj, kubeadmapiv1alpha3.SchemeGroupVersion, kubeadmscheme.Codecs)
|
||||
}
|
||||
}
|
||||
|
||||
// DetectUnsupportedVersion reads YAML bytes, extracts the TypeMeta information and errors out with an user-friendly message if the API spec is too old for this kubeadm version
|
||||
func DetectUnsupportedVersion(b []byte) error {
|
||||
gvks, err := kubeadmutil.GroupVersionKindsFromBytes(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: On our way to making the kubeadm API beta and higher, give good user output in case they use an old config file with a new kubeadm version, and
|
||||
// tell them how to upgrade. The support matrix will look something like this now and in the future:
|
||||
// v1.10 and earlier: v1alpha1
|
||||
// v1.11: v1alpha1 read-only, writes only v1alpha2 config
|
||||
// v1.12: v1alpha2 read-only, writes only v1beta1 config. Warns if the user tries to use v1alpha1
|
||||
// v1.13 and v1.14: v1beta1 read-only, writes only v1 config. Warns if the user tries to use v1alpha1 or v1alpha2.
|
||||
// v1.15: v1 is the only supported format.
|
||||
oldKnownAPIVersions := map[string]string{
|
||||
"kubeadm.k8s.io/v1alpha1": "v1.11",
|
||||
}
|
||||
// If we find an old API version in this gvk list, error out and tell the user why this doesn't work
|
||||
knownKinds := map[string]bool{}
|
||||
for _, gvk := range gvks {
|
||||
if useKubeadmVersion := oldKnownAPIVersions[gvk.GroupVersion().String()]; len(useKubeadmVersion) != 0 {
|
||||
return fmt.Errorf("your configuration file uses an old API spec: %q. Please use kubeadm %s instead and run 'kubeadm config migrate --old-config old.yaml --new-config new.yaml', which will write the new, similar spec using a newer API version.", gvk.GroupVersion().String(), useKubeadmVersion)
|
||||
}
|
||||
knownKinds[gvk.Kind] = true
|
||||
}
|
||||
// InitConfiguration, MasterConfiguration and NodeConfiguration may not apply together, warn if more than one is specified
|
||||
mutuallyExclusive := []string{constants.InitConfigurationKind, constants.MasterConfigurationKind, constants.JoinConfigurationKind, constants.NodeConfigurationKind}
|
||||
mutuallyExclusiveCount := 0
|
||||
for _, kind := range mutuallyExclusive {
|
||||
if knownKinds[kind] {
|
||||
mutuallyExclusiveCount++
|
||||
}
|
||||
}
|
||||
if mutuallyExclusiveCount > 1 {
|
||||
glog.Warningf("WARNING: Detected resource kinds that may not apply: %v", mutuallyExclusive)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NormalizeKubernetesVersion resolves version labels, sets alternative
|
||||
// image registry if requested for CI builds, and validates minimal
|
||||
// version that kubeadm SetInitDynamicDefaultssupports.
|
||||
func NormalizeKubernetesVersion(cfg *kubeadmapi.ClusterConfiguration) error {
|
||||
// Requested version is automatic CI build, thus use KubernetesCI Image Repository for core images
|
||||
if kubeadmutil.KubernetesIsCIVersion(cfg.KubernetesVersion) {
|
||||
cfg.CIImageRepository = constants.DefaultCIImageRepository
|
||||
}
|
||||
|
||||
// Parse and validate the version argument and resolve possible CI version labels
|
||||
ver, err := kubeadmutil.KubernetesReleaseVersion(cfg.KubernetesVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.KubernetesVersion = ver
|
||||
|
||||
// Parse the given kubernetes version and make sure it's higher than the lowest supported
|
||||
k8sVersion, err := version.ParseSemantic(cfg.KubernetesVersion)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't parse kubernetes version %q: %v", cfg.KubernetesVersion, err)
|
||||
}
|
||||
if k8sVersion.LessThan(constants.MinimumControlPlaneVersion) {
|
||||
return fmt.Errorf("this version of kubeadm only supports deploying clusters with the control plane version >= %s. Current version: %s", constants.MinimumControlPlaneVersion.String(), cfg.KubernetesVersion)
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VerifyAPIServerBindAddress can be used to verify if a bind address for the API Server is 0.0.0.0,
|
||||
// in which case this address is not valid and should not be used.
|
||||
func VerifyAPIServerBindAddress(address string) error {
|
||||
ip := net.ParseIP(address)
|
||||
if ip == nil {
|
||||
return fmt.Errorf("cannot parse IP address: %s", address)
|
||||
}
|
||||
if !ip.IsGlobalUnicast() {
|
||||
return fmt.Errorf("cannot use %q as the bind address for the API Server", address)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChooseAPIServerBindAddress is a wrapper for netutil.ChooseBindAddress that also handles
|
||||
// the case where no default routes were found and an IP for the API server could not be obatained.
|
||||
func ChooseAPIServerBindAddress(bindAddress net.IP) (net.IP, error) {
|
||||
ip, err := netutil.ChooseBindAddress(bindAddress)
|
||||
if err != nil {
|
||||
if netutil.IsNoRoutesError(err) {
|
||||
glog.Warningf("WARNING: could not obtain a bind address for the API Server: %v; using: %s", err, constants.DefaultAPIServerBindAddress)
|
||||
defaultIP := net.ParseIP(constants.DefaultAPIServerBindAddress)
|
||||
if defaultIP == nil {
|
||||
return nil, fmt.Errorf("cannot parse default IP address: %s", constants.DefaultAPIServerBindAddress)
|
||||
}
|
||||
return defaultIP, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return ip, nil
|
||||
}
|
277
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/common_test.go
generated
vendored
Normal file
277
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/common_test.go
generated
vendored
Normal file
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
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"
|
||||
"testing"
|
||||
|
||||
kubeadmapiv1alpha3 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha3"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
)
|
||||
|
||||
var files = map[string][]byte{
|
||||
"Master_v1alpha1": []byte(`
|
||||
apiVersion: kubeadm.k8s.io/v1alpha1
|
||||
kind: InitConfiguration
|
||||
`),
|
||||
"Node_v1alpha1": []byte(`
|
||||
apiVersion: kubeadm.k8s.io/v1alpha1
|
||||
kind: NodeConfiguration
|
||||
`),
|
||||
"Master_v1alpha2": []byte(`
|
||||
apiVersion: kubeadm.k8s.io/v1alpha2
|
||||
kind: MasterConfiguration
|
||||
`),
|
||||
"Node_v1alpha2": []byte(`
|
||||
apiVersion: kubeadm.k8s.io/v1alpha2
|
||||
kind: NodeConfiguration
|
||||
`),
|
||||
"Init_v1alpha3": []byte(`
|
||||
apiVersion: kubeadm.k8s.io/v1alpha3
|
||||
kind: InitConfiguration
|
||||
`),
|
||||
"Join_v1alpha3": []byte(`
|
||||
apiVersion: kubeadm.k8s.io/v1alpha3
|
||||
kind: JoinConfiguration
|
||||
`),
|
||||
"NoKind": []byte(`
|
||||
apiVersion: baz.k8s.io/v1
|
||||
foo: foo
|
||||
bar: bar
|
||||
`),
|
||||
"NoAPIVersion": []byte(`
|
||||
kind: Bar
|
||||
foo: foo
|
||||
bar: bar
|
||||
`),
|
||||
"Foo": []byte(`
|
||||
apiVersion: foo.k8s.io/v1
|
||||
kind: Foo
|
||||
`),
|
||||
}
|
||||
|
||||
func TestDetectUnsupportedVersion(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
fileContents []byte
|
||||
expectedErr bool
|
||||
}{
|
||||
{
|
||||
name: "Master_v1alpha1",
|
||||
fileContents: files["Master_v1alpha1"],
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
name: "Node_v1alpha1",
|
||||
fileContents: files["Node_v1alpha1"],
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
name: "Master_v1alpha2",
|
||||
fileContents: files["Master_v1alpha2"],
|
||||
},
|
||||
{
|
||||
name: "Node_v1alpha2",
|
||||
fileContents: files["Node_v1alpha2"],
|
||||
},
|
||||
{
|
||||
name: "Init_v1alpha3",
|
||||
fileContents: files["Init_v1alpha3"],
|
||||
},
|
||||
{
|
||||
name: "Join_v1alpha3",
|
||||
fileContents: files["Join_v1alpha3"],
|
||||
},
|
||||
{
|
||||
name: "DuplicateMaster",
|
||||
fileContents: bytes.Join([][]byte{files["Master_v1alpha2"], files["Master_v1alpha2"]}, []byte(constants.YAMLDocumentSeparator)),
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
name: "DuplicateNode",
|
||||
fileContents: bytes.Join([][]byte{files["Node_v1alpha2"], files["Node_v1alpha2"]}, []byte(constants.YAMLDocumentSeparator)),
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
name: "DuplicateInit",
|
||||
fileContents: bytes.Join([][]byte{files["Init_v1alpha3"], files["Init_v1alpha3"]}, []byte(constants.YAMLDocumentSeparator)),
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
name: "DuplicateJoin",
|
||||
fileContents: bytes.Join([][]byte{files["Join_v1alpha3"], files["Join_v1alpha3"]}, []byte(constants.YAMLDocumentSeparator)),
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
name: "NoKind",
|
||||
fileContents: files["NoKind"],
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
name: "NoAPIVersion",
|
||||
fileContents: files["NoAPIVersion"],
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
name: "v1alpha1InMultiple",
|
||||
fileContents: bytes.Join([][]byte{files["Foo"], files["Master_v1alpha1"]}, []byte(constants.YAMLDocumentSeparator)),
|
||||
expectedErr: true,
|
||||
},
|
||||
// CanMix* cases used to be MustNotMix*, however due to UX issues DetectUnsupportedVersion had to tolerate that.
|
||||
// So the following tests actually verify, that previously conflicting configs can be mixed together with no error.
|
||||
{
|
||||
name: "CanMixMasterNode",
|
||||
fileContents: bytes.Join([][]byte{files["Master_v1alpha2"], files["Node_v1alpha2"]}, []byte(constants.YAMLDocumentSeparator)),
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "CanMixMasterJoin",
|
||||
fileContents: bytes.Join([][]byte{files["Master_v1alpha2"], files["Join_v1alpha3"]}, []byte(constants.YAMLDocumentSeparator)),
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "CanMixJoinNode",
|
||||
fileContents: bytes.Join([][]byte{files["Join_v1alpha3"], files["Node_v1alpha2"]}, []byte(constants.YAMLDocumentSeparator)),
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "CanMixInitMaster",
|
||||
fileContents: bytes.Join([][]byte{files["Init_v1alpha3"], files["Master_v1alpha2"]}, []byte(constants.YAMLDocumentSeparator)),
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "CanMixInitNode",
|
||||
fileContents: bytes.Join([][]byte{files["Init_v1alpha3"], files["Node_v1alpha2"]}, []byte(constants.YAMLDocumentSeparator)),
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
name: "CanMixInitJoin",
|
||||
fileContents: bytes.Join([][]byte{files["Init_v1alpha3"], files["Join_v1alpha3"]}, []byte(constants.YAMLDocumentSeparator)),
|
||||
expectedErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t2 *testing.T) {
|
||||
|
||||
err := DetectUnsupportedVersion(rt.fileContents)
|
||||
if (err != nil) != rt.expectedErr {
|
||||
t2.Errorf("expected error: %t, actual: %t", rt.expectedErr, err != nil)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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 := &kubeadmapiv1alpha3.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapiv1alpha3.ClusterConfiguration{
|
||||
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])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyAPIServerBindAddress(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
address string
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "valid address: IPV4",
|
||||
address: "192.168.0.1",
|
||||
},
|
||||
{
|
||||
name: "valid address: IPV6",
|
||||
address: "2001:db8:85a3::8a2e:370:7334",
|
||||
},
|
||||
{
|
||||
name: "invalid address: not a global unicast 0.0.0.0",
|
||||
address: "0.0.0.0",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid address: not a global unicast 127.0.0.1",
|
||||
address: "127.0.0.1",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid address: not a global unicast ::",
|
||||
address: "::",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid address: cannot parse IPV4",
|
||||
address: "255.255.255.255.255",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid address: cannot parse IPV6",
|
||||
address: "2a00:800::2a00:800:10102a00",
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if err := VerifyAPIServerBindAddress(test.address); (err != nil) != test.expectedError {
|
||||
t.Errorf("expected error: %v, got %v, error: %v", test.expectedError, (err != nil), err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
399
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/masterconfig.go
generated
vendored
399
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/masterconfig.go
generated
vendored
@@ -17,63 +17,55 @@ limitations under the License.
|
||||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"strings"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
netutil "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
bootstraputil "k8s.io/client-go/tools/bootstrap/token/util"
|
||||
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"
|
||||
kubeadmapiv1alpha3 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha3"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
"k8s.io/kubernetes/pkg/util/node"
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
nodeutil "k8s.io/kubernetes/pkg/util/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(addressIP)
|
||||
if err != nil {
|
||||
// SetInitDynamicDefaults checks and sets configuration values for the InitConfiguration object
|
||||
func SetInitDynamicDefaults(cfg *kubeadmapi.InitConfiguration) error {
|
||||
if err := SetBootstrapTokensDynamicDefaults(&cfg.BootstrapTokens); err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.API.AdvertiseAddress = ip.String()
|
||||
ip = net.ParseIP(cfg.API.AdvertiseAddress)
|
||||
if ip.To4() != nil {
|
||||
cfg.KubeProxy.Config.BindAddress = kubeadmapiv1alpha2.DefaultProxyBindAddressv4
|
||||
} else {
|
||||
cfg.KubeProxy.Config.BindAddress = kubeadmapiv1alpha2.DefaultProxyBindAddressv6
|
||||
}
|
||||
// Resolve possible version labels and validate version string
|
||||
if err := NormalizeKubernetesVersion(cfg); err != nil {
|
||||
if err := SetNodeRegistrationDynamicDefaults(&cfg.NodeRegistration, true); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := SetAPIEndpointDynamicDefaults(&cfg.APIEndpoint); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := SetClusterDynamicDefaults(&cfg.ClusterConfiguration, cfg.APIEndpoint.AdvertiseAddress, cfg.APIEndpoint.BindPort); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Downcase SANs. Some domain names (like ELBs) have capitals in them.
|
||||
LowercaseSANs(cfg.APIServerCertSANs)
|
||||
|
||||
// SetBootstrapTokensDynamicDefaults checks and sets configuration values for the BootstrapTokens object
|
||||
func SetBootstrapTokensDynamicDefaults(cfg *[]kubeadmapi.BootstrapToken) error {
|
||||
// Populate the .Token field with a random value if unset
|
||||
// We do this at this layer, and not the API defaulting layer
|
||||
// because of possible security concerns, and more practically
|
||||
// because we can't return errors in the API object defaulting
|
||||
// process but here we can.
|
||||
for i, bt := range cfg.BootstrapTokens {
|
||||
for i, bt := range *cfg {
|
||||
if bt.Token != nil && len(bt.Token.String()) > 0 {
|
||||
continue
|
||||
}
|
||||
@@ -86,26 +78,88 @@ func SetInitDynamicDefaults(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.BootstrapTokens[i].Token = token
|
||||
(*cfg)[i].Token = token
|
||||
}
|
||||
|
||||
cfg.NodeRegistration.Name = node.GetHostname(cfg.NodeRegistration.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetNodeRegistrationDynamicDefaults checks and sets configuration values for the NodeRegistration object
|
||||
func SetNodeRegistrationDynamicDefaults(cfg *kubeadmapi.NodeRegistrationOptions, masterTaint bool) error {
|
||||
var err error
|
||||
cfg.Name, err = nodeutil.GetHostname(cfg.Name)
|
||||
if err != nil {
|
||||
return 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}
|
||||
if masterTaint && cfg.Taints == nil {
|
||||
cfg.Taints = []v1.Taint{kubeadmconstants.MasterTaint}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetAPIEndpointDynamicDefaults checks and sets configuration values for the APIEndpoint object
|
||||
func SetAPIEndpointDynamicDefaults(cfg *kubeadmapi.APIEndpoint) error {
|
||||
// validate cfg.API.AdvertiseAddress.
|
||||
addressIP := net.ParseIP(cfg.AdvertiseAddress)
|
||||
if addressIP == nil && cfg.AdvertiseAddress != "" {
|
||||
return fmt.Errorf("couldn't use \"%s\" as \"apiserver-advertise-address\", must be ipv4 or ipv6 address", cfg.AdvertiseAddress)
|
||||
}
|
||||
// This is the same logic as the API Server uses, except that if no interface is found the address is set to 0.0.0.0, which is invalid and cannot be used
|
||||
// for bootstrapping a cluster.
|
||||
ip, err := ChooseAPIServerBindAddress(addressIP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.AdvertiseAddress = ip.String()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetClusterDynamicDefaults checks and sets configuration values for the InitConfiguration object
|
||||
func SetClusterDynamicDefaults(cfg *kubeadmapi.ClusterConfiguration, advertiseAddress string, bindPort int32) error {
|
||||
// Default all the embedded ComponentConfig structs
|
||||
componentconfigs.Known.Default(cfg)
|
||||
|
||||
ip := net.ParseIP(advertiseAddress)
|
||||
if ip.To4() != nil {
|
||||
cfg.ComponentConfigs.KubeProxy.BindAddress = kubeadmapiv1alpha3.DefaultProxyBindAddressv4
|
||||
} else {
|
||||
cfg.ComponentConfigs.KubeProxy.BindAddress = kubeadmapiv1alpha3.DefaultProxyBindAddressv6
|
||||
}
|
||||
|
||||
// Resolve possible version labels and validate version string
|
||||
if err := NormalizeKubernetesVersion(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If ControlPlaneEndpoint is specified without a port number defaults it to
|
||||
// the bindPort number of the APIEndpoint.
|
||||
// This will allow join of additional control plane instances with different bindPort number
|
||||
if cfg.ControlPlaneEndpoint != "" {
|
||||
host, port, err := kubeadmutil.ParseHostPort(cfg.ControlPlaneEndpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if port == "" {
|
||||
cfg.ControlPlaneEndpoint = net.JoinHostPort(host, strconv.FormatInt(int64(bindPort), 10))
|
||||
}
|
||||
}
|
||||
|
||||
// Downcase SANs. Some domain names (like ELBs) have capitals in them.
|
||||
LowercaseSANs(cfg.APIServerCertSANs)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConfigFileAndDefaultsToInternalConfig takes a path to a config file and a versioned configuration that can serve as the default config
|
||||
// If cfgPath is specified, defaultversionedcfg will always get overridden. Otherwise, the default config (often populated by flags) will be used.
|
||||
// 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 *kubeadmapiv1alpha2.MasterConfiguration) (*kubeadmapi.MasterConfiguration, error) {
|
||||
internalcfg := &kubeadmapi.MasterConfiguration{}
|
||||
func ConfigFileAndDefaultsToInternalConfig(cfgPath string, defaultversionedcfg *kubeadmapiv1alpha3.InitConfiguration) (*kubeadmapi.InitConfiguration, error) {
|
||||
internalcfg := &kubeadmapi.InitConfiguration{}
|
||||
|
||||
if cfgPath != "" {
|
||||
// Loads configuration from config file, if provided
|
||||
@@ -116,117 +170,202 @@ func ConfigFileAndDefaultsToInternalConfig(cfgPath string, defaultversionedcfg *
|
||||
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
|
||||
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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
internalcfg, err = BytesToInternalConfig(b)
|
||||
if err != nil {
|
||||
return nil, 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")
|
||||
// Takes passed flags into account; the defaulting is executed once again enforcing assignment of
|
||||
// static default values to cfg only for values not provided with flags
|
||||
kubeadmscheme.Scheme.Default(defaultversionedcfg)
|
||||
kubeadmscheme.Scheme.Convert(defaultversionedcfg, internalcfg, nil)
|
||||
}
|
||||
|
||||
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 {
|
||||
if err := SetInitDynamicDefaults(internalcfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Validates cfg (flags/configs + defaults + dynamic defaults)
|
||||
if err := validation.ValidateMasterConfiguration(cfg).ToAggregate(); err != nil {
|
||||
if err := validation.ValidateInitConfiguration(internalcfg).ToAggregate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cfg, nil
|
||||
return internalcfg, nil
|
||||
}
|
||||
|
||||
// NormalizeKubernetesVersion resolves version labels, sets alternative
|
||||
// image registry if requested for CI builds, and validates minimal
|
||||
// version that kubeadm supports.
|
||||
func NormalizeKubernetesVersion(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
// Requested version is automatic CI build, thus use KubernetesCI Image Repository for core images
|
||||
if kubeadmutil.KubernetesIsCIVersion(cfg.KubernetesVersion) {
|
||||
cfg.CIImageRepository = kubeadmconstants.DefaultCIImageRepository
|
||||
// BytesToInternalConfig converts a byte slice to an internal, defaulted and validated configuration object.
|
||||
// The byte slice may contain one or many different YAML documents. These YAML documents are parsed one-by-one
|
||||
// and well-known ComponentConfig GroupVersionKinds are stored inside of the internal InitConfiguration struct
|
||||
func BytesToInternalConfig(b []byte) (*kubeadmapi.InitConfiguration, error) {
|
||||
var initcfg *kubeadmapi.InitConfiguration
|
||||
var clustercfg *kubeadmapi.ClusterConfiguration
|
||||
decodedComponentConfigObjects := map[componentconfigs.RegistrationKind]runtime.Object{}
|
||||
|
||||
if err := DetectUnsupportedVersion(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Parse and validate the version argument and resolve possible CI version labels
|
||||
ver, err := kubeadmutil.KubernetesReleaseVersion(cfg.KubernetesVersion)
|
||||
gvkmap, err := kubeadmutil.SplitYAMLDocuments(b)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
cfg.KubernetesVersion = ver
|
||||
|
||||
// Parse the given kubernetes version and make sure it's higher than the lowest supported
|
||||
k8sVersion, err := version.ParseSemantic(cfg.KubernetesVersion)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't parse kubernetes version %q: %v", cfg.KubernetesVersion, err)
|
||||
}
|
||||
if k8sVersion.LessThan(kubeadmconstants.MinimumControlPlaneVersion) {
|
||||
return fmt.Errorf("this version of kubeadm only supports deploying clusters with the control plane version >= %s. Current version: %s", kubeadmconstants.MinimumControlPlaneVersion.String(), cfg.KubernetesVersion)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
for gvk, fileContent := range gvkmap {
|
||||
// Try to get the registration for the ComponentConfig based on the kind
|
||||
regKind := componentconfigs.RegistrationKind(gvk.Kind)
|
||||
registration, found := componentconfigs.Known[regKind]
|
||||
if found {
|
||||
// Unmarshal the bytes from the YAML document into a runtime.Object containing the ComponentConfiguration struct
|
||||
obj, err := registration.Unmarshal(fileContent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decodedComponentConfigObjects[regKind] = obj
|
||||
continue
|
||||
}
|
||||
|
||||
// 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
|
||||
if kubeadmutil.GroupVersionKindsHasInitConfiguration(gvk) {
|
||||
// Set initcfg to an empty struct value the deserializer will populate
|
||||
initcfg = &kubeadmapi.InitConfiguration{}
|
||||
// Decode the bytes into the internal struct. Under the hood, the bytes will be unmarshalled into the
|
||||
// right external version, defaulted, and converted into the internal version.
|
||||
if err := runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(), fileContent, initcfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
if kubeadmutil.GroupVersionKindsHasClusterConfiguration(gvk) {
|
||||
// Set clustercfg to an empty struct value the deserializer will populate
|
||||
clustercfg = &kubeadmapi.ClusterConfiguration{}
|
||||
// Decode the bytes into the internal struct. Under the hood, the bytes will be unmarshalled into the
|
||||
// right external version, defaulted, and converted into the internal version.
|
||||
if err := runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(), fileContent, clustercfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("[config] WARNING: Ignored YAML document with GroupVersionKind %v\n", gvk)
|
||||
}
|
||||
|
||||
// Enforce that InitConfiguration and/or ClusterConfiguration has to exist among the YAML documents
|
||||
if initcfg == nil && clustercfg == nil {
|
||||
return nil, fmt.Errorf("no InitConfiguration or ClusterConfiguration kind was found in the YAML file")
|
||||
}
|
||||
|
||||
// If InitConfiguration wasn't given, default it by creating an external struct instance, default it and convert into the internal type
|
||||
if initcfg == nil {
|
||||
extinitcfg := &kubeadmapiv1alpha3.InitConfiguration{}
|
||||
kubeadmscheme.Scheme.Default(extinitcfg)
|
||||
// Set initcfg to an empty struct value the deserializer will populate
|
||||
initcfg = &kubeadmapi.InitConfiguration{}
|
||||
kubeadmscheme.Scheme.Convert(extinitcfg, initcfg, nil)
|
||||
}
|
||||
// If ClusterConfiguration was given, populate it in the InitConfiguration struct
|
||||
if clustercfg != nil {
|
||||
initcfg.ClusterConfiguration = *clustercfg
|
||||
}
|
||||
|
||||
// Save the loaded ComponentConfig objects in the initcfg object
|
||||
for kind, obj := range decodedComponentConfigObjects {
|
||||
registration, found := componentconfigs.Known[kind]
|
||||
if found {
|
||||
if ok := registration.SetToInternalConfig(obj, &initcfg.ClusterConfiguration); !ok {
|
||||
return nil, fmt.Errorf("couldn't save componentconfig value for kind %q", string(kind))
|
||||
}
|
||||
} else {
|
||||
// This should never happen in practice
|
||||
fmt.Printf("[config] WARNING: Decoded a kind that couldn't be saved to the internal configuration: %q\n", string(kind))
|
||||
}
|
||||
}
|
||||
return initcfg, nil
|
||||
}
|
||||
|
||||
func defaultedInternalConfig() *kubeadmapi.ClusterConfiguration {
|
||||
externalcfg := &kubeadmapiv1alpha3.ClusterConfiguration{}
|
||||
internalcfg := &kubeadmapi.ClusterConfiguration{}
|
||||
|
||||
kubeadmscheme.Scheme.Default(externalcfg)
|
||||
kubeadmscheme.Scheme.Convert(externalcfg, internalcfg, nil)
|
||||
|
||||
// Default the embedded ComponentConfig structs
|
||||
componentconfigs.Known.Default(internalcfg)
|
||||
return internalcfg
|
||||
}
|
||||
|
||||
// MarshalInitConfigurationToBytes marshals the internal InitConfiguration object to bytes. It writes the embedded
|
||||
// ClusterConfiguration object with ComponentConfigs out as separate YAML documents
|
||||
func MarshalInitConfigurationToBytes(cfg *kubeadmapi.InitConfiguration, gv schema.GroupVersion) ([]byte, error) {
|
||||
initbytes, err := kubeadmutil.MarshalToYamlForCodecs(cfg, gv, kubeadmscheme.Codecs)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
allFiles := [][]byte{initbytes}
|
||||
|
||||
// Exception: If the specified groupversion is targeting the internal type, don't print embedded ClusterConfiguration contents
|
||||
// This is mostly used for unit testing. In a real scenario the internal version of the API is never marshalled as-is.
|
||||
if gv.Version != runtime.APIVersionInternal {
|
||||
clusterbytes, err := MarshalClusterConfigurationToBytes(&cfg.ClusterConfiguration, gv)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
allFiles = append(allFiles, clusterbytes)
|
||||
}
|
||||
return bytes.Join(allFiles, []byte(kubeadmconstants.YAMLDocumentSeparator)), nil
|
||||
}
|
||||
|
||||
// MarshalClusterConfigurationToBytes marshals the internal ClusterConfiguration object to bytes. It writes the embedded
|
||||
// ComponentConfiguration objects out as separate YAML documents
|
||||
func MarshalClusterConfigurationToBytes(clustercfg *kubeadmapi.ClusterConfiguration, gv schema.GroupVersion) ([]byte, error) {
|
||||
clusterbytes, err := kubeadmutil.MarshalToYamlForCodecs(clustercfg, gv, kubeadmscheme.Codecs)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
allFiles := [][]byte{clusterbytes}
|
||||
componentConfigContent := map[string][]byte{}
|
||||
defaultedcfg := defaultedInternalConfig()
|
||||
|
||||
for kind, registration := range componentconfigs.Known {
|
||||
// If the ComponentConfig struct for the current registration is nil, skip it when marshalling
|
||||
realobj, ok := registration.GetFromInternalConfig(clustercfg)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
defaultedobj, ok := registration.GetFromInternalConfig(defaultedcfg)
|
||||
// Invalid: The caller asked to not print the componentconfigs if defaulted, but defaultComponentConfigs() wasn't able to create default objects to use for reference
|
||||
if !ok {
|
||||
return []byte{}, fmt.Errorf("couldn't create a default componentconfig object")
|
||||
}
|
||||
|
||||
// If the real ComponentConfig object differs from the default, print it out. If not, there's no need to print it out, so skip it
|
||||
if !reflect.DeepEqual(realobj, defaultedobj) {
|
||||
contentBytes, err := registration.Marshal(realobj)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
componentConfigContent[string(kind)] = contentBytes
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the ComponentConfig files by kind when marshalling
|
||||
sortedComponentConfigFiles := consistentOrderByteSlice(componentConfigContent)
|
||||
allFiles = append(allFiles, sortedComponentConfigFiles...)
|
||||
return bytes.Join(allFiles, []byte(kubeadmconstants.YAMLDocumentSeparator)), nil
|
||||
}
|
||||
|
||||
// consistentOrderByteSlice takes a map of a string key and a byte slice, and returns a byte slice of byte slices
|
||||
// with consistent ordering, where the keys in the map determine the ordering of the return value. This has to be
|
||||
// done as the order of a for...range loop over a map in go is undeterministic, and could otherwise lead to flakes
|
||||
// in e.g. unit tests when marshalling content with a random order
|
||||
func consistentOrderByteSlice(content map[string][]byte) [][]byte {
|
||||
keys := []string{}
|
||||
sortedContent := [][]byte{}
|
||||
for key := range content {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, key := range keys {
|
||||
sortedContent = append(sortedContent, content[key])
|
||||
}
|
||||
return sortedContent
|
||||
}
|
||||
|
214
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/masterconfig_test.go
generated
vendored
214
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/masterconfig_test.go
generated
vendored
@@ -19,30 +19,23 @@ package config
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"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"
|
||||
kubeadmapiv1alpha3 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha3"
|
||||
)
|
||||
|
||||
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"
|
||||
master_v1alpha2YAML = "testdata/conversion/master/v1alpha2.yaml"
|
||||
master_v1alpha3YAML = "testdata/conversion/master/v1alpha3.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"
|
||||
)
|
||||
|
||||
func diff(expected, actual []byte) string {
|
||||
@@ -66,45 +59,39 @@ func TestConfigFileAndDefaultsToInternalConfig(t *testing.T) {
|
||||
}{
|
||||
// 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,
|
||||
{ // v1alpha3 -> internal
|
||||
name: "v1alpha3ToInternal",
|
||||
in: master_v1alpha3YAML,
|
||||
out: master_internalYAML,
|
||||
groupVersion: kubeadm.SchemeGroupVersion,
|
||||
},
|
||||
{ // v1alpha1 -> internal -> v1alpha2
|
||||
name: "v1alpha1Tov1alpha2",
|
||||
in: master_v1alpha1YAML,
|
||||
out: master_v1alpha2YAML,
|
||||
groupVersion: v1alpha2.SchemeGroupVersion,
|
||||
{ // v1alpha2 -> internal -> v1alpha3
|
||||
name: "v1alpha2Tov1alpha3",
|
||||
in: master_v1alpha2YAML,
|
||||
out: master_v1alpha3YAML,
|
||||
groupVersion: kubeadmapiv1alpha3.SchemeGroupVersion,
|
||||
},
|
||||
{ // v1alpha3 -> internal -> v1alpha3
|
||||
name: "v1alpha3Tov1alpha3",
|
||||
in: master_v1alpha3YAML,
|
||||
out: master_v1alpha3YAML,
|
||||
groupVersion: kubeadmapiv1alpha3.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",
|
||||
{ // v1alpha2 -> default -> validate -> internal -> v1alpha3
|
||||
name: "incompleteYAMLToDefaultedv1alpha3",
|
||||
in: master_incompleteYAML,
|
||||
out: master_defaultedYAML,
|
||||
groupVersion: v1alpha2.SchemeGroupVersion,
|
||||
groupVersion: kubeadmapiv1alpha3.SchemeGroupVersion,
|
||||
},
|
||||
{ // v1alpha1 (faulty) -> validation should fail
|
||||
{ // v1alpha2 -> validation should fail
|
||||
name: "invalidYAMLShouldFail",
|
||||
in: master_invalidYAML,
|
||||
expectedErr: true,
|
||||
@@ -114,7 +101,7 @@ func TestConfigFileAndDefaultsToInternalConfig(t *testing.T) {
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t2 *testing.T) {
|
||||
|
||||
internalcfg, err := ConfigFileAndDefaultsToInternalConfig(rt.in, &v1alpha2.MasterConfiguration{})
|
||||
internalcfg, err := ConfigFileAndDefaultsToInternalConfig(rt.in, &kubeadmapiv1alpha3.InitConfiguration{})
|
||||
if err != nil {
|
||||
if rt.expectedErr {
|
||||
return
|
||||
@@ -122,7 +109,7 @@ func TestConfigFileAndDefaultsToInternalConfig(t *testing.T) {
|
||||
t2.Fatalf("couldn't unmarshal test data: %v", err)
|
||||
}
|
||||
|
||||
actual, err := kubeadmutil.MarshalToYamlForCodecs(internalcfg, rt.groupVersion, scheme.Codecs)
|
||||
actual, err := MarshalInitConfigurationToBytes(internalcfg, rt.groupVersion)
|
||||
if err != nil {
|
||||
t2.Fatalf("couldn't marshal internal object: %v", err)
|
||||
}
|
||||
@@ -140,85 +127,90 @@ func TestConfigFileAndDefaultsToInternalConfig(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
func TestConsistentOrderByteSlice(t *testing.T) {
|
||||
var (
|
||||
aKind = "Akind"
|
||||
aFile = []byte(`
|
||||
kind: Akind
|
||||
apiVersion: foo.k8s.io/v1
|
||||
`)
|
||||
aaKind = "Aakind"
|
||||
aaFile = []byte(`
|
||||
kind: Aakind
|
||||
apiVersion: foo.k8s.io/v1
|
||||
`)
|
||||
abKind = "Abkind"
|
||||
abFile = []byte(`
|
||||
kind: Abkind
|
||||
apiVersion: foo.k8s.io/v1
|
||||
`)
|
||||
)
|
||||
var tests = []struct {
|
||||
name string
|
||||
in map[string][]byte
|
||||
expected [][]byte
|
||||
}{
|
||||
{
|
||||
name: "empty struct",
|
||||
name: "a_aa_ab",
|
||||
in: map[string][]byte{
|
||||
aKind: aFile,
|
||||
aaKind: aaFile,
|
||||
abKind: abFile,
|
||||
},
|
||||
expected: [][]byte{aaFile, abFile, aFile},
|
||||
},
|
||||
{
|
||||
name: "already lowercase",
|
||||
in: []string{"example.k8s.io"},
|
||||
out: []string{"example.k8s.io"},
|
||||
name: "a_ab_aa",
|
||||
in: map[string][]byte{
|
||||
aKind: aFile,
|
||||
abKind: abFile,
|
||||
aaKind: aaFile,
|
||||
},
|
||||
expected: [][]byte{aaFile, abFile, aFile},
|
||||
},
|
||||
{
|
||||
name: "ip addresses and uppercase",
|
||||
in: []string{"EXAMPLE.k8s.io", "10.100.0.1"},
|
||||
out: []string{"example.k8s.io", "10.100.0.1"},
|
||||
name: "aa_a_ab",
|
||||
in: map[string][]byte{
|
||||
aaKind: aaFile,
|
||||
aKind: aFile,
|
||||
abKind: abFile,
|
||||
},
|
||||
expected: [][]byte{aaFile, abFile, aFile},
|
||||
},
|
||||
{
|
||||
name: "punycode and uppercase",
|
||||
in: []string{"xn--7gq663byk9a.xn--fiqz9s", "ANOTHEREXAMPLE.k8s.io"},
|
||||
out: []string{"xn--7gq663byk9a.xn--fiqz9s", "anotherexample.k8s.io"},
|
||||
name: "aa_ab_a",
|
||||
in: map[string][]byte{
|
||||
aaKind: aaFile,
|
||||
abKind: abFile,
|
||||
aKind: aFile,
|
||||
},
|
||||
expected: [][]byte{aaFile, abFile, aFile},
|
||||
},
|
||||
{
|
||||
name: "ab_a_aa",
|
||||
in: map[string][]byte{
|
||||
abKind: abFile,
|
||||
aKind: aFile,
|
||||
aaKind: aaFile,
|
||||
},
|
||||
expected: [][]byte{aaFile, abFile, aFile},
|
||||
},
|
||||
{
|
||||
name: "ab_aa_a",
|
||||
in: map[string][]byte{
|
||||
abKind: abFile,
|
||||
aaKind: aaFile,
|
||||
aKind: aFile,
|
||||
},
|
||||
expected: [][]byte{aaFile, abFile, aFile},
|
||||
},
|
||||
}
|
||||
|
||||
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])
|
||||
}
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t2 *testing.T) {
|
||||
actual := consistentOrderByteSlice(rt.in)
|
||||
if !reflect.DeepEqual(rt.expected, actual) {
|
||||
t2.Errorf("the expected and actual output differs.\n\texpected: %s\n\tout: %s\n", rt.expected, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
53
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/nodeconfig.go
generated
vendored
53
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/nodeconfig.go
generated
vendored
@@ -19,38 +19,69 @@ package config
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
|
||||
"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"
|
||||
kubeadmapiv1alpha3 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha3"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
|
||||
"k8s.io/kubernetes/pkg/util/node"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
)
|
||||
|
||||
// SetJoinDynamicDefaults checks and sets configuration values for the NodeConfiguration object
|
||||
func SetJoinDynamicDefaults(cfg *kubeadmapi.NodeConfiguration) error {
|
||||
cfg.NodeRegistration.Name = node.GetHostname(cfg.NodeRegistration.Name)
|
||||
// SetJoinDynamicDefaults checks and sets configuration values for the JoinConfiguration object
|
||||
func SetJoinDynamicDefaults(cfg *kubeadmapi.JoinConfiguration) error {
|
||||
|
||||
if err := SetNodeRegistrationDynamicDefaults(&cfg.NodeRegistration, cfg.ControlPlane); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := SetAPIEndpointDynamicDefaults(&cfg.APIEndpoint); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NodeConfigFileAndDefaultsToInternalConfig
|
||||
func NodeConfigFileAndDefaultsToInternalConfig(cfgPath string, defaultversionedcfg *kubeadmapiv1alpha2.NodeConfiguration) (*kubeadmapi.NodeConfiguration, error) {
|
||||
internalcfg := &kubeadmapi.NodeConfiguration{}
|
||||
func NodeConfigFileAndDefaultsToInternalConfig(cfgPath string, defaultversionedcfg *kubeadmapiv1alpha3.JoinConfiguration) (*kubeadmapi.JoinConfiguration, error) {
|
||||
internalcfg := &kubeadmapi.JoinConfiguration{}
|
||||
|
||||
if cfgPath != "" {
|
||||
// Loads configuration from config file, if provided
|
||||
// Nb. --config overrides command line flags
|
||||
// Nb. --config overrides command line flags, TODO: fix this
|
||||
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)
|
||||
|
||||
if err := DetectUnsupportedVersion(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gvkmap, err := kubeadmutil.SplitYAMLDocuments(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
joinBytes := []byte{}
|
||||
for gvk, bytes := range gvkmap {
|
||||
if gvk.Kind == constants.JoinConfigurationKind || gvk.Kind == constants.NodeConfigurationKind {
|
||||
joinBytes = bytes
|
||||
}
|
||||
}
|
||||
|
||||
if len(joinBytes) == 0 {
|
||||
return nil, fmt.Errorf("no %s found in config file %q", constants.JoinConfigurationKind, cfgPath)
|
||||
}
|
||||
|
||||
if err := runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(), joinBytes, internalcfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} 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
|
||||
@@ -63,7 +94,7 @@ func NodeConfigFileAndDefaultsToInternalConfig(cfgPath string, defaultversionedc
|
||||
return nil, err
|
||||
}
|
||||
// Validates cfg (flags/configs + defaults)
|
||||
if err := validation.ValidateNodeConfiguration(internalcfg).ToAggregate(); err != nil {
|
||||
if err := validation.ValidateJoinConfiguration(internalcfg).ToAggregate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
40
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/nodeconfig_test.go
generated
vendored
40
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/nodeconfig_test.go
generated
vendored
@@ -24,13 +24,13 @@ import (
|
||||
"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"
|
||||
kubeadmapiv1alpha3 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha3"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
)
|
||||
|
||||
const (
|
||||
node_v1alpha1YAML = "testdata/conversion/node/v1alpha1.yaml"
|
||||
node_v1alpha2YAML = "testdata/conversion/node/v1alpha2.yaml"
|
||||
node_v1alpha3YAML = "testdata/conversion/node/v1alpha3.yaml"
|
||||
node_internalYAML = "testdata/conversion/node/internal.yaml"
|
||||
node_incompleteYAML = "testdata/defaulting/node/incomplete.yaml"
|
||||
node_defaultedYAML = "testdata/defaulting/node/defaulted.yaml"
|
||||
@@ -45,33 +45,39 @@ func TestNodeConfigFileAndDefaultsToInternalConfig(t *testing.T) {
|
||||
}{
|
||||
// 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,
|
||||
{ // v1alpha3 -> internal
|
||||
name: "v1alpha3ToInternal",
|
||||
in: node_v1alpha3YAML,
|
||||
out: node_internalYAML,
|
||||
groupVersion: kubeadm.SchemeGroupVersion,
|
||||
},
|
||||
{ // v1alpha2 -> internal -> v1alpha3
|
||||
name: "v1alpha2Tov1alpha3",
|
||||
in: node_v1alpha2YAML,
|
||||
out: node_v1alpha3YAML,
|
||||
groupVersion: kubeadmapiv1alpha3.SchemeGroupVersion,
|
||||
},
|
||||
{ // v1alpha3 -> internal -> v1alpha3
|
||||
name: "v1alpha3Tov1alpha3",
|
||||
in: node_v1alpha3YAML,
|
||||
out: node_v1alpha3YAML,
|
||||
groupVersion: kubeadmapiv1alpha3.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
|
||||
{ // v1alpha2 -> default -> validate -> internal -> v1alpha3
|
||||
name: "incompleteYAMLToDefaulted",
|
||||
in: node_incompleteYAML,
|
||||
out: node_defaultedYAML,
|
||||
groupVersion: v1alpha2.SchemeGroupVersion,
|
||||
groupVersion: kubeadmapiv1alpha3.SchemeGroupVersion,
|
||||
},
|
||||
{ // v1alpha1 (faulty) -> validation should fail
|
||||
{ // v1alpha2 -> validation should fail
|
||||
name: "invalidYAMLShouldFail",
|
||||
in: node_invalidYAML,
|
||||
expectedErr: true,
|
||||
@@ -81,7 +87,7 @@ func TestNodeConfigFileAndDefaultsToInternalConfig(t *testing.T) {
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t2 *testing.T) {
|
||||
|
||||
internalcfg, err := NodeConfigFileAndDefaultsToInternalConfig(rt.in, &v1alpha2.NodeConfiguration{})
|
||||
internalcfg, err := NodeConfigFileAndDefaultsToInternalConfig(rt.in, &kubeadmapiv1alpha3.JoinConfiguration{})
|
||||
if err != nil {
|
||||
if rt.expectedErr {
|
||||
return
|
||||
|
@@ -1,7 +1,6 @@
|
||||
API:
|
||||
APIEndpoint:
|
||||
AdvertiseAddress: 192.168.2.2
|
||||
BindPort: 6443
|
||||
ControlPlaneEndpoint: ""
|
||||
APIServerCertSANs: null
|
||||
APIServerExtraArgs:
|
||||
authorization-mode: Node,RBAC,Webhook
|
||||
@@ -23,6 +22,143 @@ BootstrapTokens:
|
||||
CIImageRepository: ""
|
||||
CertificatesDir: /etc/kubernetes/pki
|
||||
ClusterName: kubernetes
|
||||
ComponentConfigs:
|
||||
KubeProxy:
|
||||
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: iptables
|
||||
NodePortAddresses: null
|
||||
OOMScoreAdj: -999
|
||||
PortRange: ""
|
||||
ResourceContainer: /kube-proxy
|
||||
UDPIdleTimeout: 250ms
|
||||
Kubelet:
|
||||
Address: 1.2.3.4
|
||||
Authentication:
|
||||
Anonymous:
|
||||
Enabled: false
|
||||
Webhook:
|
||||
CacheTTL: 2m0s
|
||||
Enabled: true
|
||||
X509:
|
||||
ClientCAFile: /etc/kubernetes/pki/ca.crt
|
||||
Authorization:
|
||||
Mode: Webhook
|
||||
Webhook:
|
||||
CacheAuthorizedTTL: 5m0s
|
||||
CacheUnauthorizedTTL: 30s
|
||||
CPUCFSQuota: true
|
||||
CPUCFSQuotaPeriod: 0s
|
||||
CPUManagerPolicy: none
|
||||
CPUManagerReconcilePeriod: 10s
|
||||
CgroupDriver: cgroupfs
|
||||
CgroupRoot: ""
|
||||
CgroupsPerQOS: true
|
||||
ClusterDNS:
|
||||
- 10.96.0.10
|
||||
ClusterDomain: cluster.local
|
||||
ConfigMapAndSecretChangeDetectionStrategy: Watch
|
||||
ContainerLogMaxFiles: 5
|
||||
ContainerLogMaxSize: 10Mi
|
||||
ContentType: application/vnd.kubernetes.protobuf
|
||||
EnableContentionProfiling: false
|
||||
EnableControllerAttachDetach: true
|
||||
EnableDebuggingHandlers: true
|
||||
EnforceNodeAllocatable:
|
||||
- pods
|
||||
EventBurst: 10
|
||||
EventRecordQPS: 5
|
||||
EvictionHard:
|
||||
imagefs.available: 15%
|
||||
memory.available: 100Mi
|
||||
nodefs.available: 10%
|
||||
nodefs.inodesFree: 5%
|
||||
EvictionMaxPodGracePeriod: 0
|
||||
EvictionMinimumReclaim: null
|
||||
EvictionPressureTransitionPeriod: 5m0s
|
||||
EvictionSoft: null
|
||||
EvictionSoftGracePeriod: null
|
||||
FailSwapOn: true
|
||||
FeatureGates: null
|
||||
FileCheckFrequency: 20s
|
||||
HTTPCheckFrequency: 20s
|
||||
HairpinMode: promiscuous-bridge
|
||||
HealthzBindAddress: 127.0.0.1
|
||||
HealthzPort: 10248
|
||||
IPTablesDropBit: 15
|
||||
IPTablesMasqueradeBit: 14
|
||||
ImageGCHighThresholdPercent: 85
|
||||
ImageGCLowThresholdPercent: 80
|
||||
ImageMinimumGCAge: 2m0s
|
||||
KubeAPIBurst: 10
|
||||
KubeAPIQPS: 5
|
||||
KubeReserved: null
|
||||
KubeReservedCgroup: ""
|
||||
KubeletCgroups: ""
|
||||
MakeIPTablesUtilChains: true
|
||||
MaxOpenFiles: 1000000
|
||||
MaxPods: 110
|
||||
NodeLeaseDurationSeconds: 40
|
||||
NodeStatusUpdateFrequency: 10s
|
||||
OOMScoreAdj: -999
|
||||
PodCIDR: ""
|
||||
PodPidsLimit: -1
|
||||
PodsPerCore: 0
|
||||
Port: 10250
|
||||
ProtectKernelDefaults: false
|
||||
QOSReserved: null
|
||||
ReadOnlyPort: 0
|
||||
RegistryBurst: 10
|
||||
RegistryPullQPS: 5
|
||||
ResolverConfig: /etc/resolv.conf
|
||||
RotateCertificates: true
|
||||
RuntimeRequestTimeout: 2m0s
|
||||
SerializeImagePulls: true
|
||||
ServerTLSBootstrap: false
|
||||
StaticPodPath: /etc/kubernetes/manifests
|
||||
StaticPodURL: ""
|
||||
StaticPodURLHeader: null
|
||||
StreamingConnectionIdleTimeout: 4h0m0s
|
||||
SyncFrequency: 1m0s
|
||||
SystemCgroups: ""
|
||||
SystemReserved: null
|
||||
SystemReservedCgroup: ""
|
||||
TLSCertFile: ""
|
||||
TLSCipherSuites: null
|
||||
TLSMinVersion: ""
|
||||
TLSPrivateKeyFile: ""
|
||||
VolumeStatsAggPeriod: 1m0s
|
||||
ControlPlaneEndpoint: ""
|
||||
ControllerManagerExtraArgs: null
|
||||
ControllerManagerExtraVolumes: null
|
||||
Etcd:
|
||||
@@ -35,116 +171,7 @@ Etcd:
|
||||
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
|
||||
KubernetesVersion: v1.11.2
|
||||
Networking:
|
||||
DNSDomain: cluster.local
|
||||
PodSubnet: ""
|
||||
|
@@ -1,149 +0,0 @@
|
||||
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: ""
|
@@ -1,146 +0,0 @@
|
||||
# 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: ""
|
@@ -59,7 +59,7 @@ kubeProxy:
|
||||
scheduler: ""
|
||||
syncPeriod: 30s
|
||||
metricsBindAddress: 127.0.0.1:10249
|
||||
mode: ""
|
||||
mode: iptables
|
||||
nodePortAddresses: null
|
||||
oomScoreAdj: -999
|
||||
portRange: ""
|
||||
@@ -67,7 +67,7 @@ kubeProxy:
|
||||
udpIdleTimeout: 250ms
|
||||
kubeletConfiguration:
|
||||
baseConfig:
|
||||
address: 0.0.0.0
|
||||
address: 1.2.3.4
|
||||
authentication:
|
||||
anonymous:
|
||||
enabled: false
|
||||
@@ -86,10 +86,12 @@ kubeletConfiguration:
|
||||
clusterDNS:
|
||||
- 10.96.0.10
|
||||
clusterDomain: cluster.local
|
||||
configMapAndSecretChangeDetectionStrategy: Watch
|
||||
containerLogMaxFiles: 5
|
||||
containerLogMaxSize: 10Mi
|
||||
contentType: application/vnd.kubernetes.protobuf
|
||||
cpuCFSQuota: true
|
||||
cpuCFSQuotaPeriod: 0s
|
||||
cpuManagerPolicy: none
|
||||
cpuManagerReconcilePeriod: 10s
|
||||
enableControllerAttachDetach: true
|
||||
@@ -134,7 +136,7 @@ kubeletConfiguration:
|
||||
streamingConnectionIdleTimeout: 4h0m0s
|
||||
syncFrequency: 1m0s
|
||||
volumeStatsAggPeriod: 1m0s
|
||||
kubernetesVersion: v1.10.2
|
||||
kubernetesVersion: v1.11.2
|
||||
networking:
|
||||
dnsDomain: cluster.local
|
||||
podSubnet: ""
|
||||
|
156
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/conversion/master/v1alpha3.yaml
generated
vendored
Normal file
156
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/config/testdata/conversion/master/v1alpha3.yaml
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
apiEndpoint:
|
||||
advertiseAddress: 192.168.2.2
|
||||
bindPort: 6443
|
||||
apiVersion: kubeadm.k8s.io/v1alpha3
|
||||
bootstrapTokens:
|
||||
- groups:
|
||||
- system:bootstrappers:kubeadm:default-node-token
|
||||
token: s73ybu.6tw6wnqgp5z0wb77
|
||||
ttl: 24h0m0s
|
||||
usages:
|
||||
- signing
|
||||
- authentication
|
||||
kind: InitConfiguration
|
||||
nodeRegistration:
|
||||
criSocket: /var/run/dockershim.sock
|
||||
name: master-1
|
||||
taints:
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/master
|
||||
---
|
||||
apiServerExtraArgs:
|
||||
authorization-mode: Node,RBAC,Webhook
|
||||
apiVersion: kubeadm.k8s.io/v1alpha3
|
||||
auditPolicy:
|
||||
logDir: /var/log/kubernetes/audit
|
||||
logMaxAge: 2
|
||||
path: ""
|
||||
certificatesDir: /etc/kubernetes/pki
|
||||
clusterName: kubernetes
|
||||
controlPlaneEndpoint: ""
|
||||
etcd:
|
||||
local:
|
||||
dataDir: /var/lib/etcd
|
||||
image: ""
|
||||
imageRepository: k8s.gcr.io
|
||||
kind: ClusterConfiguration
|
||||
kubernetesVersion: v1.11.2
|
||||
networking:
|
||||
dnsDomain: cluster.local
|
||||
podSubnet: ""
|
||||
serviceSubnet: 10.96.0.0/12
|
||||
unifiedControlPlaneImage: ""
|
||||
---
|
||||
apiVersion: kubeproxy.config.k8s.io/v1alpha1
|
||||
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
|
||||
kind: KubeProxyConfiguration
|
||||
metricsBindAddress: 127.0.0.1:10249
|
||||
mode: iptables
|
||||
nodePortAddresses: null
|
||||
oomScoreAdj: -999
|
||||
portRange: ""
|
||||
resourceContainer: /kube-proxy
|
||||
udpIdleTimeout: 250ms
|
||||
---
|
||||
address: 1.2.3.4
|
||||
apiVersion: kubelet.config.k8s.io/v1beta1
|
||||
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
|
||||
configMapAndSecretChangeDetectionStrategy: Watch
|
||||
containerLogMaxFiles: 5
|
||||
containerLogMaxSize: 10Mi
|
||||
contentType: application/vnd.kubernetes.protobuf
|
||||
cpuCFSQuota: true
|
||||
cpuCFSQuotaPeriod: 0s
|
||||
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
|
||||
kind: KubeletConfiguration
|
||||
kubeAPIBurst: 10
|
||||
kubeAPIQPS: 5
|
||||
makeIPTablesUtilChains: true
|
||||
maxOpenFiles: 1000000
|
||||
maxPods: 110
|
||||
nodeLeaseDurationSeconds: 40
|
||||
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
|
@@ -1,5 +1,9 @@
|
||||
APIEndpoint:
|
||||
AdvertiseAddress: 192.168.2.2
|
||||
BindPort: 6443
|
||||
CACertPath: /etc/kubernetes/pki/ca.crt
|
||||
ClusterName: kubernetes
|
||||
ControlPlane: false
|
||||
DiscoveryFile: ""
|
||||
DiscoveryTimeout: 5m0s
|
||||
DiscoveryToken: abcdef.0123456789abcdef
|
||||
|
@@ -1,3 +1,4 @@
|
||||
advertiseAddress: 192.168.2.2
|
||||
apiVersion: kubeadm.k8s.io/v1alpha2
|
||||
caCertPath: /etc/kubernetes/pki/ca.crt
|
||||
clusterName: kubernetes
|
||||
|
@@ -1,14 +1,18 @@
|
||||
apiVersion: kubeadm.k8s.io/v1alpha1
|
||||
kind: NodeConfiguration
|
||||
apiEndpoint:
|
||||
advertiseAddress: 192.168.2.2
|
||||
bindPort: 6443
|
||||
apiVersion: kubeadm.k8s.io/v1alpha3
|
||||
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
|
||||
kind: JoinConfiguration
|
||||
nodeRegistration:
|
||||
criSocket: /var/run/dockershim.sock
|
||||
name: master-1
|
||||
tlsBootstrapToken: abcdef.0123456789abcdef
|
||||
token: abcdef.0123456789abcdef
|
@@ -1,12 +1,7 @@
|
||||
api:
|
||||
apiEndpoint:
|
||||
advertiseAddress: 192.168.2.2
|
||||
bindPort: 6443
|
||||
controlPlaneEndpoint: ""
|
||||
apiVersion: kubeadm.k8s.io/v1alpha2
|
||||
auditPolicy:
|
||||
logDir: /var/log/kubernetes/audit
|
||||
logMaxAge: 2
|
||||
path: ""
|
||||
apiVersion: kubeadm.k8s.io/v1alpha3
|
||||
bootstrapTokens:
|
||||
- groups:
|
||||
- system:bootstrappers:kubeadm:default-node-token
|
||||
@@ -15,129 +10,142 @@ bootstrapTokens:
|
||||
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
|
||||
kind: InitConfiguration
|
||||
nodeRegistration:
|
||||
criSocket: /var/run/criruntime.sock
|
||||
name: master-1
|
||||
taints:
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/master
|
||||
---
|
||||
apiVersion: kubeadm.k8s.io/v1alpha3
|
||||
auditPolicy:
|
||||
logDir: /var/log/kubernetes/audit
|
||||
logMaxAge: 2
|
||||
path: ""
|
||||
certificatesDir: /var/lib/kubernetes/pki
|
||||
clusterName: kubernetes
|
||||
controlPlaneEndpoint: ""
|
||||
etcd:
|
||||
local:
|
||||
dataDir: /var/lib/etcd
|
||||
image: ""
|
||||
imageRepository: my-company.com
|
||||
kind: ClusterConfiguration
|
||||
kubernetesVersion: v1.11.2
|
||||
networking:
|
||||
dnsDomain: cluster.global
|
||||
podSubnet: 10.148.0.0/16
|
||||
serviceSubnet: 10.196.0.0/12
|
||||
unifiedControlPlaneImage: ""
|
||||
---
|
||||
apiVersion: kubeproxy.config.k8s.io/v1alpha1
|
||||
bindAddress: 0.0.0.0
|
||||
clientConnection:
|
||||
acceptContentTypes: ""
|
||||
burst: 10
|
||||
contentType: application/vnd.kubernetes.protobuf
|
||||
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
|
||||
qps: 5
|
||||
clusterCIDR: 10.148.0.0/16
|
||||
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
|
||||
kind: KubeProxyConfiguration
|
||||
metricsBindAddress: 127.0.0.1:10249
|
||||
mode: ""
|
||||
nodePortAddresses: null
|
||||
oomScoreAdj: -999
|
||||
portRange: ""
|
||||
resourceContainer: /kube-proxy
|
||||
udpIdleTimeout: 250ms
|
||||
---
|
||||
address: 0.0.0.0
|
||||
apiVersion: kubelet.config.k8s.io/v1beta1
|
||||
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
|
||||
configMapAndSecretChangeDetectionStrategy: Watch
|
||||
containerLogMaxFiles: 5
|
||||
containerLogMaxSize: 10Mi
|
||||
contentType: application/vnd.kubernetes.protobuf
|
||||
cpuCFSQuota: true
|
||||
cpuCFSQuotaPeriod: 100ms
|
||||
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
|
||||
kind: KubeletConfiguration
|
||||
kubeAPIBurst: 10
|
||||
kubeAPIQPS: 5
|
||||
makeIPTablesUtilChains: true
|
||||
maxOpenFiles: 1000000
|
||||
maxPods: 110
|
||||
nodeLeaseDurationSeconds: 40
|
||||
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
|
||||
|
@@ -1,15 +1,18 @@
|
||||
# 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.
|
||||
apiVersion: kubeadm.k8s.io/v1alpha2
|
||||
kind: MasterConfiguration
|
||||
api:
|
||||
advertiseAddress: 192.168.2.2
|
||||
bindPort: 6443
|
||||
bootstrapTokens:
|
||||
- token: s73ybu.6tw6wnqgp5z0wb77
|
||||
certificatesDir: /var/lib/kubernetes/pki
|
||||
clusterName: kubernetes
|
||||
criSocket: /var/run/criruntime.sock
|
||||
imageRepository: my-company.com
|
||||
kubernetesVersion: v1.10.2
|
||||
kubernetesVersion: v1.11.2
|
||||
networking:
|
||||
dnsDomain: cluster.global
|
||||
serviceSubnet: 10.196.0.0/12
|
||||
nodeName: master-1
|
||||
token: s73ybu.6tw6wnqgp5z0wb77
|
||||
podSubnet: 10.148.0.0/16
|
||||
nodeRegistration:
|
||||
criSocket: /var/run/criruntime.sock
|
||||
name: master-1
|
||||
|
@@ -1,4 +1,7 @@
|
||||
apiVersion: kubeadm.k8s.io/v1alpha2
|
||||
apiEndpoint:
|
||||
advertiseAddress: 192.168.2.2
|
||||
bindPort: 6443
|
||||
apiVersion: kubeadm.k8s.io/v1alpha3
|
||||
caCertPath: /etc/kubernetes/pki/ca.crt
|
||||
clusterName: kubernetes
|
||||
discoveryFile: ""
|
||||
@@ -7,7 +10,7 @@ discoveryToken: abcdef.0123456789abcdef
|
||||
discoveryTokenAPIServers:
|
||||
- kube-apiserver:6443
|
||||
discoveryTokenUnsafeSkipCAVerification: true
|
||||
kind: NodeConfiguration
|
||||
kind: JoinConfiguration
|
||||
nodeRegistration:
|
||||
criSocket: /var/run/dockershim.sock
|
||||
name: thegopher
|
||||
|
@@ -1,7 +1,9 @@
|
||||
apiVersion: kubeadm.k8s.io/v1alpha1
|
||||
advertiseAddress: 192.168.2.2
|
||||
apiVersion: kubeadm.k8s.io/v1alpha2
|
||||
kind: NodeConfiguration
|
||||
discoveryTokenAPIServers:
|
||||
- kube-apiserver:6443
|
||||
discoveryTokenUnsafeSkipCAVerification: true
|
||||
nodeName: thegopher
|
||||
nodeRegistration:
|
||||
name: thegopher
|
||||
token: abcdef.0123456789abcdef
|
||||
|
@@ -1,73 +0,0 @@
|
||||
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: ""
|
@@ -1,64 +0,0 @@
|
||||
# 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: ""
|
@@ -1,12 +1,16 @@
|
||||
apiVersion: kubeadm.k8s.io/v1alpha2
|
||||
kind: MasterConfiguration
|
||||
api:
|
||||
bindPort: 0
|
||||
bootstrapTokens:
|
||||
- token: s7bu.6tw6wn
|
||||
certificatesDir: relativepath
|
||||
clusterName: kubernetes
|
||||
criSocket: relativepath
|
||||
imageRepository: my-company.com
|
||||
kubernetesVersion: v1.10.2
|
||||
kubernetesVersion: v1.11.2
|
||||
networking:
|
||||
dnsDomain: cluster.GLOBAL
|
||||
serviceSubnet: 10.196.1000.0/100
|
||||
nodeName: MASTER
|
||||
token: s7bu.6tw6wn
|
||||
nodeRegistration:
|
||||
criSocket: relativepath
|
||||
name: MASTER
|
||||
|
@@ -1,11 +1,12 @@
|
||||
apiVersion: kubeadm.k8s.io/v1alpha1
|
||||
apiVersion: kubeadm.k8s.io/v1alpha2
|
||||
kind: NodeConfiguration
|
||||
caCertPath: relativepath
|
||||
criSocket: relativepath
|
||||
discoveryFile: relativepath
|
||||
discoveryTimeout: not-a-time
|
||||
discoveryTokenAPIServers:
|
||||
- INVALID_URL
|
||||
discoveryTokenUnsafeSkipCAVerification: false
|
||||
nodeName: NODE-1
|
||||
nodeRegistration:
|
||||
criSocket: relativepath
|
||||
name: NODE-1
|
||||
token: invalidtoken
|
||||
|
4
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/dryrun/BUILD
generated
vendored
4
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/dryrun/BUILD
generated
vendored
@@ -8,8 +8,8 @@ go_library(
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
39
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/endpoint.go
generated
vendored
39
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/endpoint.go
generated
vendored
@@ -27,42 +27,44 @@ import (
|
||||
)
|
||||
|
||||
// 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) {
|
||||
// - If the ControlPlaneEndpoint is defined, use it.
|
||||
// - if the ControlPlaneEndpoint is defined but without a port number, use the ControlPlaneEndpoint + api.BindPort is used.
|
||||
// - Otherwise, in case the ControlPlaneEndpoint is not defined, use the api.AdvertiseAddress + the api.BindPort.
|
||||
func GetMasterEndpoint(cfg *kubeadmapi.InitConfiguration) (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)
|
||||
bindPortString := strconv.Itoa(int(cfg.APIEndpoint.BindPort))
|
||||
if _, err := ParsePort(bindPortString); err != nil {
|
||||
return "", fmt.Errorf("invalid value %q given for api.bindPort: %s", cfg.APIEndpoint.BindPort, err)
|
||||
}
|
||||
|
||||
// parse the AdvertiseAddress
|
||||
var ip = net.ParseIP(api.AdvertiseAddress)
|
||||
var ip = net.ParseIP(cfg.APIEndpoint.AdvertiseAddress)
|
||||
if ip == nil {
|
||||
return "", fmt.Errorf("invalid value `%s` given for api.advertiseAddress", api.AdvertiseAddress)
|
||||
return "", fmt.Errorf("invalid value `%s` given for api.advertiseAddress", cfg.APIEndpoint.AdvertiseAddress)
|
||||
}
|
||||
|
||||
// set the master url using cfg.API.AdvertiseAddress + the cfg.API.BindPort
|
||||
masterURL := &url.URL{
|
||||
Scheme: "https",
|
||||
Host: net.JoinHostPort(ip.String(), bindPort),
|
||||
Host: net.JoinHostPort(ip.String(), bindPortString),
|
||||
}
|
||||
|
||||
// if the controlplane endpoint is defined
|
||||
if len(api.ControlPlaneEndpoint) > 0 {
|
||||
if len(cfg.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 host, port, err = ParseHostPort(cfg.ControlPlaneEndpoint); err != nil {
|
||||
return "", fmt.Errorf("invalid value %q given for controlPlaneEndpoint: %s", cfg.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")
|
||||
if port != bindPortString {
|
||||
fmt.Println("[endpoint] WARNING: port specified in controlPlaneEndpoint overrides bindPort in the controlplane address")
|
||||
}
|
||||
} else {
|
||||
port = bindPort
|
||||
port = bindPortString
|
||||
}
|
||||
|
||||
// overrides the master url using the controlPlaneAddress (and eventually the bindport)
|
||||
@@ -90,7 +92,7 @@ func ParseHostPort(hostport string) (string, string, error) {
|
||||
|
||||
// if port is defined, parse and validate it
|
||||
if port != "" {
|
||||
if _, err := parsePort(port); err != nil {
|
||||
if _, err := ParsePort(port); err != nil {
|
||||
return "", "", fmt.Errorf("port must be a valid number between 1 and 65535, inclusive")
|
||||
}
|
||||
}
|
||||
@@ -110,8 +112,9 @@ func ParseHostPort(hostport string) (string, string, error) {
|
||||
|
||||
// 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) {
|
||||
func ParsePort(port string) (int, error) {
|
||||
portInt, err := strconv.Atoi(port)
|
||||
if err == nil && (1 <= portInt && portInt <= 65535) {
|
||||
return portInt, nil
|
||||
}
|
||||
|
||||
|
146
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/endpoint_test.go
generated
vendored
146
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/endpoint_test.go
generated
vendored
@@ -25,139 +25,179 @@ import (
|
||||
func TestGetMasterEndpoint(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
api *kubeadmapi.API
|
||||
cfg *kubeadmapi.InitConfiguration
|
||||
expectedEndpoint string
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "use ControlPlaneEndpoint (dns) if fully defined",
|
||||
api: &kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "cp.k8s.io:1234",
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
APIEndpoint: kubeadmapi.APIEndpoint{
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
ControlPlaneEndpoint: "cp.k8s.io:1234",
|
||||
},
|
||||
},
|
||||
expectedEndpoint: "https://cp.k8s.io:1234",
|
||||
},
|
||||
{
|
||||
name: "use ControlPlaneEndpoint (ipv4) if fully defined",
|
||||
api: &kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "1.2.3.4:1234",
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
APIEndpoint: kubeadmapi.APIEndpoint{
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
ControlPlaneEndpoint: "1.2.3.4:1234",
|
||||
},
|
||||
},
|
||||
expectedEndpoint: "https://1.2.3.4:1234",
|
||||
},
|
||||
{
|
||||
name: "use ControlPlaneEndpoint (ipv6) if fully defined",
|
||||
api: &kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "[2001:db8::1]:1234",
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
APIEndpoint: kubeadmapi.APIEndpoint{
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
ControlPlaneEndpoint: "[2001:db8::1]:1234",
|
||||
},
|
||||
},
|
||||
expectedEndpoint: "https://[2001:db8::1]: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",
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
APIEndpoint: kubeadmapi.APIEndpoint{
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
|
||||
ControlPlaneEndpoint: "cp.k8s.io",
|
||||
},
|
||||
},
|
||||
expectedEndpoint: "https://cp.k8s.io:4567",
|
||||
},
|
||||
{
|
||||
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",
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
APIEndpoint: kubeadmapi.APIEndpoint{
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
ControlPlaneEndpoint: "1.2.3.4",
|
||||
},
|
||||
},
|
||||
expectedEndpoint: "https://1.2.3.4:4567",
|
||||
},
|
||||
{
|
||||
name: "use ControlPlaneEndpoint (ipv6) + BindPort if ControlPlaneEndpoint defined without port",
|
||||
api: &kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "2001:db8::1",
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
APIEndpoint: kubeadmapi.APIEndpoint{
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
},
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
|
||||
ControlPlaneEndpoint: "2001:db8::1",
|
||||
},
|
||||
},
|
||||
expectedEndpoint: "https://[2001:db8::1]:4567",
|
||||
},
|
||||
{
|
||||
name: "use AdvertiseAddress (ipv4) + BindPort if ControlPlaneEndpoint is not defined",
|
||||
api: &kubeadmapi.API{
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
APIEndpoint: kubeadmapi.APIEndpoint{
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "4.5.6.7",
|
||||
},
|
||||
},
|
||||
expectedEndpoint: "https://4.5.6.7:4567",
|
||||
},
|
||||
{
|
||||
name: "use AdvertiseAddress (ipv6) + BindPort if ControlPlaneEndpoint is not defined",
|
||||
api: &kubeadmapi.API{
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "2001:db8::1",
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
APIEndpoint: kubeadmapi.APIEndpoint{
|
||||
BindPort: 4567,
|
||||
AdvertiseAddress: "2001:db8::1",
|
||||
},
|
||||
},
|
||||
expectedEndpoint: "https://[2001:db8::1]:4567",
|
||||
},
|
||||
{
|
||||
name: "fail if invalid BindPort",
|
||||
api: &kubeadmapi.API{
|
||||
BindPort: 0,
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
APIEndpoint: kubeadmapi.APIEndpoint{
|
||||
BindPort: 0,
|
||||
},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "fail if invalid ControlPlaneEndpoint (dns)",
|
||||
api: &kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "bad!!.cp.k8s.io",
|
||||
BindPort: 4567,
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
ControlPlaneEndpoint: "bad!!.cp.k8s.io",
|
||||
},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "fail if invalid ControlPlaneEndpoint (ip4)",
|
||||
api: &kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "1..0",
|
||||
BindPort: 4567,
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
ControlPlaneEndpoint: "1..0",
|
||||
},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "fail if invalid ControlPlaneEndpoint (ip6)",
|
||||
api: &kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "1200::AB00:1234::2552:7777:1313",
|
||||
BindPort: 4567,
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
ControlPlaneEndpoint: "1200::AB00:1234::2552:7777:1313",
|
||||
},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "fail if invalid ControlPlaneEndpoint (port)",
|
||||
api: &kubeadmapi.API{
|
||||
ControlPlaneEndpoint: "cp.k8s.io:0",
|
||||
BindPort: 4567,
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
ControlPlaneEndpoint: "cp.k8s.io:0",
|
||||
},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "fail if invalid AdvertiseAddress (ip4)",
|
||||
api: &kubeadmapi.API{
|
||||
AdvertiseAddress: "1..0",
|
||||
BindPort: 4567,
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
APIEndpoint: kubeadmapi.APIEndpoint{
|
||||
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,
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
APIEndpoint: kubeadmapi.APIEndpoint{
|
||||
AdvertiseAddress: "1200::AB00:1234::2552:7777:1313",
|
||||
BindPort: 4567,
|
||||
},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
actualEndpoint, actualError := GetMasterEndpoint(rt.api)
|
||||
actualEndpoint, actualError := GetMasterEndpoint(rt.cfg)
|
||||
|
||||
if (actualError != nil) && !rt.expectedError {
|
||||
t.Errorf("%s unexpected failure: %v", rt.name, actualError)
|
||||
@@ -328,7 +368,7 @@ func TestParsePort(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
actualPort, actualError := parsePort(rt.port)
|
||||
actualPort, actualError := ParsePort(rt.port)
|
||||
|
||||
if (actualError != nil) && !rt.expectedError {
|
||||
t.Errorf("%s unexpected failure: %v", rt.name, actualError)
|
||||
|
2
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/etcd/etcd.go
generated
vendored
2
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/etcd/etcd.go
generated
vendored
@@ -218,7 +218,7 @@ func (c Client) WaitForClusterAvailable(delay time.Duration, retries int, retryI
|
||||
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.
|
||||
// CheckConfigurationIsHA returns true if the given InitConfiguration etcd block appears to be an HA configuration.
|
||||
func CheckConfigurationIsHA(cfg *kubeadmapi.Etcd) bool {
|
||||
return cfg.External != nil && len(cfg.External.Endpoints) > 1
|
||||
}
|
||||
|
6
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig/BUILD
generated
vendored
6
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig/BUILD
generated
vendored
@@ -17,9 +17,9 @@ go_library(
|
||||
srcs = ["kubeconfig.go"],
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig",
|
||||
deps = [
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/clientcmd/api:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
2
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig/kubeconfig.go
generated
vendored
2
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig/kubeconfig.go
generated
vendored
@@ -25,7 +25,7 @@ import (
|
||||
)
|
||||
|
||||
// CreateBasic creates a basic, general KubeConfig object that then can be extended
|
||||
func CreateBasic(serverURL string, clusterName string, userName string, caCert []byte) *clientcmdapi.Config {
|
||||
func CreateBasic(serverURL, clusterName, userName string, caCert []byte) *clientcmdapi.Config {
|
||||
// Use the cluster and the username as the context name
|
||||
contextName := fmt.Sprintf("%s@%s", userName, clusterName)
|
||||
|
||||
|
159
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/marshal.go
generated
vendored
159
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/marshal.go
generated
vendored
@@ -17,16 +17,20 @@ limitations under the License.
|
||||
package util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/util/errors"
|
||||
utilyaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||
clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
kubeadmapiv1alpha1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
)
|
||||
|
||||
// MarshalToYaml marshals an object into yaml.
|
||||
@@ -67,68 +71,95 @@ func UnmarshalFromYamlForCodecs(buffer []byte, gv schema.GroupVersion, codecs se
|
||||
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)
|
||||
// SplitYAMLDocuments reads the YAML bytes per-document, unmarshals the TypeMeta information from each document
|
||||
// and returns a map between the GroupVersionKind of the document and the document bytes
|
||||
func SplitYAMLDocuments(yamlBytes []byte) (map[schema.GroupVersionKind][]byte, error) {
|
||||
gvkmap := map[schema.GroupVersionKind][]byte{}
|
||||
knownKinds := map[string]bool{}
|
||||
errs := []error{}
|
||||
buf := bytes.NewBuffer(yamlBytes)
|
||||
reader := utilyaml.NewYAMLReader(bufio.NewReader(buf))
|
||||
for {
|
||||
typeMetaInfo := runtime.TypeMeta{}
|
||||
// Read one YAML document at a time, until io.EOF is returned
|
||||
b, err := reader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m2
|
||||
case []interface{}:
|
||||
for i, v := range x {
|
||||
x[i] = convert(v)
|
||||
if len(b) == 0 {
|
||||
break
|
||||
}
|
||||
// Deserialize the TypeMeta information of this byte slice
|
||||
if err := yaml.Unmarshal(b, &typeMetaInfo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Require TypeMeta information to be present
|
||||
if len(typeMetaInfo.APIVersion) == 0 || len(typeMetaInfo.Kind) == 0 {
|
||||
errs = append(errs, fmt.Errorf("invalid configuration: kind and apiVersion is mandatory information that needs to be specified in all YAML documents"))
|
||||
continue
|
||||
}
|
||||
// Check whether the kind has been registered before. If it has, throw an error
|
||||
if known := knownKinds[typeMetaInfo.Kind]; known {
|
||||
errs = append(errs, fmt.Errorf("invalid configuration: kind %q is specified twice in YAML file", typeMetaInfo.Kind))
|
||||
continue
|
||||
}
|
||||
knownKinds[typeMetaInfo.Kind] = true
|
||||
|
||||
// Build a GroupVersionKind object from the deserialized TypeMeta object
|
||||
gv, err := schema.ParseGroupVersion(typeMetaInfo.APIVersion)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("unable to parse apiVersion: %v", err))
|
||||
continue
|
||||
}
|
||||
gvk := gv.WithKind(typeMetaInfo.Kind)
|
||||
|
||||
// Save the mapping between the gvk and the bytes that object consists of
|
||||
gvkmap[gvk] = b
|
||||
}
|
||||
if err := errors.NewAggregate(errs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gvkmap, nil
|
||||
}
|
||||
|
||||
// GroupVersionKindsFromBytes parses the bytes and returns a gvk slice
|
||||
func GroupVersionKindsFromBytes(b []byte) ([]schema.GroupVersionKind, error) {
|
||||
gvkmap, err := SplitYAMLDocuments(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gvks := []schema.GroupVersionKind{}
|
||||
for gvk := range gvkmap {
|
||||
gvks = append(gvks, gvk)
|
||||
}
|
||||
return gvks, nil
|
||||
}
|
||||
|
||||
// GroupVersionKindsHasKind returns whether the following gvk slice contains the kind given as a parameter
|
||||
func GroupVersionKindsHasKind(gvks []schema.GroupVersionKind, kind string) bool {
|
||||
for _, gvk := range gvks {
|
||||
if gvk.Kind == kind {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return i
|
||||
return false
|
||||
}
|
||||
|
||||
// GroupVersionKindsHasClusterConfiguration returns whether the following gvk slice contains a ClusterConfiguration object
|
||||
func GroupVersionKindsHasClusterConfiguration(gvks ...schema.GroupVersionKind) bool {
|
||||
return GroupVersionKindsHasKind(gvks, constants.ClusterConfigurationKind)
|
||||
}
|
||||
|
||||
// GroupVersionKindsHasInitConfiguration returns whether the following gvk slice contains a InitConfiguration object
|
||||
func GroupVersionKindsHasInitConfiguration(gvks ...schema.GroupVersionKind) bool {
|
||||
// Finding a MasterConfiguration kind is also okay, as it will decode and convert into an InitConfiguration struct eventually
|
||||
// TODO: When we remove support for the v1alpha2 API, remove support for MasterConfiguration
|
||||
return GroupVersionKindsHasKind(gvks, constants.InitConfigurationKind) || GroupVersionKindsHasKind(gvks, constants.MasterConfigurationKind)
|
||||
}
|
||||
|
||||
// GroupVersionKindsHasJoinConfiguration returns whether the following gvk slice contains a JoinConfiguration object
|
||||
func GroupVersionKindsHasJoinConfiguration(gvks ...schema.GroupVersionKind) bool {
|
||||
return GroupVersionKindsHasKind(gvks, constants.JoinConfigurationKind) || GroupVersionKindsHasKind(gvks, constants.NodeConfigurationKind)
|
||||
}
|
||||
|
354
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/marshal_test.go
generated
vendored
354
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/marshal_test.go
generated
vendored
@@ -17,15 +17,49 @@ limitations under the License.
|
||||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"sort"
|
||||
"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"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
kubeadmapiv1alpha3 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha3"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
)
|
||||
|
||||
var files = map[string][]byte{
|
||||
"foo": []byte(`
|
||||
kind: Foo
|
||||
apiVersion: foo.k8s.io/v1
|
||||
fooField: foo
|
||||
`),
|
||||
"bar": []byte(`
|
||||
apiVersion: bar.k8s.io/v2
|
||||
barField: bar
|
||||
kind: Bar
|
||||
`),
|
||||
"baz": []byte(`
|
||||
apiVersion: baz.k8s.io/v1
|
||||
kind: Baz
|
||||
baz:
|
||||
foo: bar
|
||||
`),
|
||||
"nokind": []byte(`
|
||||
apiVersion: baz.k8s.io/v1
|
||||
foo: foo
|
||||
bar: bar
|
||||
`),
|
||||
"noapiversion": []byte(`
|
||||
kind: Bar
|
||||
foo: foo
|
||||
bar: bar
|
||||
`),
|
||||
}
|
||||
|
||||
func TestMarshalUnmarshalYaml(t *testing.T) {
|
||||
pod := &corev1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -75,51 +109,299 @@ func TestMarshalUnmarshalYaml(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMarshalUnmarshalToYamlForCodecs(t *testing.T) {
|
||||
cfg := &kubeadmapiext.MasterConfiguration{
|
||||
API: kubeadmapiext.API{
|
||||
AdvertiseAddress: "10.100.0.1",
|
||||
BindPort: 4332,
|
||||
cfg := &kubeadmapiv1alpha3.InitConfiguration{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: constants.InitConfigurationKind,
|
||||
APIVersion: kubeadmapiv1alpha3.SchemeGroupVersion.String(),
|
||||
},
|
||||
NodeName: "testNode",
|
||||
NoTaintMaster: true,
|
||||
Networking: kubeadmapiext.Networking{
|
||||
ServiceSubnet: "10.100.0.0/24",
|
||||
PodSubnet: "10.100.1.0/24",
|
||||
NodeRegistration: kubeadmapiv1alpha3.NodeRegistrationOptions{
|
||||
Name: "testNode",
|
||||
CRISocket: "/var/run/cri.sock",
|
||||
},
|
||||
BootstrapTokens: []kubeadmapiv1alpha3.BootstrapToken{
|
||||
{
|
||||
Token: &kubeadmapiv1alpha3.BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"},
|
||||
},
|
||||
},
|
||||
// NOTE: Using MarshalToYamlForCodecs and UnmarshalFromYamlForCodecs for ClusterConfiguration fields here won't work
|
||||
// by design. This is because we have a `json:"-"` annotation in order to avoid struct duplication. See the comment
|
||||
// at the kubeadmapiv1alpha3.InitConfiguration definition.
|
||||
}
|
||||
|
||||
bytes, err := MarshalToYamlForCodecs(cfg, kubeadmapiext.SchemeGroupVersion, scheme.Codecs)
|
||||
kubeadmapiv1alpha3.SetDefaults_InitConfiguration(cfg)
|
||||
scheme := runtime.NewScheme()
|
||||
if err := kubeadmapiv1alpha3.AddToScheme(scheme); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
codecs := serializer.NewCodecFactory(scheme)
|
||||
|
||||
bytes, err := MarshalToYamlForCodecs(cfg, kubeadmapiv1alpha3.SchemeGroupVersion, codecs)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error marshalling MasterConfiguration: %v", err)
|
||||
t.Fatalf("unexpected error marshalling InitConfiguration: %v", err)
|
||||
}
|
||||
t.Logf("\n%s", bytes)
|
||||
|
||||
obj, err := UnmarshalFromYamlForCodecs(bytes, kubeadmapiext.SchemeGroupVersion, scheme.Codecs)
|
||||
obj, err := UnmarshalFromYamlForCodecs(bytes, kubeadmapiv1alpha3.SchemeGroupVersion, codecs)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error unmarshalling MasterConfiguration: %v", err)
|
||||
t.Fatalf("unexpected error unmarshalling InitConfiguration: %v", err)
|
||||
}
|
||||
|
||||
cfg2, ok := obj.(*kubeadmapiext.MasterConfiguration)
|
||||
if !ok {
|
||||
t.Fatal("did not get MasterConfiguration back")
|
||||
cfg2, ok := obj.(*kubeadmapiv1alpha3.InitConfiguration)
|
||||
if !ok || cfg2 == nil {
|
||||
t.Fatal("did not get InitConfiguration 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)
|
||||
if !reflect.DeepEqual(*cfg, *cfg2) {
|
||||
t.Errorf("expected %v, got %v", *cfg, *cfg2)
|
||||
}
|
||||
}
|
||||
|
||||
// {{InitConfiguration kubeadm.k8s.io/v1alpha3} [{<nil> nil <nil> [] []}] {testNode /var/run/cri.sock [] map[]} {10.100.0.1 4332} {0xc4200ad2c0 <nil>} {10.100.0.0/24 10.100.1.0/24 cluster.local} stable-1.11 map[] map[] map[] [] [] [] [] /etc/kubernetes/pki k8s.gcr.io { /var/log/kubernetes/audit 0x156e2f4} map[] kubernetes}
|
||||
// {{InitConfiguration kubeadm.k8s.io/v1alpha3} [{<nil> &Duration{Duration:24h0m0s,} <nil> [signing authentication] [system:bootstrappers:kubeadm:default-node-token]}] {testNode /var/run/cri.sock [] map[]} {10.100.0.1 4332} {0xc4205c5260 <nil>} {10.100.0.0/24 10.100.1.0/24 cluster.local} stable-1.11 map[] map[] map[] [] [] [] [] /etc/kubernetes/pki k8s.gcr.io { /var/log/kubernetes/audit 0xc4204dd82c} map[] kubernetes}
|
||||
|
||||
// {{InitConfiguration kubeadm.k8s.io/v1alpha3} [{abcdef.abcdef0123456789 nil <nil> [] []}] {testNode /var/run/cri.sock [] map[]} {10.100.0.1 4332} {0xc42012ca80 <nil>} {10.100.0.0/24 10.100.1.0/24 cluster.local} stable-1.11 map[] map[] map[] [] [] [] [] /etc/kubernetes/pki k8s.gcr.io { /var/log/kubernetes/audit 0x156e2f4} map[] kubernetes}
|
||||
// {{InitConfiguration kubeadm.k8s.io/v1alpha3} [{abcdef.abcdef0123456789 &Duration{Duration:24h0m0s,} <nil> [signing authentication] [system:bootstrappers:kubeadm:default-node-token]}] {testNode /var/run/cri.sock [] map[]} {10.100.0.1 4332} {0xc42039d1a0 <nil>} {10.100.0.0/24 10.100.1.0/24 cluster.local} stable-1.11 map[] map[] map[] [] [] [] [] /etc/kubernetes/pki k8s.gcr.io { /var/log/kubernetes/audit 0xc4204fef3c} map[] kubernetes}
|
||||
|
||||
func TestSplitYAMLDocuments(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
fileContents []byte
|
||||
gvkmap map[schema.GroupVersionKind][]byte
|
||||
expectedErr bool
|
||||
}{
|
||||
{
|
||||
name: "FooOnly",
|
||||
fileContents: files["foo"],
|
||||
gvkmap: map[schema.GroupVersionKind][]byte{
|
||||
{Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}: files["foo"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "FooBar",
|
||||
fileContents: bytes.Join([][]byte{files["foo"], files["bar"]}, []byte(constants.YAMLDocumentSeparator)),
|
||||
gvkmap: map[schema.GroupVersionKind][]byte{
|
||||
{Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}: files["foo"],
|
||||
{Group: "bar.k8s.io", Version: "v2", Kind: "Bar"}: files["bar"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "FooTwiceInvalid",
|
||||
fileContents: bytes.Join([][]byte{files["foo"], files["bar"], files["foo"]}, []byte(constants.YAMLDocumentSeparator)),
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
name: "InvalidBaz",
|
||||
fileContents: bytes.Join([][]byte{files["foo"], files["baz"]}, []byte(constants.YAMLDocumentSeparator)),
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
name: "InvalidNoKind",
|
||||
fileContents: files["nokind"],
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
name: "InvalidNoAPIVersion",
|
||||
fileContents: files["noapiversion"],
|
||||
expectedErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t2 *testing.T) {
|
||||
|
||||
gvkmap, err := SplitYAMLDocuments(rt.fileContents)
|
||||
if (err != nil) != rt.expectedErr {
|
||||
t2.Errorf("expected error: %t, actual: %t", rt.expectedErr, err != nil)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(gvkmap, rt.gvkmap) {
|
||||
t2.Errorf("expected gvkmap: %s\n\tactual: %s\n", rt.gvkmap, gvkmap)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGroupVersionKindsFromBytes(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
fileContents []byte
|
||||
gvks []string
|
||||
expectedErr bool
|
||||
}{
|
||||
{
|
||||
name: "FooOnly",
|
||||
fileContents: files["foo"],
|
||||
gvks: []string{
|
||||
"foo.k8s.io/v1, Kind=Foo",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "FooBar",
|
||||
fileContents: bytes.Join([][]byte{files["foo"], files["bar"]}, []byte(constants.YAMLDocumentSeparator)),
|
||||
gvks: []string{
|
||||
"foo.k8s.io/v1, Kind=Foo",
|
||||
"bar.k8s.io/v2, Kind=Bar",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "FooTwiceInvalid",
|
||||
fileContents: bytes.Join([][]byte{files["foo"], files["bar"], files["foo"]}, []byte(constants.YAMLDocumentSeparator)),
|
||||
gvks: []string{},
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
name: "InvalidBaz",
|
||||
fileContents: bytes.Join([][]byte{files["foo"], files["baz"]}, []byte(constants.YAMLDocumentSeparator)),
|
||||
gvks: []string{},
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
name: "InvalidNoKind",
|
||||
fileContents: files["nokind"],
|
||||
gvks: []string{},
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
name: "InvalidNoAPIVersion",
|
||||
fileContents: files["noapiversion"],
|
||||
gvks: []string{},
|
||||
expectedErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t2 *testing.T) {
|
||||
|
||||
gvks, err := GroupVersionKindsFromBytes(rt.fileContents)
|
||||
if (err != nil) != rt.expectedErr {
|
||||
t2.Errorf("expected error: %t, actual: %t", rt.expectedErr, err != nil)
|
||||
}
|
||||
|
||||
strgvks := []string{}
|
||||
for _, gvk := range gvks {
|
||||
strgvks = append(strgvks, gvk.String())
|
||||
}
|
||||
sort.Strings(strgvks)
|
||||
sort.Strings(rt.gvks)
|
||||
|
||||
if !reflect.DeepEqual(strgvks, rt.gvks) {
|
||||
t2.Errorf("expected gvks: %s\n\tactual: %s\n", rt.gvks, strgvks)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGroupVersionKindsHasKind(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
gvks []schema.GroupVersionKind
|
||||
kind string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "FooOnly",
|
||||
gvks: []schema.GroupVersionKind{
|
||||
{Group: "foo.k8s.io", Version: "v1", Kind: "Foo"},
|
||||
},
|
||||
kind: "Foo",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "FooBar",
|
||||
gvks: []schema.GroupVersionKind{
|
||||
{Group: "foo.k8s.io", Version: "v1", Kind: "Foo"},
|
||||
{Group: "bar.k8s.io", Version: "v2", Kind: "Bar"},
|
||||
},
|
||||
kind: "Bar",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "FooBazNoBaz",
|
||||
gvks: []schema.GroupVersionKind{
|
||||
{Group: "foo.k8s.io", Version: "v1", Kind: "Foo"},
|
||||
{Group: "bar.k8s.io", Version: "v2", Kind: "Bar"},
|
||||
},
|
||||
kind: "Baz",
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t2 *testing.T) {
|
||||
|
||||
actual := GroupVersionKindsHasKind(rt.gvks, rt.kind)
|
||||
if rt.expected != actual {
|
||||
t2.Errorf("expected gvks has kind: %t\n\tactual: %t\n", rt.expected, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGroupVersionKindsHasInitConfiguration(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
gvks []schema.GroupVersionKind
|
||||
kind string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "NoInitConfiguration",
|
||||
gvks: []schema.GroupVersionKind{
|
||||
{Group: "foo.k8s.io", Version: "v1", Kind: "Foo"},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "InitConfigurationFound",
|
||||
gvks: []schema.GroupVersionKind{
|
||||
{Group: "foo.k8s.io", Version: "v1", Kind: "Foo"},
|
||||
{Group: "bar.k8s.io", Version: "v2", Kind: "InitConfiguration"},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t2 *testing.T) {
|
||||
|
||||
actual := GroupVersionKindsHasInitConfiguration(rt.gvks...)
|
||||
if rt.expected != actual {
|
||||
t2.Errorf("expected gvks has InitConfiguration: %t\n\tactual: %t\n", rt.expected, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGroupVersionKindsHasJoinConfiguration(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
gvks []schema.GroupVersionKind
|
||||
kind string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "NoJoinConfiguration",
|
||||
gvks: []schema.GroupVersionKind{
|
||||
{Group: "foo.k8s.io", Version: "v1", Kind: "Foo"},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "JoinConfigurationFound",
|
||||
gvks: []schema.GroupVersionKind{
|
||||
{Group: "foo.k8s.io", Version: "v1", Kind: "Foo"},
|
||||
{Group: "bar.k8s.io", Version: "v2", Kind: "JoinConfiguration"},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t2 *testing.T) {
|
||||
|
||||
actual := GroupVersionKindsHasJoinConfiguration(rt.gvks...)
|
||||
if rt.expected != actual {
|
||||
t2.Errorf("expected gvks has JoinConfiguration: %t\n\tactual: %t\n", rt.expected, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
38
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/runtime/BUILD
generated
vendored
Normal file
38
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/runtime/BUILD
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["runtime.go"],
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/util/runtime",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha3:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["runtime_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha3:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec/testing: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"],
|
||||
)
|
181
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/runtime/runtime.go
generated
vendored
Normal file
181
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/runtime/runtime.go
generated
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
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"
|
||||
"path/filepath"
|
||||
goruntime "runtime"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/errors"
|
||||
kubeadmapiv1alpha3 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha3"
|
||||
utilsexec "k8s.io/utils/exec"
|
||||
)
|
||||
|
||||
// ContainerRuntime is an interface for working with container runtimes
|
||||
type ContainerRuntime interface {
|
||||
IsDocker() bool
|
||||
IsRunning() error
|
||||
ListKubeContainers() ([]string, error)
|
||||
RemoveContainers(containers []string) error
|
||||
PullImage(image string) error
|
||||
ImageExists(image string) (bool, error)
|
||||
}
|
||||
|
||||
// CRIRuntime is a struct that interfaces with the CRI
|
||||
type CRIRuntime struct {
|
||||
exec utilsexec.Interface
|
||||
criSocket string
|
||||
}
|
||||
|
||||
// DockerRuntime is a struct that interfaces with the Docker daemon
|
||||
type DockerRuntime struct {
|
||||
exec utilsexec.Interface
|
||||
}
|
||||
|
||||
// NewContainerRuntime sets up and returns a ContainerRuntime struct
|
||||
func NewContainerRuntime(execer utilsexec.Interface, criSocket string) (ContainerRuntime, error) {
|
||||
var toolName string
|
||||
var runtime ContainerRuntime
|
||||
|
||||
if criSocket != kubeadmapiv1alpha3.DefaultCRISocket {
|
||||
toolName = "crictl"
|
||||
// !!! temporary work around crictl warning:
|
||||
// Using "/var/run/crio/crio.sock" as endpoint is deprecated,
|
||||
// please consider using full url format "unix:///var/run/crio/crio.sock"
|
||||
if filepath.IsAbs(criSocket) && goruntime.GOOS != "windows" {
|
||||
criSocket = "unix://" + criSocket
|
||||
}
|
||||
runtime = &CRIRuntime{execer, criSocket}
|
||||
} else {
|
||||
toolName = "docker"
|
||||
runtime = &DockerRuntime{execer}
|
||||
}
|
||||
|
||||
if _, err := execer.LookPath(toolName); err != nil {
|
||||
return nil, fmt.Errorf("%s is required for container runtime: %v", toolName, err)
|
||||
}
|
||||
|
||||
return runtime, nil
|
||||
}
|
||||
|
||||
// IsDocker returns true if the runtime is docker
|
||||
func (runtime *CRIRuntime) IsDocker() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsDocker returns true if the runtime is docker
|
||||
func (runtime *DockerRuntime) IsDocker() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsRunning checks if runtime is running
|
||||
func (runtime *CRIRuntime) IsRunning() error {
|
||||
if out, err := runtime.exec.Command("crictl", "-r", runtime.criSocket, "info").CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("container runtime is not running: output: %s, error: %v", string(out), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsRunning checks if runtime is running
|
||||
func (runtime *DockerRuntime) IsRunning() error {
|
||||
if out, err := runtime.exec.Command("docker", "info").CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("container runtime is not running: output: %s, error: %v", string(out), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListKubeContainers lists running k8s CRI pods
|
||||
func (runtime *CRIRuntime) ListKubeContainers() ([]string, error) {
|
||||
out, err := runtime.exec.Command("crictl", "-r", runtime.criSocket, "pods", "-q").CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("output: %s, error: %v", string(out), err)
|
||||
}
|
||||
pods := []string{}
|
||||
for _, pod := range strings.Fields(string(out)) {
|
||||
pods = append(pods, pod)
|
||||
}
|
||||
return pods, nil
|
||||
}
|
||||
|
||||
// ListKubeContainers lists running k8s containers
|
||||
func (runtime *DockerRuntime) ListKubeContainers() ([]string, error) {
|
||||
output, err := runtime.exec.Command("docker", "ps", "-a", "--filter", "name=k8s_", "-q").CombinedOutput()
|
||||
return strings.Fields(string(output)), err
|
||||
}
|
||||
|
||||
// RemoveContainers removes running k8s pods
|
||||
func (runtime *CRIRuntime) RemoveContainers(containers []string) error {
|
||||
errs := []error{}
|
||||
for _, container := range containers {
|
||||
out, err := runtime.exec.Command("crictl", "-r", runtime.criSocket, "stopp", container).CombinedOutput()
|
||||
if err != nil {
|
||||
// don't stop on errors, try to remove as many containers as possible
|
||||
errs = append(errs, fmt.Errorf("failed to stop running pod %s: output: %s, error: %v", container, string(out), err))
|
||||
} else {
|
||||
out, err = runtime.exec.Command("crictl", "-r", runtime.criSocket, "rmp", container).CombinedOutput()
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("failed to remove running container %s: output: %s, error: %v", container, string(out), err))
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
// RemoveContainers removes running containers
|
||||
func (runtime *DockerRuntime) RemoveContainers(containers []string) error {
|
||||
errs := []error{}
|
||||
for _, container := range containers {
|
||||
out, err := runtime.exec.Command("docker", "rm", "--force", "--volumes", container).CombinedOutput()
|
||||
if err != nil {
|
||||
// don't stop on errors, try to remove as many containers as possible
|
||||
errs = append(errs, fmt.Errorf("failed to remove running container %s: output: %s, error: %v", container, string(out), err))
|
||||
}
|
||||
}
|
||||
return errors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
// PullImage pulls the image
|
||||
func (runtime *CRIRuntime) PullImage(image string) error {
|
||||
out, err := runtime.exec.Command("crictl", "-r", runtime.criSocket, "pull", image).CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("output: %s, error: %v", string(out), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PullImage pulls the image
|
||||
func (runtime *DockerRuntime) PullImage(image string) error {
|
||||
out, err := runtime.exec.Command("docker", "pull", image).CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("output: %s, error: %v", string(out), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ImageExists checks to see if the image exists on the system
|
||||
func (runtime *CRIRuntime) ImageExists(image string) (bool, error) {
|
||||
err := runtime.exec.Command("crictl", "-r", runtime.criSocket, "inspecti", image).Run()
|
||||
return err == nil, nil
|
||||
}
|
||||
|
||||
// ImageExists checks to see if the image exists on the system
|
||||
func (runtime *DockerRuntime) ImageExists(image string) (bool, error) {
|
||||
err := runtime.exec.Command("docker", "inspect", image).Run()
|
||||
return err == nil, nil
|
||||
}
|
306
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/runtime/runtime_test.go
generated
vendored
Normal file
306
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/runtime/runtime_test.go
generated
vendored
Normal file
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
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"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
kubeadmapiv1alpha3 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha3"
|
||||
"k8s.io/utils/exec"
|
||||
fakeexec "k8s.io/utils/exec/testing"
|
||||
)
|
||||
|
||||
func TestNewContainerRuntime(t *testing.T) {
|
||||
execLookPathOK := fakeexec.FakeExec{
|
||||
LookPathFunc: func(cmd string) (string, error) { return "/usr/bin/crictl", nil },
|
||||
}
|
||||
execLookPathErr := fakeexec.FakeExec{
|
||||
LookPathFunc: func(cmd string) (string, error) { return "", fmt.Errorf("%s not found", cmd) },
|
||||
}
|
||||
cases := []struct {
|
||||
name string
|
||||
execer fakeexec.FakeExec
|
||||
criSocket string
|
||||
isDocker bool
|
||||
isError bool
|
||||
}{
|
||||
{"valid: default cri socket", execLookPathOK, kubeadmapiv1alpha3.DefaultCRISocket, true, false},
|
||||
{"valid: cri-o socket url", execLookPathOK, "unix:///var/run/crio/crio.sock", false, false},
|
||||
{"valid: cri-o socket path", execLookPathOK, "/var/run/crio/crio.sock", false, false},
|
||||
{"invalid: no crictl", execLookPathErr, "unix:///var/run/crio/crio.sock", false, true},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
runtime, err := NewContainerRuntime(&tc.execer, tc.criSocket)
|
||||
if err != nil {
|
||||
if !tc.isError {
|
||||
t.Fatalf("unexpected NewContainerRuntime error. criSocket: %s, error: %v", tc.criSocket, err)
|
||||
}
|
||||
return // expected error occurs, impossible to test runtime further
|
||||
}
|
||||
if tc.isError && err == nil {
|
||||
t.Fatalf("unexpected NewContainerRuntime success. criSocket: %s", tc.criSocket)
|
||||
}
|
||||
isDocker := runtime.IsDocker()
|
||||
if tc.isDocker != isDocker {
|
||||
t.Fatalf("unexpected isDocker() result %v for the criSocket %s", isDocker, tc.criSocket)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func genFakeActions(fcmd *fakeexec.FakeCmd, num int) []fakeexec.FakeCommandAction {
|
||||
var actions []fakeexec.FakeCommandAction
|
||||
for i := 0; i < num; i++ {
|
||||
actions = append(actions, func(cmd string, args ...string) exec.Cmd {
|
||||
return fakeexec.InitFakeCmd(fcmd, cmd, args...)
|
||||
})
|
||||
}
|
||||
return actions
|
||||
}
|
||||
|
||||
func TestIsRunning(t *testing.T) {
|
||||
fcmd := fakeexec.FakeCmd{
|
||||
CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) { return nil, nil },
|
||||
func() ([]byte, error) { return []byte("error"), &fakeexec.FakeExitError{Status: 1} },
|
||||
func() ([]byte, error) { return nil, nil },
|
||||
func() ([]byte, error) { return []byte("error"), &fakeexec.FakeExitError{Status: 1} },
|
||||
},
|
||||
}
|
||||
|
||||
criExecer := fakeexec.FakeExec{
|
||||
CommandScript: genFakeActions(&fcmd, len(fcmd.CombinedOutputScript)),
|
||||
LookPathFunc: func(cmd string) (string, error) { return "/usr/bin/crictl", nil },
|
||||
}
|
||||
|
||||
dockerExecer := fakeexec.FakeExec{
|
||||
CommandScript: genFakeActions(&fcmd, len(fcmd.CombinedOutputScript)),
|
||||
LookPathFunc: func(cmd string) (string, error) { return "/usr/bin/docker", nil },
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
criSocket string
|
||||
execer fakeexec.FakeExec
|
||||
isError bool
|
||||
}{
|
||||
{"valid: CRI-O is running", "unix:///var/run/crio/crio.sock", criExecer, false},
|
||||
{"invalid: CRI-O is not running", "unix:///var/run/crio/crio.sock", criExecer, true},
|
||||
{"valid: docker is running", kubeadmapiv1alpha3.DefaultCRISocket, dockerExecer, false},
|
||||
{"invalid: docker is not running", kubeadmapiv1alpha3.DefaultCRISocket, dockerExecer, true},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
runtime, err := NewContainerRuntime(&tc.execer, tc.criSocket)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected NewContainerRuntime error: %v", err)
|
||||
}
|
||||
isRunning := runtime.IsRunning()
|
||||
if tc.isError && isRunning == nil {
|
||||
t.Error("unexpected IsRunning() success")
|
||||
}
|
||||
if !tc.isError && isRunning != nil {
|
||||
t.Error("unexpected IsRunning() error")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListKubeContainers(t *testing.T) {
|
||||
fcmd := fakeexec.FakeCmd{
|
||||
CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) { return []byte("k8s_p1\nk8s_p2"), nil },
|
||||
func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 1} },
|
||||
func() ([]byte, error) { return []byte("k8s_p1\nk8s_p2"), nil },
|
||||
},
|
||||
}
|
||||
execer := fakeexec.FakeExec{
|
||||
CommandScript: genFakeActions(&fcmd, len(fcmd.CombinedOutputScript)),
|
||||
LookPathFunc: func(cmd string) (string, error) { return "/usr/bin/crictl", nil },
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
criSocket string
|
||||
isError bool
|
||||
}{
|
||||
{"valid: list containers using CRI socket url", "unix:///var/run/crio/crio.sock", false},
|
||||
{"invalid: list containers using CRI socket url", "unix:///var/run/crio/crio.sock", true},
|
||||
{"valid: list containers using docker", kubeadmapiv1alpha3.DefaultCRISocket, false},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
runtime, err := NewContainerRuntime(&execer, tc.criSocket)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected NewContainerRuntime error: %v", err)
|
||||
}
|
||||
|
||||
containers, err := runtime.ListKubeContainers()
|
||||
if tc.isError {
|
||||
if err == nil {
|
||||
t.Errorf("unexpected ListKubeContainers success")
|
||||
}
|
||||
return
|
||||
} else if err != nil {
|
||||
t.Errorf("unexpected ListKubeContainers error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(containers, []string{"k8s_p1", "k8s_p2"}) {
|
||||
t.Errorf("unexpected ListKubeContainers output: %v", containers)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveContainers(t *testing.T) {
|
||||
fakeOK := func() ([]byte, error) { return nil, nil }
|
||||
fakeErr := func() ([]byte, error) { return []byte("error"), &fakeexec.FakeExitError{Status: 1} }
|
||||
fcmd := fakeexec.FakeCmd{
|
||||
CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
|
||||
fakeOK, fakeOK, fakeOK, fakeOK, fakeOK, fakeOK, // Test case 1
|
||||
fakeOK, fakeOK, fakeOK, fakeErr, fakeOK, fakeOK,
|
||||
fakeErr, fakeOK, fakeOK, fakeErr, fakeOK,
|
||||
fakeOK, fakeOK, fakeOK,
|
||||
fakeOK, fakeErr, fakeOK,
|
||||
},
|
||||
}
|
||||
execer := fakeexec.FakeExec{
|
||||
CommandScript: genFakeActions(&fcmd, len(fcmd.CombinedOutputScript)),
|
||||
LookPathFunc: func(cmd string) (string, error) { return "/usr/bin/crictl", nil },
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
criSocket string
|
||||
containers []string
|
||||
isError bool
|
||||
}{
|
||||
{"valid: remove containers using CRI", "unix:///var/run/crio/crio.sock", []string{"k8s_p1", "k8s_p2", "k8s_p3"}, false}, // Test case 1
|
||||
{"invalid: CRI rmp failure", "unix:///var/run/crio/crio.sock", []string{"k8s_p1", "k8s_p2", "k8s_p3"}, true},
|
||||
{"invalid: CRI stopp failure", "unix:///var/run/crio/crio.sock", []string{"k8s_p1", "k8s_p2", "k8s_p3"}, true},
|
||||
{"valid: remove containers using docker", kubeadmapiv1alpha3.DefaultCRISocket, []string{"k8s_c1", "k8s_c2", "k8s_c3"}, false},
|
||||
{"invalid: remove containers using docker", kubeadmapiv1alpha3.DefaultCRISocket, []string{"k8s_c1", "k8s_c2", "k8s_c3"}, true},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
runtime, err := NewContainerRuntime(&execer, tc.criSocket)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected NewContainerRuntime error: %v, criSocket: %s", err, tc.criSocket)
|
||||
}
|
||||
|
||||
err = runtime.RemoveContainers(tc.containers)
|
||||
if !tc.isError && err != nil {
|
||||
t.Errorf("unexpected RemoveContainers errors: %v, criSocket: %s, containers: %v", err, tc.criSocket, tc.containers)
|
||||
}
|
||||
if tc.isError && err == nil {
|
||||
t.Errorf("unexpected RemoveContnainers success, criSocket: %s, containers: %v", tc.criSocket, tc.containers)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPullImage(t *testing.T) {
|
||||
fcmd := fakeexec.FakeCmd{
|
||||
CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) { return nil, nil },
|
||||
func() ([]byte, error) { return []byte("error"), &fakeexec.FakeExitError{Status: 1} },
|
||||
func() ([]byte, error) { return nil, nil },
|
||||
func() ([]byte, error) { return []byte("error"), &fakeexec.FakeExitError{Status: 1} },
|
||||
},
|
||||
}
|
||||
execer := fakeexec.FakeExec{
|
||||
CommandScript: genFakeActions(&fcmd, len(fcmd.CombinedOutputScript)),
|
||||
LookPathFunc: func(cmd string) (string, error) { return "/usr/bin/crictl", nil },
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
criSocket string
|
||||
image string
|
||||
isError bool
|
||||
}{
|
||||
{"valid: pull image using CRI", "unix:///var/run/crio/crio.sock", "image1", false},
|
||||
{"invalid: CRI pull error", "unix:///var/run/crio/crio.sock", "image2", true},
|
||||
{"valid: pull image using docker", kubeadmapiv1alpha3.DefaultCRISocket, "image1", false},
|
||||
{"invalide: docer pull error", kubeadmapiv1alpha3.DefaultCRISocket, "image2", true},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
runtime, err := NewContainerRuntime(&execer, tc.criSocket)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected NewContainerRuntime error: %v, criSocket: %s", err, tc.criSocket)
|
||||
}
|
||||
|
||||
err = runtime.PullImage(tc.image)
|
||||
if !tc.isError && err != nil {
|
||||
t.Errorf("unexpected PullImage error: %v, criSocket: %s, image: %s", err, tc.criSocket, tc.image)
|
||||
}
|
||||
if tc.isError && err == nil {
|
||||
t.Errorf("unexpected PullImage success, criSocket: %s, image: %s", tc.criSocket, tc.image)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageExists(t *testing.T) {
|
||||
fcmd := fakeexec.FakeCmd{
|
||||
RunScript: []fakeexec.FakeRunAction{
|
||||
func() ([]byte, []byte, error) { return nil, nil, nil },
|
||||
func() ([]byte, []byte, error) { return nil, nil, &fakeexec.FakeExitError{Status: 1} },
|
||||
func() ([]byte, []byte, error) { return nil, nil, nil },
|
||||
func() ([]byte, []byte, error) { return nil, nil, &fakeexec.FakeExitError{Status: 1} },
|
||||
},
|
||||
}
|
||||
execer := fakeexec.FakeExec{
|
||||
CommandScript: genFakeActions(&fcmd, len(fcmd.RunScript)),
|
||||
LookPathFunc: func(cmd string) (string, error) { return "/usr/bin/crictl", nil },
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
criSocket string
|
||||
image string
|
||||
result bool
|
||||
}{
|
||||
{"valid: test if image exists using CRI", "unix:///var/run/crio/crio.sock", "image1", false},
|
||||
{"invalid: CRI inspecti failure", "unix:///var/run/crio/crio.sock", "image2", true},
|
||||
{"valid: test if image exists using docker", kubeadmapiv1alpha3.DefaultCRISocket, "image1", false},
|
||||
{"invalid: docker inspect failure", kubeadmapiv1alpha3.DefaultCRISocket, "image2", true},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
runtime, err := NewContainerRuntime(&execer, tc.criSocket)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected NewContainerRuntime error: %v, criSocket: %s", err, tc.criSocket)
|
||||
}
|
||||
|
||||
result, err := runtime.ImageExists(tc.image)
|
||||
if !tc.result != result {
|
||||
t.Errorf("unexpected ImageExists result: %t, criSocket: %s, image: %s, expected result: %t", err, tc.criSocket, tc.image, tc.result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
14
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod/BUILD
generated
vendored
14
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod/BUILD
generated
vendored
@@ -15,9 +15,9 @@ go_test(
|
||||
"//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",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -31,10 +31,10 @@ go_library(
|
||||
"//cmd/kubeadm/app/features:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//pkg/kubelet/types:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
10
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod/utils.go
generated
vendored
10
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod/utils.go
generated
vendored
@@ -82,7 +82,7 @@ func ComponentResources(cpu string) v1.ResourceRequirements {
|
||||
}
|
||||
|
||||
// ComponentProbe is a helper function building a ready v1.Probe object from some simple parameters
|
||||
func ComponentProbe(cfg *kubeadmapi.MasterConfiguration, componentName string, port int, path string, scheme v1.URIScheme) *v1.Probe {
|
||||
func ComponentProbe(cfg *kubeadmapi.InitConfiguration, componentName string, port int, path string, scheme v1.URIScheme) *v1.Probe {
|
||||
return &v1.Probe{
|
||||
Handler: v1.Handler{
|
||||
HTTPGet: &v1.HTTPGetAction{
|
||||
@@ -99,7 +99,7 @@ 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 {
|
||||
func EtcdProbe(cfg *kubeadmapi.InitConfiguration, 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)
|
||||
@@ -218,7 +218,7 @@ func ReadStaticPodFromDisk(manifestPath string) (*v1.Pod, error) {
|
||||
|
||||
// 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 {
|
||||
func GetProbeAddress(cfg *kubeadmapi.InitConfiguration, componentName string) string {
|
||||
switch {
|
||||
case componentName == kubeadmconstants.KubeAPIServer:
|
||||
// In the case of a self-hosted deployment, the initial host on which kubeadm --init is run,
|
||||
@@ -230,8 +230,8 @@ func GetProbeAddress(cfg *kubeadmapi.MasterConfiguration, componentName string)
|
||||
// the node's IP. The only option then is to use localhost.
|
||||
if features.Enabled(cfg.FeatureGates, features.SelfHosting) {
|
||||
return "127.0.0.1"
|
||||
} else if cfg.API.AdvertiseAddress != "" {
|
||||
return cfg.API.AdvertiseAddress
|
||||
} else if cfg.APIEndpoint.AdvertiseAddress != "" {
|
||||
return cfg.APIEndpoint.AdvertiseAddress
|
||||
}
|
||||
case componentName == kubeadmconstants.KubeControllerManager:
|
||||
if addr, exists := cfg.ControllerManagerExtraArgs[kubeControllerManagerAddressArg]; exists {
|
||||
|
74
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod/utils_test.go
generated
vendored
74
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod/utils_test.go
generated
vendored
@@ -46,7 +46,7 @@ func TestComponentResources(t *testing.T) {
|
||||
func TestComponentProbe(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
cfg *kubeadmapi.InitConfiguration
|
||||
component string
|
||||
port int
|
||||
path string
|
||||
@@ -55,8 +55,8 @@ func TestComponentProbe(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "default apiserver advertise address with http",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
APIEndpoint: kubeadmapi.APIEndpoint{
|
||||
AdvertiseAddress: "",
|
||||
},
|
||||
},
|
||||
@@ -68,12 +68,14 @@ func TestComponentProbe(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "default apiserver advertise address with http",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
APIEndpoint: kubeadmapi.APIEndpoint{
|
||||
AdvertiseAddress: "1.2.3.4",
|
||||
},
|
||||
FeatureGates: map[string]bool{
|
||||
features.SelfHosting: true,
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
FeatureGates: map[string]bool{
|
||||
features.SelfHosting: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
component: kubeadmconstants.KubeAPIServer,
|
||||
@@ -84,8 +86,8 @@ func TestComponentProbe(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "default apiserver advertise address with https",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
APIEndpoint: kubeadmapi.APIEndpoint{
|
||||
AdvertiseAddress: "",
|
||||
},
|
||||
},
|
||||
@@ -97,8 +99,8 @@ func TestComponentProbe(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "valid ipv4 apiserver advertise address with http",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
APIEndpoint: kubeadmapi.APIEndpoint{
|
||||
AdvertiseAddress: "1.2.3.4",
|
||||
},
|
||||
},
|
||||
@@ -110,8 +112,8 @@ func TestComponentProbe(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "valid ipv6 apiserver advertise address with http",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
APIEndpoint: kubeadmapi.APIEndpoint{
|
||||
AdvertiseAddress: "2001:db8::1",
|
||||
},
|
||||
},
|
||||
@@ -123,8 +125,10 @@ func TestComponentProbe(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "valid IPv4 controller-manager probe",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
ControllerManagerExtraArgs: map[string]string{"address": "1.2.3.4"},
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
ControllerManagerExtraArgs: map[string]string{"address": "1.2.3.4"},
|
||||
},
|
||||
},
|
||||
component: kubeadmconstants.KubeControllerManager,
|
||||
port: 1,
|
||||
@@ -134,8 +138,10 @@ func TestComponentProbe(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "valid IPv6 controller-manager probe",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
ControllerManagerExtraArgs: map[string]string{"address": "2001:db8::1"},
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
ControllerManagerExtraArgs: map[string]string{"address": "2001:db8::1"},
|
||||
},
|
||||
},
|
||||
component: kubeadmconstants.KubeControllerManager,
|
||||
port: 1,
|
||||
@@ -145,8 +151,10 @@ func TestComponentProbe(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "valid IPv4 scheduler probe",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
SchedulerExtraArgs: map[string]string{"address": "1.2.3.4"},
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
SchedulerExtraArgs: map[string]string{"address": "1.2.3.4"},
|
||||
},
|
||||
},
|
||||
component: kubeadmconstants.KubeScheduler,
|
||||
port: 1,
|
||||
@@ -156,8 +164,10 @@ func TestComponentProbe(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "valid IPv6 scheduler probe",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
SchedulerExtraArgs: map[string]string{"address": "2001:db8::1"},
|
||||
cfg: &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
|
||||
SchedulerExtraArgs: map[string]string{"address": "2001:db8::1"},
|
||||
},
|
||||
},
|
||||
component: kubeadmconstants.KubeScheduler,
|
||||
port: 1,
|
||||
@@ -194,7 +204,7 @@ func TestComponentProbe(t *testing.T) {
|
||||
func TestEtcdProbe(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
cfg *kubeadmapi.ClusterConfiguration
|
||||
component string
|
||||
port int
|
||||
certsDir string
|
||||
@@ -205,7 +215,7 @@ func TestEtcdProbe(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "valid etcd probe using listen-client-urls IPv4 addresses",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
cfg: &kubeadmapi.ClusterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
ExtraArgs: map[string]string{
|
||||
@@ -223,7 +233,7 @@ func TestEtcdProbe(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "valid etcd probe using listen-client-urls unspecified IPv6 address",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
cfg: &kubeadmapi.ClusterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
ExtraArgs: map[string]string{
|
||||
@@ -241,7 +251,7 @@ func TestEtcdProbe(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "valid etcd probe using listen-client-urls unspecified IPv6 address 2",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
cfg: &kubeadmapi.ClusterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
ExtraArgs: map[string]string{
|
||||
@@ -259,7 +269,7 @@ func TestEtcdProbe(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "valid etcd probe using listen-client-urls unspecified IPv6 address 3",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
cfg: &kubeadmapi.ClusterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
ExtraArgs: map[string]string{
|
||||
@@ -277,7 +287,7 @@ func TestEtcdProbe(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "valid etcd probe using listen-client-urls unspecified IPv4 address",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
cfg: &kubeadmapi.ClusterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
ExtraArgs: map[string]string{
|
||||
@@ -295,7 +305,7 @@ func TestEtcdProbe(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "valid etcd probe using listen-client-urls IPv6 addresses",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
cfg: &kubeadmapi.ClusterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
ExtraArgs: map[string]string{
|
||||
@@ -313,7 +323,7 @@ func TestEtcdProbe(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "valid IPv4 etcd probe using hostname for listen-client-urls",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
cfg: &kubeadmapi.ClusterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
Local: &kubeadmapi.LocalEtcd{
|
||||
ExtraArgs: map[string]string{
|
||||
@@ -331,7 +341,11 @@ func TestEtcdProbe(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, rt := range tests {
|
||||
actual := EtcdProbe(rt.cfg, rt.component, rt.port, rt.certsDir, rt.cacert, rt.cert, rt.key)
|
||||
// TODO: Make EtcdProbe accept a ClusterConfiguration object instead of InitConfiguration
|
||||
initcfg := &kubeadmapi.InitConfiguration{
|
||||
ClusterConfiguration: *rt.cfg,
|
||||
}
|
||||
actual := EtcdProbe(initcfg, 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,
|
||||
|
62
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/BUILD
generated
vendored
Normal file
62
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/BUILD
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"cgroup_validator.go",
|
||||
"docker_validator.go",
|
||||
"kernel_validator.go",
|
||||
"kernel_validator_helper.go",
|
||||
"os_validator.go",
|
||||
"package_validator.go",
|
||||
"report.go",
|
||||
"types.go",
|
||||
"types_unix.go",
|
||||
"types_windows.go",
|
||||
"validators.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/util/system",
|
||||
deps = [
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
"//vendor/github.com/blang/semver:go_default_library",
|
||||
"//vendor/github.com/docker/docker/api/types:go_default_library",
|
||||
"//vendor/github.com/docker/docker/client:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"cgroup_validator_test.go",
|
||||
"docker_validator_test.go",
|
||||
"kernel_validator_test.go",
|
||||
"os_validator_test.go",
|
||||
"package_validator_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
tags = ["e2e"],
|
||||
deps = [
|
||||
"//vendor/github.com/docker/docker/api/types:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
95
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/cgroup_validator.go
generated
vendored
Normal file
95
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/cgroup_validator.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright 2016 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 system
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var _ Validator = &CgroupsValidator{}
|
||||
|
||||
type CgroupsValidator struct {
|
||||
Reporter Reporter
|
||||
}
|
||||
|
||||
func (c *CgroupsValidator) Name() string {
|
||||
return "cgroups"
|
||||
}
|
||||
|
||||
const (
|
||||
cgroupsConfigPrefix = "CGROUPS_"
|
||||
)
|
||||
|
||||
func (c *CgroupsValidator) Validate(spec SysSpec) (error, error) {
|
||||
subsystems, err := c.getCgroupSubsystems()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get cgroup subsystems: %v", err)
|
||||
}
|
||||
return nil, c.validateCgroupSubsystems(spec.Cgroups, subsystems)
|
||||
}
|
||||
|
||||
func (c *CgroupsValidator) validateCgroupSubsystems(cgroupSpec, subsystems []string) error {
|
||||
missing := []string{}
|
||||
for _, cgroup := range cgroupSpec {
|
||||
found := false
|
||||
for _, subsystem := range subsystems {
|
||||
if cgroup == subsystem {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
item := cgroupsConfigPrefix + strings.ToUpper(cgroup)
|
||||
if found {
|
||||
c.Reporter.Report(item, "enabled", good)
|
||||
} else {
|
||||
c.Reporter.Report(item, "missing", bad)
|
||||
missing = append(missing, cgroup)
|
||||
}
|
||||
}
|
||||
if len(missing) > 0 {
|
||||
return fmt.Errorf("missing cgroups: %s", strings.Join(missing, " "))
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (c *CgroupsValidator) getCgroupSubsystems() ([]string, error) {
|
||||
f, err := os.Open("/proc/cgroups")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
subsystems := []string{}
|
||||
s := bufio.NewScanner(f)
|
||||
for s.Scan() {
|
||||
if err := s.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
text := s.Text()
|
||||
if text[0] != '#' {
|
||||
parts := strings.Fields(text)
|
||||
if len(parts) >= 4 && parts[3] != "0" {
|
||||
subsystems = append(subsystems, parts[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
return subsystems, nil
|
||||
}
|
56
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/cgroup_validator_test.go
generated
vendored
Normal file
56
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/cgroup_validator_test.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright 2016 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 system
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestValidateCgroupSubsystem(t *testing.T) {
|
||||
v := &CgroupsValidator{
|
||||
Reporter: DefaultReporter,
|
||||
}
|
||||
cgroupSpec := []string{"system1", "system2"}
|
||||
for desc, test := range map[string]struct {
|
||||
cgroupSpec []string
|
||||
subsystems []string
|
||||
err bool
|
||||
}{
|
||||
"missing cgroup subsystem should report error": {
|
||||
subsystems: []string{"system1"},
|
||||
err: true,
|
||||
},
|
||||
"extra cgroup subsystems should not report error": {
|
||||
subsystems: []string{"system1", "system2", "system3"},
|
||||
err: false,
|
||||
},
|
||||
"subsystems the same with spec should not report error": {
|
||||
subsystems: []string{"system1", "system2"},
|
||||
err: false,
|
||||
},
|
||||
} {
|
||||
err := v.validateCgroupSubsystems(cgroupSpec, test.subsystems)
|
||||
if !test.err {
|
||||
assert.Nil(t, err, "%q: Expect error not to occur with cgroup", desc)
|
||||
} else {
|
||||
assert.NotNil(t, err, "%q: Expect error to occur with docker info", desc)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
100
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/docker_validator.go
generated
vendored
Normal file
100
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/docker_validator.go
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
Copyright 2016 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 system
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
)
|
||||
|
||||
var _ Validator = &DockerValidator{}
|
||||
|
||||
// DockerValidator validates docker configuration.
|
||||
type DockerValidator struct {
|
||||
Reporter Reporter
|
||||
}
|
||||
|
||||
func (d *DockerValidator) Name() string {
|
||||
return "docker"
|
||||
}
|
||||
|
||||
const (
|
||||
dockerConfigPrefix = "DOCKER_"
|
||||
latestValidatedDockerVersion = "18.06"
|
||||
)
|
||||
|
||||
// TODO(random-liu): Add more validating items.
|
||||
func (d *DockerValidator) Validate(spec SysSpec) (error, error) {
|
||||
if spec.RuntimeSpec.DockerSpec == nil {
|
||||
// If DockerSpec is not specified, assume current runtime is not
|
||||
// docker, skip the docker configuration validation.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
c, err := client.NewClient(dockerEndpoint, "", nil, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create docker client: %v", err)
|
||||
}
|
||||
info, err := c.Info(context.Background())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get docker info: %v", err)
|
||||
}
|
||||
return d.validateDockerInfo(spec.RuntimeSpec.DockerSpec, info)
|
||||
}
|
||||
|
||||
func (d *DockerValidator) validateDockerInfo(spec *DockerSpec, info types.Info) (error, error) {
|
||||
// Validate docker version.
|
||||
matched := false
|
||||
for _, v := range spec.Version {
|
||||
r := regexp.MustCompile(v)
|
||||
if r.MatchString(info.ServerVersion) {
|
||||
d.Reporter.Report(dockerConfigPrefix+"VERSION", info.ServerVersion, good)
|
||||
matched = true
|
||||
}
|
||||
}
|
||||
if !matched {
|
||||
// If it's of the new Docker version scheme but didn't match above, it
|
||||
// must be a newer version than the most recently validated one.
|
||||
ver := `\d{2}\.\d+\.\d+-[a-z]{2}`
|
||||
r := regexp.MustCompile(ver)
|
||||
if r.MatchString(info.ServerVersion) {
|
||||
d.Reporter.Report(dockerConfigPrefix+"VERSION", info.ServerVersion, good)
|
||||
w := fmt.Errorf(
|
||||
"this Docker version is not on the list of validated versions: %s. Latest validated version: %s",
|
||||
info.ServerVersion,
|
||||
latestValidatedDockerVersion,
|
||||
)
|
||||
return w, nil
|
||||
}
|
||||
d.Reporter.Report(dockerConfigPrefix+"VERSION", info.ServerVersion, bad)
|
||||
return nil, fmt.Errorf("unsupported docker version: %s", info.ServerVersion)
|
||||
}
|
||||
// Validate graph driver.
|
||||
item := dockerConfigPrefix + "GRAPH_DRIVER"
|
||||
for _, gd := range spec.GraphDriver {
|
||||
if info.Driver == gd {
|
||||
d.Reporter.Report(item, info.Driver, good)
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
d.Reporter.Report(item, info.Driver, bad)
|
||||
return nil, fmt.Errorf("unsupported graph driver: %s", info.Driver)
|
||||
}
|
98
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/docker_validator_test.go
generated
vendored
Normal file
98
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/docker_validator_test.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Copyright 2016 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 system
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestValidateDockerInfo(t *testing.T) {
|
||||
v := &DockerValidator{
|
||||
Reporter: DefaultReporter,
|
||||
}
|
||||
spec := &DockerSpec{
|
||||
Version: []string{`1\.1[1-3]\..*`, `17\.0[3,6,9]\..*`, `18\.06\..*`},
|
||||
GraphDriver: []string{"driver_1", "driver_2"},
|
||||
}
|
||||
for _, test := range []struct {
|
||||
info types.Info
|
||||
err bool
|
||||
warn bool
|
||||
}{
|
||||
{
|
||||
info: types.Info{Driver: "driver_1", ServerVersion: "1.10.1"},
|
||||
err: true,
|
||||
warn: false,
|
||||
},
|
||||
{
|
||||
info: types.Info{Driver: "bad_driver", ServerVersion: "1.11.1"},
|
||||
err: true,
|
||||
warn: false,
|
||||
},
|
||||
{
|
||||
info: types.Info{Driver: "driver_1", ServerVersion: "1.11.1"},
|
||||
err: false,
|
||||
warn: false,
|
||||
},
|
||||
{
|
||||
info: types.Info{Driver: "driver_2", ServerVersion: "1.12.1"},
|
||||
err: false,
|
||||
warn: false,
|
||||
},
|
||||
{
|
||||
info: types.Info{Driver: "driver_2", ServerVersion: "1.13.1"},
|
||||
err: false,
|
||||
warn: false,
|
||||
},
|
||||
{
|
||||
info: types.Info{Driver: "driver_2", ServerVersion: "17.03.0-ce"},
|
||||
err: false,
|
||||
warn: false,
|
||||
},
|
||||
{
|
||||
info: types.Info{Driver: "driver_2", ServerVersion: "17.06.0-ce"},
|
||||
err: false,
|
||||
warn: false,
|
||||
},
|
||||
{
|
||||
info: types.Info{Driver: "driver_2", ServerVersion: "17.09.0-ce"},
|
||||
err: false,
|
||||
warn: false,
|
||||
},
|
||||
{
|
||||
info: types.Info{Driver: "driver_2", ServerVersion: "18.06.0-ce"},
|
||||
err: false,
|
||||
warn: false,
|
||||
},
|
||||
} {
|
||||
warn, err := v.validateDockerInfo(spec, test.info)
|
||||
if !test.err {
|
||||
assert.Nil(t, err, "Expect error not to occur with docker info %+v", test.info)
|
||||
} else {
|
||||
assert.NotNil(t, err, "Expect error to occur with docker info %+v", test.info)
|
||||
}
|
||||
if !test.warn {
|
||||
assert.Nil(t, warn, "Expect error not to occur with docker info %+v", test.info)
|
||||
} else {
|
||||
assert.NotNil(t, warn, "Expect error to occur with docker info %+v", test.info)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
262
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/kernel_validator.go
generated
vendored
Normal file
262
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/kernel_validator.go
generated
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
Copyright 2016 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 system
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/apimachinery/pkg/util/errors"
|
||||
)
|
||||
|
||||
var _ Validator = &KernelValidator{}
|
||||
|
||||
// KernelValidator validates kernel. Currently only validate kernel version
|
||||
// and kernel configuration.
|
||||
type KernelValidator struct {
|
||||
kernelRelease string
|
||||
Reporter Reporter
|
||||
}
|
||||
|
||||
func (k *KernelValidator) Name() string {
|
||||
return "kernel"
|
||||
}
|
||||
|
||||
// kConfigOption is the possible kernel config option.
|
||||
type kConfigOption string
|
||||
|
||||
const (
|
||||
builtIn kConfigOption = "y"
|
||||
asModule kConfigOption = "m"
|
||||
leftOut kConfigOption = "n"
|
||||
|
||||
// validKConfigRegex is the regex matching kernel configuration line.
|
||||
validKConfigRegex = "^CONFIG_[A-Z0-9_]+=[myn]"
|
||||
// kConfigPrefix is the prefix of kernel configuration.
|
||||
kConfigPrefix = "CONFIG_"
|
||||
)
|
||||
|
||||
func (k *KernelValidator) Validate(spec SysSpec) (error, error) {
|
||||
helper := KernelValidatorHelperImpl{}
|
||||
release, err := helper.GetKernelReleaseVersion()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get kernel release: %v", err)
|
||||
}
|
||||
k.kernelRelease = release
|
||||
var errs []error
|
||||
errs = append(errs, k.validateKernelVersion(spec.KernelSpec))
|
||||
// only validate kernel config when necessary (currently no kernel config for windows)
|
||||
if len(spec.KernelSpec.Required) > 0 || len(spec.KernelSpec.Forbidden) > 0 || len(spec.KernelSpec.Optional) > 0 {
|
||||
errs = append(errs, k.validateKernelConfig(spec.KernelSpec))
|
||||
}
|
||||
return nil, errors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
// validateKernelVersion validates the kernel version.
|
||||
func (k *KernelValidator) validateKernelVersion(kSpec KernelSpec) error {
|
||||
glog.V(1).Info("Validating kernel version")
|
||||
versionRegexps := kSpec.Versions
|
||||
for _, versionRegexp := range versionRegexps {
|
||||
r := regexp.MustCompile(versionRegexp)
|
||||
if r.MatchString(k.kernelRelease) {
|
||||
k.Reporter.Report("KERNEL_VERSION", k.kernelRelease, good)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
k.Reporter.Report("KERNEL_VERSION", k.kernelRelease, bad)
|
||||
return fmt.Errorf("unsupported kernel release: %s", k.kernelRelease)
|
||||
}
|
||||
|
||||
// validateKernelConfig validates the kernel configurations.
|
||||
func (k *KernelValidator) validateKernelConfig(kSpec KernelSpec) error {
|
||||
glog.V(1).Info("Validating kernel config")
|
||||
allConfig, err := k.getKernelConfig()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse kernel config: %v", err)
|
||||
}
|
||||
return k.validateCachedKernelConfig(allConfig, kSpec)
|
||||
}
|
||||
|
||||
// validateCachedKernelConfig validates the kernel confgiurations cached in internal data type.
|
||||
func (k *KernelValidator) validateCachedKernelConfig(allConfig map[string]kConfigOption, kSpec KernelSpec) error {
|
||||
badConfigs := []string{}
|
||||
// reportAndRecord is a helper function to record bad config when
|
||||
// report.
|
||||
reportAndRecord := func(name, msg, desc string, result ValidationResultType) {
|
||||
if result == bad {
|
||||
badConfigs = append(badConfigs, name)
|
||||
}
|
||||
// report description when the config is bad or warn.
|
||||
if result != good && desc != "" {
|
||||
msg = msg + " - " + desc
|
||||
}
|
||||
k.Reporter.Report(name, msg, result)
|
||||
}
|
||||
const (
|
||||
required = iota
|
||||
optional
|
||||
forbidden
|
||||
)
|
||||
validateOpt := func(config KernelConfig, expect int) {
|
||||
var found, missing ValidationResultType
|
||||
switch expect {
|
||||
case required:
|
||||
found, missing = good, bad
|
||||
case optional:
|
||||
found, missing = good, warn
|
||||
case forbidden:
|
||||
found, missing = bad, good
|
||||
}
|
||||
var name string
|
||||
var opt kConfigOption
|
||||
var ok bool
|
||||
for _, name = range append([]string{config.Name}, config.Aliases...) {
|
||||
name = kConfigPrefix + name
|
||||
if opt, ok = allConfig[name]; ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
reportAndRecord(name, "not set", config.Description, missing)
|
||||
return
|
||||
}
|
||||
switch opt {
|
||||
case builtIn:
|
||||
reportAndRecord(name, "enabled", config.Description, found)
|
||||
case asModule:
|
||||
reportAndRecord(name, "enabled (as module)", config.Description, found)
|
||||
case leftOut:
|
||||
reportAndRecord(name, "disabled", config.Description, missing)
|
||||
default:
|
||||
reportAndRecord(name, fmt.Sprintf("unknown option: %s", opt), config.Description, missing)
|
||||
}
|
||||
}
|
||||
for _, config := range kSpec.Required {
|
||||
validateOpt(config, required)
|
||||
}
|
||||
for _, config := range kSpec.Optional {
|
||||
validateOpt(config, optional)
|
||||
}
|
||||
for _, config := range kSpec.Forbidden {
|
||||
validateOpt(config, forbidden)
|
||||
}
|
||||
if len(badConfigs) > 0 {
|
||||
return fmt.Errorf("unexpected kernel config: %s", strings.Join(badConfigs, " "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getKernelConfigReader search kernel config file in a predefined list. Once the kernel config
|
||||
// file is found it will read the configurations into a byte buffer and return. If the kernel
|
||||
// config file is not found, it will try to load kernel config module and retry again.
|
||||
func (k *KernelValidator) getKernelConfigReader() (io.Reader, error) {
|
||||
possibePaths := []string{
|
||||
"/proc/config.gz",
|
||||
"/boot/config-" + k.kernelRelease,
|
||||
"/usr/src/linux-" + k.kernelRelease + "/.config",
|
||||
"/usr/src/linux/.config",
|
||||
"/usr/lib/modules/" + k.kernelRelease + "/config",
|
||||
"/usr/lib/ostree-boot/config-" + k.kernelRelease,
|
||||
"/usr/lib/kernel/config-" + k.kernelRelease,
|
||||
}
|
||||
configsModule := "configs"
|
||||
modprobeCmd := "modprobe"
|
||||
// loadModule indicates whether we've tried to load kernel config module ourselves.
|
||||
loadModule := false
|
||||
for {
|
||||
for _, path := range possibePaths {
|
||||
_, err := os.Stat(path)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
// Buffer the whole file, so that we can close the file and unload
|
||||
// kernel config module in this function.
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var r io.Reader
|
||||
r = bytes.NewReader(b)
|
||||
// This is a gzip file (config.gz), unzip it.
|
||||
if filepath.Ext(path) == ".gz" {
|
||||
r, err = gzip.NewReader(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
// If we've tried to load kernel config module, break and return error.
|
||||
if loadModule {
|
||||
break
|
||||
}
|
||||
// If the kernel config file is not found, try to load the kernel
|
||||
// config module and check again.
|
||||
output, err := exec.Command(modprobeCmd, configsModule).CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to load kernel module %q: output - %q, err - %v",
|
||||
configsModule, output, err)
|
||||
}
|
||||
// Unload the kernel config module to make sure the validation have no side effect.
|
||||
defer exec.Command(modprobeCmd, "-r", configsModule).Run()
|
||||
loadModule = true
|
||||
}
|
||||
return nil, fmt.Errorf("no config path in %v is available", possibePaths)
|
||||
}
|
||||
|
||||
// getKernelConfig gets kernel config from kernel config file and convert kernel config to internal type.
|
||||
func (k *KernelValidator) getKernelConfig() (map[string]kConfigOption, error) {
|
||||
r, err := k.getKernelConfigReader()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return k.parseKernelConfig(r)
|
||||
}
|
||||
|
||||
// parseKernelConfig converts kernel config to internal type.
|
||||
func (k *KernelValidator) parseKernelConfig(r io.Reader) (map[string]kConfigOption, error) {
|
||||
config := map[string]kConfigOption{}
|
||||
regex := regexp.MustCompile(validKConfigRegex)
|
||||
s := bufio.NewScanner(r)
|
||||
for s.Scan() {
|
||||
if err := s.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
line := strings.TrimSpace(s.Text())
|
||||
if !regex.MatchString(line) {
|
||||
continue
|
||||
}
|
||||
fields := strings.Split(line, "=")
|
||||
if len(fields) != 2 {
|
||||
glog.Errorf("Unexpected fields number in config %q", line)
|
||||
continue
|
||||
}
|
||||
config[fields[0]] = kConfigOption(fields[1])
|
||||
}
|
||||
return config, nil
|
||||
|
||||
}
|
23
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/kernel_validator_helper.go
generated
vendored
Normal file
23
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/kernel_validator_helper.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
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 system
|
||||
|
||||
// KernelValidatorHelper is an interface intended to help with os specific kernel validation
|
||||
type KernelValidatorHelper interface {
|
||||
// GetKernelReleaseVersion gets the current kernel release version of the system
|
||||
GetKernelReleaseVersion() (string, error)
|
||||
}
|
197
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/kernel_validator_test.go
generated
vendored
Normal file
197
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/kernel_validator_test.go
generated
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
Copyright 2016 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 system
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestValidateKernelVersion(t *testing.T) {
|
||||
v := &KernelValidator{
|
||||
Reporter: DefaultReporter,
|
||||
}
|
||||
// Currently, testRegex is align with DefaultSysSpec.KernelVersion, but in the future
|
||||
// they may be different.
|
||||
// This is fine, because the test mainly tests the kernel version validation logic,
|
||||
// not the DefaultSysSpec. The DefaultSysSpec should be tested with node e2e.
|
||||
testRegex := []string{`3\.[1-9][0-9].*`, `4\..*`}
|
||||
for _, test := range []struct {
|
||||
version string
|
||||
err bool
|
||||
}{
|
||||
// first version regex matches
|
||||
{
|
||||
version: "3.19.9-99-test",
|
||||
err: false,
|
||||
},
|
||||
// one of version regexes matches
|
||||
{
|
||||
version: "4.4.14+",
|
||||
err: false,
|
||||
},
|
||||
// no version regex matches
|
||||
{
|
||||
version: "2.0.0",
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
version: "5.0.0",
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
version: "3.9.0",
|
||||
err: true,
|
||||
},
|
||||
} {
|
||||
v.kernelRelease = test.version
|
||||
err := v.validateKernelVersion(KernelSpec{Versions: testRegex})
|
||||
if !test.err {
|
||||
assert.Nil(t, err, "Expect error not to occur with kernel version %q", test.version)
|
||||
} else {
|
||||
assert.NotNil(t, err, "Expect error to occur with kenrel version %q", test.version)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateCachedKernelConfig(t *testing.T) {
|
||||
v := &KernelValidator{
|
||||
Reporter: DefaultReporter,
|
||||
}
|
||||
testKernelSpec := KernelSpec{
|
||||
Required: []KernelConfig{{Name: "REQUIRED_1"}, {Name: "REQUIRED_2", Aliases: []string{"ALIASE_REQUIRED_2"}}},
|
||||
Optional: []KernelConfig{{Name: "OPTIONAL_1"}, {Name: "OPTIONAL_2"}},
|
||||
Forbidden: []KernelConfig{
|
||||
{Name: "FORBIDDEN_1", Description: "TEST FORBIDDEN"},
|
||||
{Name: "FORBIDDEN_2", Aliases: []string{"ALIASE_FORBIDDEN_2"}},
|
||||
},
|
||||
}
|
||||
for c, test := range []struct {
|
||||
desc string
|
||||
config map[string]kConfigOption
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
desc: "meet all required configurations should not report error.",
|
||||
config: map[string]kConfigOption{
|
||||
"REQUIRED_1": builtIn,
|
||||
"REQUIRED_2": asModule,
|
||||
},
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
desc: "one required configuration disabled should report error.",
|
||||
config: map[string]kConfigOption{
|
||||
"REQUIRED_1": leftOut,
|
||||
"REQUIRED_2": builtIn,
|
||||
},
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
desc: "one required configuration missing should report error.",
|
||||
config: map[string]kConfigOption{
|
||||
"REQUIRED_1": builtIn,
|
||||
},
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
desc: "alias of required configuration should not report error.",
|
||||
config: map[string]kConfigOption{
|
||||
"REQUIRED_1": builtIn,
|
||||
"ALIASE_REQUIRED_2": asModule,
|
||||
},
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
desc: "optional configuration set or not should not report error.",
|
||||
config: map[string]kConfigOption{
|
||||
"REQUIRED_1": builtIn,
|
||||
"REQUIRED_2": asModule,
|
||||
"OPTIONAL_1": builtIn,
|
||||
},
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
desc: "forbidden configuration disabled should not report error.",
|
||||
config: map[string]kConfigOption{
|
||||
"REQUIRED_1": builtIn,
|
||||
"REQUIRED_2": asModule,
|
||||
"FORBIDDEN_1": leftOut,
|
||||
},
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
desc: "forbidden configuration built-in should report error.",
|
||||
config: map[string]kConfigOption{
|
||||
"REQUIRED_1": builtIn,
|
||||
"REQUIRED_2": asModule,
|
||||
"FORBIDDEN_1": builtIn,
|
||||
},
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
desc: "forbidden configuration built as module should report error.",
|
||||
config: map[string]kConfigOption{
|
||||
"REQUIRED_1": builtIn,
|
||||
"REQUIRED_2": asModule,
|
||||
"FORBIDDEN_1": asModule,
|
||||
},
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
desc: "alias of forbidden configuration should report error.",
|
||||
config: map[string]kConfigOption{
|
||||
"REQUIRED_1": builtIn,
|
||||
"REQUIRED_2": asModule,
|
||||
"ALIASE_FORBIDDEN_2": asModule,
|
||||
},
|
||||
err: true,
|
||||
},
|
||||
} {
|
||||
t.Logf("TestCase #%d %s", c, test.desc)
|
||||
// Add kernel config prefix.
|
||||
for k, v := range test.config {
|
||||
delete(test.config, k)
|
||||
test.config[kConfigPrefix+k] = v
|
||||
}
|
||||
err := v.validateCachedKernelConfig(test.config, testKernelSpec)
|
||||
if !test.err {
|
||||
assert.Nil(t, err, "Expect error not to occur with kernel config %q", test.config)
|
||||
} else {
|
||||
assert.NotNil(t, err, "Expect error to occur with kenrel config %q", test.config)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateParseKernelConfig(t *testing.T) {
|
||||
config := `CONFIG_1=y
|
||||
CONFIG_2=m
|
||||
CONFIG_3=n`
|
||||
expected := map[string]kConfigOption{
|
||||
"CONFIG_1": builtIn,
|
||||
"CONFIG_2": asModule,
|
||||
"CONFIG_3": leftOut,
|
||||
}
|
||||
v := &KernelValidator{
|
||||
Reporter: DefaultReporter,
|
||||
}
|
||||
got, err := v.parseKernelConfig(bytes.NewReader([]byte(config)))
|
||||
assert.Nil(t, err, "Expect error not to occur when parse kernel configuration %q", config)
|
||||
assert.Equal(t, expected, got)
|
||||
}
|
50
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/os_validator.go
generated
vendored
Normal file
50
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/os_validator.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
Copyright 2016 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 system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var _ Validator = &OSValidator{}
|
||||
|
||||
type OSValidator struct {
|
||||
Reporter Reporter
|
||||
}
|
||||
|
||||
func (o *OSValidator) Name() string {
|
||||
return "os"
|
||||
}
|
||||
|
||||
func (o *OSValidator) Validate(spec SysSpec) (error, error) {
|
||||
os, err := exec.Command("uname").CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get os name: %v", err)
|
||||
}
|
||||
return nil, o.validateOS(strings.TrimSpace(string(os)), spec.OS)
|
||||
}
|
||||
|
||||
func (o *OSValidator) validateOS(os, specOS string) error {
|
||||
if os != specOS {
|
||||
o.Reporter.Report("OS", os, bad)
|
||||
return fmt.Errorf("unsupported operating system: %s", os)
|
||||
}
|
||||
o.Reporter.Report("OS", os, good)
|
||||
return nil
|
||||
}
|
54
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/os_validator_test.go
generated
vendored
Normal file
54
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/os_validator_test.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
Copyright 2016 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 system
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestValidateOS(t *testing.T) {
|
||||
v := &OSValidator{
|
||||
Reporter: DefaultReporter,
|
||||
}
|
||||
specOS := "Linux"
|
||||
for _, test := range []struct {
|
||||
os string
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
os: "Linux",
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
os: "Windows",
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
os: "Darwin",
|
||||
err: true,
|
||||
},
|
||||
} {
|
||||
err := v.validateOS(test.os, specOS)
|
||||
if !test.err {
|
||||
assert.Nil(t, err, "Expect error not to occur with os %q", test.os)
|
||||
} else {
|
||||
assert.NotNil(t, err, "Expect error to occur with os %q", test.os)
|
||||
}
|
||||
}
|
||||
}
|
325
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/package_validator.go
generated
vendored
Normal file
325
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/package_validator.go
generated
vendored
Normal file
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
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 system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/errors"
|
||||
|
||||
"github.com/blang/semver"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// semVerDotsCount is the number of dots in a valid semantic version.
|
||||
const semVerDotsCount int = 2
|
||||
|
||||
// packageManager is an interface that abstracts the basic operations of a
|
||||
// package manager.
|
||||
type packageManager interface {
|
||||
// getPackageVersion returns the version of the package given the
|
||||
// packageName, or an error if no such package exists.
|
||||
getPackageVersion(packageName string) (string, error)
|
||||
}
|
||||
|
||||
// newPackageManager returns the package manager on the running machine, and an
|
||||
// error if no package managers is available.
|
||||
func newPackageManager() (packageManager, error) {
|
||||
if m, ok := newDPKG(); ok {
|
||||
return m, nil
|
||||
}
|
||||
return nil, fmt.Errorf("failed to find package manager")
|
||||
}
|
||||
|
||||
// dpkg implements packageManager. It uses "dpkg-query" to retrieve package
|
||||
// information.
|
||||
type dpkg struct{}
|
||||
|
||||
// newDPKG returns a Debian package manager. It returns (nil, false) if no such
|
||||
// package manager exists on the running machine.
|
||||
func newDPKG() (packageManager, bool) {
|
||||
_, err := exec.LookPath("dpkg-query")
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
return dpkg{}, true
|
||||
}
|
||||
|
||||
// getPackageVersion returns the upstream package version for the package given
|
||||
// the packageName, and an error if no such package exists.
|
||||
func (_ dpkg) getPackageVersion(packageName string) (string, error) {
|
||||
output, err := exec.Command("dpkg-query", "--show", "--showformat='${Version}'", packageName).Output()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("dpkg-query failed: %s", err)
|
||||
}
|
||||
version := extractUpstreamVersion(string(output))
|
||||
if version == "" {
|
||||
return "", fmt.Errorf("no version information")
|
||||
}
|
||||
return version, nil
|
||||
}
|
||||
|
||||
// packageValidator implements the Validator interface. It validates packages
|
||||
// and their versions.
|
||||
type packageValidator struct {
|
||||
reporter Reporter
|
||||
kernelRelease string
|
||||
osDistro string
|
||||
}
|
||||
|
||||
// Name returns the name of the package validator.
|
||||
func (self *packageValidator) Name() string {
|
||||
return "package"
|
||||
}
|
||||
|
||||
// Validate checks packages and their versions against the spec using the
|
||||
// package manager on the running machine, and returns an error on any
|
||||
// package/version mismatch.
|
||||
func (self *packageValidator) Validate(spec SysSpec) (error, error) {
|
||||
if len(spec.PackageSpecs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var err error
|
||||
if self.kernelRelease, err = getKernelRelease(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if self.osDistro, err = getOSDistro(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
manager, err := newPackageManager()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
specs := applyPackageSpecOverride(spec.PackageSpecs, spec.PackageSpecOverrides, self.osDistro)
|
||||
return self.validate(specs, manager)
|
||||
}
|
||||
|
||||
// Validate checks packages and their versions against the packageSpecs using
|
||||
// the packageManager, and returns an error on any package/version mismatch.
|
||||
func (self *packageValidator) validate(packageSpecs []PackageSpec, manager packageManager) (error, error) {
|
||||
var errs []error
|
||||
for _, spec := range packageSpecs {
|
||||
// Substitute variables in package name.
|
||||
packageName := resolvePackageName(spec.Name, self.kernelRelease)
|
||||
|
||||
nameWithVerRange := fmt.Sprintf("%s (%s)", packageName, spec.VersionRange)
|
||||
|
||||
// Get the version of the package on the running machine.
|
||||
version, err := manager.getPackageVersion(packageName)
|
||||
if err != nil {
|
||||
glog.V(1).Infof("Failed to get the version for the package %q: %s\n", packageName, err)
|
||||
errs = append(errs, err)
|
||||
self.reporter.Report(nameWithVerRange, "not installed", bad)
|
||||
continue
|
||||
}
|
||||
|
||||
// Version requirement will not be enforced if version range is
|
||||
// not specified in the spec.
|
||||
if spec.VersionRange == "" {
|
||||
self.reporter.Report(packageName, version, good)
|
||||
continue
|
||||
}
|
||||
|
||||
// Convert both the version range in the spec and the version returned
|
||||
// from package manager to semantic version format, and then check if
|
||||
// the version is in the range.
|
||||
sv, err := semver.Make(toSemVer(version))
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to convert %q to semantic version: %s\n", version, err)
|
||||
errs = append(errs, err)
|
||||
self.reporter.Report(nameWithVerRange, "internal error", bad)
|
||||
continue
|
||||
}
|
||||
versionRange := semver.MustParseRange(toSemVerRange(spec.VersionRange))
|
||||
if versionRange(sv) {
|
||||
self.reporter.Report(nameWithVerRange, version, good)
|
||||
} else {
|
||||
errs = append(errs, fmt.Errorf("package \"%s %s\" does not meet the spec \"%s (%s)\"", packageName, sv, packageName, spec.VersionRange))
|
||||
self.reporter.Report(nameWithVerRange, version, bad)
|
||||
}
|
||||
}
|
||||
return nil, errors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
// getKernelRelease returns the kernel release of the local machine.
|
||||
func getKernelRelease() (string, error) {
|
||||
output, err := exec.Command("uname", "-r").Output()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get kernel release: %s", err)
|
||||
}
|
||||
return strings.TrimSpace(string(output)), nil
|
||||
}
|
||||
|
||||
// getOSDistro returns the OS distro of the local machine.
|
||||
func getOSDistro() (string, error) {
|
||||
f := "/etc/lsb-release"
|
||||
b, err := ioutil.ReadFile(f)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read %q: %s", f, err)
|
||||
}
|
||||
content := string(b)
|
||||
switch {
|
||||
case strings.Contains(content, "Ubuntu"):
|
||||
return "ubuntu", nil
|
||||
case strings.Contains(content, "Chrome OS"):
|
||||
return "cos", nil
|
||||
case strings.Contains(content, "CoreOS"):
|
||||
return "coreos", nil
|
||||
default:
|
||||
return "", fmt.Errorf("failed to get OS distro: %s", content)
|
||||
}
|
||||
}
|
||||
|
||||
// resolvePackageName substitutes the variables in the packageName with the
|
||||
// local information.
|
||||
// E.g., "linux-headers-${KERNEL_RELEASE}" -> "linux-headers-4.4.0-75-generic".
|
||||
func resolvePackageName(packageName string, kernelRelease string) string {
|
||||
packageName = strings.Replace(packageName, "${KERNEL_RELEASE}", kernelRelease, -1)
|
||||
return packageName
|
||||
}
|
||||
|
||||
// applyPackageSpecOverride applies the package spec overrides for the given
|
||||
// osDistro to the packageSpecs and returns the applied result.
|
||||
func applyPackageSpecOverride(packageSpecs []PackageSpec, overrides []PackageSpecOverride, osDistro string) []PackageSpec {
|
||||
var override *PackageSpecOverride
|
||||
for _, o := range overrides {
|
||||
if o.OSDistro == osDistro {
|
||||
override = &o
|
||||
break
|
||||
}
|
||||
}
|
||||
if override == nil {
|
||||
return packageSpecs
|
||||
}
|
||||
|
||||
// Remove packages in the spec that matches the overrides in
|
||||
// Subtractions.
|
||||
var out []PackageSpec
|
||||
subtractions := make(map[string]bool)
|
||||
for _, spec := range override.Subtractions {
|
||||
subtractions[spec.Name] = true
|
||||
}
|
||||
for _, spec := range packageSpecs {
|
||||
if _, ok := subtractions[spec.Name]; !ok {
|
||||
out = append(out, spec)
|
||||
}
|
||||
}
|
||||
|
||||
// Add packages in the spec that matches the overrides in Additions.
|
||||
return append(out, override.Additions...)
|
||||
}
|
||||
|
||||
// extractUpstreamVersion returns the upstream version of the given full
|
||||
// version in dpkg format. E.g., "1:1.0.6-2ubuntu2.1" -> "1.0.6".
|
||||
func extractUpstreamVersion(version string) string {
|
||||
// The full version is in the format of
|
||||
// "[epoch:]upstream_version[-debian_revision]". See
|
||||
// https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version.
|
||||
version = strings.Trim(version, " '")
|
||||
if i := strings.Index(version, ":"); i != -1 {
|
||||
version = version[i+1:]
|
||||
}
|
||||
if i := strings.Index(version, "-"); i != -1 {
|
||||
version = version[:i]
|
||||
}
|
||||
return version
|
||||
}
|
||||
|
||||
// toSemVerRange converts the input to a semantic version range.
|
||||
// E.g., ">=1.0" -> ">=1.0.x"
|
||||
// ">=1" -> ">=1.x"
|
||||
// ">=1 <=2.3" -> ">=1.x <=2.3.x"
|
||||
// ">1 || >3.1.0 !4.2" -> ">1.x || >3.1.0 !4.2.x"
|
||||
func toSemVerRange(input string) string {
|
||||
var output []string
|
||||
fields := strings.Fields(input)
|
||||
for _, f := range fields {
|
||||
numDots, hasDigits := 0, false
|
||||
for _, c := range f {
|
||||
switch {
|
||||
case c == '.':
|
||||
numDots++
|
||||
case c >= '0' && c <= '9':
|
||||
hasDigits = true
|
||||
}
|
||||
}
|
||||
if hasDigits && numDots < semVerDotsCount {
|
||||
f = strings.TrimRight(f, " ")
|
||||
f += ".x"
|
||||
}
|
||||
output = append(output, f)
|
||||
}
|
||||
return strings.Join(output, " ")
|
||||
}
|
||||
|
||||
// toSemVer converts the input to a semantic version, and an empty string on
|
||||
// error.
|
||||
func toSemVer(version string) string {
|
||||
// Remove the first non-digit and non-dot character as well as the ones
|
||||
// following it.
|
||||
// E.g., "1.8.19p1" -> "1.8.19".
|
||||
if i := strings.IndexFunc(version, func(c rune) bool {
|
||||
if (c < '0' || c > '9') && c != '.' {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}); i != -1 {
|
||||
version = version[:i]
|
||||
}
|
||||
|
||||
// Remove the trailing dots if there's any, and then returns an empty
|
||||
// string if nothing left.
|
||||
version = strings.TrimRight(version, ".")
|
||||
if version == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
numDots := strings.Count(version, ".")
|
||||
switch {
|
||||
case numDots < semVerDotsCount:
|
||||
// Add minor version and patch version.
|
||||
// E.g. "1.18" -> "1.18.0" and "481" -> "481.0.0".
|
||||
version += strings.Repeat(".0", semVerDotsCount-numDots)
|
||||
case numDots > semVerDotsCount:
|
||||
// Remove anything beyond the patch version
|
||||
// E.g. "2.0.10.4" -> "2.0.10".
|
||||
for numDots != semVerDotsCount {
|
||||
if i := strings.LastIndex(version, "."); i != -1 {
|
||||
version = version[:i]
|
||||
numDots--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove leading zeros in major/minor/patch version.
|
||||
// E.g., "2.02" -> "2.2"
|
||||
// "8.0.0095" -> "8.0.95"
|
||||
var subs []string
|
||||
for _, s := range strings.Split(version, ".") {
|
||||
s := strings.TrimLeft(s, "0")
|
||||
if s == "" {
|
||||
s = "0"
|
||||
}
|
||||
subs = append(subs, s)
|
||||
}
|
||||
return strings.Join(subs, ".")
|
||||
}
|
266
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/package_validator_test.go
generated
vendored
Normal file
266
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/package_validator_test.go
generated
vendored
Normal file
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
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 system
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestExtractUpstreamVersion(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
input: "",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
input: "1.0.6",
|
||||
expected: "1.0.6",
|
||||
},
|
||||
{
|
||||
input: "1:1.0.6",
|
||||
expected: "1.0.6",
|
||||
},
|
||||
{
|
||||
input: "1.0.6-2ubuntu2.1",
|
||||
expected: "1.0.6",
|
||||
},
|
||||
{
|
||||
input: "1:1.0.6-2ubuntu2.1",
|
||||
expected: "1.0.6",
|
||||
},
|
||||
} {
|
||||
got := extractUpstreamVersion(test.input)
|
||||
if test.expected != got {
|
||||
t.Errorf("extractUpstreamVersion(%q) = %q, want %q", test.input, got, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToSemVer(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
input: "",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
input: "1.2.3",
|
||||
expected: "1.2.3",
|
||||
},
|
||||
{
|
||||
input: "1.8.19p1",
|
||||
expected: "1.8.19",
|
||||
},
|
||||
{
|
||||
input: "1.8.19.p1",
|
||||
expected: "1.8.19",
|
||||
},
|
||||
{
|
||||
input: "p1",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
input: "1.18",
|
||||
expected: "1.18.0",
|
||||
},
|
||||
{
|
||||
input: "481",
|
||||
expected: "481.0.0",
|
||||
},
|
||||
{
|
||||
input: "2.0.10.4",
|
||||
expected: "2.0.10",
|
||||
},
|
||||
{
|
||||
input: "03",
|
||||
expected: "3.0.0",
|
||||
},
|
||||
{
|
||||
input: "2.02",
|
||||
expected: "2.2.0",
|
||||
},
|
||||
{
|
||||
input: "8.0.0095",
|
||||
expected: "8.0.95",
|
||||
},
|
||||
} {
|
||||
got := toSemVer(test.input)
|
||||
if test.expected != got {
|
||||
t.Errorf("toSemVer(%q) = %q, want %q", test.input, got, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToSemVerRange(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
input: "",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
input: ">=1.0.0",
|
||||
expected: ">=1.0.0",
|
||||
},
|
||||
{
|
||||
input: ">=1.0",
|
||||
expected: ">=1.0.x",
|
||||
},
|
||||
{
|
||||
input: ">=1",
|
||||
expected: ">=1.x",
|
||||
},
|
||||
{
|
||||
input: ">=1 || !2.3",
|
||||
expected: ">=1.x || !2.3.x",
|
||||
},
|
||||
{
|
||||
input: ">1 || >3.1.0 !4.2",
|
||||
expected: ">1.x || >3.1.0 !4.2.x",
|
||||
},
|
||||
} {
|
||||
got := toSemVerRange(test.input)
|
||||
if test.expected != got {
|
||||
t.Errorf("toSemVerRange(%q) = %q, want %q", test.input, got, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// testPackageManager implements the packageManager interface.
|
||||
type testPackageManager struct {
|
||||
packageVersions map[string]string
|
||||
}
|
||||
|
||||
func (m testPackageManager) getPackageVersion(packageName string) (string, error) {
|
||||
if v, ok := m.packageVersions[packageName]; ok {
|
||||
return v, nil
|
||||
}
|
||||
return "", fmt.Errorf("package %q does not exist", packageName)
|
||||
}
|
||||
|
||||
func TestValidatePackageVersion(t *testing.T) {
|
||||
testKernelRelease := "test-kernel-release"
|
||||
manager := testPackageManager{
|
||||
packageVersions: map[string]string{
|
||||
"foo": "1.0.0",
|
||||
"bar": "2.1.0",
|
||||
"bar-" + testKernelRelease: "3.0.0",
|
||||
},
|
||||
}
|
||||
v := &packageValidator{
|
||||
reporter: DefaultReporter,
|
||||
kernelRelease: testKernelRelease,
|
||||
}
|
||||
for _, test := range []struct {
|
||||
desc string
|
||||
specs []PackageSpec
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "all packages meet the spec",
|
||||
specs: []PackageSpec{
|
||||
{Name: "foo", VersionRange: ">=1.0"},
|
||||
{Name: "bar", VersionRange: ">=2.0 <= 3.0"},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "package version does not meet the spec",
|
||||
specs: []PackageSpec{
|
||||
{Name: "foo", VersionRange: ">=1.0"},
|
||||
{Name: "bar", VersionRange: ">=3.0"},
|
||||
},
|
||||
err: errors.New("package \"bar 2.1.0\" does not meet the spec \"bar (>=3.0)\""),
|
||||
},
|
||||
{
|
||||
desc: "package not installed",
|
||||
specs: []PackageSpec{
|
||||
{Name: "baz"},
|
||||
},
|
||||
err: errors.New("package \"baz\" does not exist"),
|
||||
},
|
||||
{
|
||||
desc: "use variable in package name",
|
||||
specs: []PackageSpec{
|
||||
{Name: "bar-${KERNEL_RELEASE}", VersionRange: ">=3.0"},
|
||||
},
|
||||
},
|
||||
} {
|
||||
_, err := v.validate(test.specs, manager)
|
||||
if test.err == nil && err != nil {
|
||||
t.Errorf("%s: v.validate(): err = %s", test.desc, err)
|
||||
}
|
||||
if test.err != nil {
|
||||
if err == nil {
|
||||
t.Errorf("%s: v.validate() is expected to fail.", test.desc)
|
||||
} else if test.err.Error() != err.Error() {
|
||||
t.Errorf("%s: v.validate(): err = %q, want = %q", test.desc, err, test.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyPackageOverride(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
overrides []PackageSpecOverride
|
||||
osDistro string
|
||||
specs []PackageSpec
|
||||
expected []PackageSpec
|
||||
}{
|
||||
{
|
||||
specs: []PackageSpec{{Name: "foo", VersionRange: ">=1.0"}},
|
||||
expected: []PackageSpec{{Name: "foo", VersionRange: ">=1.0"}},
|
||||
},
|
||||
{
|
||||
osDistro: "ubuntu",
|
||||
overrides: []PackageSpecOverride{
|
||||
{
|
||||
OSDistro: "ubuntu",
|
||||
Subtractions: []PackageSpec{{Name: "foo"}},
|
||||
Additions: []PackageSpec{{Name: "bar", VersionRange: ">=2.0"}},
|
||||
},
|
||||
},
|
||||
specs: []PackageSpec{{Name: "foo", VersionRange: ">=1.0"}},
|
||||
expected: []PackageSpec{{Name: "bar", VersionRange: ">=2.0"}},
|
||||
},
|
||||
{
|
||||
osDistro: "ubuntu",
|
||||
overrides: []PackageSpecOverride{
|
||||
{
|
||||
OSDistro: "debian",
|
||||
Subtractions: []PackageSpec{{Name: "foo"}},
|
||||
},
|
||||
},
|
||||
specs: []PackageSpec{{Name: "foo", VersionRange: ">=1.0"}},
|
||||
expected: []PackageSpec{{Name: "foo", VersionRange: ">=1.0"}},
|
||||
},
|
||||
} {
|
||||
got := applyPackageSpecOverride(test.specs, test.overrides, test.osDistro)
|
||||
if !reflect.DeepEqual(test.expected, got) {
|
||||
t.Errorf("applyPackageSpecOverride(%+v, %+v, %s) = %+v, want = %+v", test.specs, test.overrides, test.osDistro, got, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
78
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/report.go
generated
vendored
Normal file
78
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/report.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright 2016 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 system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// ValidationResultType is type of the validation result. Different validation results
|
||||
// corresponds to different colors.
|
||||
type ValidationResultType int32
|
||||
|
||||
const (
|
||||
good ValidationResultType = iota
|
||||
bad
|
||||
warn
|
||||
)
|
||||
|
||||
// color is the color of the message.
|
||||
type color int32
|
||||
|
||||
const (
|
||||
red color = 31
|
||||
green = 32
|
||||
yellow = 33
|
||||
white = 37
|
||||
)
|
||||
|
||||
func colorize(s string, c color) string {
|
||||
return fmt.Sprintf("\033[0;%dm%s\033[0m", c, s)
|
||||
}
|
||||
|
||||
// The default reporter for the system verification test
|
||||
type StreamReporter struct {
|
||||
// The stream that this reporter is writing to
|
||||
WriteStream io.Writer
|
||||
}
|
||||
|
||||
func (dr *StreamReporter) Report(key, value string, resultType ValidationResultType) error {
|
||||
var c color
|
||||
switch resultType {
|
||||
case good:
|
||||
c = green
|
||||
case bad:
|
||||
c = red
|
||||
case warn:
|
||||
c = yellow
|
||||
default:
|
||||
c = white
|
||||
}
|
||||
if dr.WriteStream == nil {
|
||||
return fmt.Errorf("WriteStream has to be defined for this reporter")
|
||||
}
|
||||
|
||||
fmt.Fprintf(dr.WriteStream, "%s: %s\n", colorize(key, white), colorize(value, c))
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultReporter is the default Reporter
|
||||
var DefaultReporter = &StreamReporter{
|
||||
WriteStream: os.Stdout,
|
||||
}
|
269
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/specs/gke.yaml
generated
vendored
Normal file
269
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/specs/gke.yaml
generated
vendored
Normal file
@@ -0,0 +1,269 @@
|
||||
# This is the system spec that must be satisfied by the images running on GKE.
|
||||
|
||||
os: Linux
|
||||
|
||||
kernelSpec:
|
||||
versions:
|
||||
# GKE requires kernel version 4.4+.
|
||||
- '4\.[4-9].*'
|
||||
- '4\.[1-9][0-9].*'
|
||||
- '[5-9].*'
|
||||
|
||||
# Required kernel configurations -- the configuration must be set to "y" or
|
||||
# "m".
|
||||
required:
|
||||
# The configurations required by virtual machine or cloud provider.
|
||||
|
||||
- name: BOOTPARAM_HARDLOCKUP_PANIC
|
||||
description: 'Enable the kernel to panic on "hard lockups".'
|
||||
- name: BOOTPARAM_SOFTLOCKUP_PANIC
|
||||
description: 'Enable the kernel to panic on "soft lockups".'
|
||||
- name: PANIC_ON_OOPS
|
||||
description: 'Enable the kernel to panic when it oops.'
|
||||
- name: PVPANIC
|
||||
description: 'Enable the VM (guest) to communicate panic events with the
|
||||
host.'
|
||||
- name: DMIID
|
||||
description: 'Make sure /sys/class/dmi is exported - cAdvisor currently
|
||||
uses this to determine which the cloud provider it is: aws, azure, or
|
||||
gce, etc'
|
||||
- name: ACPI_BUTTON
|
||||
description: 'Enable the software-controlled power management, and required
|
||||
by reset or stop button of GCE console.'
|
||||
|
||||
# The configurations required by network.
|
||||
|
||||
- name: INET
|
||||
description: 'Enable TCP/IP networking.'
|
||||
- name: VXLAN
|
||||
description: 'Required by the overlay networking in Kubernetes.'
|
||||
- name: IP_SET
|
||||
description: 'Required by Kubernetes network policy.'
|
||||
- name: IP_SET_HASH_IP
|
||||
description: 'This introduces hash:ip set type support, which is required
|
||||
by Kubernetes Calico networking.'
|
||||
- name: IPVLAN
|
||||
description: 'Required by IPVLAN feature.'
|
||||
- name: IPV6
|
||||
description: 'Required by IPVLAN feature.'
|
||||
- name: IP6_NF_IPTABLES
|
||||
description: 'Required by kube-proxy.'
|
||||
- name: IP_NF_TARGET_REDIRECT
|
||||
alias:
|
||||
- NETFILTER_XT_TARGET_REDIRECT
|
||||
description: 'Enabled REDIRECT: all incoming connections are mapped onto
|
||||
the incoming interface''s address, causing the packets to come to the
|
||||
local machine instead of passing through. This is required by
|
||||
kube-proxy.'
|
||||
- name: NETFILTER_XT_MATCH_COMMENT
|
||||
description: 'This option adds a "comment" dummy-match, which allows you to
|
||||
put comments in your iptables ruleset. Today''s kube-proxy implementation
|
||||
depends on this feature.'
|
||||
# This is not critical, but debian-based container-vm kernel module study
|
||||
# shows that many customers' nodes have loaded those kernel modules. We
|
||||
# suspect sysdig module depends on these set of kernel modules for
|
||||
# monitoring.
|
||||
- name: PACKET_DIAG
|
||||
description: 'Required by ss (similar to netstat) tools to display Linux
|
||||
TCP / UDP network and socket information.'
|
||||
- name: UNIX_DIAG
|
||||
description: 'Required by ss (similar to netstat) tools to display Linux
|
||||
TCP / UDP network and socket information.'
|
||||
- name: INET_DIAG
|
||||
description: 'Required by ss (similar to netstat) tools to display Linux
|
||||
TCP / UDP network and socket information.'
|
||||
- name: INET_TCP_DIAG
|
||||
description: 'Required by ss (similar to netstat) tools to display Linux
|
||||
TCP / UDP network and socket information.'
|
||||
- name: INET_UDP_DIAG
|
||||
description: 'Required by ss (similar to netstat) tools to display Linux
|
||||
TCP / UDP network and socket information.'
|
||||
- name: NETLINK_DIAG
|
||||
description: 'Required by ss (similar to netstat) tools to display Linux
|
||||
TCP / UDP network and socket information.'
|
||||
|
||||
# The configurations are required by filesystem.
|
||||
|
||||
- name: EXT4_FS
|
||||
- name: DEBUG_FS
|
||||
- name: PROC_FS
|
||||
- name: XFS_FS
|
||||
- name: SCSI_PROC_FS
|
||||
# Currently Kubelet supports three docker graph drivers: overlay, aufs, and
|
||||
# devicemapper due to the legacy reason. But for GKE, we plan to only support
|
||||
# overlayfs.
|
||||
- name: OVERLAY_FS
|
||||
description: 'Enable OverlayFS, which will be the only docker graph driver
|
||||
supported on GKE.'
|
||||
- name: NFS_FS
|
||||
description: 'Required by NFS support.'
|
||||
- name: AUTOFS4_FS
|
||||
description: 'Required by NFS support.'
|
||||
- name: NFS_FSCACHE
|
||||
description: 'Required by NFS support.'
|
||||
- name: FSCACHE
|
||||
description: 'Required by NFS support.'
|
||||
- name: CACHEFILES
|
||||
description: 'Required by NFS support.'
|
||||
- name: FUSE_FS
|
||||
description: 'Required by GlusterFS support.'
|
||||
- name: BCACHE
|
||||
# TODO(yguo0905): Add a description for BCACHE.
|
||||
|
||||
# The configuration required by the resource isolation, accounting, and
|
||||
# management.
|
||||
|
||||
- name: NAMESPACES
|
||||
description: 'Required by kubelet and docker. Enabling it allows the
|
||||
processes within a pod or a container to have their own view of the
|
||||
system.'
|
||||
- name: IPC_NS
|
||||
description: 'Required by kubelet and docker. Enabling it allows the
|
||||
processes within a pod or a container to have their own view of the
|
||||
system.'
|
||||
- name: NET_NS
|
||||
description: 'Required by kubelet and docker. Enabling it allows the
|
||||
processes within a pod or a container to have their own view of the
|
||||
system.'
|
||||
- name: PID_NS
|
||||
description: 'Required by kubelet and docker. Enabling it allows the
|
||||
processes within a pod or a container to have their own view of the
|
||||
system.'
|
||||
- name: UTS_NS
|
||||
description: 'Required by kubelet and docker. Enabling it allows the
|
||||
processes within a pod or a container to have their own view of the
|
||||
system.'
|
||||
- name: CGROUPS
|
||||
description: 'Required by kubelet and docker. The resource usage of the
|
||||
processes within a pod or a container can be monitored, accounted, and
|
||||
controlled.'
|
||||
- name: CGROUP_CPUACCT
|
||||
description: 'Required by kubelet and docker. The resource usage of the
|
||||
processes within a pod or a container can be monitored, accounted, and
|
||||
controlled.'
|
||||
- name: CGROUP_DEVICE
|
||||
description: 'Required by kubelet and docker. The resource usage of the
|
||||
processes within a pod or a container can be monitored, accounted, and
|
||||
controlled.'
|
||||
- name: CGROUP_SCHED
|
||||
description: 'Required by kubelet and docker. The resource usage of the
|
||||
processes within a pod or a container can be monitored, accounted, and
|
||||
controlled.'
|
||||
- name: CPUSETS
|
||||
description: 'Required by kubelet and docker. The resource usage of the
|
||||
processes within a pod or a container can be monitored, accounted, and
|
||||
controlled.'
|
||||
- name: MEMCG
|
||||
description: 'Required by kubelet and docker. The resource usage of the
|
||||
processes within a pod or a container can be monitored, accounted, and
|
||||
controlled.'
|
||||
- name: QUOTA
|
||||
description: 'Required by kubelet to have an accurate and efficient disk
|
||||
space and inode accounting, and eventually to limit the usage.'
|
||||
|
||||
# The security-related configurations
|
||||
|
||||
- name: SECCOMP
|
||||
description: 'Enabled the SECCOMP application API.'
|
||||
- name: SECURITY_APPARMOR
|
||||
description: 'Enable for AppArmor support.'
|
||||
- name: CC_STACKPROTECTOR_STRONG
|
||||
alias:
|
||||
- CONFIG_CC_STACKPROTECTOR_REGULAR
|
||||
CONFIG_CC_STACKPROTECTOR_ALL
|
||||
description: 'Add the stack buffer overflow protections.'
|
||||
- name: STRICT_DEVMEM
|
||||
description: 'Required for blocking the direct physical memory access.'
|
||||
- name: IMA
|
||||
description: 'Required for security-related logging and auditing.'
|
||||
- name: AUDIT
|
||||
description: 'Required for security-related logging and auditing.'
|
||||
- name: AUDITSYSCALL
|
||||
description: 'Required for security-related logging and auditing.'
|
||||
|
||||
# Misc. configurations
|
||||
|
||||
- name: MODULES
|
||||
description: 'Required for loadable module support.'
|
||||
- name: PRINTK
|
||||
description: 'Required for kernel logging message.'
|
||||
- name: MMU
|
||||
description: 'Required for memory management hardware and mmap() system
|
||||
call.'
|
||||
|
||||
packageSpecs:
|
||||
- name: apparmor
|
||||
versionRange: '>=2.10.1'
|
||||
- name: apparmor-profiles
|
||||
versionRange: '>=2.10.1'
|
||||
- name: audit
|
||||
versionRange: '>=2.5.0'
|
||||
- name: autofs
|
||||
versionRange: '>=5.0.7'
|
||||
- name: bash
|
||||
versionRange: '>=4.3'
|
||||
- name: bridge-utils
|
||||
versionRange: '>=1.5'
|
||||
- name: cloud-init
|
||||
versionRange: '>=0.7.6'
|
||||
- name: coreutils
|
||||
versionRange: '>=8.24'
|
||||
- name: dbus
|
||||
versionRange: '>=1.6.8'
|
||||
- name: e2fsprogs
|
||||
versionRange: '>=1.4.3'
|
||||
- name: ebtables
|
||||
versionRange: '>=2.0.10'
|
||||
- name: ethtool
|
||||
versionRange: '>=3.18'
|
||||
- name: iproute2
|
||||
versionRange: '>=4.2.0'
|
||||
- name: less
|
||||
versionRange: '>=481'
|
||||
- name: netcat-openbsd
|
||||
versionRange: '>=1.10'
|
||||
- name: python
|
||||
versionRange: '>=2.7.10'
|
||||
- name: pv
|
||||
versionRange: '>=1.3.4'
|
||||
- name: sudo
|
||||
versionRange: '>=1.8.12'
|
||||
- name: systemd
|
||||
versionRange: '>=225'
|
||||
- name: tar
|
||||
versionRange: '>=1.28'
|
||||
- name: util-linux
|
||||
versionRange: '>=2.27.1'
|
||||
- name: wget
|
||||
versionRange: '>=1.18'
|
||||
- name: gce-compute-image-packages
|
||||
versionRange: '>=20170227'
|
||||
# TODO(yguo0905): Figure out whether watchdog is required.
|
||||
|
||||
# packageSpecOverrides contains the OS distro specific package requirements.
|
||||
packageSpecOverrides:
|
||||
# The following overrides apply to all Ubuntu images.
|
||||
- osDistro: ubuntu
|
||||
subtractions:
|
||||
- name: apparmor-profiles
|
||||
description: 'On Ubuntu the apparmor profiles are shipped with individual
|
||||
application package, so the "apparmor-profiles" package is not required.'
|
||||
- name: audit
|
||||
description: 'On Ubuntu the equivalent package is called "auditd", so the
|
||||
"audit" package is not required and "auditd" exists in the additions.'
|
||||
- name: wget
|
||||
description: 'The Ubuntu 1604-xenial image includes wget 1.17.1, which does
|
||||
not satisfy the spec (>=1.18), but meets the functionality requirements.
|
||||
Therefore, it is removed from the base spec. See wget in the additions.'
|
||||
additions:
|
||||
- name: auditd
|
||||
versionRange: '>=2.4.5'
|
||||
description: 'auditd 2.4.5 currently satisfies the requirements because the
|
||||
GKE features that require auditd 2.5 are not yet available.'
|
||||
- name: grub-common
|
||||
versionRange: '>=2.2'
|
||||
description: 'grub is the bootloader on Ubuntu.'
|
||||
- name: wget
|
||||
versionRange: '>=1.17.1'
|
||||
description: 'wget 1.17.1 satisfies the functionality requirements but does
|
||||
not meet the spec, which is fine'
|
124
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/types.go
generated
vendored
Normal file
124
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/types.go
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
Copyright 2016 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 system
|
||||
|
||||
// KernelConfig defines one kernel configration item.
|
||||
type KernelConfig struct {
|
||||
// Name is the general name of the kernel configuration. It is used to
|
||||
// match kernel configuration.
|
||||
Name string `json:"name,omitempty"`
|
||||
// TODO(yguo0905): Support the "or" operation, which will be the same
|
||||
// as the "aliases".
|
||||
//
|
||||
// Aliases are aliases of the kernel configuration. Some configuration
|
||||
// has different names in different kernel version. Names of different
|
||||
// versions will be treated as aliases.
|
||||
Aliases []string `json:"aliases,omitempty"`
|
||||
// Description is the description of the kernel configuration, for example:
|
||||
// * What is it used for?
|
||||
// * Why is it needed?
|
||||
// * Who needs it?
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// KernelSpec defines the specification for the kernel. Currently, it contains
|
||||
// specification for:
|
||||
// * Kernel Version
|
||||
// * Kernel Configuration
|
||||
type KernelSpec struct {
|
||||
// Versions define supported kernel version. It is a group of regexps.
|
||||
Versions []string `json:"versions,omitempty"`
|
||||
// Required contains all kernel configurations required to be enabled
|
||||
// (built in or as module).
|
||||
Required []KernelConfig `json:"required,omitempty"`
|
||||
// Optional contains all kernel configurations are required for optional
|
||||
// features.
|
||||
Optional []KernelConfig `json:"optional,omitempty"`
|
||||
// Forbidden contains all kernel configurations which areforbidden (disabled
|
||||
// or not set)
|
||||
Forbidden []KernelConfig `json:"forbidden,omitempty"`
|
||||
}
|
||||
|
||||
// DockerSpec defines the requirement configuration for docker. Currently, it only
|
||||
// contains spec for graph driver.
|
||||
type DockerSpec struct {
|
||||
// Version is a group of regex matching supported docker versions.
|
||||
Version []string `json:"version,omitempty"`
|
||||
// GraphDriver is the graph drivers supported by kubelet.
|
||||
GraphDriver []string `json:"graphDriver,omitempty"`
|
||||
}
|
||||
|
||||
// RuntimeSpec is the abstract layer for different runtimes. Different runtimes
|
||||
// should put their spec inside the RuntimeSpec.
|
||||
type RuntimeSpec struct {
|
||||
*DockerSpec `json:",inline"`
|
||||
}
|
||||
|
||||
// PackageSpec defines the required packages and their versions.
|
||||
// PackageSpec is only supported on OS distro with Debian package manager.
|
||||
//
|
||||
// TODO(yguo0905): Support operator OR of multiple packages for the case where
|
||||
// either "foo (>=1.0)" or "bar (>=2.0)" is required.
|
||||
type PackageSpec struct {
|
||||
// Name is the name of the package to be checked.
|
||||
Name string `json:"name,omitempty"`
|
||||
// VersionRange represents a range of versions that the package must
|
||||
// satisfy. Note that the version requirement will not be enforced if
|
||||
// the version range is empty. For example,
|
||||
// - "" would match any versions but the package must be installed.
|
||||
// - ">=1" would match "1.0.0", "1.0.1", "1.1.0", and "2.0".
|
||||
// - ">1.0 <2.0" would match between both ranges, so "1.1.1" and "1.8.7"
|
||||
// but not "1.0.0" or "2.0.0".
|
||||
// - "<2.0.0 || >=3.0.0" would match "1.0.0" and "3.0.0" but not "2.0.0".
|
||||
VersionRange string `json:"versionRange,omitempty"`
|
||||
// Description explains the reason behind this package requirements.
|
||||
//
|
||||
// TODO(yguo0905): Print the description where necessary.
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// PackageSpecOverride defines the overrides on the PackageSpec for an OS
|
||||
// distro.
|
||||
type PackageSpecOverride struct {
|
||||
// OSDistro identifies to which OS distro this override applies.
|
||||
// Must be "ubuntu", "cos" or "coreos".
|
||||
OSDistro string `json:"osDistro,omitempty"`
|
||||
// Subtractions is a list of package names that are excluded from the
|
||||
// package spec.
|
||||
Subtractions []PackageSpec `json:"subtractions,omitempty"`
|
||||
// Additions is a list of additional package requirements included the
|
||||
// package spec.
|
||||
Additions []PackageSpec `json:"additions,omitempty"`
|
||||
}
|
||||
|
||||
// SysSpec defines the requirement of supported system. Currently, it only contains
|
||||
// spec for OS, Kernel and Cgroups.
|
||||
type SysSpec struct {
|
||||
// OS is the operating system of the SysSpec.
|
||||
OS string `json:"os,omitempty"`
|
||||
// KernelConfig defines the spec for kernel.
|
||||
KernelSpec KernelSpec `json:"kernelSpec,omitempty"`
|
||||
// Cgroups is the required cgroups.
|
||||
Cgroups []string `json:"cgroups,omitempty"`
|
||||
// RuntimeSpec defines the spec for runtime.
|
||||
RuntimeSpec RuntimeSpec `json:"runtimeSpec,omitempty"`
|
||||
// PackageSpec defines the required packages and their versions.
|
||||
PackageSpecs []PackageSpec `json:"packageSpecs,omitempty"`
|
||||
// PackageSpec defines the overrides of the required packages and their
|
||||
// versions for an OS distro.
|
||||
PackageSpecOverrides []PackageSpecOverride `json:"packageSpecOverrides,omitempty"`
|
||||
}
|
83
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/types_unix.go
generated
vendored
Normal file
83
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/types_unix.go
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
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 system
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// dockerEndpoint is the os specific endpoint for docker communication
|
||||
const dockerEndpoint = "unix:///var/run/docker.sock"
|
||||
|
||||
// DefaultSysSpec is the default SysSpec for Linux
|
||||
var DefaultSysSpec = SysSpec{
|
||||
OS: "Linux",
|
||||
KernelSpec: KernelSpec{
|
||||
Versions: []string{`3\.[1-9][0-9].*`, `4\..*`}, // Requires 3.10+ or 4+
|
||||
// TODO(random-liu): Add more config
|
||||
// TODO(random-liu): Add description for each kernel configuration:
|
||||
Required: []KernelConfig{
|
||||
{Name: "NAMESPACES"},
|
||||
{Name: "NET_NS"},
|
||||
{Name: "PID_NS"},
|
||||
{Name: "IPC_NS"},
|
||||
{Name: "UTS_NS"},
|
||||
{Name: "CGROUPS"},
|
||||
{Name: "CGROUP_CPUACCT"},
|
||||
{Name: "CGROUP_DEVICE"},
|
||||
{Name: "CGROUP_FREEZER"},
|
||||
{Name: "CGROUP_SCHED"},
|
||||
{Name: "CPUSETS"},
|
||||
{Name: "MEMCG"},
|
||||
{Name: "INET"},
|
||||
{Name: "EXT4_FS"},
|
||||
{Name: "PROC_FS"},
|
||||
{Name: "NETFILTER_XT_TARGET_REDIRECT", Aliases: []string{"IP_NF_TARGET_REDIRECT"}},
|
||||
{Name: "NETFILTER_XT_MATCH_COMMENT"},
|
||||
},
|
||||
Optional: []KernelConfig{
|
||||
{Name: "OVERLAY_FS", Aliases: []string{"OVERLAYFS_FS"}, Description: "Required for overlayfs."},
|
||||
{Name: "AUFS_FS", Description: "Required for aufs."},
|
||||
{Name: "BLK_DEV_DM", Description: "Required for devicemapper."},
|
||||
},
|
||||
Forbidden: []KernelConfig{},
|
||||
},
|
||||
Cgroups: []string{"cpu", "cpuacct", "cpuset", "devices", "freezer", "memory"},
|
||||
RuntimeSpec: RuntimeSpec{
|
||||
DockerSpec: &DockerSpec{
|
||||
Version: []string{`1\.1[1-3]\..*`, `17\.0[3,6,9]\..*`, `18\.06\..*`},
|
||||
GraphDriver: []string{"aufs", "overlay", "overlay2", "devicemapper", "zfs"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// KernelValidatorHelperImpl is the 'linux' implementation of KernelValidatorHelper
|
||||
type KernelValidatorHelperImpl struct{}
|
||||
|
||||
var _ KernelValidatorHelper = &KernelValidatorHelperImpl{}
|
||||
|
||||
// GetKernelReleaseVersion returns the kernel release version (ex. 4.4.0-96-generic) as a string
|
||||
func (o *KernelValidatorHelperImpl) GetKernelReleaseVersion() (string, error) {
|
||||
releaseVersion, err := exec.Command("uname", "-r").CombinedOutput()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(string(releaseVersion)), nil
|
||||
}
|
60
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/types_windows.go
generated
vendored
Normal file
60
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/types_windows.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
// +build windows
|
||||
|
||||
/*
|
||||
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 system
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// dockerEndpoint is the os specific endpoint for docker communication
|
||||
const dockerEndpoint = "npipe:////./pipe/docker_engine"
|
||||
|
||||
// DefaultSysSpec is the default SysSpec for Windows
|
||||
var DefaultSysSpec = SysSpec{
|
||||
OS: "Microsoft Windows Server 2016",
|
||||
KernelSpec: KernelSpec{
|
||||
Versions: []string{`10\.0\.1439[3-9]`, `10\.0\.14[4-9][0-9]{2}`, `10\.0\.1[5-9][0-9]{3}`, `10\.0\.[2-9][0-9]{4}`, `10\.[1-9]+\.[0-9]+`}, //requires >= '10.0.14393'
|
||||
Required: []KernelConfig{},
|
||||
Optional: []KernelConfig{},
|
||||
Forbidden: []KernelConfig{},
|
||||
},
|
||||
Cgroups: []string{},
|
||||
RuntimeSpec: RuntimeSpec{
|
||||
DockerSpec: &DockerSpec{
|
||||
Version: []string{`18\.06\..*`}, //Requires [18.06] or later
|
||||
GraphDriver: []string{"windowsfilter"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// KernelValidatorHelperImpl is the 'windows' implementation of KernelValidatorHelper
|
||||
type KernelValidatorHelperImpl struct{}
|
||||
|
||||
var _ KernelValidatorHelper = &KernelValidatorHelperImpl{}
|
||||
|
||||
// GetKernelRelease returns the windows release version (ex. 10.0.14393) as a string
|
||||
func (o *KernelValidatorHelperImpl) GetKernelReleaseVersion() (string, error) {
|
||||
args := []string{"(Get-CimInstance Win32_OperatingSystem).Version"}
|
||||
releaseVersion, err := exec.Command("powershell", args...).Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(string(releaseVersion)), nil
|
||||
}
|
72
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/validators.go
generated
vendored
Normal file
72
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/system/validators.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
Copyright 2016 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 system
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/apimachinery/pkg/util/errors"
|
||||
)
|
||||
|
||||
// Validator is the interface for all validators.
|
||||
type Validator interface {
|
||||
// Name is the name of the validator.
|
||||
Name() string
|
||||
// Validate is the validate function.
|
||||
Validate(SysSpec) (error, error)
|
||||
}
|
||||
|
||||
// Reporter is the interface for the reporters for the validators.
|
||||
type Reporter interface {
|
||||
// Report reports the results of the system verification
|
||||
Report(string, string, ValidationResultType) error
|
||||
}
|
||||
|
||||
// Validate uses validators to validate the system and returns a warning or error.
|
||||
func Validate(spec SysSpec, validators []Validator) (error, error) {
|
||||
var errs []error
|
||||
var warns []error
|
||||
|
||||
for _, v := range validators {
|
||||
glog.Infof("Validating %s...", v.Name())
|
||||
warn, err := v.Validate(spec)
|
||||
errs = append(errs, err)
|
||||
warns = append(warns, warn)
|
||||
}
|
||||
return errors.NewAggregate(warns), errors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
// ValidateSpec uses all default validators to validate the system and writes to stdout.
|
||||
func ValidateSpec(spec SysSpec, runtime string) (error, error) {
|
||||
// OS-level validators.
|
||||
var osValidators = []Validator{
|
||||
&OSValidator{Reporter: DefaultReporter},
|
||||
&KernelValidator{Reporter: DefaultReporter},
|
||||
&CgroupsValidator{Reporter: DefaultReporter},
|
||||
&packageValidator{reporter: DefaultReporter},
|
||||
}
|
||||
// Docker-specific validators.
|
||||
var dockerValidators = []Validator{
|
||||
&DockerValidator{Reporter: DefaultReporter},
|
||||
}
|
||||
|
||||
validators := osValidators
|
||||
switch runtime {
|
||||
case "docker":
|
||||
validators = append(validators, dockerValidators...)
|
||||
}
|
||||
return Validate(spec, validators)
|
||||
}
|
6
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/template_test.go
generated
vendored
6
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/template_test.go
generated
vendored
@@ -21,9 +21,9 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
validTmpl = "image: {{ .ImageRepository }}/pause-{{ .Arch }}:3.1"
|
||||
validTmplOut = "image: k8s.gcr.io/pause-amd64:3.1"
|
||||
doNothing = "image: k8s.gcr.io/pause-amd64:3.1"
|
||||
validTmpl = "image: {{ .ImageRepository }}/pause:3.1"
|
||||
validTmplOut = "image: k8s.gcr.io/pause:3.1"
|
||||
doNothing = "image: k8s.gcr.io/pause:3.1"
|
||||
invalidTmpl1 = "{{ .baz }/d}"
|
||||
invalidTmpl2 = "{{ !foobar }}"
|
||||
)
|
||||
|
104
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/version.go
generated
vendored
104
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/version.go
generated
vendored
@@ -17,13 +17,22 @@ limitations under the License.
|
||||
package util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
netutil "k8s.io/apimachinery/pkg/util/net"
|
||||
versionutil "k8s.io/kubernetes/pkg/util/version"
|
||||
pkgversion "k8s.io/kubernetes/pkg/version"
|
||||
)
|
||||
|
||||
const (
|
||||
getReleaseVersionTimeout = time.Duration(10 * time.Second)
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -67,9 +76,26 @@ func KubernetesReleaseVersion(version string) (string, error) {
|
||||
return ver, nil
|
||||
}
|
||||
|
||||
// kubeReleaseLabelRegex matches labels such as: latest, latest-1, latest-1.10
|
||||
if kubeReleaseLabelRegex.MatchString(versionLabel) {
|
||||
var clientVersion string
|
||||
// Try to obtain a client version.
|
||||
clientVersion, _ = kubeadmVersion(pkgversion.Get().String())
|
||||
// Fetch version from the internet.
|
||||
url := fmt.Sprintf("%s/%s.txt", bucketURL, versionLabel)
|
||||
body, err := fetchFromURL(url)
|
||||
body, err := fetchFromURL(url, getReleaseVersionTimeout)
|
||||
if err != nil {
|
||||
// If the network operaton was successful but the server did not reply with StatusOK
|
||||
if body != "" {
|
||||
return "", err
|
||||
}
|
||||
// Handle air-gapped environments by falling back to the client version.
|
||||
glog.Infof("could not fetch a Kubernetes version from the internet: %v", err)
|
||||
glog.Infof("falling back to the local client version: %s", clientVersion)
|
||||
return KubernetesReleaseVersion(clientVersion)
|
||||
}
|
||||
// both the client and the remote version are obtained; validate them and pick a stable version
|
||||
body, err = validateStableVersion(body, clientVersion)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -132,19 +158,83 @@ func splitVersion(version string) (string, string, error) {
|
||||
}
|
||||
|
||||
// Internal helper: return content of URL
|
||||
func fetchFromURL(url string) (string, error) {
|
||||
client := &http.Client{Transport: netutil.SetOldTransportDefaults(&http.Transport{})}
|
||||
func fetchFromURL(url string, timeout time.Duration) (string, error) {
|
||||
glog.V(2).Infof("fetching Kubernetes version from URL: %s", url)
|
||||
client := &http.Client{Timeout: timeout, Transport: netutil.SetOldTransportDefaults(&http.Transport{})}
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to get URL %q: %s", url, err.Error())
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", fmt.Errorf("unable to fetch file. URL: %q Status: %v", url, resp.Status)
|
||||
}
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to read content of URL %q: %s", url, err.Error())
|
||||
}
|
||||
return strings.TrimSpace(string(body)), nil
|
||||
bodyString := strings.TrimSpace(string(body))
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
msg := fmt.Sprintf("unable to fetch file. URL: %q, status: %v", url, resp.Status)
|
||||
return bodyString, errors.New(msg)
|
||||
}
|
||||
return bodyString, nil
|
||||
}
|
||||
|
||||
// kubeadmVersion returns the version of the client without metadata.
|
||||
func kubeadmVersion(info string) (string, error) {
|
||||
v, err := versionutil.ParseSemantic(info)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("kubeadm version error: %v", err)
|
||||
}
|
||||
// There is no utility in versionutil to get the version without the metadata,
|
||||
// so this needs some manual formatting.
|
||||
// Discard offsets after a release label and keep the labels down to e.g. `alpha.0` instead of
|
||||
// including the offset e.g. `alpha.0.206`. This is done to comply with GCR image tags.
|
||||
pre := v.PreRelease()
|
||||
patch := v.Patch()
|
||||
if len(pre) > 0 {
|
||||
if patch > 0 {
|
||||
// If the patch version is more than zero, decrement it and remove the label.
|
||||
// this is done to comply with the latest stable patch release.
|
||||
patch = patch - 1
|
||||
pre = ""
|
||||
} else {
|
||||
split := strings.Split(pre, ".")
|
||||
if len(split) > 2 {
|
||||
pre = split[0] + "." + split[1] // Exclude the third element
|
||||
} else if len(split) < 2 {
|
||||
pre = split[0] + ".0" // Append .0 to a partial label
|
||||
}
|
||||
pre = "-" + pre
|
||||
}
|
||||
}
|
||||
vStr := fmt.Sprintf("v%d.%d.%d%s", v.Major(), v.Minor(), patch, pre)
|
||||
return vStr, nil
|
||||
}
|
||||
|
||||
// Validate if the remote version is one Minor release newer than the client version.
|
||||
// This is done to conform with "stable-X" and only allow remote versions from
|
||||
// the same Patch level release.
|
||||
func validateStableVersion(remoteVersion, clientVersion string) (string, error) {
|
||||
if clientVersion == "" {
|
||||
glog.Infof("could not obtain client version; using remote version: %s", remoteVersion)
|
||||
return remoteVersion, nil
|
||||
}
|
||||
|
||||
verRemote, err := versionutil.ParseGeneric(remoteVersion)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("remote version error: %v", err)
|
||||
}
|
||||
verClient, err := versionutil.ParseGeneric(clientVersion)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("client version error: %v", err)
|
||||
}
|
||||
// If the remote Major version is bigger or if the Major versions are the same,
|
||||
// but the remote Minor is bigger use the client version release. This handles Major bumps too.
|
||||
if verClient.Major() < verRemote.Major() ||
|
||||
(verClient.Major() == verRemote.Major()) && verClient.Minor() < verRemote.Minor() {
|
||||
estimatedRelease := fmt.Sprintf("stable-%d.%d", verClient.Major(), verClient.Minor())
|
||||
glog.Infof("remote version is much newer: %s; falling back to: %s", remoteVersion, estimatedRelease)
|
||||
return estimatedRelease, nil
|
||||
}
|
||||
return remoteVersion, nil
|
||||
}
|
||||
|
162
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/version_test.go
generated
vendored
162
vendor/k8s.io/kubernetes/cmd/kubeadm/app/util/version_test.go
generated
vendored
@@ -290,3 +290,165 @@ func TestNormalizedBuildVersionVersion(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestKubeadmVersion(t *testing.T) {
|
||||
type T struct {
|
||||
name string
|
||||
input string
|
||||
output string
|
||||
outputError bool
|
||||
parsingError bool
|
||||
}
|
||||
cases := []T{
|
||||
{
|
||||
name: "valid version with label and metadata",
|
||||
input: "v1.8.0-alpha.2.1231+afabd012389d53a",
|
||||
output: "v1.8.0-alpha.2",
|
||||
},
|
||||
{
|
||||
name: "valid version with label and extra metadata",
|
||||
input: "v1.8.0-alpha.2.1231+afabd012389d53a.extra",
|
||||
output: "v1.8.0-alpha.2",
|
||||
},
|
||||
{
|
||||
name: "valid patch version with label and extra metadata",
|
||||
input: "v1.11.3-beta.0.38+135cc4c1f47994",
|
||||
output: "v1.11.2",
|
||||
},
|
||||
{
|
||||
name: "valid version with label extra",
|
||||
input: "v1.8.0-alpha.2.1231",
|
||||
output: "v1.8.0-alpha.2",
|
||||
},
|
||||
{
|
||||
name: "valid patch version with label",
|
||||
input: "v1.9.11-beta.0",
|
||||
output: "v1.9.10",
|
||||
},
|
||||
{
|
||||
name: "handle version with partial label",
|
||||
input: "v1.8.0-alpha",
|
||||
output: "v1.8.0-alpha.0",
|
||||
},
|
||||
{
|
||||
name: "handle version missing 'v'",
|
||||
input: "1.11.0",
|
||||
output: "v1.11.0",
|
||||
},
|
||||
{
|
||||
name: "valid version without label and metadata",
|
||||
input: "v1.8.0",
|
||||
output: "v1.8.0",
|
||||
},
|
||||
{
|
||||
name: "valid patch version without label and metadata",
|
||||
input: "v1.8.2",
|
||||
output: "v1.8.2",
|
||||
},
|
||||
{
|
||||
name: "invalid version",
|
||||
input: "foo",
|
||||
parsingError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid version with stray dash",
|
||||
input: "v1.9.11-",
|
||||
parsingError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid version without patch release",
|
||||
input: "v1.9",
|
||||
parsingError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid version with label and metadata",
|
||||
input: "v1.8.0-alpha.2.1231+afabd012389d53a",
|
||||
output: "v1.8.0-alpha.3",
|
||||
outputError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
output, err := kubeadmVersion(tc.input)
|
||||
if (err != nil) != tc.parsingError {
|
||||
t.Fatalf("expected error: %v, got: %v", tc.parsingError, err != nil)
|
||||
}
|
||||
if (output != tc.output) != tc.outputError {
|
||||
t.Fatalf("expected output: %s, got: %s, for input: %s", tc.output, output, tc.input)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateStableVersion(t *testing.T) {
|
||||
type T struct {
|
||||
name string
|
||||
remoteVersion string
|
||||
clientVersion string
|
||||
output string
|
||||
expectedError bool
|
||||
}
|
||||
cases := []T{
|
||||
{
|
||||
name: "valid: remote version is newer; return stable label [1]",
|
||||
remoteVersion: "v1.12.0",
|
||||
clientVersion: "v1.11.0",
|
||||
output: "stable-1.11",
|
||||
},
|
||||
{
|
||||
name: "valid: remote version is newer; return stable label [2]",
|
||||
remoteVersion: "v2.0.0",
|
||||
clientVersion: "v1.11.0",
|
||||
output: "stable-1.11",
|
||||
},
|
||||
{
|
||||
name: "valid: remote version is newer; return stable label [3]",
|
||||
remoteVersion: "v2.1.5",
|
||||
clientVersion: "v1.11.5",
|
||||
output: "stable-1.11",
|
||||
},
|
||||
{
|
||||
name: "valid: return the remote version as it is part of the same release",
|
||||
remoteVersion: "v1.11.5",
|
||||
clientVersion: "v1.11.0",
|
||||
output: "v1.11.5",
|
||||
},
|
||||
{
|
||||
name: "valid: return the same version",
|
||||
remoteVersion: "v1.11.0",
|
||||
clientVersion: "v1.11.0",
|
||||
output: "v1.11.0",
|
||||
},
|
||||
{
|
||||
name: "valid: client version is empty; use remote version",
|
||||
remoteVersion: "v1.12.1",
|
||||
clientVersion: "",
|
||||
output: "v1.12.1",
|
||||
},
|
||||
{
|
||||
name: "invalid: error parsing the remote version",
|
||||
remoteVersion: "invalid-version",
|
||||
clientVersion: "v1.12.0",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid: error parsing the client version",
|
||||
remoteVersion: "v1.12.0",
|
||||
clientVersion: "invalid-version",
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
output, err := validateStableVersion(tc.remoteVersion, tc.clientVersion)
|
||||
if (err != nil) != tc.expectedError {
|
||||
t.Fatalf("expected error: %v, got: %v", tc.expectedError, err != nil)
|
||||
}
|
||||
if output != tc.output {
|
||||
t.Fatalf("expected output: %s, got: %s", tc.output, output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user