Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion cmd/minikube/cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,15 +499,36 @@ func startWithDriver(cmd *cobra.Command, starter node.Starter, existing *config.
KubernetesVersion: starter.Cfg.KubernetesConfig.KubernetesVersion,
ContainerRuntime: starter.Cfg.KubernetesConfig.ContainerRuntime,
Worker: true,
OS: "linux",
}
if i < numCPNodes { // starter node is also counted as (primary) cp node
n.ControlPlane = true
}
}

out.Ln("") // extra newline for clarity on the command line
// 1st call
if err := node.Add(starter.Cfg, n, viper.GetBool(deleteOnFailure)); err != nil {
return nil, errors.Wrap(err, "adding node")
return nil, errors.Wrap(err, "adding linux node")
}
}

// start windows node. trigger windows node start only if windows node version is set at the time of minikube start
if cmd.Flags().Changed(windowsNodeVersion) {
// TODO: if windows node version is set to windows server 2022 then the windows node name should be minikube-ws2022
nodeName := node.Name(numNodes + 1)
n := config.Node{
Name: nodeName,
Port: starter.Cfg.APIServerPort,
KubernetesVersion: starter.Cfg.KubernetesConfig.KubernetesVersion,
ContainerRuntime: starter.Cfg.KubernetesConfig.ContainerRuntime,
Worker: true,
OS: "windows",
}

out.Ln("") // extra newline for clarity on the command line
if err := node.Add(starter.Cfg, n, viper.GetBool(deleteOnFailure)); err != nil {
return nil, errors.Wrap(err, "adding windows node")
}
}

Expand Down
6 changes: 1 addition & 5 deletions cmd/minikube/cmd/start_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -483,11 +483,7 @@ func TestValidateWindowsOSVersion(t *testing.T) {
errorMsg string
}{
{
osVersion: "2019",
errorMsg: "",
},
{
osVersion: "2022",
osVersion: "2025",
errorMsg: "",
},
{
Expand Down
3 changes: 3 additions & 0 deletions pkg/minikube/bootstrapper/bootstrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,11 @@ type Bootstrapper interface {
UpdateCluster(config.ClusterConfig) error
DeleteCluster(config.KubernetesConfig) error
WaitForNode(config.ClusterConfig, config.Node, time.Duration) error
SetMinikubeFolderErrorScript(string) (string, error)
JoinClusterWindows(string, config.ClusterConfig, config.Node, string, time.Duration) (string, error)
JoinCluster(config.ClusterConfig, config.Node, string) error
UpdateNode(config.ClusterConfig, config.Node, cruntime.Manager) error
GenerateTokenWindows(config.ClusterConfig) (string, error)
GenerateToken(config.ClusterConfig) (string, error)
// LogCommands returns a map of log type to a command which will display that log.
LogCommands(config.ClusterConfig, LogOptions) map[string]string
Expand Down
5 changes: 5 additions & 0 deletions pkg/minikube/bootstrapper/certs.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ type sharedCACerts struct {

// SetupCerts gets the generated credentials required to talk to the APIServer.
func SetupCerts(k8s config.ClusterConfig, n config.Node, pcpCmd command.Runner, cmd command.Runner) error {
// no need to setup certs for windows worker nodes as the master node already took care of this
if n.OS == "windows" {
return nil
}

localPath := localpath.Profile(k8s.KubernetesConfig.ClusterName)
klog.Infof("Setting up %s for IP: %s", localPath, n.IP)

Expand Down
131 changes: 131 additions & 0 deletions pkg/minikube/bootstrapper/kubeadm/kubeadm.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/state"
"github.com/pkg/errors"
"golang.org/x/crypto/ssh"
core "k8s.io/api/core/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
Expand All @@ -58,7 +59,7 @@
"k8s.io/minikube/pkg/minikube/detect"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/kubeconfig"
"k8s.io/minikube/pkg/minikube/machine"

Check failure on line 62 in pkg/minikube/bootstrapper/kubeadm/kubeadm.go

View workflow job for this annotation

GitHub Actions / lint

could not import k8s.io/minikube/pkg/minikube/machine (-: # k8s.io/minikube/pkg/minikube/machine
"k8s.io/minikube/pkg/minikube/out"
"k8s.io/minikube/pkg/minikube/out/register"
"k8s.io/minikube/pkg/minikube/style"
Expand Down Expand Up @@ -751,6 +752,106 @@
return nil
}

func (k *Bootstrapper) SetMinikubeFolderErrorScript(hostDriverIP string) (string, error) {
out.Step(style.Provisioning, "Setting up minikube certificates folder...")
script := fmt.Sprintf(
`mkdir c:\var\lib\minikube\certs; Copy-Item C:\etc\kubernetes\pki\ca.crt -Destination C:\var\lib\Minikube\Certs; Remove-Item C:\etc\kubernetes\pki\ca.crt`)

// Escape double quotes for remote execution
script = strings.ReplaceAll(script, `"`, `\"`)

config := &ssh.ClientConfig{
User: "Administrator",
Auth: []ssh.AuthMethod{
ssh.Password("password"),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}

// Add port 22 to the IP
hostDriverIP = hostDriverIP + ":22"
// Log the IP
klog.Infof("hostDriverIP: %s", hostDriverIP)

client, err := ssh.Dial("tcp", hostDriverIP, config)
if err != nil {
klog.Warningf("Failed to connect: %v", err)
return "", err
}
defer client.Close()

// Execute the script on the remote Windows node
return machine.CmdOut(client, script)
}

// JoinCluster adds new node to an existing cluster.
func (k *Bootstrapper) JoinClusterWindows(hostDriverIP string, cc config.ClusterConfig, n config.Node, joinCmd string, timeout time.Duration) (string, error) {
// Define the path to set location
setLocationPath := `Set-Location -Path "C:\k"`

// Form the script to be executed
psScript := fmt.Sprintf("%s; %s", setLocationPath, joinCmd)

// Escape double quotes inside the script
psScript = strings.ReplaceAll(psScript, `"`, `\"`)

config := &ssh.ClientConfig{
User: "Administrator",
Auth: []ssh.AuthMethod{
ssh.Password("password"),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}

// Add port 22 to the IP
hostDriverIP = hostDriverIP + ":22"
klog.Infof("hostDriverIP: %s", hostDriverIP)

// this need to be explored more to see if we can make it better
// Create channels for result and errors
resultChan := make(chan string, 1)
errorChan := make(chan error, 1)

go func() {
client, err := ssh.Dial("tcp", hostDriverIP, config)
if err != nil {
klog.Warningf("Failed to connect: %v", err)
errorChan <- err
return
}
defer client.Close()

// Execute the script on the remote Windows node
output, err := machine.CmdOut(client, psScript)
if err != nil {
errorChan <- err
return
}

resultChan <- output
}()

if timeout > 0 {
// If timeout is set, enforce it
select {
case result := <-resultChan:
return result, nil
case err := <-errorChan:
return "", err
case <-time.After(timeout):
return "", fmt.Errorf("operation timed out after %s", timeout)
}
} else {
// If no timeout is set, just wait for result or error
select {
case result := <-resultChan:
return result, nil
case err := <-errorChan:
return "", err
}
}
}

// JoinCluster adds new node to an existing cluster.
func (k *Bootstrapper) JoinCluster(cc config.ClusterConfig, n config.Node, joinCmd string) error {
// Join the control plane by specifying its token
Expand Down Expand Up @@ -778,6 +879,30 @@
return nil
}

// GenerateToken creates a token and returns the appropriate kubeadm join command to run, or the already existing token
func (k *Bootstrapper) GenerateTokenWindows(cc config.ClusterConfig) (string, error) {
tokenCmd := exec.Command("/bin/bash", "-c", fmt.Sprintf("%s token create --print-join-command --ttl=0", bsutil.InvokeKubeadm(cc.KubernetesConfig.KubernetesVersion)))
r, err := k.c.RunCmd(tokenCmd)
if err != nil {
return "", errors.Wrap(err, "generating join command")
}

joinCmd := r.Stdout.String()
// log the join command for debugging purposes
klog.Infof("Generated join command ===: %s", joinCmd)
joinCmd = strings.Replace(joinCmd, "kubeadm", ".\\kubeadm.exe", 1)
joinCmd = fmt.Sprintf("%s --ignore-preflight-errors=all", strings.TrimSpace(joinCmd))

// append the cri-socket flag to the join command for windows
joinCmd = fmt.Sprintf("%s --cri-socket \"npipe:////./pipe/containerd-containerd\"", joinCmd)

// append --v=5 to the join command for windows
joinCmd = fmt.Sprintf("%s --v=5", joinCmd)

return joinCmd, nil

}

// GenerateToken creates a token and returns the appropriate kubeadm join command to run, or the already existing token
func (k *Bootstrapper) GenerateToken(cc config.ClusterConfig) (string, error) {
// Take that generated token and use it to get a kubeadm join command
Expand Down Expand Up @@ -931,6 +1056,12 @@

// UpdateNode updates new or existing node.
func (k *Bootstrapper) UpdateNode(cfg config.ClusterConfig, n config.Node, r cruntime.Manager) error {
// skip if the node is a windows node
if n.OS == "windows" {
klog.Infof("skipping node %v update, as it is a windows node", n)
return nil
}

klog.Infof("updating node %v ...", n)

kubeletCfg, err := bsutil.NewKubeletConfig(cfg, n, r)
Expand Down
1 change: 1 addition & 0 deletions pkg/minikube/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ type Node struct {
ContainerRuntime string
ControlPlane bool
Worker bool
OS string
}

// VersionedExtraOption holds information on flags to apply to a specific range
Expand Down
4 changes: 3 additions & 1 deletion pkg/minikube/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import (
var (
// SupportedArchitectures is the list of supported architectures
SupportedArchitectures = [5]string{"amd64", "arm", "arm64", "ppc64le", "s390x"}
// IP Address for the control plane
MasterNodeIP = ""
)

const (
Expand Down Expand Up @@ -165,7 +167,7 @@ const (
AliyunMirror = "registry.cn-hangzhou.aliyuncs.com/google_containers"

// DefaultWindowsNodeVersion is the default version of Windows node
DefaultWindowsNodeVersion = "2022"
DefaultWindowsNodeVersion = "2025"

// Windows Server ISO URL
DefaultWindowsServerIsoURL = "https://go.microsoft.com/fwlink/p/?LinkID=2195280&clcid=0x409&culture=en-us&country=US"
Expand Down
16 changes: 13 additions & 3 deletions pkg/minikube/machine/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
}
certsDir := localpath.MakeMiniPath("certs")

return &LocalClient{

Check failure on line 70 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / lint

cannot use &LocalClient{…} (value of type *LocalClient) as libmachine.API value in return statement: *LocalClient does not implement libmachine.API (wrong type for method NewHost)

Check failure on line 70 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / build_minikube_test_binaries

cannot use &LocalClient{…} (value of type *LocalClient) as libmachine.API value in return statement: *LocalClient does not implement libmachine.API (wrong type for method NewHost)

Check failure on line 70 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / unit_test

cannot use &LocalClient{…} (value of type *LocalClient) as libmachine.API value in return statement: *LocalClient does not implement libmachine.API (wrong type for method NewHost)

Check failure on line 70 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / build_minikube

cannot use &LocalClient{…} (value of type *LocalClient) as libmachine.API value in return statement: *LocalClient does not implement libmachine.API (wrong type for method NewHost)
certsDir: certsDir,
storePath: storePath,
Filestore: persist.NewFilestore(storePath, certsDir, certsDir),
Expand All @@ -86,14 +86,19 @@
flock *fslock.Lock
}

// DefineGuest is a method required by the libmachine.API interface.
func (api *LocalClient) DefineGuest(h *host.Host) {
api.legacyClient.DefineGuest(h)

Check failure on line 91 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / lint

api.legacyClient.DefineGuest undefined (type libmachine.API has no field or method DefineGuest)

Check failure on line 91 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / build_minikube_test_binaries

api.legacyClient.DefineGuest undefined (type libmachine.API has no field or method DefineGuest)

Check failure on line 91 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / unit_test

api.legacyClient.DefineGuest undefined (type libmachine.API has no field or method DefineGuest)

Check failure on line 91 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / build_minikube

api.legacyClient.DefineGuest undefined (type libmachine.API has no field or method DefineGuest)
}

// NewHost creates a new Host
func (api *LocalClient) NewHost(drvName string, rawDriver []byte) (*host.Host, error) {
func (api *LocalClient) NewHost(drvName string, guestOS string, rawDriver []byte) (*host.Host, error) {
def := registry.Driver(drvName)
if def.Empty() {
return nil, fmt.Errorf("driver %q does not exist", drvName)
}
if def.Init == nil {
return api.legacyClient.NewHost(drvName, rawDriver)
return api.legacyClient.NewHost(drvName, guestOS, rawDriver)

Check failure on line 101 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / lint

too many arguments in call to api.legacyClient.NewHost

Check failure on line 101 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / build_minikube_test_binaries

too many arguments in call to api.legacyClient.NewHost

Check failure on line 101 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / unit_test

too many arguments in call to api.legacyClient.NewHost

Check failure on line 101 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / build_minikube

too many arguments in call to api.legacyClient.NewHost
}
d := def.Init()
err := json.Unmarshal(rawDriver, d)
Expand All @@ -106,6 +111,7 @@
Name: d.GetMachineName(),
Driver: d,
DriverName: d.DriverName(),
GuestOS: guestOS,

Check failure on line 114 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / lint

unknown field GuestOS in struct literal of type host.Host

Check failure on line 114 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / build_minikube_test_binaries

unknown field GuestOS in struct literal of type host.Host

Check failure on line 114 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / unit_test

unknown field GuestOS in struct literal of type host.Host

Check failure on line 114 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / build_minikube

unknown field GuestOS in struct literal of type host.Host
HostOptions: &host.Options{
AuthOptions: &auth.Options{
CertDir: api.certsDir,
Expand Down Expand Up @@ -229,10 +235,14 @@
{
"provisioning",
func() error {
// Skippable because we don't reconfigure Docker?
// Skipped because we don't reconfigure Docker?
if driver.BareMetal(h.Driver.DriverName()) {
return nil
}
// Skipped because we don't reconfigure Docker for Windows Host
if h.GuestOS == "windows" {

Check failure on line 243 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / lint

h.GuestOS undefined (type *host.Host has no field or method GuestOS)

Check failure on line 243 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / build_minikube_test_binaries

h.GuestOS undefined (type *host.Host has no field or method GuestOS)

Check failure on line 243 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / unit_test

h.GuestOS undefined (type *host.Host has no field or method GuestOS)

Check failure on line 243 in pkg/minikube/machine/client.go

View workflow job for this annotation

GitHub Actions / build_minikube

h.GuestOS undefined (type *host.Host has no field or method GuestOS)
return nil
}
return provisionDockerMachine(h)
},
},
Expand Down
Loading
Loading