Skip to content

Commit

Permalink
Merge pull request containers#21692 from Luap99/machine-cleanup
Browse files Browse the repository at this point in the history
machine init: validate machine name and username
  • Loading branch information
openshift-merge-bot[bot] authored Feb 17, 2024
2 parents 3b34232 + 2846027 commit fbb4d5d
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 118 deletions.
9 changes: 9 additions & 0 deletions cmd/podman/machine/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v5/cmd/podman/registry"
ldefine "github.com/containers/podman/v5/libpod/define"
"github.com/containers/podman/v5/libpod/events"
"github.com/containers/podman/v5/pkg/machine"
"github.com/containers/podman/v5/pkg/machine/define"
Expand Down Expand Up @@ -136,13 +137,21 @@ func initMachine(cmd *cobra.Command, args []string) error {
return fmt.Errorf("machine name %q must be %d characters or less", args[0], maxMachineNameSize)
}
initOpts.Name = args[0]

if !ldefine.NameRegex.MatchString(initOpts.Name) {
return fmt.Errorf("invalid name %q: %w", initOpts.Name, ldefine.RegexError)
}
}

// The vmtype names need to be reserved and cannot be used for podman machine names
if _, err := define.ParseVMType(initOpts.Name, define.UnknownVirt); err == nil {
return fmt.Errorf("cannot use %q for a machine name", initOpts.Name)
}

if !ldefine.NameRegex.MatchString(initOpts.Username) {
return fmt.Errorf("invalid username %q: %w", initOpts.Username, ldefine.RegexError)
}

// Check if machine already exists
_, exists, err := shim.VMExists(initOpts.Name, []vmconfigs.VMProvider{provider})
if err != nil {
Expand Down
67 changes: 0 additions & 67 deletions pkg/machine/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,79 +3,12 @@
package machine

import (
"net"
"net/url"
"path/filepath"
"reflect"
"testing"

"github.com/containers/podman/v5/pkg/machine/connection"
"github.com/stretchr/testify/assert"
)

func TestRemoteConnectionType_MakeSSHURL(t *testing.T) {
var (
host = "foobar"
path = "/path/to/socket"
rc = "ssh"
username = "core"
)
type args struct {
host string
path string
port string
userName string
}
tests := []struct {
name string
rc connection.RemoteConnectionType
args args
want url.URL
}{
{
name: "Good no port",
rc: "ssh",
args: args{
host: host,
path: path,
port: "",
userName: username,
},
want: url.URL{
Scheme: rc,
User: url.User(username),
Host: host,
Path: path,
ForceQuery: false,
},
},
{
name: "Good with port",
rc: "ssh",
args: args{
host: host,
path: path,
port: "222",
userName: username,
},
want: url.URL{
Scheme: rc,
User: url.User(username),
Host: net.JoinHostPort(host, "222"),
Path: path,
ForceQuery: false,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.rc.MakeSSHURL(tt.args.host, tt.args.path, tt.args.port, tt.args.userName); !reflect.DeepEqual(got, tt.want) { //nolint: scopelint
t.Errorf("MakeSSHURL() = %v, want %v", got, tt.want) //nolint: scopelint
}
})
}
}

func TestGetSSHIdentityPath(t *testing.T) {
name := "p-test"
datadir, err := GetGlobalDataDir()
Expand Down
26 changes: 14 additions & 12 deletions pkg/machine/connection/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package connection

import (
"fmt"
"net/url"
"strconv"

"github.com/containers/podman/v5/pkg/machine/define"
Expand All @@ -15,22 +14,25 @@ func AddSSHConnectionsToPodmanSocket(uid, port int, identityPath, name, remoteUs
fmt.Println("An ignition path was provided. No SSH connection was added to Podman")
return nil
}
uri := SSHRemoteConnection.MakeSSHURL(LocalhostIP, fmt.Sprintf("/run/user/%d/podman/podman.sock", uid), strconv.Itoa(port), remoteUsername)
uriRoot := SSHRemoteConnection.MakeSSHURL(LocalhostIP, "/run/podman/podman.sock", strconv.Itoa(port), "root")
uri := makeSSHURL(LocalhostIP, fmt.Sprintf("/run/user/%d/podman/podman.sock", uid), strconv.Itoa(port), remoteUsername)
uriRoot := makeSSHURL(LocalhostIP, "/run/podman/podman.sock", strconv.Itoa(port), "root")

uris := []url.URL{uri, uriRoot}
names := []string{name, name + "-root"}
cons := []connection{
{
name: name,
uri: uri,
},
{
name: name + "-root",
uri: uriRoot,
},
}

// The first connection defined when connections is empty will become the default
// regardless of IsDefault, so order according to rootful
if opts.Rootful {
uris[0], names[0], uris[1], names[1] = uris[1], names[1], uris[0], names[0]
cons[0], cons[1] = cons[1], cons[0]
}

for i := 0; i < 2; i++ {
if err := AddConnection(&uris[i], names[i], identityPath, opts.IsDefault && i == 0); err != nil {
return err
}
}
return nil
return addConnection(cons, identityPath, opts.IsDefault)
}
77 changes: 38 additions & 39 deletions pkg/machine/connection/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,40 @@ import (

const LocalhostIP = "127.0.0.1"

func AddConnection(uri fmt.Stringer, name, identity string, isDefault bool) error {
type connection struct {
name string
uri *url.URL
}

func addConnection(cons []connection, identity string, isDefault bool) error {
if len(identity) < 1 {
return errors.New("identity must be defined")
}

return config.EditConnectionConfig(func(cfg *config.ConnectionsFile) error {
if _, ok := cfg.Connection.Connections[name]; ok {
return errors.New("cannot overwrite connection")
}
for i, con := range cons {
if _, ok := cfg.Connection.Connections[con.name]; ok {
return fmt.Errorf("cannot overwrite connection %q", con.name)
}

dst := config.Destination{
URI: uri.String(),
IsMachine: true,
Identity: identity,
}
dst := config.Destination{
URI: con.uri.String(),
IsMachine: true,
Identity: identity,
}

if isDefault {
cfg.Connection.Default = name
}
if isDefault && i == 0 {
cfg.Connection.Default = con.name
}

if cfg.Connection.Connections == nil {
cfg.Connection.Connections = map[string]config.Destination{
name: dst,
if cfg.Connection.Connections == nil {
cfg.Connection.Connections = map[string]config.Destination{
con.name: dst,
}
cfg.Connection.Default = con.name
} else {
cfg.Connection.Connections[con.name] = dst
}
cfg.Connection.Default = name
} else {
cfg.Connection.Connections[name] = dst
}

return nil
Expand Down Expand Up @@ -108,27 +115,19 @@ func RemoveFilesAndConnections(files []string, names ...string) {
}
}

type RemoteConnectionType string

var SSHRemoteConnection RemoteConnectionType = "ssh"

// MakeSSHURL
func (rc RemoteConnectionType) MakeSSHURL(host, path, port, userName string) url.URL {
// TODO Should this function have input verification?
userInfo := url.User(userName)
uri := url.URL{
Scheme: "ssh",
Opaque: "",
User: userInfo,
Host: host,
Path: path,
RawPath: "",
ForceQuery: false,
RawQuery: "",
Fragment: "",
}
// makeSSHURL creates a URL from the given input
func makeSSHURL(host, path, port, userName string) *url.URL {
var hostname string
if len(port) > 0 {
uri.Host = net.JoinHostPort(uri.Hostname(), port)
hostname = net.JoinHostPort(host, port)
} else {
hostname = host
}
userInfo := url.User(userName)
return &url.URL{
Scheme: "ssh",
User: userInfo,
Host: hostname,
Path: path,
}
return uri
}
68 changes: 68 additions & 0 deletions pkg/machine/connection/connection_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//go:build amd64 || arm64

package connection

import (
"net"
"net/url"
"testing"

"github.com/stretchr/testify/assert"
)

func Test_makeSSHURL(t *testing.T) {
var (
host = "foobar"
path = "/path/to/socket"
rc = "ssh"
username = "core"
)
type args struct {
host string
path string
port string
userName string
}
tests := []struct {
name string
args args
want *url.URL
}{
{
name: "Good no port",
args: args{
host: host,
path: path,
port: "",
userName: username,
},
want: &url.URL{
Scheme: rc,
User: url.User(username),
Host: host,
Path: path,
},
},
{
name: "Good with port",
args: args{
host: host,
path: path,
port: "222",
userName: username,
},
want: &url.URL{
Scheme: rc,
User: url.User(username),
Host: net.JoinHostPort(host, "222"),
Path: path,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := makeSSHURL(tt.args.host, tt.args.path, tt.args.port, tt.args.userName)
assert.Equal(t, tt.want, got, "URL matches")
})
}
}
12 changes: 12 additions & 0 deletions pkg/machine/e2e/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,19 @@ var _ = Describe("podman machine init", func() {
Expect(badInit).To(Exit(125))
Expect(badInit.errorToString()).To(ContainSubstring(want))

invalidName := "ab/cd"
session, err = mb.setName(invalidName).setCmd(&i).run()
Expect(err).ToNot(HaveOccurred())
Expect(session).To(Exit(125))
Expect(session.errorToString()).To(ContainSubstring(`invalid name "ab/cd": names must match [a-zA-Z0-9][a-zA-Z0-9_.-]*: invalid argument`))

i.username = "-/a"
session, err = mb.setName("").setCmd(&i).run()
Expect(err).ToNot(HaveOccurred())
Expect(session).To(Exit(125))
Expect(session.errorToString()).To(ContainSubstring(`invalid username "-/a": names must match [a-zA-Z0-9][a-zA-Z0-9_.-]*: invalid argument`))
})

It("simple init", func() {
i := new(initMachine)
session, err := mb.setCmd(i.withImagePath(mb.imagePath)).run()
Expand Down

0 comments on commit fbb4d5d

Please sign in to comment.