diff --git a/build/BUILD b/build/BUILD index aa6efab3d4d6c..5d16b60421cb2 100644 --- a/build/BUILD +++ b/build/BUILD @@ -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", ], diff --git a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/BUILD b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/BUILD index 427c31061cd86..5600981190fb0 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/BUILD +++ b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/BUILD @@ -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", diff --git a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults.go b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults.go index ec0676886f503..f67f5bdbcaf2b 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults.go @@ -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" // DefaultImageRepository defines default image registry diff --git a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults_unix.go b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults_unix.go new file mode 100644 index 0000000000000..5de428506261a --- /dev/null +++ b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults_unix.go @@ -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" diff --git a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults_windows.go b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults_windows.go new file mode 100644 index 0000000000000..d073613930d59 --- /dev/null +++ b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults_windows.go @@ -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" diff --git a/cmd/kubeadm/app/preflight/BUILD b/cmd/kubeadm/app/preflight/BUILD index ebcd4d5b1a140..c3dae018135df 100644 --- a/cmd/kubeadm/app/preflight/BUILD +++ b/cmd/kubeadm/app/preflight/BUILD @@ -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", diff --git a/cmd/kubeadm/app/preflight/checks.go b/cmd/kubeadm/app/preflight/checks.go index 034faa45efc20..66c31a726caac 100644 --- a/cmd/kubeadm/app/preflight/checks.go +++ b/cmd/kubeadm/app/preflight/checks.go @@ -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) diff --git a/cmd/kubeadm/app/preflight/checks_unix.go b/cmd/kubeadm/app/preflight/checks_unix.go new file mode 100644 index 0000000000000..1f2fb754e0133 --- /dev/null +++ b/cmd/kubeadm/app/preflight/checks_unix.go @@ -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 +} diff --git a/cmd/kubeadm/app/preflight/checks_windows.go b/cmd/kubeadm/app/preflight/checks_windows.go new file mode 100644 index 0000000000000..1cc9bb3e59ec7 --- /dev/null +++ b/cmd/kubeadm/app/preflight/checks_windows.go @@ -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 +} diff --git a/hack/lib/golang.sh b/hack/lib/golang.sh index d6ed00bf0cca5..027a080415cbd 100755 --- a/hack/lib/golang.sh +++ b/hack/lib/golang.sh @@ -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[@]}" diff --git a/pkg/util/initsystem/initsystem.go b/pkg/util/initsystem/initsystem.go index 435cf57ad3e38..e4f8870a36445 100644 --- a/pkg/util/initsystem/initsystem.go +++ b/pkg/util/initsystem/initsystem.go @@ -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") }