Skip to content

Commit c0e2585

Browse files
committed
Add update-connection to machine start and init
This allows users to set the associated machine's system connection to the system default when running `podman machine init --now` or `podman machine start`. It also changes the default bbehavior of these commands in that the user will be prompted and asked if they would like to switch the system connection. It also introduces a command line switch called `--update-connection`. If the switch is unset, then the user will be prmpted. If the command value is explicitly set to `false`, the user will not be prompted and the system connection will not be altered. If the value is set to `true`, the system connection will be made the default and the user will not be prompted. Signed-off-by: Brent Baude <[email protected]>
1 parent 87b16eb commit c0e2585

File tree

10 files changed

+290
-19
lines changed

10 files changed

+290
-19
lines changed

cmd/podman/machine/init.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ func init() {
166166
providerFlagName := "provider"
167167
flags.StringVar(&providerOverride, providerFlagName, "", "Override the default machine provider")
168168
_ = initCmd.RegisterFlagCompletionFunc(providerFlagName, autocompleteMachineProvider)
169+
170+
setDefaultConnectionFlagName := "update-connection"
171+
flags.BoolVarP(&setDefaultSystemConn, setDefaultConnectionFlagName, "u", false, "Set default system connection for this machine")
169172
}
170173

171174
func initMachine(cmd *cobra.Command, args []string) error {
@@ -294,8 +297,11 @@ func initMachine(cmd *cobra.Command, args []string) error {
294297
fmt.Println("Machine init complete")
295298

296299
if now {
297-
return start(cmd, args)
300+
if err := start(cmd, args); err != nil {
301+
return err
302+
}
298303
}
304+
299305
extra := ""
300306
if initOpts.Name != defaultMachineName {
301307
extra = " " + initOpts.Name

cmd/podman/machine/start.go

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ var (
2323
Example: `podman machine start podman-machine-default`,
2424
ValidArgsFunction: autocompleteMachine,
2525
}
26-
startOpts = machine.StartOptions{}
26+
startOpts = machine.StartOptions{}
27+
setDefaultSystemConn bool
2728
)
2829

2930
func init() {
@@ -38,15 +39,13 @@ func init() {
3839

3940
quietFlagName := "quiet"
4041
flags.BoolVarP(&startOpts.Quiet, quietFlagName, "q", false, "Suppress machine starting status output")
41-
}
4242

43-
func start(_ *cobra.Command, args []string) error {
44-
var (
45-
err error
46-
)
43+
setDefaultConnectionFlagName := "update-connection"
44+
flags.BoolVarP(&setDefaultSystemConn, setDefaultConnectionFlagName, "u", false, "Set default system connection for this machine")
45+
}
4746

47+
func start(cmd *cobra.Command, args []string) error {
4848
startOpts.NoInfo = startOpts.Quiet || startOpts.NoInfo
49-
5049
vmName := defaultMachineName
5150
if len(args) > 0 && len(args[0]) > 0 {
5251
vmName = args[0]
@@ -61,10 +60,18 @@ func start(_ *cobra.Command, args []string) error {
6160
fmt.Printf("Starting machine %q\n", vmName)
6261
}
6362

64-
if err := shim.Start(mc, vmProvider, startOpts); err != nil {
63+
shouldUpdate := processSystemConnUpdate(cmd, setDefaultSystemConn)
64+
if err := shim.Start(mc, vmProvider, startOpts, shouldUpdate); err != nil {
6565
return err
6666
}
6767
fmt.Printf("Machine %q started successfully\n", vmName)
6868
newMachineEvent(events.Start, events.Event{Name: vmName})
6969
return nil
7070
}
71+
72+
func processSystemConnUpdate(cmd *cobra.Command, updateVal bool) *bool {
73+
if !cmd.Flags().Changed("update-connection") {
74+
return nil
75+
}
76+
return &updateVal
77+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
####> This option file is used in:
2+
####> podman machine init, machine start
3+
####> If file is edited, make sure the changes
4+
####> are applicable to all of those.
5+
#### **--update-connection**, **-u**
6+
7+
When used in conjunction with `podman machine init --now` or `podman machine start`, this option sets the
8+
associated machine system connection as the default. When using this option, a `-u-update-connection` will
9+
set the value to true. To set this value to false, meaning no change and no prompting,
10+
use `--update-connection=false`.
11+
12+
If the value is set to true, the machine connection will be set as the system default.
13+
If the value is set to false, the system default will be unchanged.
14+
If the option is not set, the user will be prompted and asked if it should be changed.

docs/source/markdown/podman-machine-init.1.md.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ as the host Windows operating system.
127127

128128
@@option tls-verify
129129

130+
@@option update-connection
131+
130132
#### **--usb**=*bus=number,devnum=number* or *vendor=hexadecimal,product=hexadecimal*
131133

132134
Assign a USB device from the host to the VM via USB passthrough.

docs/source/markdown/podman-machine-start.1.md renamed to docs/source/markdown/podman-machine-start.1.md.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ Suppress informational tips.
3939

4040
Suppress machine starting status output.
4141

42+
@@option update-connection
43+
4244
## EXAMPLES
4345

4446
Start the specified podman machine.

pkg/machine/e2e/config_init_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package e2e_test
22

33
import (
4+
"fmt"
45
"strconv"
56
"strings"
67

@@ -23,6 +24,7 @@ type initMachine struct {
2324
timezone string
2425
rootful bool
2526
volumes []string
27+
updateConnection *bool
2628
userModeNetworking bool
2729
tlsVerify *bool
2830

@@ -78,6 +80,10 @@ func (i *initMachine) buildCmd(m *machineTestBuilder) []string {
7880
if i.tlsVerify != nil {
7981
cmd = append(cmd, "--tls-verify="+strconv.FormatBool(*i.tlsVerify))
8082
}
83+
if i.updateConnection != nil {
84+
cmd = append(cmd, fmt.Sprintf("--update-connection=%s", strconv.FormatBool(*i.updateConnection)))
85+
}
86+
8187
name := m.name
8288
cmd = append(cmd, name)
8389

@@ -175,6 +181,11 @@ func (i *initMachine) withTlsVerify(tlsVerify *bool) *initMachine {
175181
return i
176182
}
177183

184+
func (i *initMachine) withUpdateConnection(value *bool) *initMachine {
185+
i.updateConnection = value
186+
return i
187+
}
188+
178189
func (i *initMachine) withUserModeNetworking(r bool) *initMachine { //nolint:unused,nolintlint
179190
i.userModeNetworking = r
180191
return i

pkg/machine/e2e/config_start_test.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
package e2e_test
22

3+
import (
4+
"fmt"
5+
"strconv"
6+
)
7+
38
type startMachine struct {
49
/*
510
No command line args other than a machine vm name (also not required)
611
*/
7-
quiet bool
8-
noInfo bool
12+
quiet bool
13+
noInfo bool
14+
updateConnection *bool
915
}
1016

1117
func (s *startMachine) buildCmd(m *machineTestBuilder) []string {
@@ -19,6 +25,9 @@ func (s *startMachine) buildCmd(m *machineTestBuilder) []string {
1925
if s.noInfo {
2026
cmd = append(cmd, "--no-info")
2127
}
28+
if s.updateConnection != nil {
29+
cmd = append(cmd, fmt.Sprintf("--update-connection=%s", strconv.FormatBool(*s.updateConnection)))
30+
}
2231
return cmd
2332
}
2433

@@ -31,3 +40,12 @@ func (s *startMachine) withNoInfo() *startMachine {
3140
s.noInfo = true
3241
return s
3342
}
43+
44+
func (s *startMachine) withUpdateConnection(value *bool) *startMachine {
45+
s.updateConnection = value
46+
return s
47+
}
48+
49+
func ptrBool(v bool) *bool {
50+
return &v
51+
}

pkg/machine/e2e/start_test.go

Lines changed: 155 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@ import (
44
"fmt"
55
"net"
66
"net/url"
7+
"strconv"
78
"sync"
89
"time"
910

1011
"github.com/containers/podman/v6/pkg/machine/define"
12+
jsoniter "github.com/json-iterator/go"
1113
. "github.com/onsi/ginkgo/v2"
1214
. "github.com/onsi/gomega"
1315
. "github.com/onsi/gomega/gexec"
1416
)
1517

1618
var _ = Describe("podman machine start", func() {
17-
1819
It("start simple machine", func() {
1920
i := new(initMachine)
2021
session, err := mb.setCmd(i.withImage(mb.imagePath)).run()
@@ -67,6 +68,7 @@ var _ = Describe("podman machine start", func() {
6768
session, err := machineTestBuilderInit.run()
6869
Expect(err).ToNot(HaveOccurred())
6970
Expect(session).To(Exit(0))
71+
7072
s := new(startMachine)
7173
startSession, err := mb.setCmd(s).run()
7274
Expect(err).ToNot(HaveOccurred())
@@ -184,7 +186,7 @@ var _ = Describe("podman machine start", func() {
184186
defer GinkgoRecover()
185187
defer wg.Done()
186188
s := &startMachine{}
187-
startSession1, err = mb.setName(machine1).setCmd(s).setTimeout(time.Minute * 10).run()
189+
startSession1, err = mb.setName(machine1).setCmd(s.withUpdateConnection(ptrBool(false))).setTimeout(time.Minute * 10).run()
188190
Expect(err).ToNot(HaveOccurred())
189191
}()
190192
go func() {
@@ -197,7 +199,7 @@ var _ = Describe("podman machine start", func() {
197199
// second run.
198200
nmb, err := newMB()
199201
Expect(err).ToNot(HaveOccurred())
200-
startSession2, err = nmb.setName(machine2).setCmd(s).setTimeout(time.Minute * 10).run()
202+
startSession2, err = nmb.setName(machine2).setCmd(s.withUpdateConnection(ptrBool(false))).setTimeout(time.Minute * 10).run()
201203
Expect(err).ToNot(HaveOccurred())
202204
}()
203205
wg.Wait()
@@ -218,6 +220,89 @@ var _ = Describe("podman machine start", func() {
218220
Expect(startSession1.errorToString()).To(ContainSubstring("%s already starting or running: only one VM can be active at a time", machine2))
219221
}
220222
})
223+
224+
It("machine start with --update-connection", func() {
225+
// Add a connection and verify it was set to the default
226+
defConnName := "QA"
227+
err := addSystemConnection(defConnName, true)
228+
Expect(err).ToNot(HaveOccurred())
229+
230+
listings, err := getSystemConnectionsAsSysConns()
231+
Expect(err).ToNot(HaveOccurred())
232+
Expect(listings.IsDefault(defConnName)).To(BeTrue())
233+
234+
// Create a new machine
235+
i := initMachine{}
236+
machineName := randomString()
237+
initSession, err := mb.setName(machineName).setCmd(i.withImage(mb.imagePath)).run()
238+
Expect(err).ToNot(HaveOccurred())
239+
Expect(initSession).To(Exit(0))
240+
241+
// Start the new machine with --update-connection=false
242+
s := startMachine{}
243+
startSession, err := mb.setName(machineName).setCmd(s.withUpdateConnection(ptrBool(false))).run()
244+
Expect(err).ToNot(HaveOccurred())
245+
Expect(startSession).To(Exit(0))
246+
247+
// We started the machine with --update-connection=false so it should not be default
248+
listings, err = getSystemConnectionsAsSysConns()
249+
Expect(err).ToNot(HaveOccurred())
250+
Expect(listings.IsDefault(defConnName)).To(BeTrue())
251+
252+
// Stop the machine
253+
halt := stopMachine{}
254+
stopSession, err := mb.setName(machineName).setCmd(halt).run()
255+
Expect(err).ToNot(HaveOccurred())
256+
Expect(stopSession).To(Exit(0))
257+
258+
// Start the new machine with --update-connection
259+
startSession, err = mb.setName(machineName).setCmd(s.withUpdateConnection(ptrBool(true))).run()
260+
Expect(err).ToNot(HaveOccurred())
261+
Expect(startSession).To(Exit(0))
262+
263+
// We set true so the new default connection should have changed
264+
listings, err = getSystemConnectionsAsSysConns()
265+
Expect(err).ToNot(HaveOccurred())
266+
Expect(listings.IsDefault(machineName)).To(BeTrue())
267+
})
268+
It("machine init --now with --update-connection", func() {
269+
// Add a connection and verify it was set to the default
270+
defConnName := "QA"
271+
err := addSystemConnection(defConnName, true)
272+
Expect(err).ToNot(HaveOccurred())
273+
274+
listings, err := getSystemConnectionsAsSysConns()
275+
Expect(err).ToNot(HaveOccurred())
276+
Expect(listings.IsDefault(defConnName)).To(BeTrue())
277+
278+
// Create a new machine
279+
i := initMachine{}
280+
machineName1 := randomString()
281+
initSession, err := mb.setName(machineName1).setCmd(i.withImage(mb.imagePath).withUpdateConnection(ptrBool(false)).withNow()).run()
282+
Expect(err).ToNot(HaveOccurred())
283+
Expect(initSession).To(Exit(0))
284+
285+
// We started the machine with --update-connection=false so it should not be default
286+
listings, err = getSystemConnectionsAsSysConns()
287+
Expect(err).ToNot(HaveOccurred())
288+
Expect(listings.IsDefault(defConnName)).To(BeTrue())
289+
290+
// Stop the machine
291+
halt := stopMachine{}
292+
stopSession, err := mb.setName(machineName1).setCmd(halt).run()
293+
Expect(err).ToNot(HaveOccurred())
294+
Expect(stopSession).To(Exit(0))
295+
296+
// Create another machine
297+
machineName2 := randomString()
298+
initSession2, err := mb.setName(machineName2).setCmd(i.withImage(mb.imagePath).withUpdateConnection(ptrBool(true)).withNow()).run()
299+
Expect(err).ToNot(HaveOccurred())
300+
Expect(initSession2).To(Exit(0))
301+
302+
listings, err = getSystemConnectionsAsSysConns()
303+
Expect(err).ToNot(HaveOccurred())
304+
Expect(listings.IsDefault(machineName2)).To(BeTrue())
305+
})
221306
})
222307

223308
func mapToPort(uris []string) ([]string, error) {
@@ -238,3 +323,70 @@ func mapToPort(uris []string) ([]string, error) {
238323
}
239324
return ports, nil
240325
}
326+
327+
func addSystemConnection(name string, setDefault bool) error {
328+
addConn := []string{
329+
"system", "connection", "add",
330+
fmt.Sprintf("--default=%s", strconv.FormatBool(setDefault)),
331+
"--identity", "~/.ssh/id_rsa",
332+
name,
333+
"ssh://[email protected]:2222/run/podman/podman.sock",
334+
}
335+
mb.cmd = addConn
336+
addConnSession, err := mb.run()
337+
if err != nil {
338+
return err
339+
}
340+
if addConnSession.ExitCode() != 0 {
341+
fmt.Println(addConnSession.outputToString())
342+
return fmt.Errorf("error: %s", addConnSession.errorToString())
343+
}
344+
return nil
345+
}
346+
347+
func systemConnectionLsToSysConns(output []byte) (SysConns, error) {
348+
var conns SysConns
349+
err := jsoniter.Unmarshal(output, &conns)
350+
return conns, err
351+
}
352+
353+
type SysConn struct {
354+
Name string
355+
URI string
356+
Identity string
357+
IsMachine bool
358+
Default bool
359+
ReadWrite bool
360+
}
361+
362+
type SysConns []SysConn
363+
364+
func (s SysConns) IsDefault(name string) bool {
365+
for _, conn := range s {
366+
if conn.Name == name {
367+
return conn.Default
368+
}
369+
}
370+
return false
371+
}
372+
373+
func (s SysConns) GetDefault() (SysConn, error) {
374+
for _, conn := range s {
375+
if conn.Default {
376+
return conn, nil
377+
}
378+
}
379+
return SysConn{}, fmt.Errorf("no default connection found")
380+
}
381+
382+
func getSystemConnectionsAsSysConns() (SysConns, error) {
383+
connections := new(listSystemConnection)
384+
connSession, err := mb.setCmd(connections.withFormat("json")).run()
385+
if err != nil {
386+
return nil, err
387+
}
388+
if connSession.ExitCode() != 0 {
389+
return nil, fmt.Errorf("error: %s", connSession.errorToString())
390+
}
391+
return systemConnectionLsToSysConns(connSession.Out.Contents())
392+
}

0 commit comments

Comments
 (0)