mirror of https://github.com/containers/podman.git
machine: implement http proxy logic for all providers
Copy all proxy envs into the VM on each start, this allows for updates without having to recrate the VM. This is implemented via shell script that is passed via ssh to the VM after it is started. With that we now use the same logic for all providers the old fw_cfg logic for qemu has been removed and the WSL code as well which keeps the behavior the same. There is a small risk now because we only update the env via ssh that processes started before will have the old incorrect env but it should really only effect core system processes which likely do not need them anyway. The podman system service should not be started at this point so it should be good enough. It also fixes the broken behavior with SSL_CERT_FILE/SSL_CERT_DIR which were updated on each start which is not correct as the files are only copied with ignition so these should not be updated and just set statically when the VM was created. e2e test has been added to ensure the behavior works as expected. Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
parent
59b6f48d90
commit
f218f8430a
|
|
@ -2,6 +2,7 @@ package e2e_test
|
|||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/containers/podman/v5/pkg/machine/define"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
|
|
@ -23,29 +24,30 @@ var _ = Describe("podman machine proxy settings propagation", func() {
|
|||
})
|
||||
|
||||
It("ssh to running machine and check proxy settings", func() {
|
||||
// TODO the proxy test is currently failing on applehv. FIX ME
|
||||
skipIfVmtype(define.AppleHvVirt, "TODO: this test fails on applehv")
|
||||
defer func() {
|
||||
os.Unsetenv("HTTP_PROXY")
|
||||
os.Unsetenv("HTTPS_PROXY")
|
||||
os.Unsetenv("SSL_CERT_DIR")
|
||||
os.Unsetenv("SSL_CERT_FILE")
|
||||
}()
|
||||
|
||||
certFileDir := GinkgoT().TempDir()
|
||||
certDir := GinkgoT().TempDir()
|
||||
certFile := filepath.Join(certFileDir, "cert1")
|
||||
err := os.WriteFile(certFile, []byte("cert1 content\n"), os.ModePerm)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = os.WriteFile(filepath.Join(certDir, "cert2"), []byte("cert2 content\n"), os.ModePerm)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
os.Setenv("SSL_CERT_FILE", certFile)
|
||||
os.Setenv("SSL_CERT_DIR", certDir)
|
||||
|
||||
// https://github.com/containers/podman/issues/20129
|
||||
if testProvider.VMType() == define.HyperVVirt {
|
||||
Skip("proxy settings not yet supported")
|
||||
}
|
||||
name := randomString()
|
||||
i := new(initMachine)
|
||||
session, err := mb.setName(name).setCmd(i.withImagePath(mb.imagePath)).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(session).To(Exit(0))
|
||||
|
||||
defer func() {
|
||||
httpProxyEnv := os.Getenv("HTTP_PROXY")
|
||||
httpsProxyEnv := os.Getenv("HTTPS_PROXY")
|
||||
if httpProxyEnv != "" {
|
||||
os.Unsetenv("HTTP_PROXY")
|
||||
}
|
||||
if httpsProxyEnv != "" {
|
||||
os.Unsetenv("HTTPS_PROXY")
|
||||
}
|
||||
}()
|
||||
proxyURL := "http://abcdefghijklmnopqrstuvwxyz-proxy"
|
||||
os.Setenv("HTTP_PROXY", proxyURL)
|
||||
os.Setenv("HTTPS_PROXY", proxyURL)
|
||||
|
|
@ -65,5 +67,52 @@ var _ = Describe("podman machine proxy settings propagation", func() {
|
|||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(sshSession).To(Exit(0))
|
||||
Expect(sshSession.outputToString()).To(ContainSubstring(proxyURL))
|
||||
|
||||
// SSL_CERT not implemented for WSL
|
||||
if !isVmtype(define.WSLVirt) {
|
||||
sshSession, err = mb.setName(name).setCmd(sshProxy.withSSHCommand([]string{"printenv", "SSL_CERT_DIR", "SSL_CERT_FILE"})).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(sshSession).To(Exit(0))
|
||||
Expect(string(sshSession.Out.Contents())).To(Equal(define.UserCertsTargetPath + "\n" + define.UserCertsTargetPath + "/cert1" + "\n"))
|
||||
|
||||
sshSession, err = mb.setName(name).setCmd(sshProxy.withSSHCommand([]string{"cat", "$SSL_CERT_DIR/cert2", "$SSL_CERT_FILE"})).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(sshSession).To(Exit(0))
|
||||
Expect(string(sshSession.Out.Contents())).To(Equal("cert2 content\ncert1 content\n"))
|
||||
}
|
||||
|
||||
stop := new(stopMachine)
|
||||
stopSession, err := mb.setName(name).setCmd(stop).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(stopSession).To(Exit(0))
|
||||
|
||||
// Now update proxy env, lets use some special vars to make sure our scripts can handle it
|
||||
proxy1 := "http:// some special @;\" here"
|
||||
proxy2 := "https://abc :£$%6 : |\"\""
|
||||
os.Setenv("HTTP_PROXY", proxy1)
|
||||
os.Setenv("HTTPS_PROXY", proxy2)
|
||||
|
||||
// changing SSL_CERT vars should not have an effect
|
||||
os.Setenv("SSL_CERT_FILE", "/tmp/1")
|
||||
os.Setenv("SSL_CERT_DIR", "/tmp")
|
||||
|
||||
// start it again should update the proxies
|
||||
startSession, err = mb.setName(name).setCmd(s).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(startSession).To(Exit(0))
|
||||
|
||||
sshSession, err = mb.setName(name).setCmd(sshProxy.withSSHCommand([]string{"printenv", "HTTP_PROXY", "HTTPS_PROXY"})).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(sshSession).To(Exit(0))
|
||||
Expect(string(sshSession.Out.Contents())).To(Equal(proxy1 + "\n" + proxy2 + "\n"))
|
||||
|
||||
// SSL_CERT not implemented for WSL
|
||||
if !isVmtype(define.WSLVirt) {
|
||||
// SSL_CERT... must still be the same as before
|
||||
sshSession, err = mb.setName(name).setCmd(sshProxy.withSSHCommand([]string{"cat", "$SSL_CERT_DIR/cert2", "$SSL_CERT_FILE"})).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(sshSession).To(Exit(0))
|
||||
Expect(string(sshSession.Out.Contents())).To(Equal("cert2 content\ncert1 content\n"))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"io/fs"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/containers/podman/v5/pkg/machine/define"
|
||||
|
|
@ -178,46 +179,6 @@ ExecStart=
|
|||
ExecStart=-/usr/sbin/agetty --autologin root --noclear %I $TERM
|
||||
`
|
||||
|
||||
// This service gets environment variables that are provided
|
||||
// through qemu fw_cfg and then sets them into systemd/system.conf.d,
|
||||
// profile.d and environment.d files
|
||||
//
|
||||
// Currently, it is used for propagating
|
||||
// proxy settings e.g. HTTP_PROXY and others, on a start avoiding
|
||||
// a need of re-creating/re-initiating a VM
|
||||
|
||||
envset := parser.NewUnitFile()
|
||||
envset.Add("Unit", "Description", "Environment setter from QEMU FW_CFG")
|
||||
|
||||
envset.Add("Service", "Type", "oneshot")
|
||||
envset.Add("Service", "RemainAfterExit", "yes")
|
||||
envset.Add("Service", "Environment", "FWCFGRAW=/sys/firmware/qemu_fw_cfg/by_name/opt/com.coreos/environment/raw")
|
||||
envset.Add("Service", "Environment", "SYSTEMD_CONF=/etc/systemd/system.conf.d/default-env.conf")
|
||||
envset.Add("Service", "Environment", "ENVD_CONF=/etc/environment.d/default-env.conf")
|
||||
envset.Add("Service", "Environment", "PROFILE_CONF=/etc/profile.d/default-env.sh")
|
||||
envset.Add("Service", "ExecStart", `/usr/bin/bash -c '/usr/bin/test -f ${FWCFGRAW} &&\
|
||||
echo "[Manager]\n#Got from QEMU FW_CFG\nDefaultEnvironment=$(/usr/bin/base64 -d ${FWCFGRAW} | sed -e "s+|+ +g")\n" > ${SYSTEMD_CONF} ||\
|
||||
echo "[Manager]\n#Got nothing from QEMU FW_CFG\n#DefaultEnvironment=\n" > ${SYSTEMD_CONF}'`)
|
||||
envset.Add("Service", "ExecStart", `/usr/bin/bash -c '/usr/bin/test -f ${FWCFGRAW} && (\
|
||||
echo "#Got from QEMU FW_CFG"> ${ENVD_CONF};\
|
||||
IFS="|";\
|
||||
for iprxy in $(/usr/bin/base64 -d ${FWCFGRAW}); do\
|
||||
echo "$iprxy" >> ${ENVD_CONF}; done ) || \
|
||||
echo "#Got nothing from QEMU FW_CFG"> ${ENVD_CONF}'`)
|
||||
envset.Add("Service", "ExecStart", `/usr/bin/bash -c '/usr/bin/test -f ${FWCFGRAW} && (\
|
||||
echo "#Got from QEMU FW_CFG"> ${PROFILE_CONF};\
|
||||
IFS="|";\
|
||||
for iprxy in $(/usr/bin/base64 -d ${FWCFGRAW}); do\
|
||||
echo "export $iprxy" >> ${PROFILE_CONF}; done ) || \
|
||||
echo "#Got nothing from QEMU FW_CFG"> ${PROFILE_CONF}'`)
|
||||
envset.Add("Service", "ExecStartPost", "/usr/bin/systemctl daemon-reload")
|
||||
|
||||
envset.Add("Install", "WantedBy", "sysinit.target")
|
||||
envsetFile, err := envset.ToString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ignSystemd := Systemd{
|
||||
Units: []Unit{
|
||||
{
|
||||
|
|
@ -261,16 +222,6 @@ ExecStart=-/usr/sbin/agetty --autologin root --noclear %I $TERM
|
|||
},
|
||||
}
|
||||
|
||||
// Only qemu has the qemu firmware environment setting
|
||||
if ign.VMType == define.QemuVirt {
|
||||
qemuUnit := Unit{
|
||||
Enabled: BoolToPtr(true),
|
||||
Name: "envset-fwcfg.service",
|
||||
Contents: &envsetFile,
|
||||
}
|
||||
ignSystemd.Units = append(ignSystemd.Units, qemuUnit)
|
||||
}
|
||||
|
||||
if ign.NetRecover {
|
||||
contents, err := GetNetRecoveryUnitFile().ToString()
|
||||
if err != nil {
|
||||
|
|
@ -582,23 +533,29 @@ Delegate=memory pids cpu io
|
|||
certFiles = getCerts(filepath.Join(userHome, ".config/docker/certs.d"), true)
|
||||
files = append(files, certFiles...)
|
||||
|
||||
if sslCertFile, ok := os.LookupEnv("SSL_CERT_FILE"); ok {
|
||||
if _, err := os.Stat(sslCertFile); err == nil {
|
||||
certFiles = getCerts(sslCertFile, false)
|
||||
sslCertFileName, ok := os.LookupEnv(sslCertFile)
|
||||
if ok {
|
||||
if _, err := os.Stat(sslCertFileName); err == nil {
|
||||
certFiles = getCerts(sslCertFileName, false)
|
||||
files = append(files, certFiles...)
|
||||
} else {
|
||||
logrus.Warnf("Invalid path in SSL_CERT_FILE: %q", err)
|
||||
logrus.Warnf("Invalid path in %s: %q", sslCertFile, err)
|
||||
}
|
||||
}
|
||||
|
||||
if sslCertDir, ok := os.LookupEnv("SSL_CERT_DIR"); ok {
|
||||
if _, err := os.Stat(sslCertDir); err == nil {
|
||||
certFiles = getCerts(sslCertDir, true)
|
||||
sslCertDirName, ok := os.LookupEnv(sslCertDir)
|
||||
if ok {
|
||||
if _, err := os.Stat(sslCertDirName); err == nil {
|
||||
certFiles = getCerts(sslCertDirName, true)
|
||||
files = append(files, certFiles...)
|
||||
} else {
|
||||
logrus.Warnf("Invalid path in SSL_CERT_DIR: %q", err)
|
||||
logrus.Warnf("Invalid path in %s: %q", sslCertDir, err)
|
||||
}
|
||||
}
|
||||
if sslCertFileName != "" || sslCertDirName != "" {
|
||||
// If we copied certs via env then also make the to set the env in the VM.
|
||||
files = append(files, getSSLEnvironmentFiles(sslCertFileName, sslCertDirName)...)
|
||||
}
|
||||
|
||||
files = append(files, File{
|
||||
Node: Node{
|
||||
|
|
@ -686,16 +643,18 @@ func getCerts(certsDir string, isDir bool) []File {
|
|||
return files
|
||||
}
|
||||
|
||||
func prepareCertFile(path string, name string) (File, error) {
|
||||
b, err := os.ReadFile(path)
|
||||
func prepareCertFile(fpath string, name string) (File, error) {
|
||||
b, err := os.ReadFile(fpath)
|
||||
if err != nil {
|
||||
logrus.Warnf("Unable to read cert file %v", err)
|
||||
return File{}, err
|
||||
}
|
||||
|
||||
targetPath := filepath.Join(define.UserCertsTargetPath, name)
|
||||
// Note path is required here as we always create a path for the linux VM
|
||||
// even when the client run on windows so we cannot use filepath.
|
||||
targetPath := path.Join(define.UserCertsTargetPath, name)
|
||||
|
||||
logrus.Debugf("Copying cert file from '%s' to '%s'.", path, targetPath)
|
||||
logrus.Debugf("Copying cert file from '%s' to '%s'.", fpath, targetPath)
|
||||
|
||||
file := File{
|
||||
Node: Node{
|
||||
|
|
@ -714,6 +673,57 @@ func prepareCertFile(path string, name string) (File, error) {
|
|||
return file, nil
|
||||
}
|
||||
|
||||
const (
|
||||
systemdSSLConf = "/etc/systemd/system.conf.d/podman-machine-ssl.conf"
|
||||
envdSSLConf = "/etc/environment.d/podman-machine-ssl.conf"
|
||||
profileSSLConf = "/etc/profile.d/podman-machine-ssl.sh"
|
||||
sslCertFile = "SSL_CERT_FILE"
|
||||
sslCertDir = "SSL_CERT_DIR"
|
||||
)
|
||||
|
||||
func getSSLEnvironmentFiles(sslFileName, sslDirName string) []File {
|
||||
systemdFileContent := "[Manager]\n"
|
||||
envdFileContent := ""
|
||||
profileFileContent := ""
|
||||
if sslFileName != "" {
|
||||
// certs are written to UserCertsTargetPath see prepareCertFile()
|
||||
// Note the mix of path/filepath is intentional and required, we want to get the name of
|
||||
// a path on the client (i.e. windows) but then join to linux path that will be used inside the VM.
|
||||
env := fmt.Sprintf("%s=%q\n", sslCertFile, path.Join(define.UserCertsTargetPath, filepath.Base(sslFileName)))
|
||||
systemdFileContent += "DefaultEnvironment=" + env
|
||||
envdFileContent += env
|
||||
profileFileContent += "export " + env
|
||||
}
|
||||
if sslDirName != "" {
|
||||
// certs are written to UserCertsTargetPath see prepareCertFile()
|
||||
env := fmt.Sprintf("%s=%q\n", sslCertDir, define.UserCertsTargetPath)
|
||||
systemdFileContent += "DefaultEnvironment=" + env
|
||||
envdFileContent += env
|
||||
profileFileContent += "export " + env
|
||||
}
|
||||
return []File{
|
||||
getSSLFile(systemdSSLConf, systemdFileContent),
|
||||
getSSLFile(envdSSLConf, envdFileContent),
|
||||
getSSLFile(profileSSLConf, profileFileContent),
|
||||
}
|
||||
}
|
||||
|
||||
func getSSLFile(path, content string) File {
|
||||
return File{
|
||||
Node: Node{
|
||||
Group: GetNodeGrp("root"),
|
||||
Path: path,
|
||||
User: GetNodeUsr("root"),
|
||||
},
|
||||
FileEmbedded1: FileEmbedded1{
|
||||
Contents: Resource{
|
||||
Source: EncodeDataURLPtr(content),
|
||||
},
|
||||
Mode: IntToPtr(0644),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getLinks(usrName string) []Link {
|
||||
return []Link{{
|
||||
Node: Node{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
package proxyenv
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/common/libnetwork/etchosts"
|
||||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/podman/v5/pkg/machine"
|
||||
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const proxySetupScriptTemplate = `#!/bin/bash
|
||||
|
||||
SYSTEMD_CONF=/etc/systemd/system.conf.d/default-env.conf
|
||||
ENVD_CONF=/etc/environment.d/default-env.conf
|
||||
PROFILE_CONF=/etc/profile.d/default-env.sh
|
||||
|
||||
mkdir -p /etc/profile.d /etc/environment.d /etc/systemd/system.conf.d/
|
||||
rm -f $SYSTEMD_CONF $ENVD_CONF $PROFILE_CONF
|
||||
|
||||
echo "[Manager]" >> $SYSTEMD_CONF
|
||||
for proxy in %s; do
|
||||
printf "DefaultEnvironment=%%q\n" "$proxy" >> $SYSTEMD_CONF
|
||||
printf "%%q\n" "$proxy" >> $ENVD_CONF
|
||||
printf "export %%q\n" "$proxy" >> $PROFILE_CONF
|
||||
done
|
||||
|
||||
systemctl daemon-reload
|
||||
`
|
||||
|
||||
func getProxyScript(isWSL bool) io.Reader {
|
||||
var envs []string
|
||||
for _, key := range config.ProxyEnv {
|
||||
if value, ok := os.LookupEnv(key); ok {
|
||||
// WSL does not use host.containers.internal as valid name for the VM.
|
||||
if !isWSL {
|
||||
value = strings.ReplaceAll(value, "127.0.0.1", etchosts.HostContainersInternal)
|
||||
value = strings.ReplaceAll(value, "localhost", etchosts.HostContainersInternal)
|
||||
}
|
||||
// %q to quote the value correctly
|
||||
envs = append(envs, fmt.Sprintf("%q", key+"="+value))
|
||||
}
|
||||
}
|
||||
|
||||
script := fmt.Sprintf(proxySetupScriptTemplate, strings.Join(envs, " "))
|
||||
logrus.Tracef("Final environment variable setup script: %s", script)
|
||||
return strings.NewReader(script)
|
||||
}
|
||||
|
||||
func ApplyProxies(mc *vmconfigs.MachineConfig) error {
|
||||
return machine.CommonSSHWithStdin("root", mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, []string{"/usr/bin/bash"},
|
||||
getProxyScript(mc.WSLHypervisor != nil))
|
||||
}
|
||||
|
|
@ -107,11 +107,6 @@ func (q *QemuCmd) SetDisplay(display string) {
|
|||
*q = append(*q, "-display", display)
|
||||
}
|
||||
|
||||
// SetPropagatedHostEnvs adds options that propagate SSL and proxy settings
|
||||
func (q *QemuCmd) SetPropagatedHostEnvs() {
|
||||
*q = PropagateHostEnv(*q)
|
||||
}
|
||||
|
||||
func (q *QemuCmd) Build() []string {
|
||||
return *q
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,96 +0,0 @@
|
|||
//go:build !darwin
|
||||
|
||||
package command
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/containers/common/libnetwork/etchosts"
|
||||
"github.com/containers/podman/v5/pkg/machine/define"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPropagateHostEnv(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
value string
|
||||
expect string
|
||||
}{
|
||||
"HTTP_PROXY": {
|
||||
"proxy",
|
||||
"equal",
|
||||
},
|
||||
"ftp_proxy": {
|
||||
"domain.com:8888",
|
||||
"equal",
|
||||
},
|
||||
"FTP_PROXY": {
|
||||
"proxy",
|
||||
"equal",
|
||||
},
|
||||
"NO_PROXY": {
|
||||
"localaddress",
|
||||
"equal",
|
||||
},
|
||||
"HTTPS_PROXY": {
|
||||
"",
|
||||
"unset",
|
||||
},
|
||||
"no_proxy": {
|
||||
"",
|
||||
"unset",
|
||||
},
|
||||
"http_proxy": {
|
||||
"127.0.0.1:8888",
|
||||
fmt.Sprintf("%s:8888", etchosts.HostContainersInternal),
|
||||
},
|
||||
"https_proxy": {
|
||||
"localhost:8888",
|
||||
fmt.Sprintf("%s:8888", etchosts.HostContainersInternal),
|
||||
},
|
||||
"SSL_CERT_FILE": {
|
||||
"/some/f=oo.cert",
|
||||
fmt.Sprintf("%s/f=oo.cert", define.UserCertsTargetPath),
|
||||
},
|
||||
"SSL_CERT_DIR": {
|
||||
"/some/my/certs",
|
||||
define.UserCertsTargetPath,
|
||||
},
|
||||
}
|
||||
|
||||
for key, item := range tests {
|
||||
t.Setenv(key, item.value)
|
||||
}
|
||||
|
||||
cmdLine := PropagateHostEnv(make([]string, 0))
|
||||
|
||||
assert.Len(t, cmdLine, 2)
|
||||
assert.Equal(t, "-fw_cfg", cmdLine[0])
|
||||
tokens := strings.Split(cmdLine[1], ",string=")
|
||||
decodeString, err := base64.StdEncoding.DecodeString(tokens[1])
|
||||
assert.NoError(t, err)
|
||||
|
||||
// envsRawArr looks like: ["BAR=\"bar\"", "FOO=\"foo\""]
|
||||
envsRawArr := strings.Split(string(decodeString), "|")
|
||||
// envs looks like: {"BAR": "bar", "FOO": "foo"}
|
||||
envs := make(map[string]string)
|
||||
for _, env := range envsRawArr {
|
||||
key, value, _ := strings.Cut(env, "=")
|
||||
envs[key] = strings.Trim(value, "\"")
|
||||
}
|
||||
|
||||
for key, test := range tests {
|
||||
switch test.expect {
|
||||
case "equal":
|
||||
assert.Equal(t, envs[key], test.value)
|
||||
case "unset":
|
||||
if _, ok := envs[key]; ok {
|
||||
t.Errorf("env %s should not be set", key)
|
||||
}
|
||||
default:
|
||||
assert.Equal(t, envs[key], test.expect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
//go:build !darwin
|
||||
|
||||
package command
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/common/libnetwork/etchosts"
|
||||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/podman/v5/pkg/machine/define"
|
||||
)
|
||||
|
||||
func GetProxyVariables() map[string]string {
|
||||
proxyOpts := make(map[string]string)
|
||||
for _, variable := range config.ProxyEnv {
|
||||
if value, ok := os.LookupEnv(variable); ok {
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
v := strings.ReplaceAll(value, "127.0.0.1", etchosts.HostContainersInternal)
|
||||
v = strings.ReplaceAll(v, "localhost", etchosts.HostContainersInternal)
|
||||
proxyOpts[variable] = v
|
||||
}
|
||||
}
|
||||
return proxyOpts
|
||||
}
|
||||
|
||||
// PropagateHostEnv is here for providing the ability to propagate
|
||||
// proxy and SSL settings (e.g. HTTP_PROXY and others) on a start
|
||||
// and avoid a need of re-creating/re-initiating a VM
|
||||
func PropagateHostEnv(cmdLine QemuCmd) QemuCmd {
|
||||
varsToPropagate := make([]string, 0)
|
||||
|
||||
for k, v := range GetProxyVariables() {
|
||||
varsToPropagate = append(varsToPropagate, fmt.Sprintf("%s=%q", k, v))
|
||||
}
|
||||
|
||||
if sslCertFile, ok := os.LookupEnv("SSL_CERT_FILE"); ok {
|
||||
pathInVM := filepath.Join(define.UserCertsTargetPath, filepath.Base(sslCertFile))
|
||||
varsToPropagate = append(varsToPropagate, fmt.Sprintf("%s=%q", "SSL_CERT_FILE", pathInVM))
|
||||
}
|
||||
|
||||
if _, ok := os.LookupEnv("SSL_CERT_DIR"); ok {
|
||||
varsToPropagate = append(varsToPropagate, fmt.Sprintf("%s=%q", "SSL_CERT_DIR", define.UserCertsTargetPath))
|
||||
}
|
||||
|
||||
if len(varsToPropagate) > 0 {
|
||||
prefix := "name=opt/com.coreos/environment,string="
|
||||
envVarsJoined := strings.Join(varsToPropagate, "|")
|
||||
fwCfgArg := prefix + base64.StdEncoding.EncodeToString([]byte(envVarsJoined))
|
||||
return append(cmdLine, "-fw_cfg", fwCfgArg)
|
||||
}
|
||||
|
||||
return cmdLine
|
||||
}
|
||||
|
|
@ -170,8 +170,6 @@ func (q *QEMUStubber) StartVM(mc *vmconfigs.MachineConfig) (func() error, func()
|
|||
|
||||
cmdLine := q.Command
|
||||
|
||||
cmdLine.SetPropagatedHostEnvs()
|
||||
|
||||
// Disable graphic window when not in debug mode
|
||||
// Done in start, so we're not suck with the debug level we used on init
|
||||
if !logrus.IsLevelEnabled(logrus.DebugLevel) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/containers/podman/v5/pkg/machine/connection"
|
||||
machineDefine "github.com/containers/podman/v5/pkg/machine/define"
|
||||
"github.com/containers/podman/v5/pkg/machine/ignition"
|
||||
"github.com/containers/podman/v5/pkg/machine/proxyenv"
|
||||
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
|
||||
"github.com/containers/podman/v5/utils"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
|
|
@ -414,6 +415,10 @@ func Start(mc *vmconfigs.MachineConfig, mp vmconfigs.VMProvider, _ *machineDefin
|
|||
return errors.New(msg)
|
||||
}
|
||||
|
||||
if err := proxyenv.ApplyProxies(mc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// mount the volumes to the VM
|
||||
if err := mp.MountVolumesToVM(mc, opts.Quiet); err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ package machine
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
|
||||
|
|
@ -12,14 +14,18 @@ import (
|
|||
// and a port
|
||||
// TODO This should probably be taught about an machineconfig to reduce input
|
||||
func CommonSSH(username, identityPath, name string, sshPort int, inputArgs []string) error {
|
||||
return commonSSH(username, identityPath, name, sshPort, inputArgs, false)
|
||||
return commonSSH(username, identityPath, name, sshPort, inputArgs, false, os.Stdin)
|
||||
}
|
||||
|
||||
func CommonSSHSilent(username, identityPath, name string, sshPort int, inputArgs []string) error {
|
||||
return commonSSH(username, identityPath, name, sshPort, inputArgs, true)
|
||||
return commonSSH(username, identityPath, name, sshPort, inputArgs, true, os.Stdin)
|
||||
}
|
||||
|
||||
func commonSSH(username, identityPath, name string, sshPort int, inputArgs []string, silent bool) error {
|
||||
func CommonSSHWithStdin(username, identityPath, name string, sshPort int, inputArgs []string, stdin io.Reader) error {
|
||||
return commonSSH(username, identityPath, name, sshPort, inputArgs, false, stdin)
|
||||
}
|
||||
|
||||
func commonSSH(username, identityPath, name string, sshPort int, inputArgs []string, silent bool, stdin io.Reader) error {
|
||||
sshDestination := username + "@localhost"
|
||||
port := strconv.Itoa(sshPort)
|
||||
interactive := true
|
||||
|
|
@ -40,7 +46,7 @@ func commonSSH(username, identityPath, name string, sshPort int, inputArgs []str
|
|||
logrus.Debugf("Executing: ssh %v\n", args)
|
||||
|
||||
if !silent {
|
||||
if err := setupIOPassthrough(cmd, interactive); err != nil {
|
||||
if err := setupIOPassthrough(cmd, interactive, stdin); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,13 @@
|
|||
package machine
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func setupIOPassthrough(cmd *exec.Cmd, interactive bool) error {
|
||||
cmd.Stdin = os.Stdin
|
||||
func setupIOPassthrough(cmd *exec.Cmd, interactive bool, stdin io.Reader) error {
|
||||
cmd.Stdin = stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func setupIOPassthrough(cmd *exec.Cmd, interactive bool) error {
|
||||
cmd.Stdin = os.Stdin
|
||||
func setupIOPassthrough(cmd *exec.Cmd, interactive bool, stdin io.Reader) error {
|
||||
cmd.Stdin = stdin
|
||||
|
||||
if interactive {
|
||||
cmd.Stdout = os.Stdout
|
||||
|
|
|
|||
|
|
@ -175,43 +175,6 @@ SocketMode=0660
|
|||
SocketGroup=wheel
|
||||
`
|
||||
|
||||
const proxyConfigSetup = `#!/bin/bash
|
||||
|
||||
SYSTEMD_CONF=/etc/systemd/system.conf.d/default-env.conf
|
||||
ENVD_CONF=/etc/environment.d/default-env.conf
|
||||
PROFILE_CONF=/etc/profile.d/default-env.sh
|
||||
|
||||
IFS="|"
|
||||
read proxies
|
||||
|
||||
mkdir -p /etc/profile.d /etc/environment.d /etc/systemd/system.conf.d/
|
||||
rm -f $SYSTEMD_CONF
|
||||
for proxy in $proxies; do
|
||||
output+="$proxy "
|
||||
done
|
||||
echo "[Manager]" >> $SYSTEMD_CONF
|
||||
echo -ne "DefaultEnvironment=" >> $SYSTEMD_CONF
|
||||
|
||||
echo $output >> $SYSTEMD_CONF
|
||||
rm -f $ENVD_CONF
|
||||
for proxy in $proxies; do
|
||||
echo "$proxy" >> $ENVD_CONF
|
||||
done
|
||||
rm -f $PROFILE_CONF
|
||||
for proxy in $proxies; do
|
||||
echo "export $proxy" >> $PROFILE_CONF
|
||||
done
|
||||
`
|
||||
|
||||
const proxyConfigAttempt = `if [ -f /usr/local/bin/proxyinit ]; \
|
||||
then /usr/local/bin/proxyinit; \
|
||||
else exit 42; \
|
||||
fi`
|
||||
|
||||
const clearProxySettings = `rm -f /etc/systemd/system.conf.d/default-env.conf \
|
||||
/etc/environment.d/default-env.conf \
|
||||
/etc/profile.d/default-env.sh`
|
||||
|
||||
const wslInstallError = `Could not %s. See previous output for any potential failure details.
|
||||
If you can not resolve the issue, and rerunning fails, try the "wsl --install" process
|
||||
outlined in the following article:
|
||||
|
|
|
|||
|
|
@ -244,41 +244,6 @@ func setupPodmanDockerSock(dist string, rootful bool) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func configureProxy(dist string, useProxy bool, quiet bool) error {
|
||||
if !useProxy {
|
||||
_ = wslInvoke(dist, "sh", "-c", clearProxySettings)
|
||||
return nil
|
||||
}
|
||||
var content string
|
||||
for i, key := range config.ProxyEnv {
|
||||
if value, _ := os.LookupEnv(key); len(value) > 0 {
|
||||
var suffix string
|
||||
if i < (len(config.ProxyEnv) - 1) {
|
||||
suffix = "|"
|
||||
}
|
||||
content = fmt.Sprintf("%s%s=\"%s\"%s", content, key, value, suffix)
|
||||
}
|
||||
}
|
||||
|
||||
if err := wslPipe(content, dist, "sh", "-c", proxyConfigAttempt); err != nil {
|
||||
const failMessage = "Failure creating proxy configuration"
|
||||
if exitErr, isExit := err.(*exec.ExitError); isExit && exitErr.ExitCode() != 42 {
|
||||
return fmt.Errorf("%v: %w", failMessage, err)
|
||||
}
|
||||
if !quiet {
|
||||
fmt.Println("Installing proxy support")
|
||||
}
|
||||
_ = wslPipe(proxyConfigSetup, dist, "sh", "-c",
|
||||
"cat > /usr/local/bin/proxyinit; chmod 755 /usr/local/bin/proxyinit")
|
||||
|
||||
if err = wslPipe(content, dist, "/usr/local/bin/proxyinit"); err != nil {
|
||||
return fmt.Errorf("%v: %w", failMessage, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func enableUserLinger(mc *vmconfigs.MachineConfig, dist string) error {
|
||||
lingerCmd := "mkdir -p /var/lib/systemd/linger; touch /var/lib/systemd/linger/" + mc.SSH.RemoteUsername
|
||||
if err := wslInvoke(dist, "sh", "-c", lingerCmd); err != nil {
|
||||
|
|
@ -317,11 +282,6 @@ func installScripts(dist string) error {
|
|||
return fmt.Errorf("could not create bootstrap script for guest OS: %w", err)
|
||||
}
|
||||
|
||||
if err := wslPipe(proxyConfigSetup, dist, "sh", "-c",
|
||||
"cat > /usr/local/bin/proxyinit; chmod 755 /usr/local/bin/proxyinit"); err != nil {
|
||||
return fmt.Errorf("could not create proxyinit script for guest OS: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -204,14 +204,8 @@ func (w WSLStubber) PostStartNetworking(mc *vmconfigs.MachineConfig, noInfo bool
|
|||
}
|
||||
|
||||
func (w WSLStubber) StartVM(mc *vmconfigs.MachineConfig) (func() error, func() error, error) {
|
||||
useProxy := setupWslProxyEnv()
|
||||
dist := machine.ToDist(mc.Name)
|
||||
|
||||
// TODO Quiet is hard set to false: follow up
|
||||
if err := configureProxy(dist, useProxy, false); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// TODO The original code checked to see if the SSH port was actually open and re-assigned if it was
|
||||
// we could consider this but it should be higher up the stack
|
||||
// if !machine.IsLocalPortAvailable(v.Port) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue