diff --git a/cmd/minikube/cmd/podman-env.go b/cmd/minikube/cmd/podman-env.go index 1d4d93c6daab..a0290d78e909 100644 --- a/cmd/minikube/cmd/podman-env.go +++ b/cmd/minikube/cmd/podman-env.go @@ -39,12 +39,16 @@ import ( "k8s.io/minikube/pkg/minikube/shell" ) -var podmanEnvTmpl = fmt.Sprintf("{{ .Prefix }}%s{{ .Delimiter }}{{ .VarlinkBridge }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .MinikubePodmanProfile }}{{ .Suffix }}{{ .UsageHint }}", constants.PodmanVarlinkBridgeEnv, constants.MinikubeActivePodmanEnv) +var podmanEnv1Tmpl = fmt.Sprintf("{{ .Prefix }}%s{{ .Delimiter }}{{ .VarlinkBridge }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .MinikubePodmanProfile }}{{ .Suffix }}{{ .UsageHint }}", constants.PodmanVarlinkBridgeEnv, constants.MinikubeActivePodmanEnv) + +var podmanEnv2Tmpl = fmt.Sprintf("{{ .Prefix }}%s{{ .Delimiter }}{{ .ContainerHost }}{{ .Suffix }}{{ if .ContainerSSHKey }}{{ .Prefix }}%s{{ .Delimiter }}{{ .ContainerSSHKey}}{{ .Suffix }}{{ end }}{{ .Prefix }}%s{{ .Delimiter }}{{ .MinikubePodmanProfile }}{{ .Suffix }}{{ .UsageHint }}", constants.PodmanContainerHostEnv, constants.PodmanContainerSSHKeyEnv, constants.MinikubeActivePodmanEnv) // PodmanShellConfig represents the shell config for Podman type PodmanShellConfig struct { shell.Config VarlinkBridge string + ContainerHost string + ContainerSSHKey string MinikubePodmanProfile string } @@ -59,17 +63,24 @@ func podmanShellCfgSet(ec PodmanEnvConfig, envMap map[string]string) *PodmanShel Config: *shell.CfgSet(ec.EnvConfig, usgPlz, usgCmd), } s.VarlinkBridge = envMap[constants.PodmanVarlinkBridgeEnv] + s.ContainerHost = envMap[constants.PodmanContainerHostEnv] + s.ContainerSSHKey = envMap[constants.PodmanContainerSSHKeyEnv] s.MinikubePodmanProfile = envMap[constants.MinikubeActivePodmanEnv] return s } -// isPodmanAvailable checks if Podman is available -func isPodmanAvailable(r command.Runner) bool { +// isVarlinkAvailable checks if varlink command is available +func isVarlinkAvailable(r command.Runner) bool { if _, err := r.RunCmd(exec.Command("which", "varlink")); err != nil { return false } + return true +} + +// isPodmanAvailable checks if podman command is available +func isPodmanAvailable(r command.Runner) bool { if _, err := r.RunCmd(exec.Command("which", "podman")); err != nil { return false } @@ -130,11 +141,25 @@ var podmanEnvCmd = &cobra.Command{ exit.Message(reason.Usage, `The podman-env command is incompatible with multi-node clusters. Use the 'registry' add-on: https://minikube.sigs.k8s.io/docs/handbook/registry/`) } - if ok := isPodmanAvailable(co.CP.Runner); !ok { + r := co.CP.Runner + if ok := isPodmanAvailable(r); !ok { exit.Message(reason.EnvPodmanUnavailable, `The podman service within '{{.cluster}}' is not active`, out.V{"cluster": cname}) } - client, err := createExternalSSHClient(co.CP.Host.Driver) + varlink := isVarlinkAvailable(r) + + d := co.CP.Host.Driver + client, err := createExternalSSHClient(d) + if err != nil { + exit.Error(reason.IfSSHClient, "Error getting ssh client", err) + } + + hostname, err := d.GetSSHHostname() + if err != nil { + exit.Error(reason.IfSSHClient, "Error getting ssh client", err) + } + + port, err := d.GetSSHPort() if err != nil { exit.Error(reason.IfSSHClient, "Error getting ssh client", err) } @@ -143,7 +168,12 @@ var podmanEnvCmd = &cobra.Command{ EnvConfig: sh, profile: cname, driver: driverName, + varlink: varlink, client: client, + username: d.GetSSHUsername(), + hostname: hostname, + port: port, + keypath: d.GetSSHKeyPath(), } if ec.Shell == "" { @@ -162,23 +192,31 @@ var podmanEnvCmd = &cobra.Command{ // PodmanEnvConfig encapsulates all external inputs into shell generation for Podman type PodmanEnvConfig struct { shell.EnvConfig - profile string - driver string - client *ssh.ExternalClient + profile string + driver string + varlink bool + client *ssh.ExternalClient + username string + hostname string + port int + keypath string } // podmanSetScript writes out a shell-compatible 'podman-env' script func podmanSetScript(ec PodmanEnvConfig, w io.Writer) error { + var podmanEnvTmpl string + if ec.varlink { + podmanEnvTmpl = podmanEnv1Tmpl + } else { + podmanEnvTmpl = podmanEnv2Tmpl + } envVars := podmanEnvVars(ec) return shell.SetScript(ec.EnvConfig, w, podmanEnvTmpl, podmanShellCfgSet(ec, envVars)) } // podmanUnsetScript writes out a shell-compatible 'podman-env unset' script func podmanUnsetScript(ec PodmanEnvConfig, w io.Writer) error { - vars := []string{ - constants.PodmanVarlinkBridgeEnv, - constants.MinikubeActivePodmanEnv, - } + vars := podmanEnvNames(ec) return shell.UnsetScript(ec.EnvConfig, w, vars) } @@ -190,15 +228,73 @@ func podmanBridge(client *ssh.ExternalClient) string { return strings.Join(command, " ") } +// podmanURL returns the url to use in a var for accessing the podman socket over ssh +func podmanURL(username string, hostname string, port int) string { + path := "/run/podman/podman.sock" + return fmt.Sprintf("ssh://%s@%s:%d%s", username, hostname, port, path) +} + // podmanEnvVars gets the necessary podman env variables to allow the use of minikube's podman service func podmanEnvVars(ec PodmanEnvConfig) map[string]string { - env := map[string]string{ - constants.PodmanVarlinkBridgeEnv: podmanBridge(ec.client), + // podman v1 + env1 := map[string]string{ + constants.PodmanVarlinkBridgeEnv: podmanBridge(ec.client), + } + // podman v2 + env2 := map[string]string{ + constants.PodmanContainerHostEnv: podmanURL(ec.username, ec.hostname, ec.port), + constants.PodmanContainerSSHKeyEnv: ec.keypath, + } + //common + env0 := map[string]string{ constants.MinikubeActivePodmanEnv: ec.profile, } + + var env map[string]string + if ec.varlink { + env = env1 + } else { + env = env2 + } + for k, v := range env0 { + env[k] = v + } return env } +// podmanEnvNames gets the necessary podman env variables to reset after using minikube's podman service +func podmanEnvNames(ec PodmanEnvConfig) []string { + // podman v1 + vars1 := []string{ + constants.PodmanVarlinkBridgeEnv, + } + // podman v2 + vars2 := []string{ + constants.PodmanContainerHostEnv, + constants.PodmanContainerSSHKeyEnv, + } + // common + vars0 := []string{ + constants.MinikubeActivePodmanEnv, + } + + var vars []string + if ec.client != nil || ec.hostname != "" { + // getting ec.varlink needs a running machine + if ec.varlink { + vars = vars1 + } else { + vars = vars2 + } + } else { + // just unset *all* of the variables instead + vars = vars1 + vars = append(vars, vars2...) + } + vars = append(vars, vars0...) + return vars +} + func init() { podmanEnvCmd.Flags().StringVar(&shell.ForceShell, "shell", "", "Force environment to be configured for a specified shell: [fish, cmd, powershell, tcsh, bash, zsh], default is auto-detect") podmanEnvCmd.Flags().BoolVarP(&podmanUnset, "unset", "u", false, "Unset variables instead of setting them") diff --git a/cmd/minikube/cmd/podman-env_test.go b/cmd/minikube/cmd/podman-env_test.go index 088867193a6e..6dbb1eb32919 100644 --- a/cmd/minikube/cmd/podman-env_test.go +++ b/cmd/minikube/cmd/podman-env_test.go @@ -41,7 +41,7 @@ func TestGeneratePodmanScripts(t *testing.T) { }{ { "bash", - PodmanEnvConfig{profile: "bash", driver: "kvm2", client: newFakeClient()}, + PodmanEnvConfig{profile: "bash", driver: "kvm2", varlink: true, client: newFakeClient()}, nil, `export PODMAN_VARLINK_BRIDGE="/usr/bin/ssh root@host -- sudo varlink -A \'podman varlink \\\$VARLINK_ADDRESS\' bridge" export MINIKUBE_ACTIVE_PODMAN="bash" @@ -50,6 +50,19 @@ export MINIKUBE_ACTIVE_PODMAN="bash" # eval $(minikube -p bash podman-env) `, `unset PODMAN_VARLINK_BRIDGE MINIKUBE_ACTIVE_PODMAN +`, + }, + { + "bash", + PodmanEnvConfig{profile: "bash", driver: "kvm2", client: newFakeClient(), username: "root", hostname: "host", port: 22}, + nil, + `export CONTAINER_HOST="ssh://root@host:22/run/podman/podman.sock" +export MINIKUBE_ACTIVE_PODMAN="bash" + +# To point your shell to minikube's podman service, run: +# eval $(minikube -p bash podman-env) +`, + `unset CONTAINER_HOST CONTAINER_SSHKEY MINIKUBE_ACTIVE_PODMAN `, }, } diff --git a/pkg/minikube/constants/constants.go b/pkg/minikube/constants/constants.go index fd330a96d973..4145ebb280d9 100644 --- a/pkg/minikube/constants/constants.go +++ b/pkg/minikube/constants/constants.go @@ -68,6 +68,10 @@ const ( MinikubeActiveDockerdEnv = "MINIKUBE_ACTIVE_DOCKERD" // PodmanVarlinkBridgeEnv is used for podman settings PodmanVarlinkBridgeEnv = "PODMAN_VARLINK_BRIDGE" + // PodmanContainerHostEnv is used for podman settings + PodmanContainerHostEnv = "CONTAINER_HOST" + // PodmanContainerSSHKeyEnv is used for podman settings + PodmanContainerSSHKeyEnv = "CONTAINER_SSHKEY" // MinikubeActivePodmanEnv holds the podman service that the user's shell is pointing at // value would be profile or empty if pointing to the user's host. MinikubeActivePodmanEnv = "MINIKUBE_ACTIVE_PODMAN"