mirror of https://github.com/containers/podman.git
Merge pull request #21652 from Luap99/machine-http-proxy
machine: implement http proxy logic for all providers
This commit is contained in:
commit
5a844511c8
|
@ -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"
|
||||
|
@ -413,6 +414,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