github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/cmd/podman/common.go (about) 1 package main 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 8 "github.com/containers/buildah" 9 buildahcli "github.com/containers/buildah/pkg/cli" 10 "github.com/containers/libpod/cmd/podman/cliconfig" 11 "github.com/containers/libpod/pkg/util/camelcase" 12 jsoniter "github.com/json-iterator/go" 13 "github.com/pkg/errors" 14 "github.com/spf13/cobra" 15 "github.com/spf13/pflag" 16 ) 17 18 var ( 19 json = jsoniter.ConfigCompatibleWithStandardLibrary 20 ) 21 22 const ( 23 idTruncLength = 12 24 sizeWithUnitFormat = "(format: `<number>[<unit>]`, where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes))" 25 ) 26 27 func splitCamelCase(src string) string { 28 entries := camelcase.Split(src) 29 return strings.Join(entries, " ") 30 } 31 32 func shortID(id string) string { 33 if len(id) > idTruncLength { 34 return id[:idTruncLength] 35 } 36 return id 37 } 38 39 // checkAllLatestAndCIDFile checks that --all and --latest are used correctly. 40 // If cidfile is set, also check for the --cidfile flag. 41 func checkAllLatestAndCIDFile(c *cobra.Command, args []string, ignoreArgLen bool, cidfile bool) error { 42 argLen := len(args) 43 if c.Flags().Lookup("all") == nil || c.Flags().Lookup("latest") == nil { 44 if !cidfile { 45 return errors.New("unable to lookup values for 'latest' or 'all'") 46 } else if c.Flags().Lookup("cidfile") == nil { 47 return errors.New("unable to lookup values for 'latest', 'all' or 'cidfile'") 48 } 49 } 50 51 specifiedAll, _ := c.Flags().GetBool("all") 52 specifiedLatest, _ := c.Flags().GetBool("latest") 53 specifiedCIDFile := false 54 if cid, _ := c.Flags().GetStringArray("cidfile"); len(cid) > 0 { 55 specifiedCIDFile = true 56 } 57 58 if specifiedCIDFile && (specifiedAll || specifiedLatest) { 59 return errors.Errorf("--all, --latest and --cidfile cannot be used together") 60 } else if specifiedAll && specifiedLatest { 61 return errors.Errorf("--all and --latest cannot be used together") 62 } 63 64 if ignoreArgLen { 65 return nil 66 } 67 if (argLen > 0) && (specifiedAll || specifiedLatest) { 68 return errors.Errorf("no arguments are needed with --all or --latest") 69 } else if cidfile && (argLen > 0) && (specifiedAll || specifiedLatest || specifiedCIDFile) { 70 return errors.Errorf("no arguments are needed with --all, --latest or --cidfile") 71 } 72 73 if specifiedCIDFile { 74 return nil 75 } 76 77 if argLen < 1 && !specifiedAll && !specifiedLatest && !specifiedCIDFile { 78 return errors.Errorf("you must provide at least one name or id") 79 } 80 return nil 81 } 82 83 // noSubArgs checks that there are no further positional parameters 84 func noSubArgs(c *cobra.Command, args []string) error { 85 if len(args) > 0 { 86 return errors.Errorf("`%s` takes no arguments", c.CommandPath()) 87 } 88 return nil 89 } 90 91 func commandRunE() func(*cobra.Command, []string) error { 92 return func(cmd *cobra.Command, args []string) error { 93 if len(args) > 0 { 94 return errors.Errorf("unrecognized command `%s %s`\nTry '%s --help' for more information.", cmd.CommandPath(), args[0], cmd.CommandPath()) 95 } else { 96 return errors.Errorf("missing command '%s COMMAND'\nTry '%s --help' for more information.", cmd.CommandPath(), cmd.CommandPath()) 97 } 98 } 99 } 100 101 // getContext returns a non-nil, empty context 102 func getContext() context.Context { 103 if Ctx != nil { 104 return Ctx 105 } 106 return context.TODO() 107 } 108 109 func getNetFlags() *pflag.FlagSet { 110 netFlags := pflag.FlagSet{} 111 netFlags.StringSlice( 112 "add-host", []string{}, 113 "Add a custom host-to-IP mapping (host:ip)", 114 ) 115 netFlags.StringSlice( 116 "dns", getDefaultDNSServers(), 117 "Set custom DNS servers", 118 ) 119 netFlags.StringSlice( 120 "dns-opt", getDefaultDNSOptions(), 121 "Set custom DNS options", 122 ) 123 netFlags.StringSlice( 124 "dns-search", getDefaultDNSSearches(), 125 "Set custom DNS search domains", 126 ) 127 netFlags.String( 128 "ip", "", 129 "Specify a static IPv4 address for the container", 130 ) 131 netFlags.String( 132 "mac-address", "", 133 "Container MAC address (e.g. 92:d0:c6:0a:29:33)", 134 ) 135 netFlags.String( 136 "network", getDefaultNetNS(), 137 "Connect a container to a network", 138 ) 139 netFlags.StringSliceP( 140 "publish", "p", []string{}, 141 "Publish a container's port, or a range of ports, to the host (default [])", 142 ) 143 netFlags.Bool( 144 "no-hosts", false, 145 "Do not create /etc/hosts within the container, instead use the version from the image", 146 ) 147 return &netFlags 148 } 149 150 func getCreateFlags(c *cliconfig.PodmanCommand) { 151 createFlags := c.Flags() 152 createFlags.StringSlice( 153 "annotation", []string{}, 154 "Add annotations to container (key:value)", 155 ) 156 createFlags.StringSliceP( 157 "attach", "a", []string{}, 158 "Attach to STDIN, STDOUT or STDERR", 159 ) 160 createFlags.String( 161 "authfile", buildahcli.GetDefaultAuthFile(), 162 "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override", 163 ) 164 createFlags.String( 165 "blkio-weight", "", 166 "Block IO weight (relative weight) accepts a weight value between 10 and 1000.", 167 ) 168 createFlags.StringSlice( 169 "blkio-weight-device", []string{}, 170 "Block IO weight (relative device weight, format: `DEVICE_NAME:WEIGHT`)", 171 ) 172 createFlags.StringSlice( 173 "cap-add", []string{}, 174 "Add capabilities to the container", 175 ) 176 createFlags.StringSlice( 177 "cap-drop", []string{}, 178 "Drop capabilities from the container", 179 ) 180 createFlags.String( 181 "cgroupns", getDefaultCgroupNS(), 182 "cgroup namespace to use", 183 ) 184 createFlags.String( 185 "cgroups", "enabled", 186 `control container cgroup configuration ("enabled"|"disabled"|"no-conmon")`, 187 ) 188 createFlags.String( 189 "cgroup-parent", "", 190 "Optional parent cgroup for the container", 191 ) 192 createFlags.String( 193 "cidfile", "", 194 "Write the container ID to the file", 195 ) 196 createFlags.String( 197 "conmon-pidfile", "", 198 "Path to the file that will receive the PID of conmon", 199 ) 200 createFlags.Uint64( 201 "cpu-period", 0, 202 "Limit the CPU CFS (Completely Fair Scheduler) period", 203 ) 204 createFlags.Int64( 205 "cpu-quota", 0, 206 "Limit the CPU CFS (Completely Fair Scheduler) quota", 207 ) 208 createFlags.Uint64( 209 "cpu-rt-period", 0, 210 "Limit the CPU real-time period in microseconds", 211 ) 212 createFlags.Int64( 213 "cpu-rt-runtime", 0, 214 "Limit the CPU real-time runtime in microseconds", 215 ) 216 createFlags.Uint64( 217 "cpu-shares", 0, 218 "CPU shares (relative weight)", 219 ) 220 createFlags.Float64( 221 "cpus", 0, 222 "Number of CPUs. The default is 0.000 which means no limit", 223 ) 224 createFlags.String( 225 "cpuset-cpus", "", 226 "CPUs in which to allow execution (0-3, 0,1)", 227 ) 228 createFlags.String( 229 "cpuset-mems", "", 230 "Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.", 231 ) 232 createFlags.BoolP( 233 "detach", "d", false, 234 "Run container in background and print container ID", 235 ) 236 createFlags.String( 237 "detach-keys", getDefaultDetachKeys(), 238 "Override the key sequence for detaching a container. Format is a single character `[a-Z]` or a comma separated sequence of `ctrl-<value>`, where `<value>` is one of: `a-z`, `@`, `^`, `[`, `\\`, `]`, `^` or `_`", 239 ) 240 createFlags.StringSlice( 241 "device", getDefaultDevices(), 242 fmt.Sprintf("Add a host device to the container"), 243 ) 244 createFlags.StringSlice( 245 "device-cgroup-rule", []string{}, 246 "Add a rule to the cgroup allowed devices list", 247 ) 248 createFlags.StringSlice( 249 "device-read-bps", []string{}, 250 "Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb)", 251 ) 252 createFlags.StringSlice( 253 "device-read-iops", []string{}, 254 "Limit read rate (IO per second) from a device (e.g. --device-read-iops=/dev/sda:1000)", 255 ) 256 createFlags.StringSlice( 257 "device-write-bps", []string{}, 258 "Limit write rate (bytes per second) to a device (e.g. --device-write-bps=/dev/sda:1mb)", 259 ) 260 createFlags.StringSlice( 261 "device-write-iops", []string{}, 262 "Limit write rate (IO per second) to a device (e.g. --device-write-iops=/dev/sda:1000)", 263 ) 264 createFlags.String( 265 "entrypoint", "", 266 "Overwrite the default ENTRYPOINT of the image", 267 ) 268 createFlags.StringArrayP( 269 "env", "e", getDefaultEnv(), 270 "Set environment variables in container", 271 ) 272 createFlags.Bool( 273 "env-host", false, "Use all current host environment variables in container", 274 ) 275 createFlags.StringSlice( 276 "env-file", []string{}, 277 "Read in a file of environment variables", 278 ) 279 createFlags.StringSlice( 280 "expose", []string{}, 281 "Expose a port or a range of ports", 282 ) 283 createFlags.StringSlice( 284 "gidmap", []string{}, 285 "GID map to use for the user namespace", 286 ) 287 createFlags.StringSlice( 288 "group-add", []string{}, 289 "Add additional groups to join", 290 ) 291 createFlags.Bool( 292 "help", false, "", 293 ) 294 createFlags.String( 295 "health-cmd", "", 296 "set a healthcheck command for the container ('none' disables the existing healthcheck)", 297 ) 298 createFlags.String( 299 "health-interval", cliconfig.DefaultHealthCheckInterval, 300 "set an interval for the healthchecks (a value of disable results in no automatic timer setup)", 301 ) 302 createFlags.Uint( 303 "health-retries", cliconfig.DefaultHealthCheckRetries, 304 "the number of retries allowed before a healthcheck is considered to be unhealthy", 305 ) 306 createFlags.String( 307 "health-start-period", cliconfig.DefaultHealthCheckStartPeriod, 308 "the initialization time needed for a container to bootstrap", 309 ) 310 createFlags.String( 311 "health-timeout", cliconfig.DefaultHealthCheckTimeout, 312 "the maximum time allowed to complete the healthcheck before an interval is considered failed", 313 ) 314 createFlags.StringP( 315 "hostname", "h", "", 316 "Set container hostname", 317 ) 318 createFlags.Bool( 319 "http-proxy", true, 320 "Set proxy environment variables in the container based on the host proxy vars", 321 ) 322 createFlags.String( 323 "image-volume", cliconfig.DefaultImageVolume, 324 `Tells podman how to handle the builtin image volumes ("bind"|"tmpfs"|"ignore")`, 325 ) 326 createFlags.Bool( 327 "init", false, 328 "Run an init binary inside the container that forwards signals and reaps processes", 329 ) 330 createFlags.String( 331 "init-path", getDefaultInitPath(), 332 // Do not use the Value field for setting the default value to determine user input (i.e., non-empty string) 333 fmt.Sprintf("Path to the container-init binary"), 334 ) 335 createFlags.BoolP( 336 "interactive", "i", false, 337 "Keep STDIN open even if not attached", 338 ) 339 createFlags.String( 340 "ipc", getDefaultIPCNS(), 341 "IPC namespace to use", 342 ) 343 createFlags.String( 344 "kernel-memory", "", 345 "Kernel memory limit "+sizeWithUnitFormat, 346 ) 347 createFlags.StringArrayP( 348 "label", "l", []string{}, 349 "Set metadata on container", 350 ) 351 createFlags.StringSlice( 352 "label-file", []string{}, 353 "Read in a line delimited file of labels", 354 ) 355 createFlags.String( 356 "log-driver", "", 357 "Logging driver for the container", 358 ) 359 createFlags.StringSlice( 360 "log-opt", []string{}, 361 "Logging driver options", 362 ) 363 createFlags.StringP( 364 "memory", "m", "", 365 "Memory limit "+sizeWithUnitFormat, 366 ) 367 createFlags.String( 368 "memory-reservation", "", 369 "Memory soft limit "+sizeWithUnitFormat, 370 ) 371 createFlags.String( 372 "memory-swap", "", 373 "Swap limit equal to memory plus swap: '-1' to enable unlimited swap", 374 ) 375 createFlags.Int64( 376 "memory-swappiness", -1, 377 "Tune container memory swappiness (0 to 100, or -1 for system default)", 378 ) 379 createFlags.String( 380 "name", "", 381 "Assign a name to the container", 382 ) 383 createFlags.Bool( 384 "no-healthcheck", false, 385 "Disable healthchecks on container", 386 ) 387 createFlags.Bool( 388 "oom-kill-disable", false, 389 "Disable OOM Killer", 390 ) 391 createFlags.Int( 392 "oom-score-adj", 0, 393 "Tune the host's OOM preferences (-1000 to 1000)", 394 ) 395 createFlags.String( 396 "override-arch", "", 397 "use `ARCH` instead of the architecture of the machine for choosing images", 398 ) 399 markFlagHidden(createFlags, "override-arch") 400 createFlags.String( 401 "override-os", "", 402 "use `OS` instead of the running OS for choosing images", 403 ) 404 markFlagHidden(createFlags, "override-os") 405 createFlags.String( 406 "pid", getDefaultPidNS(), 407 "PID namespace to use", 408 ) 409 createFlags.Int64( 410 "pids-limit", getDefaultPidsLimit(), 411 getDefaultPidsDescription(), 412 ) 413 createFlags.String( 414 "pod", "", 415 "Run container in an existing pod", 416 ) 417 createFlags.Bool( 418 "privileged", false, 419 "Give extended privileges to container", 420 ) 421 createFlags.BoolP( 422 "publish-all", "P", false, 423 "Publish all exposed ports to random ports on the host interface", 424 ) 425 createFlags.String( 426 "pull", "missing", 427 `Pull image before creating ("always"|"missing"|"never")`, 428 ) 429 createFlags.BoolP( 430 "quiet", "q", false, 431 "Suppress output information when pulling images", 432 ) 433 createFlags.Bool( 434 "read-only", false, 435 "Make containers root filesystem read-only", 436 ) 437 createFlags.Bool( 438 "read-only-tmpfs", true, 439 "When running containers in read-only mode mount a read-write tmpfs on /run, /tmp and /var/tmp", 440 ) 441 createFlags.String( 442 "restart", "", 443 `Restart policy to apply when a container exits ("always"|"no"|"on-failure")`, 444 ) 445 createFlags.Bool( 446 "rm", false, 447 "Remove container (and pod if created) after exit", 448 ) 449 createFlags.Bool( 450 "rootfs", false, 451 "The first argument is not an image but the rootfs to the exploded container", 452 ) 453 createFlags.StringArray( 454 "security-opt", getDefaultSecurityOptions(), 455 fmt.Sprintf("Security Options"), 456 ) 457 createFlags.String( 458 "shm-size", getDefaultShmSize(), 459 "Size of /dev/shm "+sizeWithUnitFormat, 460 ) 461 createFlags.String( 462 "stop-signal", "", 463 "Signal to stop a container. Default is SIGTERM", 464 ) 465 createFlags.Uint( 466 "stop-timeout", defaultContainerConfig.Engine.StopTimeout, 467 "Timeout (in seconds) to stop a container. Default is 10", 468 ) 469 createFlags.StringSlice( 470 "storage-opt", []string{}, 471 "Storage driver options per container", 472 ) 473 createFlags.String( 474 "subgidname", "", 475 "Name of range listed in /etc/subgid for use in user namespace", 476 ) 477 createFlags.String( 478 "subuidname", "", 479 "Name of range listed in /etc/subuid for use in user namespace", 480 ) 481 482 createFlags.StringSlice( 483 "sysctl", getDefaultSysctls(), 484 "Sysctl options", 485 ) 486 createFlags.String( 487 "systemd", "true", 488 `Run container in systemd mode ("true"|"false"|"always")`, 489 ) 490 createFlags.StringArray( 491 "tmpfs", []string{}, 492 "Mount a temporary filesystem (`tmpfs`) into a container", 493 ) 494 createFlags.BoolP( 495 "tty", "t", false, 496 "Allocate a pseudo-TTY for container", 497 ) 498 createFlags.StringSlice( 499 "uidmap", []string{}, 500 "UID map to use for the user namespace", 501 ) 502 createFlags.StringSlice( 503 "ulimit", getDefaultUlimits(), 504 "Ulimit options", 505 ) 506 createFlags.StringP( 507 "user", "u", "", 508 "Username or UID (format: <name|uid>[:<group|gid>])", 509 ) 510 createFlags.String( 511 "userns", getDefaultUserNS(), 512 "User namespace to use", 513 ) 514 createFlags.String( 515 "uts", getDefaultUTSNS(), 516 "UTS namespace to use", 517 ) 518 createFlags.StringArray( 519 "mount", []string{}, 520 "Attach a filesystem mount to the container", 521 ) 522 createFlags.StringArrayP( 523 "volume", "v", getDefaultVolumes(), 524 "Bind mount a volume into the container", 525 ) 526 createFlags.StringSlice( 527 "volumes-from", []string{}, 528 "Mount volumes from the specified container(s)", 529 ) 530 createFlags.StringP( 531 "workdir", "w", "", 532 "Working directory inside the container", 533 ) 534 createFlags.String( 535 "seccomp-policy", "default", 536 "Policy for selecting a seccomp profile (experimental)", 537 ) 538 } 539 540 func getFormat(c *cliconfig.PodmanCommand) (string, error) { 541 format := strings.ToLower(c.String("format")) 542 if strings.HasPrefix(format, buildah.OCI) { 543 return buildah.OCIv1ImageManifest, nil 544 } 545 546 if strings.HasPrefix(format, buildah.DOCKER) { 547 return buildah.Dockerv2ImageManifest, nil 548 } 549 return "", errors.Errorf("unrecognized image type %q", format) 550 } 551 552 // scrubServer removes 'http://' or 'https://' from the front of the 553 // server/registry string if either is there. This will be mostly used 554 // for user input from 'podman login' and 'podman logout'. 555 func scrubServer(server string) string { 556 server = strings.TrimPrefix(server, "https://") 557 return strings.TrimPrefix(server, "http://") 558 } 559 560 // HelpTemplate returns the help template for podman commands 561 // This uses the short and long options. 562 // command should not use this. 563 func HelpTemplate() string { 564 return `{{.Short}} 565 566 Description: 567 {{.Long}} 568 569 {{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` 570 } 571 572 // UsageTemplate returns the usage template for podman commands 573 // This blocks the desplaying of the global options. The main podman 574 // command should not use this. 575 func UsageTemplate() string { 576 return `Usage:{{if (and .Runnable (not .HasAvailableSubCommands))}} 577 {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} 578 {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}} 579 580 Aliases: 581 {{.NameAndAliases}}{{end}}{{if .HasExample}} 582 583 Examples: 584 {{.Example}}{{end}}{{if .HasAvailableSubCommands}} 585 586 Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} 587 {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} 588 589 Flags: 590 {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} 591 {{end}} 592 ` 593 }