Merge pull request #12036 from jwhonce/issues/11984

test connection add
This commit is contained in:
OpenShift Merge Robot
2021-11-08 18:53:29 +01:00
committed by GitHub
10 changed files with 457 additions and 305 deletions

View File

@ -168,7 +168,7 @@ func loadToRemote(localFile string, tag string, url *urlP.URL, iden string) (str
n, err := scpD.CopyTo(dial, localFile, remoteFile) n, err := scpD.CopyTo(dial, localFile, remoteFile)
if err != nil { if err != nil {
errOut := (strconv.Itoa(int(n)) + " Bytes copied before error") errOut := strconv.Itoa(int(n)) + " Bytes copied before error"
return " ", errors.Wrapf(err, errOut) return " ", errors.Wrapf(err, errOut)
} }
run := "" run := ""
@ -181,7 +181,7 @@ func loadToRemote(localFile string, tag string, url *urlP.URL, iden string) (str
if err != nil { if err != nil {
return "", err return "", err
} }
return strings.TrimSuffix(out, "\n"), nil return strings.TrimSuffix(string(out), "\n"), nil
} }
// saveToRemote takes image information and remote connection information. it connects to the specified client // saveToRemote takes image information and remote connection information. it connects to the specified client
@ -207,7 +207,7 @@ func saveToRemote(image, localFile string, tag string, uri *urlP.URL, iden strin
n, err := scpD.CopyFrom(dial, remoteFile, localFile) n, err := scpD.CopyFrom(dial, remoteFile, localFile)
connection.ExecRemoteCommand(dial, "rm "+remoteFile) connection.ExecRemoteCommand(dial, "rm "+remoteFile)
if err != nil { if err != nil {
errOut := (strconv.Itoa(int(n)) + " Bytes copied before error") errOut := strconv.Itoa(int(n)) + " Bytes copied before error"
return errors.Wrapf(err, errOut) return errors.Wrapf(err, errOut)
} }
return nil return nil
@ -221,11 +221,7 @@ func makeRemoteFile(dial *ssh.Client) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
remoteFile = strings.TrimSuffix(remoteFile, "\n") return strings.TrimSuffix(string(remoteFile), "\n"), nil
if err != nil {
return "", err
}
return remoteFile, nil
} }
// createConnections takes a boolean determining which ssh client to dial // createConnections takes a boolean determining which ssh client to dial

View File

@ -226,12 +226,7 @@ func getUDS(cmd *cobra.Command, uri *url.URL, iden string) (string, error) {
if v, found := os.LookupEnv("PODMAN_BINARY"); found { if v, found := os.LookupEnv("PODMAN_BINARY"); found {
podman = v podman = v
} }
run := podman + " info --format=json" infoJSON, err := ExecRemoteCommand(dial, podman+" info --format=json")
out, err := ExecRemoteCommand(dial, run)
if err != nil {
return "", err
}
infoJSON, err := json.Marshal(out)
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@ -9,10 +9,10 @@ import (
// ExecRemoteCommand takes a ssh client connection and a command to run and executes the // ExecRemoteCommand takes a ssh client connection and a command to run and executes the
// command on the specified client. The function returns the Stdout from the client or the Stderr // command on the specified client. The function returns the Stdout from the client or the Stderr
func ExecRemoteCommand(dial *ssh.Client, run string) (string, error) { func ExecRemoteCommand(dial *ssh.Client, run string) ([]byte, error) {
sess, err := dial.NewSession() // new ssh client session sess, err := dial.NewSession() // new ssh client session
if err != nil { if err != nil {
return "", err return nil, err
} }
defer sess.Close() defer sess.Close()
@ -21,8 +21,7 @@ func ExecRemoteCommand(dial *ssh.Client, run string) (string, error) {
sess.Stdout = &buffer // output from client funneled into buffer sess.Stdout = &buffer // output from client funneled into buffer
sess.Stderr = &bufferErr // err form client funneled into buffer sess.Stderr = &bufferErr // err form client funneled into buffer
if err := sess.Run(run); err != nil { // run the command on the ssh client if err := sess.Run(run); err != nil { // run the command on the ssh client
return "", errors.Wrapf(err, bufferErr.String()) return nil, errors.Wrapf(err, bufferErr.String())
} }
out := buffer.String() // output from command return buffer.Bytes(), nil
return out, nil
} }

View File

@ -166,30 +166,42 @@ setup_rootless() {
useradd -g $rootless_gid -u $rootless_uid --no-user-group --create-home $ROOTLESS_USER useradd -g $rootless_gid -u $rootless_uid --no-user-group --create-home $ROOTLESS_USER
chown -R $ROOTLESS_USER:$ROOTLESS_USER "$GOPATH" "$GOSRC" chown -R $ROOTLESS_USER:$ROOTLESS_USER "$GOPATH" "$GOSRC"
msg "creating ssh key pair for $USER" mkdir -p "$HOME/.ssh" "/home/$ROOTLESS_USER/.ssh"
[[ -r "$HOME/.ssh/id_rsa" ]] || \
ssh-keygen -P "" -f "$HOME/.ssh/id_rsa"
msg "Allowing ssh key for $ROOTLESS_USER" msg "Creating ssh key pairs"
akfilepath="/home/$ROOTLESS_USER/.ssh/authorized_keys" [[ -r "$HOME/.ssh/id_rsa" ]] || \
(umask 077 && mkdir "/home/$ROOTLESS_USER/.ssh") ssh-keygen -t rsa -P "" -f "$HOME/.ssh/id_rsa"
chown -R $ROOTLESS_USER:$ROOTLESS_USER "/home/$ROOTLESS_USER/.ssh" ssh-keygen -t ed25519 -P "" -f "/home/$ROOTLESS_USER/.ssh/id_ed25519"
install -o $ROOTLESS_USER -g $ROOTLESS_USER -m 0600 \ ssh-keygen -t rsa -P "" -f "/home/$ROOTLESS_USER/.ssh/id_rsa"
"$HOME/.ssh/id_rsa.pub" "$akfilepath"
# Makes debugging easier msg "Setup authorized_keys"
cat /root/.ssh/authorized_keys >> "$akfilepath" cat $HOME/.ssh/*.pub /home/$ROOTLESS_USER/.ssh/*.pub >> $HOME/.ssh/authorized_keys
cat $HOME/.ssh/*.pub /home/$ROOTLESS_USER/.ssh/*.pub >> /home/$ROOTLESS_USER/.ssh/authorized_keys
msg "Ensure the ssh daemon is up and running within 5 minutes" msg "Ensure the ssh daemon is up and running within 5 minutes"
systemctl start sshd systemctl start sshd
sshcmd="ssh $ROOTLESS_USER@localhost lilto systemctl is-active sshd
-o UserKnownHostsFile=/dev/null
-o StrictHostKeyChecking=no
-o CheckHostIP=no"
lilto $sshcmd true # retry until sshd is up
msg "Configuring rootless user self-access to ssh to localhost" msg "Configure ssh file permissions"
$sshcmd ssh-keygen -P '""' -f "/home/$ROOTLESS_USER/.ssh/id_rsa" chmod -R 700 "$HOME/.ssh"
cat "/home/$ROOTLESS_USER/.ssh/id_rsa" >> "$akfilepath" chmod -R 700 "/home/$ROOTLESS_USER/.ssh"
chown -R $ROOTLESS_USER:$ROOTLESS_USER "/home/$ROOTLESS_USER/.ssh"
msg " setup known_hosts for $USER"
ssh -q root@localhost \
-o UserKnownHostsFile=/root/.ssh/known_hosts \
-o UpdateHostKeys=yes \
-o StrictHostKeyChecking=no \
-o CheckHostIP=no \
true
msg " setup known_hosts for $ROOTLESS_USER"
su $ROOTLESS_USER -c "ssh -q $ROOTLESS_USER@localhost \
-o UserKnownHostsFile=/home/$ROOTLESS_USER/.ssh/known_hosts \
-o UpdateHostKeys=yes \
-o StrictHostKeyChecking=no \
-o CheckHostIP=no \
true"
} }
install_test_configs() { install_test_configs() {

View File

@ -208,9 +208,7 @@ var _ = SynchronizedAfterSuite(func() {},
// PodmanTestCreate creates a PodmanTestIntegration instance for the tests // PodmanTestCreate creates a PodmanTestIntegration instance for the tests
func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration { func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration {
var ( var podmanRemoteBinary string
podmanRemoteBinary string
)
host := GetHostDistributionInfo() host := GetHostDistributionInfo()
cwd, _ := os.Getwd() cwd, _ := os.Getwd()
@ -220,12 +218,11 @@ func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration {
podmanBinary = os.Getenv("PODMAN_BINARY") podmanBinary = os.Getenv("PODMAN_BINARY")
} }
if remote { podmanRemoteBinary = filepath.Join(cwd, "../../bin/podman-remote")
podmanRemoteBinary = filepath.Join(cwd, "../../bin/podman-remote") if os.Getenv("PODMAN_REMOTE_BINARY") != "" {
if os.Getenv("PODMAN_REMOTE_BINARY") != "" { podmanRemoteBinary = os.Getenv("PODMAN_REMOTE_BINARY")
podmanRemoteBinary = os.Getenv("PODMAN_REMOTE_BINARY")
}
} }
conmonBinary := filepath.Join("/usr/libexec/podman/conmon") conmonBinary := filepath.Join("/usr/libexec/podman/conmon")
altConmonBinary := "/usr/bin/conmon" altConmonBinary := "/usr/bin/conmon"
if _, err := os.Stat(conmonBinary); os.IsNotExist(err) { if _, err := os.Stat(conmonBinary); os.IsNotExist(err) {
@ -271,12 +268,13 @@ func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration {
p := &PodmanTestIntegration{ p := &PodmanTestIntegration{
PodmanTest: PodmanTest{ PodmanTest: PodmanTest{
PodmanBinary: podmanBinary, PodmanBinary: podmanBinary,
ArtifactPath: ARTIFACT_DIR, RemotePodmanBinary: podmanRemoteBinary,
TempDir: tempDir, ArtifactPath: ARTIFACT_DIR,
RemoteTest: remote, TempDir: tempDir,
ImageCacheFS: storageFs, RemoteTest: remote,
ImageCacheDir: ImageCacheDir, ImageCacheFS: storageFs,
ImageCacheDir: ImageCacheDir,
}, },
ConmonBinary: conmonBinary, ConmonBinary: conmonBinary,
CrioRoot: filepath.Join(tempDir, "crio"), CrioRoot: filepath.Join(tempDir, "crio"),
@ -289,8 +287,8 @@ func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration {
CgroupManager: cgroupManager, CgroupManager: cgroupManager,
Host: host, Host: host,
} }
if remote { if remote {
p.PodmanTest.RemotePodmanBinary = podmanRemoteBinary
uuid := stringid.GenerateNonCryptoID() uuid := stringid.GenerateNonCryptoID()
if !rootless.IsRootless() { if !rootless.IsRootless() {
p.RemoteSocket = fmt.Sprintf("unix:/run/podman/podman-%s.sock", uuid) p.RemoteSocket = fmt.Sprintf("unix:/run/podman/podman-%s.sock", uuid)
@ -632,6 +630,19 @@ func SkipIfNotRootless(reason string) {
} }
} }
func SkipIfSystemdNotRunning(reason string) {
checkReason(reason)
cmd := exec.Command("systemctl", "list-units")
err := cmd.Run()
if err != nil {
if _, ok := err.(*exec.Error); ok {
ginkgo.Skip("[notSystemd]: not running " + reason)
}
Expect(err).ToNot(HaveOccurred())
}
}
func SkipIfNotSystemd(manager, reason string) { func SkipIfNotSystemd(manager, reason string) {
checkReason(reason) checkReason(reason)
if manager != "systemd" { if manager != "systemd" {
@ -683,6 +694,41 @@ func SkipIfContainerized(reason string) {
} }
} }
func SkipIfRemote(reason string) {
checkReason(reason)
if !IsRemote() {
return
}
ginkgo.Skip("[remote]: " + reason)
}
// SkipIfInContainer skips a test if the test is run inside a container
func SkipIfInContainer(reason string) {
checkReason(reason)
if os.Getenv("TEST_ENVIRON") == "container" {
Skip("[container]: " + reason)
}
}
// SkipIfNotActive skips a test if the given systemd unit is not active
func SkipIfNotActive(unit string, reason string) {
checkReason(reason)
var buffer bytes.Buffer
cmd := exec.Command("systemctl", "is-active", unit)
cmd.Stdout = &buffer
err := cmd.Start()
Expect(err).ToNot(HaveOccurred())
err = cmd.Wait()
Expect(err).ToNot(HaveOccurred())
Expect(err).ToNot(HaveOccurred())
if strings.TrimSpace(buffer.String()) != "active" {
Skip(fmt.Sprintf("[systemd]: unit %s is not active: %s", unit, reason))
}
}
// PodmanAsUser is the exec call to podman on the filesystem with the specified uid/gid and environment // PodmanAsUser is the exec call to podman on the filesystem with the specified uid/gid and environment
func (p *PodmanTestIntegration) PodmanAsUser(args []string, uid, gid uint32, cwd string, env []string) *PodmanSessionIntegration { func (p *PodmanTestIntegration) PodmanAsUser(args []string, uid, gid uint32, cwd string, env []string) *PodmanSessionIntegration {
podmanSession := p.PodmanAsUserBase(args, uid, gid, cwd, env, false, false, nil, nil) podmanSession := p.PodmanAsUserBase(args, uid, gid, cwd, env, false, false, nil, nil)

View File

@ -16,20 +16,12 @@ import (
"time" "time"
"github.com/containers/podman/v3/pkg/rootless" "github.com/containers/podman/v3/pkg/rootless"
"github.com/onsi/ginkgo"
) )
func IsRemote() bool { func IsRemote() bool {
return true return true
} }
func SkipIfRemote(reason string) {
if len(reason) < 5 {
panic("SkipIfRemote must specify a reason to skip")
}
ginkgo.Skip("[remote]: " + reason)
}
// Podman is the exec call to podman on the filesystem // Podman is the exec call to podman on the filesystem
func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration { func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration {
var remoteArgs = []string{"--remote", "--url", p.RemoteSocket} var remoteArgs = []string{"--remote", "--url", p.RemoteSocket}

View File

@ -16,9 +16,6 @@ func IsRemote() bool {
return false return false
} }
func SkipIfRemote(string) {
}
// Podman is the exec call to podman on the filesystem // Podman is the exec call to podman on the filesystem
func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration { func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration {
podmanSession := p.PodmanBase(args, false, false) podmanSession := p.PodmanBase(args, false, false)

View File

@ -3,7 +3,11 @@ package integration
import ( import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/url"
"os" "os"
"os/exec"
"os/user"
"path/filepath"
"github.com/containers/common/pkg/config" "github.com/containers/common/pkg/config"
. "github.com/containers/podman/v3/test/utils" . "github.com/containers/podman/v3/test/utils"
@ -19,22 +23,16 @@ var _ = Describe("podman system connection", func() {
IsSet bool IsSet bool
}{} }{}
var ( var podmanTest *PodmanTestIntegration
podmanTest *PodmanTestIntegration
)
BeforeEach(func() { BeforeEach(func() {
ConfPath.Value, ConfPath.IsSet = os.LookupEnv("CONTAINERS_CONF") ConfPath.Value, ConfPath.IsSet = os.LookupEnv("CONTAINERS_CONF")
conf, err := ioutil.TempFile("", "containersconf") conf, err := ioutil.TempFile("", "containersconf")
if err != nil { Expect(err).ToNot(HaveOccurred())
panic(err)
}
os.Setenv("CONTAINERS_CONF", conf.Name()) os.Setenv("CONTAINERS_CONF", conf.Name())
tempdir, err := CreateTempDirInTempDir() tempdir, err := CreateTempDirInTempDir()
if err != nil { Expect(err).ToNot(HaveOccurred())
panic(err)
}
podmanTest = PodmanTestCreate(tempdir) podmanTest = PodmanTestCreate(tempdir)
podmanTest.Setup() podmanTest.Setup()
}) })
@ -49,221 +47,241 @@ var _ = Describe("podman system connection", func() {
} }
f := CurrentGinkgoTestDescription() f := CurrentGinkgoTestDescription()
timedResult := fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds()) GinkgoWriter.Write(
GinkgoWriter.Write([]byte(timedResult)) []byte(
fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds())))
}) })
It("add ssh://", func() { Context("without running API service", func() {
cmd := []string{"system", "connection", "add", It("add ssh://", func() {
"--default",
"--identity", "~/.ssh/id_rsa",
"QA",
"ssh://root@server.fubar.com:2222/run/podman/podman.sock",
}
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.Out).Should(Say(""))
cfg, err := config.ReadCustomConfig()
Expect(err).ShouldNot(HaveOccurred())
Expect(cfg.Engine.ActiveService).To(Equal("QA"))
Expect(cfg.Engine.ServiceDestinations["QA"]).To(Equal(
config.Destination{
URI: "ssh://root@server.fubar.com:2222/run/podman/podman.sock",
Identity: "~/.ssh/id_rsa",
},
))
cmd = []string{"system", "connection", "rename",
"QA",
"QE",
}
session = podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
cfg, err = config.ReadCustomConfig()
Expect(err).ShouldNot(HaveOccurred())
Expect(cfg.Engine.ActiveService).To(Equal("QE"))
Expect(cfg.Engine.ServiceDestinations["QE"]).To(Equal(
config.Destination{
URI: "ssh://root@server.fubar.com:2222/run/podman/podman.sock",
Identity: "~/.ssh/id_rsa",
},
))
})
It("add UDS", func() {
cmd := []string{"system", "connection", "add",
"QA-UDS",
"unix:///run/podman/podman.sock",
}
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.Out).Should(Say(""))
cfg, err := config.ReadCustomConfig()
Expect(err).ShouldNot(HaveOccurred())
Expect(cfg.Engine.ActiveService).To(Equal("QA-UDS"))
Expect(cfg.Engine.ServiceDestinations["QA-UDS"]).To(Equal(
config.Destination{
URI: "unix:///run/podman/podman.sock",
Identity: "",
},
))
cmd = []string{"system", "connection", "add",
"QA-UDS1",
"--socket-path", "/run/user/podman/podman.sock",
"unix:///run/podman/podman.sock",
}
session = podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.Out).Should(Say(""))
cfg, err = config.ReadCustomConfig()
Expect(err).ShouldNot(HaveOccurred())
Expect(cfg.Engine.ActiveService).To(Equal("QA-UDS"))
Expect(cfg.Engine.ServiceDestinations["QA-UDS1"]).To(Equal(
config.Destination{
URI: "unix:///run/user/podman/podman.sock",
Identity: "",
},
))
})
It("add tcp", func() {
cmd := []string{"system", "connection", "add",
"QA-TCP",
"tcp://localhost:8888",
}
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.Out).Should(Say(""))
cfg, err := config.ReadCustomConfig()
Expect(err).ShouldNot(HaveOccurred())
Expect(cfg.Engine.ActiveService).To(Equal("QA-TCP"))
Expect(cfg.Engine.ServiceDestinations["QA-TCP"]).To(Equal(
config.Destination{
URI: "tcp://localhost:8888",
Identity: "",
},
))
})
It("remove", func() {
cmd := []string{"system", "connection", "add",
"--default",
"--identity", "~/.ssh/id_rsa",
"QA",
"ssh://root@server.fubar.com:2222/run/podman/podman.sock",
}
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
for i := 0; i < 2; i++ {
cmd = []string{"system", "connection", "remove", "QA"}
session = podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.Out).Should(Say(""))
cfg, err := config.ReadCustomConfig()
Expect(err).ShouldNot(HaveOccurred())
Expect(cfg.Engine.ActiveService).To(BeEmpty())
Expect(cfg.Engine.ServiceDestinations).To(BeEmpty())
}
})
It("remove --all", func() {
cmd := []string{"system", "connection", "add",
"--default",
"--identity", "~/.ssh/id_rsa",
"QA",
"ssh://root@server.fubar.com:2222/run/podman/podman.sock",
}
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
cmd = []string{"system", "connection", "remove", "--all"}
session = podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.Out).Should(Say(""))
cmd = []string{"system", "connection", "list"}
session = podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.Out).Should(Say(""))
Expect(session.Err).Should(Say(""))
})
It("default", func() {
for _, name := range []string{"devl", "qe"} {
cmd := []string{"system", "connection", "add", cmd := []string{"system", "connection", "add",
"--default", "--default",
"--identity", "~/.ssh/id_rsa", "--identity", "~/.ssh/id_rsa",
name, "QA",
"ssh://root@server.fubar.com:2222/run/podman/podman.sock", "ssh://root@server.fubar.com:2222/run/podman/podman.sock",
} }
session := podmanTest.Podman(cmd) session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0)) Expect(session).Should(Exit(0))
} Expect(session.Out.Contents()).Should(BeEmpty())
cmd := []string{"system", "connection", "default", "devl"} cfg, err := config.ReadCustomConfig()
session := podmanTest.Podman(cmd) Expect(err).ShouldNot(HaveOccurred())
session.WaitWithDefaultTimeout() Expect(cfg).To(HaveActiveService("QA"))
Expect(session).Should(Exit(0)) Expect(cfg).Should(VerifyService(
Expect(session.Out).Should(Say("")) "QA",
"ssh://root@server.fubar.com:2222/run/podman/podman.sock",
"~/.ssh/id_rsa",
))
cfg, err := config.ReadCustomConfig() cmd = []string{"system", "connection", "rename",
Expect(err).ShouldNot(HaveOccurred()) "QA",
Expect(cfg.Engine.ActiveService).To(Equal("devl")) "QE",
}
session = podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
cmd = []string{"system", "connection", "list"} Expect(config.ReadCustomConfig()).To(HaveActiveService("QE"))
session = podmanTest.Podman(cmd) })
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.Out).Should(Say("Name *URI *Identity *Default"))
cmd = []string{"system", "connection", "list", "--format", "{{.Name}}"} It("add UDS", func() {
session = podmanTest.Podman(cmd) cmd := []string{"system", "connection", "add",
session.WaitWithDefaultTimeout() "QA-UDS",
Expect(session).Should(Exit(0)) "unix:///run/podman/podman.sock",
Expect(session.OutputToString()).Should(Equal("devl qe")) }
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.Out.Contents()).Should(BeEmpty())
Expect(config.ReadCustomConfig()).Should(VerifyService(
"QA-UDS",
"unix:///run/podman/podman.sock",
"",
))
cmd = []string{"system", "connection", "add",
"QA-UDS1",
"--socket-path", "/run/user/podman/podman.sock",
"unix:///run/podman/podman.sock",
}
session = podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.Out.Contents()).Should(BeEmpty())
Expect(config.ReadCustomConfig()).Should(HaveActiveService("QA-UDS"))
Expect(config.ReadCustomConfig()).Should(VerifyService(
"QA-UDS1",
"unix:///run/user/podman/podman.sock",
"",
))
})
It("add tcp", func() {
cmd := []string{"system", "connection", "add",
"QA-TCP",
"tcp://localhost:8888",
}
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.Out.Contents()).Should(BeEmpty())
Expect(config.ReadCustomConfig()).Should(VerifyService(
"QA-TCP",
"tcp://localhost:8888",
"",
))
})
It("remove", func() {
session := podmanTest.Podman([]string{"system", "connection", "add",
"--default",
"--identity", "~/.ssh/id_rsa",
"QA",
"ssh://root@server.fubar.com:2222/run/podman/podman.sock",
})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
// two passes to test that removing non-existent connection is not an error
for i := 0; i < 2; i++ {
session = podmanTest.Podman([]string{"system", "connection", "remove", "QA"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.Out.Contents()).Should(BeEmpty())
cfg, err := config.ReadCustomConfig()
Expect(err).ShouldNot(HaveOccurred())
Expect(cfg.Engine.ActiveService).To(BeEmpty())
Expect(cfg.Engine.ServiceDestinations).To(BeEmpty())
}
})
It("remove --all", func() {
session := podmanTest.Podman([]string{"system", "connection", "add",
"--default",
"--identity", "~/.ssh/id_rsa",
"QA",
"ssh://root@server.fubar.com:2222/run/podman/podman.sock",
})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"system", "connection", "remove", "--all"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.Out.Contents()).Should(BeEmpty())
Expect(session.Err.Contents()).Should(BeEmpty())
session = podmanTest.Podman([]string{"system", "connection", "list"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
})
It("default", func() {
for _, name := range []string{"devl", "qe"} {
cmd := []string{"system", "connection", "add",
"--default",
"--identity", "~/.ssh/id_rsa",
name,
"ssh://root@server.fubar.com:2222/run/podman/podman.sock",
}
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
}
cmd := []string{"system", "connection", "default", "devl"}
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.Out.Contents()).Should(BeEmpty())
Expect(config.ReadCustomConfig()).Should(HaveActiveService("devl"))
cmd = []string{"system", "connection", "list"}
session = podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.Out).Should(Say("Name *URI *Identity *Default"))
cmd = []string{"system", "connection", "list", "--format", "{{.Name}}"}
session = podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).Should(Equal("devl qe"))
})
It("failed default", func() {
cmd := []string{"system", "connection", "default", "devl"}
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).ShouldNot(Exit(0))
Expect(session.Err).Should(Say("destination is not defined"))
})
It("failed rename", func() {
cmd := []string{"system", "connection", "rename", "devl", "QE"}
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).ShouldNot(Exit(0))
Expect(session.Err).Should(Say("destination is not defined"))
})
It("empty list", func() {
cmd := []string{"system", "connection", "list"}
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.Out.Contents()).Should(BeEmpty())
Expect(session.Err.Contents()).Should(BeEmpty())
})
}) })
It("failed default", func() { Context("sshd and API services required", func() {
cmd := []string{"system", "connection", "default", "devl"} BeforeEach(func() {
session := podmanTest.Podman(cmd) // These tests are unique in as much as they require podman, podman-remote, systemd and sshd.
session.WaitWithDefaultTimeout() // podman-remote commands will be executed by ginkgo directly.
Expect(session).ShouldNot(Exit(0)) SkipIfContainerized("sshd is not available when running in a container")
Expect(session.Err).Should(Say("destination is not defined")) SkipIfRemote("connection heuristic requires both podman and podman-remote binaries")
}) SkipIfNotRootless("FIXME: setup ssh keys when root")
SkipIfSystemdNotRunning("cannot test connection heuristic if systemd is not running")
SkipIfNotActive("sshd", "cannot test connection heuristic if sshd is not running")
})
It("failed rename", func() { It("add ssh:// socket path using connection heuristic", func() {
cmd := []string{"system", "connection", "rename", "devl", "QE"} u, err := user.Current()
session := podmanTest.Podman(cmd) Expect(err).ShouldNot(HaveOccurred())
session.WaitWithDefaultTimeout()
Expect(session).ShouldNot(Exit(0))
Expect(session.Err).Should(Say("destination is not defined"))
})
It("empty list", func() { cmd := exec.Command(podmanTest.RemotePodmanBinary,
cmd := []string{"system", "connection", "list"} "system", "connection", "add",
session := podmanTest.Podman(cmd) "--default",
session.WaitWithDefaultTimeout() "--identity", filepath.Join(u.HomeDir, ".ssh", "id_ed25519"),
Expect(session).Should(Exit(0)) "QA",
Expect(session.Out).Should(Say("")) fmt.Sprintf("ssh://%s@localhost", u.Username))
Expect(session.Err).Should(Say(""))
session, err := Start(cmd, GinkgoWriter, GinkgoWriter)
Expect(err).ToNot(HaveOccurred(), fmt.Sprintf("%q failed to execute", podmanTest.RemotePodmanBinary))
Eventually(session, DefaultWaitTimeout).Should(Exit(0))
Expect(session.Out.Contents()).Should(BeEmpty())
Expect(session.Err.Contents()).Should(BeEmpty())
uri := url.URL{
Scheme: "ssh",
User: url.User(u.Username),
Host: "localhost:22",
Path: fmt.Sprintf("/run/user/%s/podman/podman.sock", u.Uid),
}
Expect(config.ReadCustomConfig()).Should(HaveActiveService("QA"))
Expect(config.ReadCustomConfig()).Should(VerifyService(
"QA",
uri.String(),
filepath.Join(u.HomeDir, ".ssh", "id_ed25519"),
))
})
}) })
}) })

View File

@ -2,57 +2,164 @@ package utils
import ( import (
"fmt" "fmt"
"net/url"
"github.com/containers/common/pkg/config"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/format" "github.com/onsi/gomega/format"
"github.com/onsi/gomega/gexec" "github.com/onsi/gomega/gexec"
"github.com/onsi/gomega/matchers"
"github.com/onsi/gomega/types"
) )
// HaveActiveService verifies the given service is the active service
func HaveActiveService(name interface{}) OmegaMatcher {
return WithTransform(
func(cfg *config.Config) string {
return cfg.Engine.ActiveService
},
Equal(name))
}
type ServiceMatcher struct {
types.GomegaMatcher
Name interface{}
URI interface{}
Identity interface{}
failureMessage string
negatedFailureMessage string
}
func VerifyService(name, uri, identity interface{}) OmegaMatcher {
return &ServiceMatcher{
Name: name,
URI: uri,
Identity: identity,
}
}
func (matcher *ServiceMatcher) Match(actual interface{}) (success bool, err error) {
cfg, ok := actual.(*config.Config)
if !ok {
return false, fmt.Errorf("ServiceMatcher matcher expects a config.Config")
}
if _, err = url.Parse(matcher.URI.(string)); err != nil {
return false, err
}
success, err = HaveKey(matcher.Name).Match(cfg.Engine.ServiceDestinations)
if !success || err != nil {
matcher.failureMessage = HaveKey(matcher.Name).FailureMessage(cfg.Engine.ServiceDestinations)
matcher.negatedFailureMessage = HaveKey(matcher.Name).NegatedFailureMessage(cfg.Engine.ServiceDestinations)
return
}
sd := cfg.Engine.ServiceDestinations[matcher.Name.(string)]
success, err = Equal(matcher.URI).Match(sd.URI)
if !success || err != nil {
matcher.failureMessage = Equal(matcher.URI).FailureMessage(sd.URI)
matcher.negatedFailureMessage = Equal(matcher.URI).NegatedFailureMessage(sd.URI)
return
}
success, err = Equal(matcher.Identity).Match(sd.Identity)
if !success || err != nil {
matcher.failureMessage = Equal(matcher.Identity).FailureMessage(sd.Identity)
matcher.negatedFailureMessage = Equal(matcher.Identity).NegatedFailureMessage(sd.Identity)
return
}
return true, nil
}
func (matcher *ServiceMatcher) FailureMessage(_ interface{}) string {
return matcher.failureMessage
}
func (matcher *ServiceMatcher) NegatedFailureMessage(_ interface{}) string {
return matcher.negatedFailureMessage
}
type URLMatcher struct {
matchers.EqualMatcher
}
// VerifyURL matches when actual is a valid URL and matches expected
func VerifyURL(uri interface{}) OmegaMatcher {
return &URLMatcher{matchers.EqualMatcher{Expected: uri}}
}
func (matcher *URLMatcher) Match(actual interface{}) (bool, error) {
e, ok := matcher.Expected.(string)
if !ok {
return false, fmt.Errorf("VerifyURL requires string inputs %T is not supported", matcher.Expected)
}
e_uri, err := url.Parse(e)
if err != nil {
return false, err
}
a, ok := actual.(string)
if !ok {
return false, fmt.Errorf("VerifyURL requires string inputs %T is not supported", actual)
}
a_uri, err := url.Parse(a)
if err != nil {
return false, err
}
return (&matchers.EqualMatcher{Expected: e_uri}).Match(a_uri)
}
type ExitMatcher struct {
types.GomegaMatcher
Expected int
Actual int
}
// ExitWithError matches when assertion is > argument. Default 0 // ExitWithError matches when assertion is > argument. Default 0
// Modeled after the gomega Exit() matcher // Modeled after the gomega Exit() matcher and also operates on sessions.
func ExitWithError(optionalExitCode ...int) *exitMatcher { func ExitWithError(optionalExitCode ...int) *ExitMatcher {
exitCode := 0 exitCode := 0
if len(optionalExitCode) > 0 { if len(optionalExitCode) > 0 {
exitCode = optionalExitCode[0] exitCode = optionalExitCode[0]
} }
return &exitMatcher{exitCode: exitCode} return &ExitMatcher{Expected: exitCode}
} }
type exitMatcher struct { // Match follows gexec.Matcher interface
exitCode int func (matcher *ExitMatcher) Match(actual interface{}) (success bool, err error) {
actualExitCode int
}
func (m *exitMatcher) Match(actual interface{}) (success bool, err error) {
exiter, ok := actual.(gexec.Exiter) exiter, ok := actual.(gexec.Exiter)
if !ok { if !ok {
return false, fmt.Errorf("ExitWithError must be passed a gexec.Exiter (Missing method ExitCode() int) Got:\n#{format.Object(actual, 1)}") return false, fmt.Errorf("ExitWithError must be passed a gexec.Exiter (Missing method ExitCode() int) Got:\n#{format.Object(actual, 1)}")
} }
m.actualExitCode = exiter.ExitCode() matcher.Actual = exiter.ExitCode()
if m.actualExitCode == -1 { if matcher.Actual == -1 {
return false, nil return false, nil
} }
return m.actualExitCode > m.exitCode, nil return matcher.Actual > matcher.Expected, nil
} }
func (m *exitMatcher) FailureMessage(actual interface{}) (message string) { func (matcher *ExitMatcher) FailureMessage(_ interface{}) (message string) {
if m.actualExitCode == -1 { if matcher.Actual == -1 {
return "Expected process to exit. It did not." return "Expected process to exit. It did not."
} }
return format.Message(m.actualExitCode, "to be greater than exit code:", m.exitCode) return format.Message(matcher.Actual, "to be greater than exit code: ", matcher.Expected)
} }
func (m *exitMatcher) NegatedFailureMessage(actual interface{}) (message string) { func (matcher *ExitMatcher) NegatedFailureMessage(_ interface{}) (message string) {
if m.actualExitCode == -1 { switch {
case matcher.Actual == -1:
return "you really shouldn't be able to see this!" return "you really shouldn't be able to see this!"
} else { case matcher.Expected == -1:
if m.exitCode == -1 { return "Expected process not to exit. It did."
return "Expected process not to exit. It did."
}
return format.Message(m.actualExitCode, "is less than or equal to exit code:", m.exitCode)
} }
return format.Message(matcher.Actual, "is less than or equal to exit code: ", matcher.Expected)
} }
func (m *exitMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
func (matcher *ExitMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
session, ok := actual.(*gexec.Session) session, ok := actual.(*gexec.Session)
if ok { if ok {
return session.ExitCode() == -1 return session.ExitCode() == -1

View File

@ -397,7 +397,7 @@ func tagOutputToMap(imagesOutput []string) map[string]map[string]bool {
return m return m
} }
// GetHostDistributionInfo returns a struct with its distribution name and version // GetHostDistributionInfo returns a struct with its distribution Name and version
func GetHostDistributionInfo() HostOS { func GetHostDistributionInfo() HostOS {
f, err := os.Open(OSReleasePath) f, err := os.Open(OSReleasePath)
defer f.Close() defer f.Close()
@ -491,13 +491,3 @@ func RandomString(n int) string {
} }
return string(b) return string(b)
} }
//SkipIfInContainer skips a test if the test is run inside a container
func SkipIfInContainer(reason string) {
if len(reason) < 5 {
panic("SkipIfInContainer must specify a reason to skip")
}
if os.Getenv("TEST_ENVIRON") == "container" {
Skip("[container]: " + reason)
}
}