Add glide.yaml and vendor deps
This commit is contained in:
parent
db918f12ad
commit
5b3d5e81bd
18880 changed files with 5166045 additions and 1 deletions
67
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/BUILD
generated
vendored
Normal file
67
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"addons.go",
|
||||
"apiclient.go",
|
||||
"discovery.go",
|
||||
"kubeconfig.go",
|
||||
"manifests.go",
|
||||
"pki.go",
|
||||
"tokens.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library",
|
||||
"//cmd/kubeadm/app/images:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/errors:go_default_library",
|
||||
"//pkg/api/resource:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//pkg/apis/meta/v1:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
||||
"//pkg/client/unversioned/clientcmd/api:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/registry/core/service/ipallocator:go_default_library",
|
||||
"//pkg/util/cert:go_default_library",
|
||||
"//pkg/util/intstr:go_default_library",
|
||||
"//pkg/util/uuid:go_default_library",
|
||||
"//pkg/util/wait:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"addons_test.go",
|
||||
"apiclient_test.go",
|
||||
"discovery_test.go",
|
||||
"kubeconfig_test.go",
|
||||
"manifests_test.go",
|
||||
"pki_test.go",
|
||||
"tokens_test.go",
|
||||
],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/util/cert:go_default_library",
|
||||
"//pkg/util/intstr:go_default_library",
|
||||
],
|
||||
)
|
||||
264
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/addons.go
generated
vendored
Normal file
264
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/addons.go
generated
vendored
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
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 master
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"path"
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/images"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/resource"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
ipallocator "k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
|
||||
"k8s.io/kubernetes/pkg/util/intstr"
|
||||
)
|
||||
|
||||
func createKubeProxyPodSpec(cfg *kubeadmapi.MasterConfiguration) v1.PodSpec {
|
||||
privilegedTrue := true
|
||||
return v1.PodSpec{
|
||||
HostNetwork: true,
|
||||
SecurityContext: &v1.PodSecurityContext{},
|
||||
Containers: []v1.Container{{
|
||||
Name: kubeProxy,
|
||||
Image: images.GetCoreImage(images.KubeProxyImage, cfg, kubeadmapi.GlobalEnvParams.HyperkubeImage),
|
||||
Command: append(getProxyCommand(cfg), "--kubeconfig=/run/kubeconfig"),
|
||||
SecurityContext: &v1.SecurityContext{Privileged: &privilegedTrue},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: "dbus",
|
||||
MountPath: "/var/run/dbus",
|
||||
ReadOnly: false,
|
||||
},
|
||||
{
|
||||
// TODO there are handful of clever options to get around this, but it's
|
||||
// easier to just mount kubelet's config here; we should probably just
|
||||
// make sure that proxy reads the token and CA cert from /run/secrets
|
||||
// and accepts `--master` at the same time
|
||||
//
|
||||
// clever options include:
|
||||
// - do CSR dance and create kubeconfig and mount it as a secret
|
||||
// - create a service account with a second secret encoding kubeconfig
|
||||
// - use init container to convert known information to kubeconfig
|
||||
// - ...whatever
|
||||
Name: "kubeconfig",
|
||||
MountPath: "/run/kubeconfig",
|
||||
ReadOnly: false,
|
||||
},
|
||||
},
|
||||
}},
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: "kubeconfig",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{Path: path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "kubelet.conf")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "dbus",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{Path: "/var/run/dbus"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createKubeDNSPodSpec(cfg *kubeadmapi.MasterConfiguration) v1.PodSpec {
|
||||
|
||||
dnsPodResources := v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("100m"),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("170Mi"),
|
||||
}
|
||||
|
||||
healthzPodResources := v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10m"),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("50Mi"),
|
||||
}
|
||||
|
||||
kubeDNSPort := int32(10053)
|
||||
dnsmasqPort := int32(53)
|
||||
|
||||
nslookup := fmt.Sprintf("nslookup kubernetes.default.svc.%s 127.0.0.1", cfg.Networking.DNSDomain)
|
||||
|
||||
nslookup = fmt.Sprintf("-cmd=%s:%d >/dev/null && %s:%d >/dev/null",
|
||||
nslookup, dnsmasqPort,
|
||||
nslookup, kubeDNSPort,
|
||||
)
|
||||
|
||||
return v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
// DNS server
|
||||
{
|
||||
Name: "kube-dns",
|
||||
Image: images.GetAddonImage(images.KubeDNSImage),
|
||||
Resources: v1.ResourceRequirements{
|
||||
Limits: dnsPodResources,
|
||||
Requests: dnsPodResources,
|
||||
},
|
||||
Args: []string{
|
||||
fmt.Sprintf("--domain=%s", cfg.Networking.DNSDomain),
|
||||
fmt.Sprintf("--dns-port=%d", kubeDNSPort),
|
||||
// TODO __PILLAR__FEDERATIONS__DOMAIN__MAP__
|
||||
},
|
||||
LivenessProbe: &v1.Probe{
|
||||
Handler: v1.Handler{
|
||||
HTTPGet: &v1.HTTPGetAction{
|
||||
Path: "/healthz",
|
||||
Port: intstr.FromInt(8080),
|
||||
Scheme: v1.URISchemeHTTP,
|
||||
},
|
||||
},
|
||||
InitialDelaySeconds: 60,
|
||||
TimeoutSeconds: 5,
|
||||
SuccessThreshold: 1,
|
||||
FailureThreshold: 1,
|
||||
},
|
||||
// # we poll on pod startup for the Kubernetes master service and
|
||||
// # only setup the /readiness HTTP server once that's available.
|
||||
ReadinessProbe: &v1.Probe{
|
||||
Handler: v1.Handler{
|
||||
HTTPGet: &v1.HTTPGetAction{
|
||||
Path: "/readiness",
|
||||
Port: intstr.FromInt(8081),
|
||||
Scheme: v1.URISchemeHTTP,
|
||||
},
|
||||
},
|
||||
InitialDelaySeconds: 30,
|
||||
TimeoutSeconds: 5,
|
||||
},
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
ContainerPort: kubeDNSPort,
|
||||
Name: "dns-local",
|
||||
Protocol: v1.ProtocolUDP,
|
||||
},
|
||||
{
|
||||
ContainerPort: kubeDNSPort,
|
||||
Name: "dns-tcp-local",
|
||||
Protocol: v1.ProtocolTCP,
|
||||
},
|
||||
},
|
||||
},
|
||||
// dnsmasq
|
||||
{
|
||||
Name: "dnsmasq",
|
||||
Image: images.GetAddonImage(images.KubeDNSmasqImage),
|
||||
Resources: v1.ResourceRequirements{
|
||||
Limits: dnsPodResources,
|
||||
Requests: dnsPodResources,
|
||||
},
|
||||
Args: []string{
|
||||
"--cache-size=1000",
|
||||
"--no-resolv",
|
||||
fmt.Sprintf("--server=127.0.0.1#%d", kubeDNSPort),
|
||||
},
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
ContainerPort: dnsmasqPort,
|
||||
Name: "dns",
|
||||
Protocol: v1.ProtocolUDP,
|
||||
},
|
||||
{
|
||||
ContainerPort: dnsmasqPort,
|
||||
Name: "dns-tcp",
|
||||
Protocol: v1.ProtocolTCP,
|
||||
},
|
||||
},
|
||||
},
|
||||
// healthz
|
||||
{
|
||||
Name: "healthz",
|
||||
Image: images.GetAddonImage(images.KubeExechealthzImage),
|
||||
Resources: v1.ResourceRequirements{
|
||||
Limits: healthzPodResources,
|
||||
Requests: healthzPodResources,
|
||||
},
|
||||
Args: []string{
|
||||
nslookup,
|
||||
"-port=8080",
|
||||
"-quiet",
|
||||
},
|
||||
Ports: []v1.ContainerPort{{
|
||||
ContainerPort: 8080,
|
||||
Protocol: v1.ProtocolTCP,
|
||||
}},
|
||||
},
|
||||
},
|
||||
DNSPolicy: v1.DNSDefault,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func createKubeDNSServiceSpec(cfg *kubeadmapi.MasterConfiguration) (*v1.ServiceSpec, error) {
|
||||
_, n, err := net.ParseCIDR(cfg.Networking.ServiceSubnet)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not parse %q: %v", cfg.Networking.ServiceSubnet, err)
|
||||
}
|
||||
ip, err := ipallocator.GetIndexedIP(n, 10)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to allocate IP address for kube-dns addon from the given CIDR (%q) [%v]", cfg.Networking.ServiceSubnet, err)
|
||||
}
|
||||
|
||||
svc := &v1.ServiceSpec{
|
||||
Selector: map[string]string{"name": "kube-dns"},
|
||||
Ports: []v1.ServicePort{
|
||||
{Name: "dns", Port: 53, Protocol: v1.ProtocolUDP},
|
||||
{Name: "dns-tcp", Port: 53, Protocol: v1.ProtocolTCP},
|
||||
},
|
||||
ClusterIP: ip.String(),
|
||||
}
|
||||
|
||||
return svc, nil
|
||||
}
|
||||
|
||||
func CreateEssentialAddons(cfg *kubeadmapi.MasterConfiguration, client *clientset.Clientset) error {
|
||||
kubeProxyDaemonSet := NewDaemonSet(kubeProxy, createKubeProxyPodSpec(cfg))
|
||||
SetMasterTaintTolerations(&kubeProxyDaemonSet.Spec.Template.ObjectMeta)
|
||||
SetNodeAffinity(&kubeProxyDaemonSet.Spec.Template.ObjectMeta, NativeArchitectureNodeAffinity())
|
||||
|
||||
if _, err := client.Extensions().DaemonSets(api.NamespaceSystem).Create(kubeProxyDaemonSet); err != nil {
|
||||
return fmt.Errorf("<master/addons> failed creating essential kube-proxy addon [%v]", err)
|
||||
}
|
||||
|
||||
fmt.Println("<master/addons> created essential addon: kube-proxy")
|
||||
|
||||
kubeDNSDeployment := NewDeployment("kube-dns", 1, createKubeDNSPodSpec(cfg))
|
||||
SetMasterTaintTolerations(&kubeDNSDeployment.Spec.Template.ObjectMeta)
|
||||
SetNodeAffinity(&kubeDNSDeployment.Spec.Template.ObjectMeta, NativeArchitectureNodeAffinity())
|
||||
|
||||
if _, err := client.Extensions().Deployments(api.NamespaceSystem).Create(kubeDNSDeployment); err != nil {
|
||||
return fmt.Errorf("<master/addons> failed creating essential kube-dns addon [%v]", err)
|
||||
}
|
||||
|
||||
kubeDNSServiceSpec, err := createKubeDNSServiceSpec(cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("<master/addons> failed creating essential kube-dns addon - %v", err)
|
||||
}
|
||||
|
||||
kubeDNSService := NewService("kube-dns", *kubeDNSServiceSpec)
|
||||
if _, err := client.Services(api.NamespaceSystem).Create(kubeDNSService); err != nil {
|
||||
return fmt.Errorf("<master/addons> failed creating essential kube-dns addon [%v]", err)
|
||||
}
|
||||
|
||||
fmt.Println("<master/addons> created essential addon: kube-dns")
|
||||
|
||||
return nil
|
||||
}
|
||||
115
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/addons_test.go
generated
vendored
Normal file
115
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/addons_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
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 master
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
)
|
||||
|
||||
func TestCreateKubeProxyPodSpec(t *testing.T) {
|
||||
var tests = []struct {
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
actual := createKubeProxyPodSpec(rt.cfg)
|
||||
if (actual.Containers[0].Name != "") != rt.expected {
|
||||
t.Errorf(
|
||||
"failed createKubeProxyPodSpec:\n\texpected: %t\n\t actual: %t",
|
||||
rt.expected,
|
||||
(actual.Containers[0].Name != ""),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateKubeDNSPodSpec(t *testing.T) {
|
||||
var tests = []struct {
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Networking: kubeadm.Networking{DNSDomain: "localhost"},
|
||||
},
|
||||
expected: "--domain=localhost",
|
||||
},
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Networking: kubeadm.Networking{DNSDomain: "foo"},
|
||||
},
|
||||
expected: "--domain=foo",
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
actual := createKubeDNSPodSpec(rt.cfg)
|
||||
if actual.Containers[0].Args[0] != rt.expected {
|
||||
t.Errorf(
|
||||
"failed createKubeDNSPodSpec:\n\texpected: %s\n\t actual: %s",
|
||||
rt.expected,
|
||||
actual.Containers[0].Args[0],
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateKubeDNSServiceSpec(t *testing.T) {
|
||||
var tests = []struct {
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Networking: kubeadm.Networking{ServiceSubnet: "foo"},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Networking: kubeadm.Networking{ServiceSubnet: "10.0.0.1/1"},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Networking: kubeadm.Networking{ServiceSubnet: "10.0.0.1/24"},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
_, actual := createKubeDNSServiceSpec(rt.cfg)
|
||||
if (actual == nil) != rt.expected {
|
||||
t.Errorf(
|
||||
"failed createKubeDNSServiceSpec:\n\texpected: %t\n\t actual: %t",
|
||||
rt.expected,
|
||||
(actual == nil),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
279
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/apiclient.go
generated
vendored
Normal file
279
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/apiclient.go
generated
vendored
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
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 master
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/images"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
apierrs "k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
extensions "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
)
|
||||
|
||||
const apiCallRetryInterval = 500 * time.Millisecond
|
||||
|
||||
func CreateClientAndWaitForAPI(adminConfig *clientcmdapi.Config) (*clientset.Clientset, error) {
|
||||
adminClientConfig, err := clientcmd.NewDefaultClientConfig(
|
||||
*adminConfig,
|
||||
&clientcmd.ConfigOverrides{},
|
||||
).ClientConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("<master/apiclient> failed to create API client configuration [%v]", err)
|
||||
}
|
||||
|
||||
fmt.Println("<master/apiclient> created API client configuration")
|
||||
|
||||
client, err := clientset.NewForConfig(adminClientConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("<master/apiclient> failed to create API client [%v]", err)
|
||||
}
|
||||
|
||||
fmt.Println("<master/apiclient> created API client, waiting for the control plane to become ready")
|
||||
|
||||
start := time.Now()
|
||||
wait.PollInfinite(apiCallRetryInterval, func() (bool, error) {
|
||||
cs, err := client.ComponentStatuses().List(v1.ListOptions{})
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
// TODO(phase2) must revisit this when we implement HA
|
||||
if len(cs.Items) < 3 {
|
||||
fmt.Println("<master/apiclient> not all control plane components are ready yet")
|
||||
return false, nil
|
||||
}
|
||||
for _, item := range cs.Items {
|
||||
for _, condition := range item.Conditions {
|
||||
if condition.Type != v1.ComponentHealthy {
|
||||
fmt.Printf("<master/apiclient> control plane component %q is still unhealthy: %#v\n", item.ObjectMeta.Name, item.Conditions)
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("<master/apiclient> all control plane components are healthy after %f seconds\n", time.Since(start).Seconds())
|
||||
return true, nil
|
||||
})
|
||||
|
||||
fmt.Println("<master/apiclient> waiting for at least one node to register and become ready")
|
||||
start = time.Now()
|
||||
wait.PollInfinite(apiCallRetryInterval, func() (bool, error) {
|
||||
nodeList, err := client.Nodes().List(v1.ListOptions{})
|
||||
if err != nil {
|
||||
fmt.Println("<master/apiclient> temporarily unable to list nodes (will retry)")
|
||||
return false, nil
|
||||
}
|
||||
if len(nodeList.Items) < 1 {
|
||||
return false, nil
|
||||
}
|
||||
n := &nodeList.Items[0]
|
||||
if !v1.IsNodeReady(n) {
|
||||
fmt.Println("<master/apiclient> first node has registered, but is not ready yet")
|
||||
return false, nil
|
||||
}
|
||||
|
||||
fmt.Printf("<master/apiclient> first node is ready after %f seconds\n", time.Since(start).Seconds())
|
||||
return true, nil
|
||||
})
|
||||
|
||||
createDummyDeployment(client)
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func standardLabels(n string) map[string]string {
|
||||
return map[string]string{
|
||||
"component": n, "name": n, "k8s-app": n,
|
||||
"kubernetes.io/cluster-service": "true", "tier": "node",
|
||||
}
|
||||
}
|
||||
|
||||
func NewDaemonSet(daemonName string, podSpec v1.PodSpec) *extensions.DaemonSet {
|
||||
l := standardLabels(daemonName)
|
||||
return &extensions.DaemonSet{
|
||||
ObjectMeta: v1.ObjectMeta{Name: daemonName},
|
||||
Spec: extensions.DaemonSetSpec{
|
||||
Selector: &metav1.LabelSelector{MatchLabels: l},
|
||||
Template: v1.PodTemplateSpec{
|
||||
ObjectMeta: v1.ObjectMeta{Labels: l},
|
||||
Spec: podSpec,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewService(serviceName string, spec v1.ServiceSpec) *v1.Service {
|
||||
l := standardLabels(serviceName)
|
||||
return &v1.Service{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: serviceName,
|
||||
Labels: l,
|
||||
},
|
||||
Spec: spec,
|
||||
}
|
||||
}
|
||||
|
||||
func NewDeployment(deploymentName string, replicas int32, podSpec v1.PodSpec) *extensions.Deployment {
|
||||
l := standardLabels(deploymentName)
|
||||
return &extensions.Deployment{
|
||||
ObjectMeta: v1.ObjectMeta{Name: deploymentName},
|
||||
Spec: extensions.DeploymentSpec{
|
||||
Replicas: &replicas,
|
||||
Selector: &metav1.LabelSelector{MatchLabels: l},
|
||||
Template: v1.PodTemplateSpec{
|
||||
ObjectMeta: v1.ObjectMeta{Labels: l},
|
||||
Spec: podSpec,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// It's safe to do this for alpha, as we don't have HA and there is no way we can get
|
||||
// more then one node here (TODO(phase1+) use os.Hostname)
|
||||
func findMyself(client *clientset.Clientset) (*v1.Node, error) {
|
||||
nodeList, err := client.Nodes().List(v1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to list nodes [%v]", err)
|
||||
}
|
||||
if len(nodeList.Items) < 1 {
|
||||
return nil, fmt.Errorf("no nodes found")
|
||||
}
|
||||
node := &nodeList.Items[0]
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func attemptToUpdateMasterRoleLabelsAndTaints(client *clientset.Clientset, schedulable bool) error {
|
||||
n, err := findMyself(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n.ObjectMeta.Labels[metav1.NodeLabelKubeadmAlphaRole] = metav1.NodeLabelRoleMaster
|
||||
|
||||
if !schedulable {
|
||||
taintsAnnotation, _ := json.Marshal([]v1.Taint{{Key: "dedicated", Value: "master", Effect: "NoSchedule"}})
|
||||
n.ObjectMeta.Annotations[v1.TaintsAnnotationKey] = string(taintsAnnotation)
|
||||
}
|
||||
|
||||
if _, err := client.Nodes().Update(n); err != nil {
|
||||
if apierrs.IsConflict(err) {
|
||||
fmt.Println("<master/apiclient> temporarily unable to update master node metadata due to conflict (will retry)")
|
||||
time.Sleep(apiCallRetryInterval)
|
||||
attemptToUpdateMasterRoleLabelsAndTaints(client, schedulable)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdateMasterRoleLabelsAndTaints(client *clientset.Clientset, schedulable bool) error {
|
||||
// TODO(phase1+) use iterate instead of recursion
|
||||
err := attemptToUpdateMasterRoleLabelsAndTaints(client, schedulable)
|
||||
if err != nil {
|
||||
return fmt.Errorf("<master/apiclient> failed to update master node - %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetMasterTaintTolerations(meta *v1.ObjectMeta) {
|
||||
tolerationsAnnotation, _ := json.Marshal([]v1.Toleration{{Key: "dedicated", Value: "master", Effect: "NoSchedule"}})
|
||||
if meta.Annotations == nil {
|
||||
meta.Annotations = map[string]string{}
|
||||
}
|
||||
meta.Annotations[v1.TolerationsAnnotationKey] = string(tolerationsAnnotation)
|
||||
}
|
||||
|
||||
// SetNodeAffinity is a basic helper to set meta.Annotations[v1.AffinityAnnotationKey] for one or more v1.NodeSelectorRequirement(s)
|
||||
func SetNodeAffinity(meta *v1.ObjectMeta, expr ...v1.NodeSelectorRequirement) {
|
||||
nodeAffinity := &v1.NodeAffinity{
|
||||
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
|
||||
NodeSelectorTerms: []v1.NodeSelectorTerm{{MatchExpressions: expr}},
|
||||
},
|
||||
}
|
||||
affinityAnnotation, _ := json.Marshal(v1.Affinity{NodeAffinity: nodeAffinity})
|
||||
if meta.Annotations == nil {
|
||||
meta.Annotations = map[string]string{}
|
||||
}
|
||||
meta.Annotations[v1.AffinityAnnotationKey] = string(affinityAnnotation)
|
||||
}
|
||||
|
||||
// MasterNodeAffinity returns v1.NodeSelectorRequirement to be used with SetNodeAffinity to set affinity to master node
|
||||
func MasterNodeAffinity() v1.NodeSelectorRequirement {
|
||||
return v1.NodeSelectorRequirement{
|
||||
Key: metav1.NodeLabelKubeadmAlphaRole,
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{metav1.NodeLabelRoleMaster},
|
||||
}
|
||||
}
|
||||
|
||||
// NativeArchitectureNodeAffinity returns v1.NodeSelectorRequirement to be used with SetNodeAffinity to nodes with CPU architecture
|
||||
// the same as master node
|
||||
func NativeArchitectureNodeAffinity() v1.NodeSelectorRequirement {
|
||||
return v1.NodeSelectorRequirement{
|
||||
Key: "beta.kubernetes.io/arch", Operator: v1.NodeSelectorOpIn, Values: []string{runtime.GOARCH},
|
||||
}
|
||||
}
|
||||
|
||||
func createDummyDeployment(client *clientset.Clientset) {
|
||||
fmt.Println("<master/apiclient> attempting a test deployment")
|
||||
dummyDeployment := NewDeployment("dummy", 1, v1.PodSpec{
|
||||
HostNetwork: true,
|
||||
SecurityContext: &v1.PodSecurityContext{},
|
||||
Containers: []v1.Container{{
|
||||
Name: "dummy",
|
||||
Image: images.GetAddonImage("pause"),
|
||||
}},
|
||||
})
|
||||
|
||||
wait.PollInfinite(apiCallRetryInterval, func() (bool, error) {
|
||||
// TODO: we should check the error, as some cases may be fatal
|
||||
if _, err := client.Extensions().Deployments(api.NamespaceSystem).Create(dummyDeployment); err != nil {
|
||||
fmt.Printf("<master/apiclient> failed to create test deployment [%v] (will retry)", err)
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
|
||||
wait.PollInfinite(apiCallRetryInterval, func() (bool, error) {
|
||||
d, err := client.Extensions().Deployments(api.NamespaceSystem).Get("dummy")
|
||||
if err != nil {
|
||||
fmt.Printf("<master/apiclient> failed to get test deployment [%v] (will retry)", err)
|
||||
return false, nil
|
||||
}
|
||||
if d.Status.AvailableReplicas < 1 {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
|
||||
fmt.Println("<master/apiclient> test deployment succeeded")
|
||||
|
||||
if err := client.Extensions().Deployments(api.NamespaceSystem).Delete("dummy", &v1.DeleteOptions{}); err != nil {
|
||||
fmt.Printf("<master/apiclient> failed to delete test deployment [%v] (will ignore)", err)
|
||||
}
|
||||
}
|
||||
201
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/apiclient_test.go
generated
vendored
Normal file
201
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/apiclient_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
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 master
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
apiv1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
)
|
||||
|
||||
func TestCreateClientAndWaitForAPI(t *testing.T) {
|
||||
cfg := &kubeadmapi.MasterConfiguration{
|
||||
Networking: kubeadm.Networking{DNSDomain: "localhost"},
|
||||
}
|
||||
fmt.Println(cfg)
|
||||
|
||||
}
|
||||
|
||||
func TestStandardLabels(t *testing.T) {
|
||||
var tests = []struct {
|
||||
n string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
n: "foo",
|
||||
expected: "foo",
|
||||
},
|
||||
{
|
||||
n: "bar",
|
||||
expected: "bar",
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
actual := standardLabels(rt.n)
|
||||
if actual["component"] != rt.expected {
|
||||
t.Errorf(
|
||||
"failed standardLabels:\n\texpected: %s\n\t actual: %s",
|
||||
rt.expected,
|
||||
actual["component"],
|
||||
)
|
||||
}
|
||||
if actual["name"] != rt.expected {
|
||||
t.Errorf(
|
||||
"failed standardLabels:\n\texpected: %s\n\t actual: %s",
|
||||
rt.expected,
|
||||
actual["name"],
|
||||
)
|
||||
}
|
||||
if actual["k8s-app"] != rt.expected {
|
||||
t.Errorf(
|
||||
"failed standardLabels:\n\texpected: %s\n\t actual: %s",
|
||||
rt.expected,
|
||||
actual["k8s-app"],
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDaemonSet(t *testing.T) {
|
||||
var tests = []struct {
|
||||
dn string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
dn: "foo",
|
||||
expected: "foo",
|
||||
},
|
||||
{
|
||||
dn: "bar",
|
||||
expected: "bar",
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
p := apiv1.PodSpec{}
|
||||
actual := NewDaemonSet(rt.dn, p)
|
||||
if actual.Spec.Selector.MatchLabels["k8s-app"] != rt.expected {
|
||||
t.Errorf(
|
||||
"failed NewDaemonSet:\n\texpected: %s\n\t actual: %s",
|
||||
rt.expected,
|
||||
actual.Spec.Selector.MatchLabels["k8s-app"],
|
||||
)
|
||||
}
|
||||
if actual.Spec.Selector.MatchLabels["component"] != rt.expected {
|
||||
t.Errorf(
|
||||
"failed NewDaemonSet:\n\texpected: %s\n\t actual: %s",
|
||||
rt.expected,
|
||||
actual.Spec.Selector.MatchLabels["component"],
|
||||
)
|
||||
}
|
||||
if actual.Spec.Selector.MatchLabels["name"] != rt.expected {
|
||||
t.Errorf(
|
||||
"failed NewDaemonSet:\n\texpected: %s\n\t actual: %s",
|
||||
rt.expected,
|
||||
actual.Spec.Selector.MatchLabels["name"],
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewService(t *testing.T) {
|
||||
var tests = []struct {
|
||||
dn string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
dn: "foo",
|
||||
expected: "foo",
|
||||
},
|
||||
{
|
||||
dn: "bar",
|
||||
expected: "bar",
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
p := apiv1.ServiceSpec{}
|
||||
actual := NewService(rt.dn, p)
|
||||
if actual.ObjectMeta.Labels["k8s-app"] != rt.expected {
|
||||
t.Errorf(
|
||||
"failed NewService:\n\texpected: %s\n\t actual: %s",
|
||||
rt.expected,
|
||||
actual.ObjectMeta.Labels["k8s-app"],
|
||||
)
|
||||
}
|
||||
if actual.ObjectMeta.Labels["component"] != rt.expected {
|
||||
t.Errorf(
|
||||
"failed NewService:\n\texpected: %s\n\t actual: %s",
|
||||
rt.expected,
|
||||
actual.ObjectMeta.Labels["component"],
|
||||
)
|
||||
}
|
||||
if actual.ObjectMeta.Labels["name"] != rt.expected {
|
||||
t.Errorf(
|
||||
"failed NewService:\n\texpected: %s\n\t actual: %s",
|
||||
rt.expected,
|
||||
actual.ObjectMeta.Labels["name"],
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDeployment(t *testing.T) {
|
||||
var tests = []struct {
|
||||
dn string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
dn: "foo",
|
||||
expected: "foo",
|
||||
},
|
||||
{
|
||||
dn: "bar",
|
||||
expected: "bar",
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
p := apiv1.PodSpec{}
|
||||
actual := NewDeployment(rt.dn, 1, p)
|
||||
if actual.Spec.Selector.MatchLabels["k8s-app"] != rt.expected {
|
||||
t.Errorf(
|
||||
"failed NewDeployment:\n\texpected: %s\n\t actual: %s",
|
||||
rt.expected,
|
||||
actual.Spec.Selector.MatchLabels["k8s-app"],
|
||||
)
|
||||
}
|
||||
if actual.Spec.Selector.MatchLabels["component"] != rt.expected {
|
||||
t.Errorf(
|
||||
"failed NewDeployment:\n\texpected: %s\n\t actual: %s",
|
||||
rt.expected,
|
||||
actual.Spec.Selector.MatchLabels["component"],
|
||||
)
|
||||
}
|
||||
if actual.Spec.Selector.MatchLabels["name"] != rt.expected {
|
||||
t.Errorf(
|
||||
"failed NewDeployment:\n\texpected: %s\n\t actual: %s",
|
||||
rt.expected,
|
||||
actual.Spec.Selector.MatchLabels["name"],
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
148
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/discovery.go
generated
vendored
Normal file
148
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/discovery.go
generated
vendored
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
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 master
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
extensions "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
)
|
||||
|
||||
type kubeDiscovery struct {
|
||||
Deployment *extensions.Deployment
|
||||
Secret *v1.Secret
|
||||
}
|
||||
|
||||
const (
|
||||
kubeDiscoveryName = "kube-discovery"
|
||||
kubeDiscoverySecretName = "clusterinfo"
|
||||
)
|
||||
|
||||
func encodeKubeDiscoverySecretData(cfg *kubeadmapi.MasterConfiguration, caCert *x509.Certificate) map[string][]byte {
|
||||
var (
|
||||
data = map[string][]byte{}
|
||||
endpointList = []string{}
|
||||
tokenMap = map[string]string{}
|
||||
)
|
||||
|
||||
for _, addr := range cfg.API.AdvertiseAddresses {
|
||||
endpointList = append(endpointList, fmt.Sprintf("https://%s:%d", addr, cfg.API.BindPort))
|
||||
}
|
||||
|
||||
tokenMap[cfg.Secrets.TokenID] = cfg.Secrets.BearerToken
|
||||
|
||||
data["endpoint-list.json"], _ = json.Marshal(endpointList)
|
||||
data["token-map.json"], _ = json.Marshal(tokenMap)
|
||||
data["ca.pem"] = certutil.EncodeCertPEM(caCert)
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
func newKubeDiscoveryPodSpec(cfg *kubeadmapi.MasterConfiguration) v1.PodSpec {
|
||||
return v1.PodSpec{
|
||||
// We have to use host network namespace, as `HostPort`/`HostIP` are Docker's
|
||||
// buisness and CNI support isn't quite there yet (except for kubenet)
|
||||
// (see https://github.com/kubernetes/kubernetes/issues/31307)
|
||||
// TODO update this when #31307 is resolved
|
||||
HostNetwork: true,
|
||||
SecurityContext: &v1.PodSecurityContext{},
|
||||
Containers: []v1.Container{{
|
||||
Name: kubeDiscoveryName,
|
||||
Image: kubeadmapi.GlobalEnvParams.DiscoveryImage,
|
||||
Command: []string{"/usr/local/bin/kube-discovery"},
|
||||
VolumeMounts: []v1.VolumeMount{{
|
||||
Name: kubeDiscoverySecretName,
|
||||
MountPath: "/tmp/secret", // TODO use a shared constant
|
||||
ReadOnly: true,
|
||||
}},
|
||||
Ports: []v1.ContainerPort{
|
||||
// TODO when CNI issue (#31307) is resolved, we should consider adding
|
||||
// `HostIP: s.API.AdvertiseAddrs[0]`, if there is only one address`
|
||||
{Name: "http", ContainerPort: kubeadmapiext.DefaultDiscoveryBindPort, HostPort: cfg.Discovery.BindPort},
|
||||
},
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
SELinuxOptions: &v1.SELinuxOptions{
|
||||
// TODO: This implies our discovery container is not being restricted by
|
||||
// SELinux. This is not optimal and would be nice to adjust in future
|
||||
// so it can read /tmp/secret, but for now this avoids recommending
|
||||
// setenforce 0 system-wide.
|
||||
Type: "spc_t",
|
||||
},
|
||||
},
|
||||
}},
|
||||
Volumes: []v1.Volume{{
|
||||
Name: kubeDiscoverySecretName,
|
||||
VolumeSource: v1.VolumeSource{
|
||||
Secret: &v1.SecretVolumeSource{SecretName: kubeDiscoverySecretName},
|
||||
}},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newKubeDiscovery(cfg *kubeadmapi.MasterConfiguration, caCert *x509.Certificate) kubeDiscovery {
|
||||
kd := kubeDiscovery{
|
||||
Deployment: NewDeployment(kubeDiscoveryName, 1, newKubeDiscoveryPodSpec(cfg)),
|
||||
Secret: &v1.Secret{
|
||||
ObjectMeta: v1.ObjectMeta{Name: kubeDiscoverySecretName},
|
||||
Type: v1.SecretTypeOpaque,
|
||||
Data: encodeKubeDiscoverySecretData(cfg, caCert),
|
||||
},
|
||||
}
|
||||
|
||||
SetMasterTaintTolerations(&kd.Deployment.Spec.Template.ObjectMeta)
|
||||
SetNodeAffinity(&kd.Deployment.Spec.Template.ObjectMeta, MasterNodeAffinity(), NativeArchitectureNodeAffinity())
|
||||
|
||||
return kd
|
||||
}
|
||||
|
||||
func CreateDiscoveryDeploymentAndSecret(cfg *kubeadmapi.MasterConfiguration, client *clientset.Clientset, caCert *x509.Certificate) error {
|
||||
kd := newKubeDiscovery(cfg, caCert)
|
||||
|
||||
if _, err := client.Extensions().Deployments(api.NamespaceSystem).Create(kd.Deployment); err != nil {
|
||||
return fmt.Errorf("<master/discovery> failed to create %q deployment [%v]", kubeDiscoveryName, err)
|
||||
}
|
||||
if _, err := client.Secrets(api.NamespaceSystem).Create(kd.Secret); err != nil {
|
||||
return fmt.Errorf("<master/discovery> failed to create %q secret [%v]", kubeDiscoverySecretName, err)
|
||||
}
|
||||
|
||||
fmt.Println("<master/discovery> created essential addon: kube-discovery, waiting for it to become ready")
|
||||
|
||||
start := time.Now()
|
||||
wait.PollInfinite(apiCallRetryInterval, func() (bool, error) {
|
||||
d, err := client.Extensions().Deployments(api.NamespaceSystem).Get(kubeDiscoveryName)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
if d.Status.AvailableReplicas < 1 {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
fmt.Printf("<master/discovery> kube-discovery is ready after %f seconds\n", time.Since(start).Seconds())
|
||||
|
||||
return nil
|
||||
}
|
||||
104
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/discovery_test.go
generated
vendored
Normal file
104
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/discovery_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
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 master
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"testing"
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
)
|
||||
|
||||
func TestEncodeKubeDiscoverySecretData(t *testing.T) {
|
||||
var tests = []struct {
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{BindPort: 123, AdvertiseAddresses: []string{"10.0.0.1"}},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.0.0.1/1"},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
caCert := &x509.Certificate{}
|
||||
actual := encodeKubeDiscoverySecretData(rt.cfg, caCert)
|
||||
if (actual != nil) != rt.expected {
|
||||
t.Errorf(
|
||||
"failed encodeKubeDiscoverySecretData, return map[string][]byte was nil",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewKubeDiscoveryPodSpec(t *testing.T) {
|
||||
var tests = []struct {
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
p int32
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Discovery: kubeadmapi.Discovery{BindPort: 123},
|
||||
},
|
||||
p: 123,
|
||||
},
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Discovery: kubeadmapi.Discovery{BindPort: 456},
|
||||
},
|
||||
p: 456,
|
||||
},
|
||||
}
|
||||
for _, rt := range tests {
|
||||
actual := newKubeDiscoveryPodSpec(rt.cfg)
|
||||
if actual.Containers[0].Ports[0].HostPort != rt.p {
|
||||
t.Errorf(
|
||||
"failed newKubeDiscoveryPodSpec:\n\texpected: %d\n\t actual: %d",
|
||||
rt.p,
|
||||
actual.Containers[0].Ports[0].HostPort,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewKubeDiscovery(t *testing.T) {
|
||||
var tests = []struct {
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
caCert *x509.Certificate
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadmapi.API{BindPort: 123, AdvertiseAddresses: []string{"10.0.0.1"}},
|
||||
Networking: kubeadmapi.Networking{ServiceSubnet: "10.0.0.1/1"},
|
||||
},
|
||||
caCert: &x509.Certificate{},
|
||||
},
|
||||
}
|
||||
for _, rt := range tests {
|
||||
actual := newKubeDiscovery(rt.cfg, rt.caCert)
|
||||
if actual.Deployment == nil || actual.Secret == nil {
|
||||
t.Errorf(
|
||||
"failed newKubeDiscovery, kubeDiscovery was nil",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
60
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/kubeconfig.go
generated
vendored
Normal file
60
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/kubeconfig.go
generated
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
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 master
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
|
||||
// TODO: "k8s.io/client-go/client/tools/clientcmd/api"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||
)
|
||||
|
||||
func CreateCertsAndConfigForClients(cfg kubeadmapi.API, clientNames []string, caKey *rsa.PrivateKey, caCert *x509.Certificate) (map[string]*clientcmdapi.Config, error) {
|
||||
|
||||
basicClientConfig := kubeadmutil.CreateBasicClientConfig(
|
||||
"kubernetes",
|
||||
// TODO this is not great, but there is only one address we can use here
|
||||
// so we'll pick the first one, there is much of chance to have an empty
|
||||
// slice by the time this gets called
|
||||
fmt.Sprintf("https://%s:%d", cfg.AdvertiseAddresses[0], cfg.BindPort),
|
||||
certutil.EncodeCertPEM(caCert),
|
||||
)
|
||||
|
||||
configs := map[string]*clientcmdapi.Config{}
|
||||
|
||||
for _, client := range clientNames {
|
||||
key, cert, err := newClientKeyAndCert(caCert, caKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("<master/kubeconfig> failure while creating %s client certificate - %v", client, err)
|
||||
}
|
||||
config := kubeadmutil.MakeClientConfigWithCerts(
|
||||
basicClientConfig,
|
||||
"kubernetes",
|
||||
client,
|
||||
certutil.EncodePrivateKeyPEM(key),
|
||||
certutil.EncodeCertPEM(cert),
|
||||
)
|
||||
configs[client] = config
|
||||
}
|
||||
|
||||
return configs, nil
|
||||
}
|
||||
70
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/kubeconfig_test.go
generated
vendored
Normal file
70
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/kubeconfig_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
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 master
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"testing"
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
)
|
||||
|
||||
func TestCreateCertsAndConfigForClients(t *testing.T) {
|
||||
var tests = []struct {
|
||||
a kubeadmapi.API
|
||||
cn []string
|
||||
caKeySize int
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
a: kubeadmapi.API{AdvertiseAddresses: []string{"foo"}},
|
||||
cn: []string{"localhost"},
|
||||
caKeySize: 128,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
a: kubeadmapi.API{AdvertiseAddresses: []string{"foo"}},
|
||||
cn: []string{},
|
||||
caKeySize: 128,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
a: kubeadmapi.API{AdvertiseAddresses: []string{"foo"}},
|
||||
cn: []string{"localhost"},
|
||||
caKeySize: 2048,
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
caKey, err := rsa.GenerateKey(rand.Reader, rt.caKeySize)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create rsa Private Key")
|
||||
}
|
||||
caCert := &x509.Certificate{}
|
||||
_, actual := CreateCertsAndConfigForClients(rt.a, rt.cn, caKey, caCert)
|
||||
if (actual == nil) != rt.expected {
|
||||
t.Errorf(
|
||||
"failed CreateCertsAndConfigForClients:\n\texpected: %t\n\t actual: %t",
|
||||
rt.expected,
|
||||
(actual == nil),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
316
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/manifests.go
generated
vendored
Normal file
316
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/manifests.go
generated
vendored
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
/*
|
||||
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 master
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/images"
|
||||
"k8s.io/kubernetes/pkg/api/resource"
|
||||
api "k8s.io/kubernetes/pkg/api/v1"
|
||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/util/intstr"
|
||||
)
|
||||
|
||||
// Static pod definitions in golang form are included below so that `kubeadm init` can get going.
|
||||
|
||||
const (
|
||||
DefaultClusterName = "kubernetes"
|
||||
DefaultCloudConfigPath = "/etc/kubernetes/cloud-config.json"
|
||||
|
||||
etcd = "etcd"
|
||||
apiServer = "apiserver"
|
||||
controllerManager = "controller-manager"
|
||||
scheduler = "scheduler"
|
||||
proxy = "proxy"
|
||||
kubeAPIServer = "kube-apiserver"
|
||||
kubeControllerManager = "kube-controller-manager"
|
||||
kubeScheduler = "kube-scheduler"
|
||||
kubeProxy = "kube-proxy"
|
||||
pkiDir = "/etc/kubernetes/pki"
|
||||
)
|
||||
|
||||
// WriteStaticPodManifests builds manifest objects based on user provided configuration and then dumps it to disk
|
||||
// where kubelet will pick and schedule them.
|
||||
func WriteStaticPodManifests(cfg *kubeadmapi.MasterConfiguration) error {
|
||||
// Prepare static pod specs
|
||||
staticPodSpecs := map[string]api.Pod{
|
||||
kubeAPIServer: componentPod(api.Container{
|
||||
Name: kubeAPIServer,
|
||||
Image: images.GetCoreImage(images.KubeAPIServerImage, cfg, kubeadmapi.GlobalEnvParams.HyperkubeImage),
|
||||
Command: getAPIServerCommand(cfg),
|
||||
VolumeMounts: []api.VolumeMount{certsVolumeMount(), k8sVolumeMount()},
|
||||
LivenessProbe: componentProbe(8080, "/healthz"),
|
||||
Resources: componentResources("250m"),
|
||||
}, certsVolume(cfg), k8sVolume(cfg)),
|
||||
kubeControllerManager: componentPod(api.Container{
|
||||
Name: kubeControllerManager,
|
||||
Image: images.GetCoreImage(images.KubeControllerManagerImage, cfg, kubeadmapi.GlobalEnvParams.HyperkubeImage),
|
||||
Command: getControllerManagerCommand(cfg),
|
||||
VolumeMounts: []api.VolumeMount{certsVolumeMount(), k8sVolumeMount()},
|
||||
LivenessProbe: componentProbe(10252, "/healthz"),
|
||||
Resources: componentResources("200m"),
|
||||
}, certsVolume(cfg), k8sVolume(cfg)),
|
||||
kubeScheduler: componentPod(api.Container{
|
||||
Name: kubeScheduler,
|
||||
Image: images.GetCoreImage(images.KubeSchedulerImage, cfg, kubeadmapi.GlobalEnvParams.HyperkubeImage),
|
||||
Command: getSchedulerCommand(cfg),
|
||||
LivenessProbe: componentProbe(10251, "/healthz"),
|
||||
Resources: componentResources("100m"),
|
||||
}),
|
||||
}
|
||||
|
||||
// Add etcd static pod spec only if external etcd is not configured
|
||||
if len(cfg.Etcd.Endpoints) == 0 {
|
||||
staticPodSpecs[etcd] = componentPod(api.Container{
|
||||
Name: etcd,
|
||||
Command: []string{
|
||||
"etcd",
|
||||
"--listen-client-urls=http://127.0.0.1:2379",
|
||||
"--advertise-client-urls=http://127.0.0.1:2379",
|
||||
"--data-dir=/var/etcd/data",
|
||||
},
|
||||
VolumeMounts: []api.VolumeMount{certsVolumeMount(), etcdVolumeMount(), k8sVolumeMount()},
|
||||
Image: images.GetCoreImage(images.KubeEtcdImage, cfg, kubeadmapi.GlobalEnvParams.EtcdImage),
|
||||
LivenessProbe: componentProbe(2379, "/health"),
|
||||
Resources: componentResources("200m"),
|
||||
SecurityContext: &api.SecurityContext{
|
||||
SELinuxOptions: &api.SELinuxOptions{
|
||||
// TODO: This implies our etcd container is not being restricted by
|
||||
// SELinux. This is not optimal and would be nice to adjust in future
|
||||
// so it can create and write /var/lib/etcd, but for now this avoids
|
||||
// recommending setenforce 0 system-wide.
|
||||
Type: "spc_t",
|
||||
},
|
||||
},
|
||||
}, certsVolume(cfg), etcdVolume(cfg), k8sVolume(cfg))
|
||||
}
|
||||
|
||||
manifestsPath := path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "manifests")
|
||||
if err := os.MkdirAll(manifestsPath, 0700); err != nil {
|
||||
return fmt.Errorf("<master/manifests> failed to create directory %q [%v]", manifestsPath, err)
|
||||
}
|
||||
for name, spec := range staticPodSpecs {
|
||||
filename := path.Join(manifestsPath, name+".json")
|
||||
serialized, err := json.MarshalIndent(spec, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("<master/manifests> failed to marshall manifest for %q to JSON [%v]", name, err)
|
||||
}
|
||||
if err := cmdutil.DumpReaderToFile(bytes.NewReader(serialized), filename); err != nil {
|
||||
return fmt.Errorf("<master/manifests> failed to create static pod manifest file for %q (%q) [%v]", name, filename, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// etcdVolume exposes a path on the host in order to guarantee data survival during reboot.
|
||||
func etcdVolume(cfg *kubeadmapi.MasterConfiguration) api.Volume {
|
||||
return api.Volume{
|
||||
Name: "etcd",
|
||||
VolumeSource: api.VolumeSource{
|
||||
HostPath: &api.HostPathVolumeSource{Path: kubeadmapi.GlobalEnvParams.HostEtcdPath},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func etcdVolumeMount() api.VolumeMount {
|
||||
return api.VolumeMount{
|
||||
Name: "etcd",
|
||||
MountPath: "/var/etcd",
|
||||
}
|
||||
}
|
||||
|
||||
// certsVolume exposes host SSL certificates to pod containers.
|
||||
func certsVolume(cfg *kubeadmapi.MasterConfiguration) api.Volume {
|
||||
return api.Volume{
|
||||
Name: "certs",
|
||||
VolumeSource: api.VolumeSource{
|
||||
// TODO(phase1+) make path configurable
|
||||
HostPath: &api.HostPathVolumeSource{Path: "/etc/ssl/certs"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func certsVolumeMount() api.VolumeMount {
|
||||
return api.VolumeMount{
|
||||
Name: "certs",
|
||||
MountPath: "/etc/ssl/certs",
|
||||
}
|
||||
}
|
||||
|
||||
func k8sVolume(cfg *kubeadmapi.MasterConfiguration) api.Volume {
|
||||
return api.Volume{
|
||||
Name: "pki",
|
||||
VolumeSource: api.VolumeSource{
|
||||
HostPath: &api.HostPathVolumeSource{Path: kubeadmapi.GlobalEnvParams.KubernetesDir},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func k8sVolumeMount() api.VolumeMount {
|
||||
return api.VolumeMount{
|
||||
Name: "pki",
|
||||
MountPath: "/etc/kubernetes/",
|
||||
ReadOnly: true,
|
||||
}
|
||||
}
|
||||
|
||||
func componentResources(cpu string) api.ResourceRequirements {
|
||||
return api.ResourceRequirements{
|
||||
Requests: api.ResourceList{
|
||||
api.ResourceName(api.ResourceCPU): resource.MustParse(cpu),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func componentProbe(port int, path string) *api.Probe {
|
||||
return &api.Probe{
|
||||
Handler: api.Handler{
|
||||
HTTPGet: &api.HTTPGetAction{
|
||||
Host: "127.0.0.1",
|
||||
Path: path,
|
||||
Port: intstr.FromInt(port),
|
||||
},
|
||||
},
|
||||
InitialDelaySeconds: 15,
|
||||
TimeoutSeconds: 15,
|
||||
FailureThreshold: 8,
|
||||
}
|
||||
}
|
||||
|
||||
func componentPod(container api.Container, volumes ...api.Volume) api.Pod {
|
||||
return api.Pod{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Pod",
|
||||
},
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: container.Name,
|
||||
Namespace: "kube-system",
|
||||
Labels: map[string]string{"component": container.Name, "tier": "control-plane"},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{container},
|
||||
HostNetwork: true,
|
||||
Volumes: volumes,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getComponentBaseCommand(component string) (command []string) {
|
||||
if kubeadmapi.GlobalEnvParams.HyperkubeImage != "" {
|
||||
command = []string{"/hyperkube", component}
|
||||
} else {
|
||||
command = []string{"kube-" + component}
|
||||
}
|
||||
command = append(command, kubeadmapi.GlobalEnvParams.ComponentLoglevel)
|
||||
return
|
||||
}
|
||||
|
||||
func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration) (command []string) {
|
||||
command = append(getComponentBaseCommand(apiServer),
|
||||
"--insecure-bind-address=127.0.0.1",
|
||||
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota",
|
||||
"--service-cluster-ip-range="+cfg.Networking.ServiceSubnet,
|
||||
"--service-account-key-file="+pkiDir+"/apiserver-key.pem",
|
||||
"--client-ca-file="+pkiDir+"/ca.pem",
|
||||
"--tls-cert-file="+pkiDir+"/apiserver.pem",
|
||||
"--tls-private-key-file="+pkiDir+"/apiserver-key.pem",
|
||||
"--token-auth-file="+pkiDir+"/tokens.csv",
|
||||
fmt.Sprintf("--secure-port=%d", cfg.API.BindPort),
|
||||
"--allow-privileged",
|
||||
)
|
||||
|
||||
// Use first address we are given
|
||||
if len(cfg.API.AdvertiseAddresses) > 0 {
|
||||
command = append(command, fmt.Sprintf("--advertise-address=%s", cfg.API.AdvertiseAddresses[0]))
|
||||
}
|
||||
|
||||
// Check if the user decided to use an external etcd cluster
|
||||
if len(cfg.Etcd.Endpoints) > 0 {
|
||||
command = append(command, fmt.Sprintf("--etcd-servers=%s", strings.Join(cfg.Etcd.Endpoints, ",")))
|
||||
} else {
|
||||
command = append(command, "--etcd-servers=http://127.0.0.1:2379")
|
||||
}
|
||||
|
||||
// Is etcd secured?
|
||||
if cfg.Etcd.CAFile != "" {
|
||||
command = append(command, fmt.Sprintf("--etcd-cafile=%s", cfg.Etcd.CAFile))
|
||||
}
|
||||
if cfg.Etcd.CertFile != "" && cfg.Etcd.KeyFile != "" {
|
||||
etcdClientFileArg := fmt.Sprintf("--etcd-certfile=%s", cfg.Etcd.CertFile)
|
||||
etcdKeyFileArg := fmt.Sprintf("--etcd-keyfile=%s", cfg.Etcd.KeyFile)
|
||||
command = append(command, etcdClientFileArg, etcdKeyFileArg)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getControllerManagerCommand(cfg *kubeadmapi.MasterConfiguration) (command []string) {
|
||||
command = append(getComponentBaseCommand(controllerManager),
|
||||
"--address=127.0.0.1",
|
||||
"--leader-elect",
|
||||
"--master=127.0.0.1:8080",
|
||||
"--cluster-name="+DefaultClusterName,
|
||||
"--root-ca-file="+pkiDir+"/ca.pem",
|
||||
"--service-account-private-key-file="+pkiDir+"/apiserver-key.pem",
|
||||
"--cluster-signing-cert-file="+pkiDir+"/ca.pem",
|
||||
"--cluster-signing-key-file="+pkiDir+"/ca-key.pem",
|
||||
"--insecure-experimental-approve-all-kubelet-csrs-for-group=system:kubelet-bootstrap",
|
||||
)
|
||||
|
||||
if cfg.CloudProvider != "" {
|
||||
command = append(command, "--cloud-provider="+cfg.CloudProvider)
|
||||
|
||||
// Only append the --cloud-config option if there's a such file
|
||||
// TODO(phase1+) this won't work unless it's in one of the few directories we bind-mount
|
||||
if _, err := os.Stat(DefaultCloudConfigPath); err == nil {
|
||||
command = append(command, "--cloud-config="+DefaultCloudConfigPath)
|
||||
}
|
||||
}
|
||||
|
||||
// Let the controller-manager allocate Node CIDRs for the Pod network.
|
||||
// Each node will get a subspace of the address CIDR provided with --pod-network-cidr.
|
||||
if cfg.Networking.PodSubnet != "" {
|
||||
command = append(command, "--allocate-node-cidrs=true", "--cluster-cidr="+cfg.Networking.PodSubnet)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getSchedulerCommand(cfg *kubeadmapi.MasterConfiguration) (command []string) {
|
||||
command = append(getComponentBaseCommand(scheduler),
|
||||
"--address=127.0.0.1",
|
||||
"--leader-elect",
|
||||
"--master=127.0.0.1:8080",
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getProxyCommand(cfg *kubeadmapi.MasterConfiguration) (command []string) {
|
||||
command = getComponentBaseCommand(proxy)
|
||||
|
||||
return
|
||||
}
|
||||
577
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/manifests_test.go
generated
vendored
Normal file
577
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/manifests_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
200
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/pki.go
generated
vendored
Normal file
200
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/pki.go
generated
vendored
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
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 master
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net"
|
||||
"path"
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
ipallocator "k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
|
||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||
)
|
||||
|
||||
func newCertificateAuthority() (*rsa.PrivateKey, *x509.Certificate, error) {
|
||||
key, err := certutil.NewPrivateKey()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to create private key [%v]", err)
|
||||
}
|
||||
|
||||
config := certutil.Config{
|
||||
CommonName: "kubernetes",
|
||||
}
|
||||
|
||||
cert, err := certutil.NewSelfSignedCACert(config, key)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to create self-signed certificate [%v]", err)
|
||||
}
|
||||
|
||||
return key, cert, nil
|
||||
}
|
||||
|
||||
func newServerKeyAndCert(cfg *kubeadmapi.MasterConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey, altNames certutil.AltNames) (*rsa.PrivateKey, *x509.Certificate, error) {
|
||||
key, err := certutil.NewPrivateKey()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to create private key [%v]", err)
|
||||
}
|
||||
|
||||
internalAPIServerFQDN := []string{
|
||||
"kubernetes",
|
||||
"kubernetes.default",
|
||||
"kubernetes.default.svc",
|
||||
fmt.Sprintf("kubernetes.default.svc.%s", cfg.Networking.DNSDomain),
|
||||
}
|
||||
|
||||
_, n, err := net.ParseCIDR(cfg.Networking.ServiceSubnet)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error parsing CIDR %q: %v", cfg.Networking.ServiceSubnet, err)
|
||||
}
|
||||
internalAPIServerVirtualIP, err := ipallocator.GetIndexedIP(n, 1)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to allocate IP address for the API server from the given CIDR (%q) [%v]", &cfg.Networking.ServiceSubnet, err)
|
||||
}
|
||||
|
||||
altNames.IPs = append(altNames.IPs, internalAPIServerVirtualIP)
|
||||
altNames.DNSNames = append(altNames.DNSNames, internalAPIServerFQDN...)
|
||||
|
||||
config := certutil.Config{
|
||||
CommonName: "kube-apiserver",
|
||||
AltNames: altNames,
|
||||
}
|
||||
cert, err := certutil.NewSignedCert(config, key, caCert, caKey)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to sign certificate [%v]", err)
|
||||
}
|
||||
|
||||
return key, cert, nil
|
||||
}
|
||||
|
||||
func newClientKeyAndCert(caCert *x509.Certificate, caKey *rsa.PrivateKey) (*rsa.PrivateKey, *x509.Certificate, error) {
|
||||
key, err := certutil.NewPrivateKey()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to create private key [%v]", err)
|
||||
}
|
||||
|
||||
config := certutil.Config{
|
||||
CommonName: "kubernetes-admin",
|
||||
}
|
||||
cert, err := certutil.NewSignedCert(config, key, caCert, caKey)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to sign certificate [%v]", err)
|
||||
}
|
||||
|
||||
return key, cert, nil
|
||||
}
|
||||
|
||||
func writeKeysAndCert(pkiPath string, name string, key *rsa.PrivateKey, cert *x509.Certificate) error {
|
||||
publicKeyPath, privateKeyPath, certificatePath := pathsKeysCerts(pkiPath, name)
|
||||
|
||||
if key != nil {
|
||||
if err := certutil.WriteKey(privateKeyPath, certutil.EncodePrivateKeyPEM(key)); err != nil {
|
||||
return fmt.Errorf("unable to write private key file (%q) [%v]", privateKeyPath, err)
|
||||
}
|
||||
if pubKey, err := certutil.EncodePublicKeyPEM(&key.PublicKey); err == nil {
|
||||
if err := certutil.WriteKey(publicKeyPath, pubKey); err != nil {
|
||||
return fmt.Errorf("unable to write public key file (%q) [%v]", publicKeyPath, err)
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("unable to encode public key to PEM [%v]", err)
|
||||
}
|
||||
}
|
||||
|
||||
if cert != nil {
|
||||
if err := certutil.WriteCert(certificatePath, certutil.EncodeCertPEM(cert)); err != nil {
|
||||
return fmt.Errorf("unable to write certificate file (%q) [%v]", certificatePath, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func pathsKeysCerts(pkiPath, name string) (string, string, string) {
|
||||
return path.Join(pkiPath, fmt.Sprintf("%s-pub.pem", name)),
|
||||
path.Join(pkiPath, fmt.Sprintf("%s-key.pem", name)),
|
||||
path.Join(pkiPath, fmt.Sprintf("%s.pem", name))
|
||||
}
|
||||
|
||||
func newServiceAccountKey() (*rsa.PrivateKey, error) {
|
||||
key, err := certutil.NewPrivateKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// CreatePKIAssets will create and write to disk all PKI assets necessary to establish the control plane.
|
||||
// It first generates a self-signed CA certificate, a server certificate (signed by the CA) and a key for
|
||||
// signing service account tokens. It returns CA key and certificate, which is convenient for use with
|
||||
// client config funcs.
|
||||
func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration) (*rsa.PrivateKey, *x509.Certificate, error) {
|
||||
var (
|
||||
err error
|
||||
altNames certutil.AltNames
|
||||
)
|
||||
|
||||
for _, a := range cfg.API.AdvertiseAddresses {
|
||||
if ip := net.ParseIP(a); ip != nil {
|
||||
altNames.IPs = append(altNames.IPs, ip)
|
||||
} else {
|
||||
return nil, nil, fmt.Errorf("could not parse ip %q", a)
|
||||
}
|
||||
}
|
||||
altNames.DNSNames = append(altNames.DNSNames, cfg.API.ExternalDNSNames...)
|
||||
|
||||
pkiPath := path.Join(kubeadmapi.GlobalEnvParams.HostPKIPath)
|
||||
|
||||
caKey, caCert, err := newCertificateAuthority()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("<master/pki> failure while creating CA keys and certificate - %v", err)
|
||||
}
|
||||
|
||||
if err := writeKeysAndCert(pkiPath, "ca", caKey, caCert); err != nil {
|
||||
return nil, nil, fmt.Errorf("<master/pki> failure while saving CA keys and certificate - %v", err)
|
||||
}
|
||||
fmt.Printf("<master/pki> generated Certificate Authority key and certificate:\n%s\n", certutil.FormatCert(caCert))
|
||||
pub, prv, cert := pathsKeysCerts(pkiPath, "ca")
|
||||
fmt.Printf("Public: %s\nPrivate: %s\nCert: %s\n", pub, prv, cert)
|
||||
|
||||
apiKey, apiCert, err := newServerKeyAndCert(cfg, caCert, caKey, altNames)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("<master/pki> failure while creating API server keys and certificate - %v", err)
|
||||
}
|
||||
|
||||
if err := writeKeysAndCert(pkiPath, "apiserver", apiKey, apiCert); err != nil {
|
||||
return nil, nil, fmt.Errorf("<master/pki> failure while saving API server keys and certificate - %v", err)
|
||||
}
|
||||
fmt.Printf("<master/pki> generated API Server key and certificate:\n%s\n", certutil.FormatCert(apiCert))
|
||||
pub, prv, cert = pathsKeysCerts(pkiPath, "apiserver")
|
||||
fmt.Printf("Public: %s\nPrivate: %s\nCert: %s\n", pub, prv, cert)
|
||||
|
||||
saKey, err := newServiceAccountKey()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("<master/pki> failure while creating service account signing keys [%v]", err)
|
||||
}
|
||||
if err := writeKeysAndCert(pkiPath, "sa", saKey, nil); err != nil {
|
||||
return nil, nil, fmt.Errorf("<master/pki> failure while saving service account signing keys - %v", err)
|
||||
}
|
||||
fmt.Printf("<master/pki> generated Service Account Signing keys:\n")
|
||||
pub, prv, _ = pathsKeysCerts(pkiPath, "sa")
|
||||
fmt.Printf("Public: %s\nPrivate: %s\n", pub, prv)
|
||||
|
||||
fmt.Printf("<master/pki> created keys and certificates in %q\n", pkiPath)
|
||||
return caKey, caCert, nil
|
||||
}
|
||||
258
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/pki_test.go
generated
vendored
Normal file
258
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/pki_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
/*
|
||||
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 master
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||
)
|
||||
|
||||
func TestNewCertificateAuthority(t *testing.T) {
|
||||
r, x, err := newCertificateAuthority()
|
||||
|
||||
if r == nil {
|
||||
t.Errorf(
|
||||
"failed newCertificateAuthority, rsa key == nil",
|
||||
)
|
||||
}
|
||||
if x == nil {
|
||||
t.Errorf(
|
||||
"failed newCertificateAuthority, x509 cert == nil",
|
||||
)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf(
|
||||
"failed newCertificateAuthority with an error: %v",
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewServerKeyAndCert(t *testing.T) {
|
||||
var tests = []struct {
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
caKeySize int
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
// given CIDR too small
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Networking: kubeadm.Networking{ServiceSubnet: "10.0.0.1/1"},
|
||||
},
|
||||
caKeySize: 2048,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
// bad CIDR
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Networking: kubeadm.Networking{ServiceSubnet: "foo"},
|
||||
},
|
||||
caKeySize: 2048,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
// RSA key too small
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Networking: kubeadm.Networking{ServiceSubnet: "10.0.0.1/24"},
|
||||
},
|
||||
caKeySize: 128,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Networking: kubeadm.Networking{ServiceSubnet: "10.0.0.1/24"},
|
||||
},
|
||||
caKeySize: 2048,
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
caKey, err := rsa.GenerateKey(rand.Reader, rt.caKeySize)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create rsa Private Key")
|
||||
}
|
||||
caCert := &x509.Certificate{}
|
||||
altNames := certutil.AltNames{}
|
||||
_, _, actual := newServerKeyAndCert(rt.cfg, caCert, caKey, altNames)
|
||||
if (actual == nil) != rt.expected {
|
||||
t.Errorf(
|
||||
"failed newServerKeyAndCert:\n\texpected: %t\n\t actual: %t",
|
||||
rt.expected,
|
||||
(actual == nil),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewClientKeyAndCert(t *testing.T) {
|
||||
var tests = []struct {
|
||||
caKeySize int
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
// RSA key too small
|
||||
caKeySize: 128,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
caKeySize: 2048,
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
caKey, err := rsa.GenerateKey(rand.Reader, rt.caKeySize)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create rsa Private Key")
|
||||
}
|
||||
caCert := &x509.Certificate{}
|
||||
_, _, actual := newClientKeyAndCert(caCert, caKey)
|
||||
if (actual == nil) != rt.expected {
|
||||
t.Errorf(
|
||||
"failed newClientKeyAndCert:\n\texpected: %t\n\t actual: %t",
|
||||
rt.expected,
|
||||
(actual == nil),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteKeysAndCert(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create tmpdir")
|
||||
}
|
||||
defer os.Remove(tmpdir)
|
||||
|
||||
caKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create rsa Private Key")
|
||||
}
|
||||
caCert := &x509.Certificate{}
|
||||
actual := writeKeysAndCert(tmpdir, "foo", caKey, caCert)
|
||||
if actual != nil {
|
||||
t.Errorf(
|
||||
"failed writeKeysAndCert with an error: %v",
|
||||
actual,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPathsKeysCerts(t *testing.T) {
|
||||
var tests = []struct {
|
||||
pkiPath string
|
||||
name string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
pkiPath: "foo",
|
||||
name: "bar",
|
||||
expected: []string{"foo/bar-pub.pem", "foo/bar-key.pem", "foo/bar.pem"},
|
||||
},
|
||||
{
|
||||
pkiPath: "bar",
|
||||
name: "foo",
|
||||
expected: []string{"bar/foo-pub.pem", "bar/foo-key.pem", "bar/foo.pem"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
a, b, c := pathsKeysCerts(rt.pkiPath, rt.name)
|
||||
all := []string{a, b, c}
|
||||
for i := range all {
|
||||
if all[i] != rt.expected[i] {
|
||||
t.Errorf(
|
||||
"failed pathsKeysCerts:\n\texpected: %s\n\t actual: %s",
|
||||
rt.expected[i],
|
||||
all[i],
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewServiceAccountKey(t *testing.T) {
|
||||
r, err := newServiceAccountKey()
|
||||
if r == nil {
|
||||
t.Errorf(
|
||||
"failed newServiceAccountKey, rsa key == nil",
|
||||
)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf(
|
||||
"failed newServiceAccountKey with an error: %v",
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreatePKIAssets(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create tmpdir")
|
||||
}
|
||||
defer os.Remove(tmpdir)
|
||||
|
||||
// set up tmp GlobalEnvParams values for testing
|
||||
oldEnv := kubeadmapi.GlobalEnvParams
|
||||
kubeadmapi.GlobalEnvParams.HostPKIPath = fmt.Sprintf("%s/etc/kubernetes/pki", tmpdir)
|
||||
defer func() { kubeadmapi.GlobalEnvParams = oldEnv }()
|
||||
|
||||
var tests = []struct {
|
||||
cfg *kubeadmapi.MasterConfiguration
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadm.API{AdvertiseAddresses: []string{"10.0.0.1"}},
|
||||
Networking: kubeadm.Networking{ServiceSubnet: "10.0.0.1/1"},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
API: kubeadm.API{AdvertiseAddresses: []string{"10.0.0.1"}},
|
||||
Networking: kubeadm.Networking{ServiceSubnet: "10.0.0.1/24"},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
for _, rt := range tests {
|
||||
_, _, actual := CreatePKIAssets(rt.cfg)
|
||||
if (actual == nil) != rt.expected {
|
||||
t.Errorf(
|
||||
"failed CreatePKIAssets with an error:\n\texpected: %t\n\t actual: %t",
|
||||
rt.expected,
|
||||
(actual == nil),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
64
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/tokens.go
generated
vendored
Normal file
64
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/tokens.go
generated
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
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 master
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/util/uuid"
|
||||
)
|
||||
|
||||
func generateTokenIfNeeded(s *kubeadmapi.Secrets) error {
|
||||
ok, err := kubeadmutil.UseGivenTokenIfValid(s)
|
||||
// TODO(phase1+) @krousey: I know it won't happen with the way it is currently implemented, but this doesn't handle case where ok is true and err is non-nil.
|
||||
if !ok {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = kubeadmutil.GenerateToken(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("<master/tokens> generated token: %q\n", s.GivenToken)
|
||||
} else {
|
||||
fmt.Println("<master/tokens> accepted provided token")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateTokenAuthFile(s *kubeadmapi.Secrets) error {
|
||||
tokenAuthFilePath := path.Join(kubeadmapi.GlobalEnvParams.HostPKIPath, "tokens.csv")
|
||||
if err := generateTokenIfNeeded(s); err != nil {
|
||||
return fmt.Errorf("<master/tokens> failed to generate token(s) [%v]", err)
|
||||
}
|
||||
if err := os.MkdirAll(kubeadmapi.GlobalEnvParams.HostPKIPath, 0700); err != nil {
|
||||
return fmt.Errorf("<master/tokens> failed to create directory %q [%v]", kubeadmapi.GlobalEnvParams.HostPKIPath, err)
|
||||
}
|
||||
serialized := []byte(fmt.Sprintf("%s,kubeadm-node-csr,%s,system:kubelet-bootstrap\n", s.BearerToken, uuid.NewUUID()))
|
||||
// DumpReaderToFile create a file with mode 0600
|
||||
if err := cmdutil.DumpReaderToFile(bytes.NewReader(serialized), tokenAuthFilePath); err != nil {
|
||||
return fmt.Errorf("<master/tokens> failed to save token auth file (%q) [%v]", tokenAuthFilePath, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
83
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/tokens_test.go
generated
vendored
Normal file
83
vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/tokens_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
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 master
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
)
|
||||
|
||||
func TestGenerateTokenIfNeeded(t *testing.T) {
|
||||
var tests = []struct {
|
||||
s kubeadmapi.Secrets
|
||||
expected bool
|
||||
}{
|
||||
{kubeadmapi.Secrets{GivenToken: "noperiod"}, false}, // not 2-part '.' format
|
||||
{kubeadmapi.Secrets{GivenToken: "abcd.a"}, false}, // len(tokenID) != 6
|
||||
{kubeadmapi.Secrets{GivenToken: "abcdef.a"}, true},
|
||||
{kubeadmapi.Secrets{GivenToken: ""}, true},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
actual := generateTokenIfNeeded(&rt.s)
|
||||
if (actual == nil) != rt.expected {
|
||||
t.Errorf(
|
||||
"failed UseGivenTokenIfValid:\n\texpected: %t\n\t actual: %t\n\t token:%s",
|
||||
rt.expected,
|
||||
(actual == nil),
|
||||
rt.s.GivenToken,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateTokenAuthFile(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create tmpdir")
|
||||
}
|
||||
defer os.Remove(tmpdir)
|
||||
|
||||
// set up tmp GlobalEnvParams values for testing
|
||||
oldEnv := kubeadmapi.GlobalEnvParams
|
||||
kubeadmapi.GlobalEnvParams.HostPKIPath = fmt.Sprintf("%s/etc/kubernetes/pki", tmpdir)
|
||||
defer func() { kubeadmapi.GlobalEnvParams = oldEnv }()
|
||||
|
||||
var tests = []struct {
|
||||
s kubeadmapi.Secrets
|
||||
expected bool
|
||||
}{
|
||||
{kubeadmapi.Secrets{GivenToken: "noperiod"}, false}, // not 2-part '.' format
|
||||
{kubeadmapi.Secrets{GivenToken: "abcd.a"}, false}, // len(tokenID) != 6
|
||||
{kubeadmapi.Secrets{GivenToken: "abcdef.a"}, true},
|
||||
{kubeadmapi.Secrets{GivenToken: ""}, true},
|
||||
}
|
||||
for _, rt := range tests {
|
||||
actual := CreateTokenAuthFile(&rt.s)
|
||||
if (actual == nil) != rt.expected {
|
||||
t.Errorf(
|
||||
"failed WriteKubeconfigIfNotExists with an error:\n\texpected: %t\n\t actual: %t",
|
||||
rt.expected,
|
||||
(actual == nil),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue