Skip to content

Commit

Permalink
Merge pull request kubernetes#53553 from bsteciuk/kubeadm-windows
Browse files Browse the repository at this point in the history
Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

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

**What this PR does / why we need it**:
This PR adds initial support for adding a Windows worker node to a Kubernetes cluster with kubeadm.  Also adds Windows build of kubeadm to node build targets. 

**Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes kubernetes/kubeadm#364 

**Special notes for your reviewer**:

Depends on kubernetes#53730 

**Release note**:

```release-note
kubeadm: Add support for adding a Windows node
```
  • Loading branch information
Kubernetes Submit Queue authored Nov 1, 2017
2 parents fcf9b1f + 44fbec2 commit 574492a
Show file tree
Hide file tree
Showing 11 changed files with 221 additions and 40 deletions.
2 changes: 1 addition & 1 deletion build/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ release_filegroup(
name = "node-targets",
srcs = [
"//cmd/kube-proxy",
"//cmd/kubeadm",
"//cmd/kubelet",
],
)
Expand All @@ -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",
],
Expand Down
8 changes: 7 additions & 1 deletion cmd/kubeadm/app/apis/kubeadm/v1alpha1/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 0 additions & 2 deletions cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 22 additions & 0 deletions cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults_unix.go
Original file line number Diff line number Diff line change
@@ -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"
22 changes: 22 additions & 0 deletions cmd/kubeadm/app/apis/kubeadm/v1alpha1/defaults_windows.go
Original file line number Diff line number Diff line change
@@ -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"
8 changes: 7 additions & 1 deletion cmd/kubeadm/app/preflight/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
61 changes: 30 additions & 31 deletions cmd/kubeadm/app/preflight/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"time"

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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},
Expand Down Expand Up @@ -774,7 +769,7 @@ func RunJoinNodeChecks(cfg *kubeadmapi.NodeConfiguration) error {

checks := []Checker{
SystemVerificationCheck{},
IsRootCheck{},
IsPrivilegedUserCheck{},
HostnameCheck{cfg.NodeName},
KubeletVersionCheck{},
ServiceCheck{Service: "kubelet", CheckIfActive: false},
Expand All @@ -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 {
Expand All @@ -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)
Expand Down
34 changes: 34 additions & 0 deletions cmd/kubeadm/app/preflight/checks_unix.go
Original file line number Diff line number Diff line change
@@ -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
}
44 changes: 44 additions & 0 deletions cmd/kubeadm/app/preflight/checks_windows.go
Original file line number Diff line number Diff line change
@@ -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
}
1 change: 1 addition & 0 deletions hack/lib/golang.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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[@]}"
Expand Down
57 changes: 53 additions & 4 deletions pkg/util/initsystem/initsystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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
}
Expand All @@ -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) {
Expand All @@ -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")
}

0 comments on commit 574492a

Please sign in to comment.