Merge pull request #16789 from spowelljr/detectBlock
QEMU: Unblock bootpd if start fails to due to blockingpull/16867/head
commit
926cfe4469
|
@ -47,6 +47,7 @@ import (
|
||||||
"golang.org/x/text/cases"
|
"golang.org/x/text/cases"
|
||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
"k8s.io/minikube/pkg/minikube/command"
|
"k8s.io/minikube/pkg/minikube/command"
|
||||||
|
"k8s.io/minikube/pkg/minikube/firewall"
|
||||||
netutil "k8s.io/minikube/pkg/network"
|
netutil "k8s.io/minikube/pkg/network"
|
||||||
|
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
@ -339,7 +340,11 @@ func provisionWithDriver(cmd *cobra.Command, ds registry.DriverState, existing *
|
||||||
return node.Starter{}, errors.Wrap(err, "Failed to generate config")
|
return node.Starter{}, errors.Wrap(err, "Failed to generate config")
|
||||||
}
|
}
|
||||||
|
|
||||||
unblockBootpdFirewall(cc)
|
if firewall.IsBootpdBlocked(cc) {
|
||||||
|
if err := firewall.UnblockBootpd(); err != nil {
|
||||||
|
klog.Warningf("failed unblocking bootpd from firewall: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if driver.IsVM(cc.Driver) && runtime.GOARCH == "arm64" && cc.KubernetesConfig.ContainerRuntime == "crio" {
|
if driver.IsVM(cc.Driver) && runtime.GOARCH == "arm64" && cc.KubernetesConfig.ContainerRuntime == "crio" {
|
||||||
exit.Message(reason.Unimplemented, "arm64 VM drivers do not currently support the crio container runtime. See https://github.com/kubernetes/minikube/issues/14146 for details.")
|
exit.Message(reason.Unimplemented, "arm64 VM drivers do not currently support the crio container runtime. See https://github.com/kubernetes/minikube/issues/14146 for details.")
|
||||||
|
@ -416,64 +421,6 @@ func vmwareUnsupported(driverName string) {
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// isBootpdBlocked returns true if the built-in macOS firewall is on and bootpd is not unblocked
|
|
||||||
func isBootpdBlocked(cc config.ClusterConfig) bool {
|
|
||||||
// only applies to qemu, on macOS, with socket_vmnet
|
|
||||||
if cc.Driver != driver.QEMU2 || runtime.GOOS != "darwin" || cc.Network != "socket_vmnet" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
out, err := exec.Command("/usr/libexec/ApplicationFirewall/socketfilterfw", "--getglobalstate").Output()
|
|
||||||
if err != nil {
|
|
||||||
klog.Warningf("failed to get firewall state: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if regexp.MustCompile(`Firewall is disabled`).Match(out) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
out, err = exec.Command("/usr/libexec/ApplicationFirewall/socketfilterfw", "--listapps").Output()
|
|
||||||
if err != nil {
|
|
||||||
klog.Warningf("failed to list firewall apps: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return !regexp.MustCompile(`\/usr\/libexec\/bootpd.*\n.*\( Allow`).Match(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
// unblockBootpdFirewall adds bootpd to the built-in macOS firewall and then unblocks it
|
|
||||||
func unblockBootpdFirewall(cc config.ClusterConfig) {
|
|
||||||
if !isBootpdBlocked(cc) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cmds := []*exec.Cmd{
|
|
||||||
exec.Command("sudo", "/usr/libexec/ApplicationFirewall/socketfilterfw", "--add", "/usr/libexec/bootpd"),
|
|
||||||
exec.Command("sudo", "/usr/libexec/ApplicationFirewall/socketfilterfw", "--unblock", "/usr/libexec/bootpd"),
|
|
||||||
}
|
|
||||||
|
|
||||||
var cmdString strings.Builder
|
|
||||||
for _, c := range cmds {
|
|
||||||
cmdString.WriteString(fmt.Sprintf(" $ %s \n", strings.Join(c.Args, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
out.Styled(style.Permissions, "Your firewall is blocking bootpd which is required for socket_vmnet. The following commands will be executed to unblock bootpd:\n\n{{.commands}}\n", out.V{"commands": cmdString.String()})
|
|
||||||
|
|
||||||
for _, c := range cmds {
|
|
||||||
testArgs := append([]string{"-n"}, c.Args[1:]...)
|
|
||||||
test := exec.Command("sudo", testArgs...)
|
|
||||||
klog.Infof("testing: %s", test.Args)
|
|
||||||
if err := test.Run(); err != nil {
|
|
||||||
klog.Infof("%v may require a password: %v", c.Args, err)
|
|
||||||
if !viper.GetBool("interactive") {
|
|
||||||
klog.Warningf("%s requires a password, and --interactive=false", c.Args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
klog.Infof("running: %s", c.Args)
|
|
||||||
err := c.Run()
|
|
||||||
if err != nil {
|
|
||||||
klog.Warningf("running %s failed: %v", c.Args, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateBuiltImageVersion(r command.Runner, driverName string) {
|
func validateBuiltImageVersion(r command.Runner, driverName string) {
|
||||||
if driver.IsNone(driverName) {
|
if driver.IsNone(driverName) {
|
||||||
return
|
return
|
||||||
|
|
|
@ -40,9 +40,13 @@ import (
|
||||||
"github.com/docker/machine/libmachine/state"
|
"github.com/docker/machine/libmachine/state"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
"k8s.io/klog/v2"
|
||||||
pkgdrivers "k8s.io/minikube/pkg/drivers"
|
pkgdrivers "k8s.io/minikube/pkg/drivers"
|
||||||
"k8s.io/minikube/pkg/minikube/exit"
|
"k8s.io/minikube/pkg/minikube/exit"
|
||||||
|
"k8s.io/minikube/pkg/minikube/firewall"
|
||||||
|
"k8s.io/minikube/pkg/minikube/out"
|
||||||
"k8s.io/minikube/pkg/minikube/reason"
|
"k8s.io/minikube/pkg/minikube/reason"
|
||||||
|
"k8s.io/minikube/pkg/minikube/style"
|
||||||
"k8s.io/minikube/pkg/network"
|
"k8s.io/minikube/pkg/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -515,13 +519,19 @@ func (d *Driver) Start() error {
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err == nil {
|
||||||
if isBootpdError(err) {
|
log.Debugf("IP: %s", d.IPAddress)
|
||||||
exit.Error(reason.IfBootpdFirewall, "ip not found", err)
|
break
|
||||||
}
|
}
|
||||||
|
if !isBootpdError(err) {
|
||||||
return errors.Wrap(err, "IP address never found in dhcp leases file")
|
return errors.Wrap(err, "IP address never found in dhcp leases file")
|
||||||
}
|
}
|
||||||
log.Debugf("IP: %s", d.IPAddress)
|
if unblockErr := firewall.UnblockBootpd(); unblockErr != nil {
|
||||||
|
klog.Errorf("failed unblocking bootpd from firewall: %v", unblockErr)
|
||||||
|
exit.Error(reason.IfBootpdFirewall, "ip not found", err)
|
||||||
|
}
|
||||||
|
out.Styled(style.Restarting, "Successfully unblocked bootpd process from firewall, retrying")
|
||||||
|
return fmt.Errorf("ip not found: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Waiting for VM to start (ssh -p %d docker@%s)...", d.SSHPort, d.IPAddress)
|
log.Infof("Waiting for VM to start (ssh -p %d docker@%s)...", d.SSHPort, d.IPAddress)
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
Copyright 2023 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
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 firewall
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"k8s.io/klog/v2"
|
||||||
|
"k8s.io/minikube/pkg/minikube/config"
|
||||||
|
"k8s.io/minikube/pkg/minikube/driver"
|
||||||
|
"k8s.io/minikube/pkg/minikube/out"
|
||||||
|
"k8s.io/minikube/pkg/minikube/style"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsBootpdBlocked checks if the bootpd process is blocked by the macOS builtin firewall
|
||||||
|
func IsBootpdBlocked(cc config.ClusterConfig) bool {
|
||||||
|
// only applies to qemu, on macOS, with socket_vmnet
|
||||||
|
if cc.Driver != driver.QEMU2 || runtime.GOOS != "darwin" || cc.Network != "socket_vmnet" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
out, err := exec.Command("/usr/libexec/ApplicationFirewall/socketfilterfw", "--getglobalstate").Output()
|
||||||
|
if err != nil {
|
||||||
|
klog.Warningf("failed to get firewall state: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if regexp.MustCompile(`Firewall is disabled`).Match(out) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
out, err = exec.Command("/usr/libexec/ApplicationFirewall/socketfilterfw", "--listapps").Output()
|
||||||
|
if err != nil {
|
||||||
|
klog.Warningf("failed to list firewall apps: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return !regexp.MustCompile(`\/usr\/libexec\/bootpd.*\n.*\( Allow`).Match(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnblockBootpd adds bootpd to the built-in macOS firewall and then unblocks it
|
||||||
|
func UnblockBootpd() error {
|
||||||
|
cmds := []*exec.Cmd{
|
||||||
|
exec.Command("sudo", "/usr/libexec/ApplicationFirewall/socketfilterfw", "--add", "/usr/libexec/bootpd"),
|
||||||
|
exec.Command("sudo", "/usr/libexec/ApplicationFirewall/socketfilterfw", "--unblock", "/usr/libexec/bootpd"),
|
||||||
|
}
|
||||||
|
|
||||||
|
var cmdString strings.Builder
|
||||||
|
for _, c := range cmds {
|
||||||
|
cmdString.WriteString(fmt.Sprintf(" $ %s \n", strings.Join(c.Args, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
out.Styled(style.Permissions, "Your firewall is blocking bootpd which is required for socket_vmnet. The following commands will be executed to unblock bootpd:\n\n{{.commands}}\n", out.V{"commands": cmdString.String()})
|
||||||
|
|
||||||
|
for _, c := range cmds {
|
||||||
|
testArgs := append([]string{"-n"}, c.Args[1:]...)
|
||||||
|
test := exec.Command("sudo", testArgs...)
|
||||||
|
klog.Infof("testing: %s", test.Args)
|
||||||
|
if err := test.Run(); err != nil {
|
||||||
|
klog.Infof("%v may require a password: %v", c.Args, err)
|
||||||
|
if !viper.GetBool("interactive") {
|
||||||
|
klog.Warningf("%s requires a password, and --interactive=false", c.Args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
klog.Infof("running: %s", c.Args)
|
||||||
|
err := c.Run()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("running %s failed: %v", c.Args, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in New Issue