Kubeadm - Added initial support for Windows worker nodes to join cluster using kubeadm

Added kubeadm to node build targets

Created unix/windows specific conditionally compiled for checks.go and defaults.go
pull/6/head
Bob Steciuk 2017-10-11 11:18:03 -04:00
parent f6a89df3fb
commit 44fbec29c4
11 changed files with 221 additions and 40 deletions

View File

@ -111,6 +111,7 @@ release_filegroup(
name = "node-targets",
srcs = [
"//cmd/kube-proxy",
"//cmd/kubeadm",
"//cmd/kubelet",
],
)
@ -125,7 +126,6 @@ release_filegroup(
"//cmd/hyperkube",
"//cmd/kube-apiserver",
"//cmd/kube-controller-manager",
"//cmd/kubeadm",
"//plugin/cmd/kube-scheduler",
"//vendor/k8s.io/kube-aggregator",
],

View File

@ -9,13 +9,19 @@ go_library(
name = "go_default_library",
srcs = [
"defaults.go",
"defaults_unix.go",
"doc.go",
"register.go",
"types.go",
"zz_generated.conversion.go",
"zz_generated.deepcopy.go",
"zz_generated.defaults.go",
],
] + select({
"@io_bazel_rules_go//go/platform:windows_amd64": [
"defaults_windows.go",
],
"//conditions:default": [],
}),
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1",
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",

View File

@ -36,8 +36,6 @@ const (
DefaultAPIBindPort = 6443
// DefaultAuthorizationModes defines default authorization modes
DefaultAuthorizationModes = "Node,RBAC"
// DefaultCACertPath defines default location of CA certificate
DefaultCACertPath = "/etc/kubernetes/pki/ca.crt"
// DefaultCertificatesDir defines default certificate directory
DefaultCertificatesDir = "/etc/kubernetes/pki"
// DefaultEtcdDataDir defines default location of etcd

View File

@ -0,0 +1,22 @@
// +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 v1alpha1
// DefaultCACertPath defines default location of CA certificate on Linux
const DefaultCACertPath = "/etc/kubernetes/pki/ca.crt"

View File

@ -0,0 +1,22 @@
// +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 v1alpha1
// DefaultCACertPath defines default location of CA certificate on Windows
const DefaultCACertPath = "C:/etc/kubernetes/pki/ca.crt"

View File

@ -10,8 +10,14 @@ go_library(
name = "go_default_library",
srcs = [
"checks.go",
"checks_unix.go",
"utils.go",
],
] + select({
"@io_bazel_rules_go//go/platform:windows_amd64": [
"checks_windows.go",
],
"//conditions:default": [],
}),
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/preflight",
deps = [
"//cmd/kube-apiserver/app/options:go_default_library",

View File

@ -28,6 +28,7 @@ import (
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"time"
@ -166,18 +167,8 @@ func (poc PortOpenCheck) Check() (warnings, errors []error) {
return nil, errors
}
// IsRootCheck verifies user is root
type IsRootCheck struct{}
// Check validates if an user has root privileges.
func (irc IsRootCheck) Check() (warnings, errors []error) {
errors = []error{}
if os.Getuid() != 0 {
errors = append(errors, fmt.Errorf("user is not running as root"))
}
return nil, errors
}
// IsPrivilegedUserCheck verifies user is privileged (linux - root, windows - Administrator)
type IsPrivilegedUserCheck struct{}
// DirAvailableCheck checks if the given directory either does not exist, or is empty.
type DirAvailableCheck struct {
@ -438,12 +429,16 @@ func (sysver SystemVerificationCheck) Check() (warnings, errors []error) {
var errs []error
var warns []error
// All the validators we'd like to run:
// All the common validators we'd like to run:
var validators = []system.Validator{
&system.OSValidator{Reporter: reporter},
&system.KernelValidator{Reporter: reporter},
&system.CgroupsValidator{Reporter: reporter},
&system.DockerValidator{Reporter: reporter},
&system.DockerValidator{Reporter: reporter}}
if runtime.GOOS == "linux" {
//add linux validators
validators = append(validators,
&system.OSValidator{Reporter: reporter},
&system.CgroupsValidator{Reporter: reporter})
}
// Run all validators
@ -691,7 +686,7 @@ func RunInitMasterChecks(cfg *kubeadmapi.MasterConfiguration) error {
checks := []Checker{
KubernetesVersionCheck{KubernetesVersion: cfg.KubernetesVersion, KubeadmVersion: kubeadmversion.Get().GitVersion},
SystemVerificationCheck{},
IsRootCheck{},
IsPrivilegedUserCheck{},
HostnameCheck{nodeName: cfg.NodeName},
KubeletVersionCheck{},
ServiceCheck{Service: "kubelet", CheckIfActive: false},
@ -774,7 +769,7 @@ func RunJoinNodeChecks(cfg *kubeadmapi.NodeConfiguration) error {
checks := []Checker{
SystemVerificationCheck{},
IsRootCheck{},
IsPrivilegedUserCheck{},
HostnameCheck{cfg.NodeName},
KubeletVersionCheck{},
ServiceCheck{Service: "kubelet", CheckIfActive: false},
@ -783,17 +778,21 @@ func RunJoinNodeChecks(cfg *kubeadmapi.NodeConfiguration) error {
DirAvailableCheck{Path: filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ManifestsSubDirName)},
FileAvailableCheck{Path: cfg.CACertPath},
FileAvailableCheck{Path: filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.KubeletKubeConfigFileName)},
FileContentCheck{Path: bridgenf, Content: []byte{'1'}},
SwapCheck{},
InPathCheck{executable: "ip", mandatory: true},
InPathCheck{executable: "iptables", mandatory: true},
InPathCheck{executable: "mount", mandatory: true},
InPathCheck{executable: "nsenter", mandatory: true},
InPathCheck{executable: "ebtables", mandatory: false},
InPathCheck{executable: "ethtool", mandatory: false},
InPathCheck{executable: "socat", mandatory: false},
InPathCheck{executable: "tc", mandatory: false},
InPathCheck{executable: "touch", mandatory: false},
}
//non-windows checks
if runtime.GOOS == "linux" {
checks = append(checks,
FileContentCheck{Path: bridgenf, Content: []byte{'1'}},
SwapCheck{},
InPathCheck{executable: "ip", mandatory: true},
InPathCheck{executable: "iptables", mandatory: true},
InPathCheck{executable: "mount", mandatory: true},
InPathCheck{executable: "nsenter", mandatory: true},
InPathCheck{executable: "ebtables", mandatory: false},
InPathCheck{executable: "ethtool", mandatory: false},
InPathCheck{executable: "socat", mandatory: false},
InPathCheck{executable: "tc", mandatory: false},
InPathCheck{executable: "touch", mandatory: false})
}
if len(cfg.DiscoveryTokenAPIServers) > 0 {
@ -808,10 +807,10 @@ func RunJoinNodeChecks(cfg *kubeadmapi.NodeConfiguration) error {
return RunChecks(checks, os.Stderr)
}
// RunRootCheckOnly initializes cheks slice of structs and call RunChecks
// RunRootCheckOnly initializes checks slice of structs and call RunChecks
func RunRootCheckOnly() error {
checks := []Checker{
IsRootCheck{},
IsPrivilegedUserCheck{},
}
return RunChecks(checks, os.Stderr)

View File

@ -0,0 +1,34 @@
// +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 preflight
import (
"fmt"
"os"
)
// Check validates if an user has elevated (root) privileges.
func (ipuc IsPrivilegedUserCheck) Check() (warnings, errors []error) {
errors = []error{}
if os.Getuid() != 0 {
errors = append(errors, fmt.Errorf("user is not running as root"))
}
return nil, errors
}

View File

@ -0,0 +1,44 @@
// +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 preflight
import (
"fmt"
"os/exec"
"strings"
)
// Check validates if an user has elevated (administrator) privileges.
func (ipuc IsPrivilegedUserCheck) Check() (warnings, errors []error) {
errors = []error{}
// The "Well-known SID" of Administrator group is S-1-5-32-544
// The following powershell will return "True" if run as an administrator, "False" otherwise
// See https://msdn.microsoft.com/en-us/library/cc980032.aspx
args := []string{"[bool](([System.Security.Principal.WindowsIdentity]::GetCurrent()).groups -match \"S-1-5-32-544\")"}
isAdmin, err := exec.Command("powershell", args...).Output()
if err != nil {
errors = append(errors, fmt.Errorf("unable to determine if user is running as administrator: %s", err))
} else if strings.EqualFold(strings.TrimSpace(string(isAdmin)), "false") {
errors = append(errors, fmt.Errorf("user is not running as administrator"))
}
return nil, errors
}

View File

@ -44,6 +44,7 @@ readonly KUBE_SERVER_BINARIES=("${KUBE_SERVER_TARGETS[@]##*/}")
kube::golang::node_targets() {
local targets=(
cmd/kube-proxy
cmd/kubeadm
cmd/kubelet
)
echo "${targets[@]}"

View File

@ -43,13 +43,13 @@ type SystemdInitSystem struct{}
func (sysd SystemdInitSystem) ServiceStart(service string) error {
args := []string{"start", service}
_, err := exec.Command("systemctl", args...).Output()
err := exec.Command("systemctl", args...).Run()
return err
}
func (sysd SystemdInitSystem) ServiceStop(service string) error {
args := []string{"stop", service}
_, err := exec.Command("systemctl", args...).Output()
err := exec.Command("systemctl", args...).Run()
return err
}
@ -65,7 +65,7 @@ func (sysd SystemdInitSystem) ServiceExists(service string) bool {
func (sysd SystemdInitSystem) ServiceIsEnabled(service string) bool {
args := []string{"is-enabled", service}
_, err := exec.Command("systemctl", args...).Output()
err := exec.Command("systemctl", args...).Run()
if err != nil {
return false
}
@ -86,7 +86,52 @@ func (sysd SystemdInitSystem) ServiceIsActive(service string) bool {
return false
}
// getInitSystem returns an InitSystem for the current system, or nil
// WindowsInitSystem is the windows implementation of InitSystem
type WindowsInitSystem struct{}
func (sysd WindowsInitSystem) ServiceStart(service string) error {
args := []string{"Start-Service", service}
err := exec.Command("powershell", args...).Run()
return err
}
func (sysd WindowsInitSystem) ServiceStop(service string) error {
args := []string{"Stop-Service", service}
err := exec.Command("powershell", args...).Run()
return err
}
func (sysd WindowsInitSystem) ServiceExists(service string) bool {
args := []string{"Get-Service", service}
err := exec.Command("powershell", args...).Run()
if err != nil {
return false
}
return true
}
func (sysd WindowsInitSystem) ServiceIsEnabled(service string) bool {
args := []string{"Get-Service", service + "| select -property starttype"}
outBytes, _ := exec.Command("powershell", args...).Output()
output := strings.TrimSpace(string(outBytes))
if strings.Contains(output, "Automatic") {
return true
}
return false
}
func (sysd WindowsInitSystem) ServiceIsActive(service string) bool {
args := []string{"Get-Service", service + "| select -property status"}
outBytes, _ := exec.Command("powershell", args...).Output()
output := strings.TrimSpace(string(outBytes))
if strings.Contains(output, "Running") {
return true
}
return false
}
// GetInitSystem returns an InitSystem for the current system, or nil
// if we cannot detect a supported init system for pre-flight checks.
// This indicates we will skip init system checks, not an error.
func GetInitSystem() (InitSystem, error) {
@ -95,5 +140,9 @@ func GetInitSystem() (InitSystem, error) {
if err == nil {
return &SystemdInitSystem{}, nil
}
_, err = exec.LookPath("wininit.exe")
if err == nil {
return &WindowsInitSystem{}, nil
}
return nil, fmt.Errorf("no supported init system detected, skipping checking for services")
}