diff options
Diffstat (limited to 'cmd/podman')
-rw-r--r-- | cmd/podman/common/completion.go | 12 | ||||
-rw-r--r-- | cmd/podman/common/create.go | 29 | ||||
-rw-r--r-- | cmd/podman/common/create_test.go | 53 | ||||
-rw-r--r-- | cmd/podman/containers/cleanup.go | 8 | ||||
-rw-r--r-- | cmd/podman/containers/create.go | 17 | ||||
-rw-r--r-- | cmd/podman/containers/ps.go | 12 | ||||
-rw-r--r-- | cmd/podman/containers/run.go | 8 | ||||
-rw-r--r-- | cmd/podman/generate/generate.go | 2 | ||||
-rw-r--r-- | cmd/podman/images/build.go | 14 | ||||
-rw-r--r-- | cmd/podman/images/inspect.go | 6 | ||||
-rw-r--r-- | cmd/podman/images/prune.go | 5 | ||||
-rw-r--r-- | cmd/podman/images/save.go | 2 | ||||
-rw-r--r-- | cmd/podman/images/utils_linux.go | 4 | ||||
-rw-r--r-- | cmd/podman/inspect/inspect.go | 2 | ||||
-rw-r--r-- | cmd/podman/machine/init.go | 29 | ||||
-rw-r--r-- | cmd/podman/machine/list.go | 81 | ||||
-rw-r--r-- | cmd/podman/machine/ssh.go | 29 | ||||
-rw-r--r-- | cmd/podman/networks/inspect.go | 2 | ||||
-rw-r--r-- | cmd/podman/play/play.go | 2 | ||||
-rw-r--r-- | cmd/podman/pods/create.go | 32 | ||||
-rw-r--r-- | cmd/podman/registry/config.go | 7 | ||||
-rw-r--r-- | cmd/podman/root.go | 11 | ||||
-rw-r--r-- | cmd/podman/system/prune.go | 6 | ||||
-rw-r--r-- | cmd/podman/system/service.go | 7 |
24 files changed, 272 insertions, 108 deletions
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go index 2ea5fa10f..ea453a331 100644 --- a/cmd/podman/common/completion.go +++ b/cmd/podman/common/completion.go @@ -194,21 +194,14 @@ func getImages(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellComp } else { // suggested "registry.fedoraproject.org/f29/httpd:latest" as // - "registry.fedoraproject.org/f29/httpd:latest" - // - "registry.fedoraproject.org/f29/httpd" // - "f29/httpd:latest" - // - "f29/httpd" // - "httpd:latest" - // - "httpd" paths := strings.Split(repo, "/") for i := range paths { suggestionWithTag := strings.Join(paths[i:], "/") if strings.HasPrefix(suggestionWithTag, toComplete) { suggestions = append(suggestions, suggestionWithTag) } - suggestionWithoutTag := strings.SplitN(strings.SplitN(suggestionWithTag, ":", 2)[0], "@", 2)[0] - if strings.HasPrefix(suggestionWithoutTag, toComplete) { - suggestions = append(suggestions, suggestionWithoutTag) - } } } } @@ -778,10 +771,13 @@ func AutocompleteImageVolume(cmd *cobra.Command, args []string, toComplete strin } // AutocompleteLogDriver - Autocomplete log-driver options. -// -> "journald", "none", "k8s-file" +// -> "journald", "none", "k8s-file", "passthrough" func AutocompleteLogDriver(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { // don't show json-file logDrivers := []string{define.JournaldLogging, define.NoLogging, define.KubernetesLogging} + if !registry.IsRemote() { + logDrivers = append(logDrivers, define.PassthroughLogging) + } return logDrivers, cobra.ShellCompDirectiveNoFileComp } diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index 6200592b4..e490fa121 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -15,6 +15,18 @@ const sizeWithUnitFormat = "(format: `<number>[<unit>]`, where unit = b (bytes), var containerConfig = registry.PodmanConfig() +// ContainerToPodOptions takes the Container and Pod Create options, assigning the matching values back to podCreate for the purpose of the libpod API +// For this function to succeed, the JSON tags in PodCreateOptions and ContainerCreateOptions need to match due to the Marshaling and Unmarshaling done. +// The types of the options also need to match or else the unmarshaling will fail even if the tags match +func ContainerToPodOptions(containerCreate *entities.ContainerCreateOptions, podCreate *entities.PodCreateOptions) error { + contMarshal, err := json.Marshal(containerCreate) + if err != nil { + return err + } + return json.Unmarshal(contMarshal, podCreate) +} + +// DefineCreateFlags declares and instantiates the container create flags func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, isInfra bool) { createFlags := cmd.Flags() @@ -144,14 +156,6 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, ) _ = cmd.RegisterFlagCompletionFunc(cpusetMemsFlagName, completion.AutocompleteNone) - deviceFlagName := "device" - createFlags.StringSliceVar( - &cf.Devices, - deviceFlagName, devices(), - "Add a host device to the container", - ) - _ = cmd.RegisterFlagCompletionFunc(deviceFlagName, completion.AutocompleteDefault) - deviceCgroupRuleFlagName := "device-cgroup-rule" createFlags.StringSliceVar( &cf.DeviceCGroupRule, @@ -417,7 +421,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, pidsLimitFlagName := "pids-limit" createFlags.Int64( pidsLimitFlagName, pidsLimit(), - "Tune container pids limit (set 0 for unlimited, -1 for server defaults)", + "Tune container pids limit (set -1 for unlimited)", ) _ = cmd.RegisterFlagCompletionFunc(pidsLimitFlagName, completion.AutocompleteNone) @@ -865,4 +869,11 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, volumeDesciption, ) _ = cmd.RegisterFlagCompletionFunc(volumeFlagName, AutocompleteVolumeFlag) + deviceFlagName := "device" + createFlags.StringSliceVar( + &cf.Devices, + deviceFlagName, devices(), + "Add a host device to the container", + ) + _ = cmd.RegisterFlagCompletionFunc(deviceFlagName, completion.AutocompleteDefault) } diff --git a/cmd/podman/common/create_test.go b/cmd/podman/common/create_test.go new file mode 100644 index 000000000..17b47dd16 --- /dev/null +++ b/cmd/podman/common/create_test.go @@ -0,0 +1,53 @@ +package common_test + +import ( + "reflect" + "strings" + "testing" + + "github.com/containers/podman/v3/cmd/podman/common" + "github.com/containers/podman/v3/pkg/domain/entities" + "github.com/stretchr/testify/assert" +) + +func TestPodOptions(t *testing.T) { + entry := "/test1" + exampleOptions := entities.ContainerCreateOptions{CPUS: 5.5, CPUSetCPUs: "0-4", Entrypoint: &entry, Hostname: "foo", Name: "testing123", Volume: []string{"/fakeVol1", "/fakeVol2"}, Net: &entities.NetOptions{CNINetworks: []string{"FakeNetwork"}}, PID: "ns:/proc/self/ns"} + + podOptions := entities.PodCreateOptions{} + err := common.ContainerToPodOptions(&exampleOptions, &podOptions) + assert.Nil(t, err) + + cc := reflect.ValueOf(&exampleOptions).Elem() + pc := reflect.ValueOf(&podOptions).Elem() + + pcType := reflect.TypeOf(podOptions) + for i := 0; i < pc.NumField(); i++ { + podField := pc.FieldByIndex([]int{i}) + podType := pcType.Field(i) + for j := 0; j < cc.NumField(); j++ { + containerField := cc.FieldByIndex([]int{j}) + containerType := reflect.TypeOf(exampleOptions).Field(j) + tagPod := strings.Split(string(podType.Tag.Get("json")), ",")[0] + tagContainer := strings.Split(string(containerType.Tag.Get("json")), ",")[0] + if tagPod == tagContainer && (tagPod != "" && tagContainer != "") { + areEqual := true + if containerField.Kind() == podField.Kind() { + switch containerField.Kind() { + case reflect.Slice: + for i, w := range containerField.Interface().([]string) { + areEqual = podField.Interface().([]string)[i] == w + } + case reflect.String: + areEqual = (podField.String() == containerField.String()) + case reflect.Bool: + areEqual = (podField.Bool() == containerField.Bool()) + case reflect.Ptr: + areEqual = (reflect.DeepEqual(podField.Elem().Interface(), containerField.Elem().Interface())) + } + } + assert.True(t, areEqual) + } + } + } +} diff --git a/cmd/podman/containers/cleanup.go b/cmd/podman/containers/cleanup.go index 98706c575..a3d339358 100644 --- a/cmd/podman/containers/cleanup.go +++ b/cmd/podman/containers/cleanup.go @@ -80,7 +80,7 @@ func cleanup(cmd *cobra.Command, args []string) error { // is via syslog. // As such, we need to logrus.Errorf our errors to ensure they // are properly printed if --syslog is set. - logrus.Errorf("Error running container cleanup: %v", err) + logrus.Errorf("Running container cleanup: %v", err) return err } for _, r := range responses { @@ -89,15 +89,15 @@ func cleanup(cmd *cobra.Command, args []string) error { continue } if r.RmErr != nil { - logrus.Errorf("Error removing container: %v", r.RmErr) + logrus.Errorf("Removing container: %v", r.RmErr) errs = append(errs, r.RmErr) } if r.RmiErr != nil { - logrus.Errorf("Error removing image: %v", r.RmiErr) + logrus.Errorf("Removing image: %v", r.RmiErr) errs = append(errs, r.RmiErr) } if r.CleanErr != nil { - logrus.Errorf("Error cleaning up container: %v", r.CleanErr) + logrus.Errorf("Cleaning up container: %v", r.CleanErr) errs = append(errs, r.CleanErr) } } diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go index 8b27de53e..bfeeb7ebe 100644 --- a/cmd/podman/containers/create.go +++ b/cmd/podman/containers/create.go @@ -19,6 +19,7 @@ import ( "github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/specgenutil" "github.com/containers/podman/v3/pkg/util" + "github.com/mattn/go-isatty" "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -161,7 +162,9 @@ func create(cmd *cobra.Command, args []string) error { } } - fmt.Println(report.Id) + if cliVals.LogDriver != define.PassthroughLogging { + fmt.Println(report.Id) + } return nil } @@ -188,6 +191,14 @@ func CreateInit(c *cobra.Command, vals entities.ContainerCreateOptions, isInfra vals.UserNS = "private" } } + if cliVals.LogDriver == define.PassthroughLogging { + if isatty.IsTerminal(0) || isatty.IsTerminal(1) || isatty.IsTerminal(2) { + return vals, errors.New("the '--log-driver passthrough' option cannot be used on a TTY") + } + if registry.IsRemote() { + return vals, errors.New("the '--log-driver passthrough' option is not supported in remote mode") + } + } if !isInfra { if c.Flag("shm-size").Changed { @@ -224,6 +235,10 @@ func CreateInit(c *cobra.Command, vals entities.ContainerCreateOptions, isInfra if c.Flags().Changed("pids-limit") { val := c.Flag("pids-limit").Value.String() + // Convert -1 to 0, so that -1 maps to unlimited pids limit + if val == "-1" { + val = "0" + } pidsLimit, err := strconv.ParseInt(val, 10, 32) if err != nil { return vals, err diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go index ff792b78b..9687cd5bd 100644 --- a/cmd/podman/containers/ps.go +++ b/cmd/podman/containers/ps.go @@ -221,7 +221,10 @@ func ps(cmd *cobra.Command, _ []string) error { } hdrs, format := createPsOut() + + noHeading, _ := cmd.Flags().GetBool("noheading") if cmd.Flags().Changed("format") { + noHeading = noHeading || !report.HasTable(listOpts.Format) format = report.NormalizeFormat(listOpts.Format) format = report.EnforceRange(format) } @@ -240,8 +243,7 @@ func ps(cmd *cobra.Command, _ []string) error { defer w.Flush() headers := func() error { return nil } - noHeading, _ := cmd.Flags().GetBool("noheading") - if !(noHeading || listOpts.Quiet || cmd.Flags().Changed("format")) { + if !noHeading { headers = func() error { return tmpl.Execute(w, hdrs) } @@ -298,9 +300,11 @@ func createPsOut() ([]map[string]string, string) { "IPC": "ipc", "MNT": "mnt", "NET": "net", + "Networks": "networks", "PIDNS": "pidns", "Pod": "pod id", "PodName": "podname", // undo camelcase space break + "RunningFor": "running for", "UTS": "uts", "User": "userns", }) @@ -371,6 +375,10 @@ func (l psReporter) State() string { // Status is a synonym for State() func (l psReporter) Status() string { + hc := l.ListContainer.Status + if hc != "" { + return l.State() + " (" + hc + ")" + } return l.State() } diff --git a/cmd/podman/containers/run.go b/cmd/podman/containers/run.go index d14961829..071708b76 100644 --- a/cmd/podman/containers/run.go +++ b/cmd/podman/containers/run.go @@ -158,8 +158,13 @@ func run(cmd *cobra.Command, args []string) error { runOpts.InputStream = nil } + passthrough := cliVals.LogDriver == define.PassthroughLogging + // If attach is set, clear stdin/stdout/stderr and only attach requested if cmd.Flag("attach").Changed { + if passthrough { + return errors.Wrapf(define.ErrInvalidArg, "cannot specify --attach with --log-driver=passthrough") + } runOpts.OutputStream = nil runOpts.ErrorStream = nil if !cliVals.Interactive { @@ -179,6 +184,7 @@ func run(cmd *cobra.Command, args []string) error { } } } + cliVals.PreserveFDs = runOpts.PreserveFDs s := specgen.NewSpecGenerator(imageName, cliVals.RootFS) if err := specgenutil.FillOutSpecGen(s, &cliVals, args); err != nil { @@ -200,7 +206,7 @@ func run(cmd *cobra.Command, args []string) error { return err } - if runOpts.Detach { + if runOpts.Detach && !passthrough { fmt.Println(report.Id) return nil } diff --git a/cmd/podman/generate/generate.go b/cmd/podman/generate/generate.go index 6b48a342e..a42aa9f21 100644 --- a/cmd/podman/generate/generate.go +++ b/cmd/podman/generate/generate.go @@ -11,7 +11,7 @@ var ( // Command: podman _generate_ generateCmd = &cobra.Command{ Use: "generate", - Short: "Generate structured data based on containers, pods or volumes.", + Short: "Generate structured data based on containers, pods or volumes", Long: "Generate structured data (e.g., Kubernetes YAML or systemd units) based on containers, pods or volumes.", RunE: validate.SubCommandExists, } diff --git a/cmd/podman/images/build.go b/cmd/podman/images/build.go index 642da0c83..4c563ed27 100644 --- a/cmd/podman/images/build.go +++ b/cmd/podman/images/build.go @@ -131,7 +131,7 @@ func buildFlags(cmd *cobra.Command) { // --pull flag flag := budFlags.Lookup("pull") if err := flag.Value.Set("true"); err != nil { - logrus.Errorf("unable to set --pull to true: %v", err) + logrus.Errorf("Unable to set --pull to true: %v", err) } flag.DefValue = "true" flag.Usage = "Always attempt to pull the image (errors are fatal)" @@ -148,13 +148,13 @@ func buildFlags(cmd *cobra.Command) { useLayersVal := useLayers() buildOpts.Layers = useLayersVal == "true" if err := flag.Value.Set(useLayersVal); err != nil { - logrus.Errorf("unable to set --layers to %v: %v", useLayersVal, err) + logrus.Errorf("Unable to set --layers to %v: %v", useLayersVal, err) } flag.DefValue = useLayersVal // --force-rm flag flag = layerFlags.Lookup("force-rm") if err := flag.Value.Set("true"); err != nil { - logrus.Errorf("unable to set --force-rm to true: %v", err) + logrus.Errorf("Unable to set --force-rm to true: %v", err) } flag.DefValue = "true" flags.AddFlagSet(&layerFlags) @@ -162,7 +162,7 @@ func buildFlags(cmd *cobra.Command) { // FromAndBud flags fromAndBudFlags, err := buildahCLI.GetFromAndBudFlags(&buildOpts.FromAndBudResults, &buildOpts.UserNSResults, &buildOpts.NameSpaceResults) if err != nil { - logrus.Errorf("error setting up build flags: %v", err) + logrus.Errorf("Setting up build flags: %v", err) os.Exit(1) } // --http-proxy flag @@ -171,7 +171,7 @@ func buildFlags(cmd *cobra.Command) { flag = fromAndBudFlags.Lookup("http-proxy") buildOpts.HTTPProxy = false if err := flag.Value.Set("false"); err != nil { - logrus.Errorf("unable to set --https-proxy to %v: %v", false, err) + logrus.Errorf("Unable to set --https-proxy to %v: %v", false, err) } flag.DefValue = "false" } @@ -184,7 +184,7 @@ func buildFlags(cmd *cobra.Command) { flag = flags.Lookup("isolation") buildOpts.Isolation = buildahDefine.OCI if err := flag.Value.Set(buildahDefine.OCI); err != nil { - logrus.Errorf("unable to set --isolation to %v: %v", buildahDefine.OCI, err) + logrus.Errorf("Unable to set --isolation to %v: %v", buildahDefine.OCI, err) } flag.DefValue = buildahDefine.OCI _ = flags.MarkHidden("disable-content-trust") @@ -228,7 +228,7 @@ func build(cmd *cobra.Command, args []string) error { // Delete it later. defer func() { if err = os.RemoveAll(tempDir); err != nil { - logrus.Errorf("error removing temporary directory %q: %v", contextDir, err) + logrus.Errorf("Removing temporary directory %q: %v", contextDir, err) } }() contextDir = filepath.Join(tempDir, subDir) diff --git a/cmd/podman/images/inspect.go b/cmd/podman/images/inspect.go index 35c173a60..dd8cf8056 100644 --- a/cmd/podman/images/inspect.go +++ b/cmd/podman/images/inspect.go @@ -17,9 +17,9 @@ var ( Long: `Displays the low-level information of an image identified by name or ID.`, RunE: inspectExec, ValidArgsFunction: common.AutocompleteImages, - Example: `podman inspect alpine - podman inspect --format "imageId: {{.Id}} size: {{.Size}}" alpine - podman inspect --format "image: {{.ImageName}} driver: {{.Driver}}" myctr`, + Example: `podman image inspect alpine + podman image inspect --format "imageId: {{.Id}} size: {{.Size}}" alpine + podman image inspect --format "image: {{.ImageName}} driver: {{.Driver}}" myctr`, } inspectOpts *entities.InspectOptions ) diff --git a/cmd/podman/images/prune.go b/cmd/podman/images/prune.go index 8a484495a..6c39e5c69 100644 --- a/cmd/podman/images/prune.go +++ b/cmd/podman/images/prune.go @@ -41,6 +41,7 @@ func init() { flags := pruneCmd.Flags() flags.BoolVarP(&pruneOpts.All, "all", "a", false, "Remove all images not in use by containers, not just dangling ones") + flags.BoolVarP(&pruneOpts.External, "external", "", false, "Remove images even when they are used by external containers (e.g., by build containers)") flags.BoolVarP(&force, "force", "f", false, "Do not prompt for confirmation") filterFlagName := "filter" @@ -80,7 +81,7 @@ func prune(cmd *cobra.Command, args []string) error { func createPruneWarningMessage(pruneOpts entities.ImagePruneOptions) string { question := "Are you sure you want to continue? [y/N] " if pruneOpts.All { - return "WARNING! This will remove all images without at least one container associated to them.\n" + question + return "WARNING! This command removes all images without at least one container associated with them.\n" + question } - return "WARNING! This will remove all dangling images.\n" + question + return "WARNING! This command removes all dangling images.\n" + question } diff --git a/cmd/podman/images/save.go b/cmd/podman/images/save.go index 19dadb2ad..4f45cb912 100644 --- a/cmd/podman/images/save.go +++ b/cmd/podman/images/save.go @@ -84,6 +84,8 @@ func saveFlags(cmd *cobra.Command) { flags.BoolVar(&saveOpts.Compress, "compress", false, "Compress tarball image layers when saving to a directory using the 'dir' transport. (default is same compression type as source)") + flags.BoolVar(&saveOpts.OciAcceptUncompressedLayers, "uncompressed", false, "Accept uncompressed layers when copying OCI images") + formatFlagName := "format" flags.StringVar(&saveOpts.Format, formatFlagName, define.V2s2Archive, "Save image to oci-archive, oci-dir (directory with oci manifest type), docker-archive, docker-dir (directory with v2s2 manifest type)") _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteImageSaveFormat) diff --git a/cmd/podman/images/utils_linux.go b/cmd/podman/images/utils_linux.go index 5521abab4..f7c159415 100644 --- a/cmd/podman/images/utils_linux.go +++ b/cmd/podman/images/utils_linux.go @@ -24,7 +24,7 @@ func setupPipe() (string, func() <-chan error, error) { err = unix.Mkfifo(pipePath, 0600) if err != nil { if e := os.RemoveAll(pipeDir); e != nil { - logrus.Errorf("error removing named pipe: %q", e) + logrus.Errorf("Removing named pipe: %q", e) } return "", nil, errors.Wrapf(err, "error creating named pipe") } @@ -40,7 +40,7 @@ func setupPipe() (string, func() <-chan error, error) { }() return pipePath, func() <-chan error { if e := os.RemoveAll(pipeDir); e != nil { - logrus.Errorf("error removing named pipe: %q", e) + logrus.Errorf("Removing named pipe: %q", e) } return errc }, nil diff --git a/cmd/podman/inspect/inspect.go b/cmd/podman/inspect/inspect.go index 4c7fa33a4..64b586388 100644 --- a/cmd/podman/inspect/inspect.go +++ b/cmd/podman/inspect/inspect.go @@ -220,7 +220,7 @@ func (i *inspector) inspect(namesOrIDs []string) error { err = printTmpl(tmpType, row, data) } if err != nil { - logrus.Errorf("Error printing inspect output: %v", err) + logrus.Errorf("Printing inspect output: %v", err) } if len(errs) > 0 { diff --git a/cmd/podman/machine/init.go b/cmd/podman/machine/init.go index ec44a707d..adde887f7 100644 --- a/cmd/podman/machine/init.go +++ b/cmd/podman/machine/init.go @@ -3,6 +3,8 @@ package machine import ( + "fmt" + "github.com/containers/common/pkg/completion" "github.com/containers/podman/v3/cmd/podman/registry" "github.com/containers/podman/v3/pkg/machine" @@ -26,6 +28,7 @@ var ( var ( initOpts = machine.InitOptions{} defaultMachineName = "podman-machine-default" + now bool ) func init() { @@ -39,7 +42,7 @@ func init() { cpusFlagName := "cpus" flags.Uint64Var( &initOpts.CPUS, - cpusFlagName, 1, + cpusFlagName, cfg.Machine.CPUs, "Number of CPUs", ) _ = initCmd.RegisterFlagCompletionFunc(cpusFlagName, completion.AutocompleteNone) @@ -47,7 +50,7 @@ func init() { diskSizeFlagName := "disk-size" flags.Uint64Var( &initOpts.DiskSize, - diskSizeFlagName, 10, + diskSizeFlagName, cfg.Machine.DiskSize, "Disk size in GB", ) @@ -56,13 +59,19 @@ func init() { memoryFlagName := "memory" flags.Uint64VarP( &initOpts.Memory, - memoryFlagName, "m", 2048, + memoryFlagName, "m", cfg.Machine.Memory, "Memory in MB", ) _ = initCmd.RegisterFlagCompletionFunc(memoryFlagName, completion.AutocompleteNone) + flags.BoolVar( + &now, + "now", false, + "Start machine now", + ) + ImagePathFlagName := "image-path" - flags.StringVar(&initOpts.ImagePath, ImagePathFlagName, cfg.Engine.MachineImage, "Path to qcow image") + flags.StringVar(&initOpts.ImagePath, ImagePathFlagName, cfg.Machine.Image, "Path to qcow image") _ = initCmd.RegisterFlagCompletionFunc(ImagePathFlagName, completion.AutocompleteDefault) IgnitionPathFlagName := "ignition-path" @@ -91,5 +100,15 @@ func initMachine(cmd *cobra.Command, args []string) error { if err != nil { return err } - return vm.Init(initOpts) + err = vm.Init(initOpts) + if err != nil { + return err + } + if now { + err = vm.Start(initOpts.Name, machine.StartOptions{}) + if err == nil { + fmt.Printf("Machine %q started successfully\n", initOpts.Name) + } + } + return err } diff --git a/cmd/podman/machine/list.go b/cmd/podman/machine/list.go index d4360bb9b..95b7d860f 100644 --- a/cmd/podman/machine/list.go +++ b/cmd/podman/machine/list.go @@ -3,13 +3,16 @@ package machine import ( + "encoding/json" "os" "sort" + "strconv" "time" "github.com/containers/common/pkg/completion" "github.com/containers/common/pkg/config" "github.com/containers/common/pkg/report" + "github.com/containers/podman/v3/cmd/podman/common" "github.com/containers/podman/v3/cmd/podman/registry" "github.com/containers/podman/v3/cmd/podman/validate" "github.com/containers/podman/v3/pkg/machine" @@ -40,10 +43,15 @@ type listFlagType struct { } type machineReporter struct { - Name string - Created string - LastUp string - VMType string + Name string + Default bool + Created string + Running bool + LastUp string + VMType string + CPUs uint64 + Memory string + DiskSize string } func init() { @@ -54,8 +62,8 @@ func init() { flags := lsCmd.Flags() formatFlagName := "format" - flags.StringVar(&listFlag.format, formatFlagName, "{{.Name}}\t{{.VMType}}\t{{.Created}}\t{{.LastUp}}\n", "Format volume output using Go template") - _ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, completion.AutocompleteNone) + flags.StringVar(&listFlag.format, formatFlagName, "{{.Name}}\t{{.VMType}}\t{{.Created}}\t{{.LastUp}}\t{{.CPUs}}\t{{.Memory}}\t{{.DiskSize}}\n", "Format volume output using JSON or a Go template") + _ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(machineReporter{})) flags.BoolVar(&listFlag.noHeading, "noheading", false, "Do not print headers") } @@ -75,6 +83,21 @@ func list(cmd *cobra.Command, args []string) error { sort.Slice(listResponse, func(i, j int) bool { return listResponse[i].Running }) + + if report.IsJSON(listFlag.format) { + machineReporter, err := toMachineFormat(listResponse) + if err != nil { + return err + } + + b, err := json.Marshal(machineReporter) + if err != nil { + return err + } + os.Stdout.Write(b) + return nil + } + machineReporter, err := toHumanFormat(listResponse) if err != nil { return err @@ -85,8 +108,11 @@ func list(cmd *cobra.Command, args []string) error { func outputTemplate(cmd *cobra.Command, responses []*machineReporter) error { headers := report.Headers(machineReporter{}, map[string]string{ - "LastUp": "LAST UP", - "VmType": "VM TYPE", + "LastUp": "LAST UP", + "VmType": "VM TYPE", + "CPUs": "CPUS", + "Memory": "MEMORY", + "DiskSize": "DISK SIZE", }) row := report.NormalizeFormat(listFlag.format) @@ -115,6 +141,42 @@ func outputTemplate(cmd *cobra.Command, responses []*machineReporter) error { return tmpl.Execute(w, responses) } +func strTime(t time.Time) string { + iso, err := t.MarshalText() + if err != nil { + return "" + } + return string(iso) +} + +func strUint(u uint64) string { + return strconv.FormatUint(u, 10) +} + +func toMachineFormat(vms []*machine.ListResponse) ([]*machineReporter, error) { + cfg, err := config.ReadCustomConfig() + if err != nil { + return nil, err + } + + machineResponses := make([]*machineReporter, 0, len(vms)) + for _, vm := range vms { + response := new(machineReporter) + response.Default = vm.Name == cfg.Engine.ActiveService + response.Name = vm.Name + response.Running = vm.Running + response.LastUp = strTime(vm.LastUp) + response.Created = strTime(vm.CreatedAt) + response.VMType = vm.VMType + response.CPUs = vm.CPUs + response.Memory = strUint(vm.Memory * units.MiB) + response.DiskSize = strUint(vm.DiskSize * units.GiB) + + machineResponses = append(machineResponses, response) + } + return machineResponses, nil +} + func toHumanFormat(vms []*machine.ListResponse) ([]*machineReporter, error) { cfg, err := config.ReadCustomConfig() if err != nil { @@ -136,6 +198,9 @@ func toHumanFormat(vms []*machine.ListResponse) ([]*machineReporter, error) { } response.Created = units.HumanDuration(time.Since(vm.CreatedAt)) + " ago" response.VMType = vm.VMType + response.CPUs = vm.CPUs + response.Memory = units.HumanSize(float64(vm.Memory) * units.MiB) + response.DiskSize = units.HumanSize(float64(vm.DiskSize) * units.GiB) humanResponses = append(humanResponses, response) } diff --git a/cmd/podman/machine/ssh.go b/cmd/podman/machine/ssh.go index 84e9e88ab..da0a09338 100644 --- a/cmd/podman/machine/ssh.go +++ b/cmd/podman/machine/ssh.go @@ -5,6 +5,7 @@ package machine import ( "net/url" + "github.com/containers/common/pkg/completion" "github.com/containers/common/pkg/config" "github.com/containers/podman/v3/cmd/podman/registry" "github.com/containers/podman/v3/pkg/machine" @@ -15,7 +16,7 @@ import ( var ( sshCmd = &cobra.Command{ - Use: "ssh [NAME] [COMMAND [ARG ...]]", + Use: "ssh [options] [NAME] [COMMAND [ARG ...]]", Short: "SSH into an existing machine", Long: "SSH into a managed virtual machine ", RunE: ssh, @@ -35,6 +36,10 @@ func init() { Command: sshCmd, Parent: machineCmd, }) + flags := sshCmd.Flags() + usernameFlagName := "username" + flags.StringVar(&sshOpts.Username, usernameFlagName, "", "Username to use when ssh-ing into the VM.") + _ = sshCmd.RegisterFlagCompletionFunc(usernameFlagName, completion.AutocompleteNone) } func ssh(cmd *cobra.Command, args []string) error { @@ -48,13 +53,6 @@ func ssh(cmd *cobra.Command, args []string) error { // Set the VM to default vmName := defaultMachineName - // If we're not given a VM name, use the remote username from the connection config - if len(args) == 0 { - sshOpts.Username, err = remoteConnectionUsername() - if err != nil { - return err - } - } // If len is greater than 0, it means we may have been // provided the VM name. If so, we check. The VM name, // if provided, must be in args[0]. @@ -68,10 +66,6 @@ func ssh(cmd *cobra.Command, args []string) error { if validVM { vmName = args[0] } else { - sshOpts.Username, err = remoteConnectionUsername() - if err != nil { - return err - } sshOpts.Args = append(sshOpts.Args, args[0]) } } @@ -83,14 +77,17 @@ func ssh(cmd *cobra.Command, args []string) error { if validVM { sshOpts.Args = args[1:] } else { - sshOpts.Username, err = remoteConnectionUsername() - if err != nil { - return err - } sshOpts.Args = args } } + if !validVM && sshOpts.Username == "" { + sshOpts.Username, err = remoteConnectionUsername() + if err != nil { + return err + } + } + switch vmType { default: vm, err = qemu.LoadVMByName(vmName) diff --git a/cmd/podman/networks/inspect.go b/cmd/podman/networks/inspect.go index c0e5b9720..4f3e86fc9 100644 --- a/cmd/podman/networks/inspect.go +++ b/cmd/podman/networks/inspect.go @@ -12,7 +12,7 @@ var ( networkinspectDescription = `Inspect network` networkinspectCommand = &cobra.Command{ Use: "inspect [options] NETWORK [NETWORK...]", - Short: "network inspect", + Short: "Displays the raw CNI network configuration for one or more networks.", Long: networkinspectDescription, RunE: networkInspect, Example: `podman network inspect podman`, diff --git a/cmd/podman/play/play.go b/cmd/podman/play/play.go index f121d6a2d..d676bd701 100644 --- a/cmd/podman/play/play.go +++ b/cmd/podman/play/play.go @@ -10,7 +10,7 @@ var ( // Command: podman _play_ playCmd = &cobra.Command{ Use: "play", - Short: "Play containers, pods or volumes from a structured file.", + Short: "Play containers, pods or volumes from a structured file", Long: "Play structured data (e.g., Kubernetes YAML) based on containers, pods or volumes.", RunE: validate.SubCommandExists, } diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go index 7000c92c8..ca73a8356 100644 --- a/cmd/podman/pods/create.go +++ b/cmd/podman/pods/create.go @@ -132,7 +132,6 @@ func create(cmd *cobra.Command, args []string) error { createOptions.Share = nil } else { // reassign certain optios for lbpod api, these need to be populated in spec - MapOptions() flags := cmd.Flags() infraOptions.Net, err = common.NetFlagsToNetOptions(nil, *flags, false) if err != nil { @@ -142,13 +141,11 @@ func create(cmd *cobra.Command, args []string) error { if err != nil { return err } - createOptions.Net = infraOptions.Net createOptions.Share = strings.Split(share, ",") if cmd.Flag("infra-command").Changed { // Only send content to server side if user changed defaults cmdIn, err := cmd.Flags().GetString("infra-command") infraOptions.Entrypoint = &cmdIn - createOptions.InfraCommand = cmdIn if err != nil { return err } @@ -161,6 +158,10 @@ func create(cmd *cobra.Command, args []string) error { return err } } + err = common.ContainerToPodOptions(&infraOptions, &createOptions) + if err != nil { + return err + } } if cmd.Flag("pod-id-file").Changed { @@ -196,8 +197,8 @@ func create(cmd *cobra.Command, args []string) error { if createOptions.Cpus > float64(numCPU) { createOptions.Cpus = float64(numCPU) } - copy := createOptions.CpusetCpus - cpuSet := createOptions.Cpus + copy := infraOptions.CPUSetCPUs + cpuSet := infraOptions.CPUS if cpuSet == 0 { cpuSet = float64(sysinfo.NumCPU()) } @@ -217,10 +218,10 @@ func create(cmd *cobra.Command, args []string) error { if core > int(cpuSet) { if copy == "" { copy = "0-" + strconv.Itoa(int(cpuSet)) - createOptions.CpusetCpus = copy + infraOptions.CPUSetCPUs = copy break } else { - createOptions.CpusetCpus = copy + infraOptions.CPUSetCPUs = copy break } } else if ind != 0 { @@ -229,6 +230,8 @@ func create(cmd *cobra.Command, args []string) error { copy = "" + strconv.Itoa(core) } } + createOptions.Cpus = infraOptions.CPUS + createOptions.CpusetCpus = infraOptions.CPUSetCPUs podSpec := specgen.NewPodSpecGenerator() podSpec, err = entities.ToPodSpecGen(*podSpec, &createOptions) if err != nil { @@ -248,11 +251,8 @@ func create(cmd *cobra.Command, args []string) error { } podSpec.InfraImage = imageName if infraOptions.Entrypoint != nil { - createOptions.InfraCommand = *infraOptions.Entrypoint + createOptions.InfraCommand = infraOptions.Entrypoint } - infraOptions.CPUS = createOptions.Cpus - infraOptions.CPUSetCPUs = createOptions.CpusetCpus - infraOptions.PID = createOptions.Pid podSpec.InfraContainerSpec = specgen.NewSpecGenerator(imageName, false) podSpec.InfraContainerSpec.RawImageName = rawImageName podSpec.InfraContainerSpec.NetworkOptions = podSpec.NetworkOptions @@ -290,13 +290,3 @@ func replacePod(name string) error { } return removePods([]string{name}, rmOptions, false) } - -func MapOptions() { - createOptions.Cpus = infraOptions.CPUS - createOptions.CpusetCpus = infraOptions.CPUSetCPUs - createOptions.Hostname = infraOptions.Hostname - createOptions.InfraConmonPidFile = infraOptions.ConmonPIDFile - createOptions.InfraName = infraOptions.Name - createOptions.Pid = infraOptions.PID - createOptions.Volume = infraOptions.Volume -} diff --git a/cmd/podman/registry/config.go b/cmd/podman/registry/config.go index 50e488b02..b512ba341 100644 --- a/cmd/podman/registry/config.go +++ b/cmd/podman/registry/config.go @@ -89,12 +89,7 @@ func newPodmanConfig() { // use for the containers.conf configuration file. func setXdgDirs() error { if !rootless.IsRootless() { - // unset XDG_RUNTIME_DIR for root - // Sometimes XDG_RUNTIME_DIR is set to /run/user/0 sometimes it is unset, - // the inconsistency is causing issues for the dnsname plugin. - // It is already set to an empty string for conmon so lets do the same - // for podman. see #10806 and #10745 - return os.Unsetenv("XDG_RUNTIME_DIR") + return nil } // Setup XDG_RUNTIME_DIR diff --git a/cmd/podman/root.go b/cmd/podman/root.go index 02e6dcd27..eb30f1ef6 100644 --- a/cmd/podman/root.go +++ b/cmd/podman/root.go @@ -92,6 +92,11 @@ func Execute() { if registry.GetExitCode() == 0 { registry.SetExitCode(define.ExecErrorCodeGeneric) } + if registry.IsRemote() { + if strings.Contains(err.Error(), "unable to connect to Podman") { + fmt.Fprintln(os.Stderr, "Cannot connect to Podman. Please verify your connection to the Linux system using `podman system connection list`, or try `podman machine init` and `podman machine start` to manage a new Linux VM") + } + } fmt.Fprintln(os.Stderr, formatError(err)) } os.Exit(registry.GetExitCode()) @@ -175,7 +180,7 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error { // Hard code TMPDIR functions to use /var/tmp, if user did not override if _, ok := os.LookupEnv("TMPDIR"); !ok { if tmpdir, err := cfg.ImageCopyTmpDir(); err != nil { - logrus.Warnf("failed to retrieve default tmp dir: %s", err.Error()) + logrus.Warnf("Failed to retrieve default tmp dir: %s", err.Error()) } else { os.Setenv("TMPDIR", tmpdir) } @@ -313,7 +318,7 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) { pFlags := cmd.PersistentFlags() if registry.IsRemote() { if err := lFlags.MarkHidden("remote"); err != nil { - logrus.Warnf("unable to mark --remote flag as hidden: %s", err.Error()) + logrus.Warnf("Unable to mark --remote flag as hidden: %s", err.Error()) } opts.Remote = true } else { @@ -387,7 +392,7 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) { "trace", } { if err := pFlags.MarkHidden(f); err != nil { - logrus.Warnf("unable to mark %s flag as hidden: %s", f, err.Error()) + logrus.Warnf("Unable to mark %s flag as hidden: %s", f, err.Error()) } } } diff --git a/cmd/podman/system/prune.go b/cmd/podman/system/prune.go index e09e2d5e5..5565ea2f9 100644 --- a/cmd/podman/system/prune.go +++ b/cmd/podman/system/prune.go @@ -113,15 +113,15 @@ func prune(cmd *cobra.Command, args []string) error { func createPruneWarningMessage(pruneOpts entities.SystemPruneOptions) string { if pruneOpts.All { - return `WARNING! This will remove: + return `WARNING! This command removes: - all stopped containers - all networks not used by at least one container%s - - all images without at least one container associated to them + - all images without at least one container associated with them - all build cache %s` } - return `WARNING! This will remove: + return `WARNING! This command removes: - all stopped containers - all networks not used by at least one container%s - all dangling images diff --git a/cmd/podman/system/service.go b/cmd/podman/system/service.go index a30f43839..99a6b1e1e 100644 --- a/cmd/podman/system/service.go +++ b/cmd/podman/system/service.go @@ -52,8 +52,9 @@ func init() { flags := srvCmd.Flags() + cfg := registry.PodmanConfig() timeFlagName := "time" - flags.Int64VarP(&srvArgs.Timeout, timeFlagName, "t", 5, "Time until the service session expires in seconds. Use 0 to disable the timeout") + flags.Int64VarP(&srvArgs.Timeout, timeFlagName, "t", int64(cfg.Engine.ServiceTimeout), "Time until the service session expires in seconds. Use 0 to disable the timeout") _ = srvCmd.RegisterFlagCompletionFunc(timeFlagName, completion.AutocompleteNone) flags.StringVarP(&srvArgs.CorsHeaders, "cors", "", "", "Set CORS Headers") _ = srvCmd.RegisterFlagCompletionFunc("cors", completion.AutocompleteNone) @@ -73,7 +74,7 @@ func service(cmd *cobra.Command, args []string) error { if err != nil { return err } - logrus.Infof("using API endpoint: '%s'", apiURI) + logrus.Infof("Using API endpoint: '%s'", apiURI) // Clean up any old existing unix domain socket if len(apiURI) > 0 { uri, err := url.Parse(apiURI) @@ -119,7 +120,7 @@ func resolveAPIURI(_url []string) (string, error) { case len(_url) > 0 && _url[0] != "": return _url[0], nil case systemd.SocketActivated(): - logrus.Info("using systemd socket activation to determine API endpoint") + logrus.Info("Using systemd socket activation to determine API endpoint") return "", nil case rootless.IsRootless(): xdg, err := util.GetRuntimeDir() |