diff options
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/cli/main.go | 113 | ||||
-rw-r--r-- | cmd/podman/build.go | 5 | ||||
-rw-r--r-- | cmd/podman/login.go | 18 | ||||
-rw-r--r-- | cmd/podman/logout.go | 12 | ||||
-rw-r--r-- | cmd/podman/logs.go | 2 | ||||
-rw-r--r-- | cmd/podman/pod_create.go | 17 | ||||
-rw-r--r-- | cmd/podman/service.go | 112 | ||||
-rw-r--r-- | cmd/podman/shared/container.go | 8 | ||||
-rw-r--r-- | cmd/podman/shared/create.go | 3 | ||||
-rw-r--r-- | cmd/podman/tree.go | 97 | ||||
-rw-r--r-- | cmd/podman/varlink/io.podman.varlink | 10 |
11 files changed, 127 insertions, 270 deletions
diff --git a/cmd/cli/main.go b/cmd/cli/main.go deleted file mode 100644 index 4eec05ef2..000000000 --- a/cmd/cli/main.go +++ /dev/null @@ -1,113 +0,0 @@ -package main - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io/ioutil" - "net" - "net/http" - "net/url" - "os" - - "golang.org/x/crypto/ssh" -) - -// remote PODMAN_HOST=ssh://<user>@<host>[:port]/run/podman/podman.sock -// local PODMAN_HOST=unix://run/podman/podman.sock - -var ( - DefaultURL = "unix://root@localhost/run/podman/podman.sock" -) - -func main() { - connectionURL := DefaultURL - if value, found := os.LookupEnv("PODMAN_HOST"); found { - connectionURL = value - } - - _url, err := url.Parse(connectionURL) - if err != nil { - die("Value of PODMAN_HOST is not a valid url: %s\n", connectionURL) - } - - if _url.Scheme != "ssh" && _url.Scheme != "unix" { - die("Scheme from PODMAN_HOST is not supported: %s\n", _url.Scheme) - } - - // Now we setup the http client to use the connection above - client := &http.Client{} - if _url.Scheme == "ssh" { - var auth ssh.AuthMethod - if value, found := os.LookupEnv("PODMAN_SSHKEY"); found { - auth, err = publicKey(value) - if err != nil { - die("Failed to parse %s: %v\n", value, err) - } - } else { - die("PODMAN_SSHKEY was not defined\n") - } - - // Connect to sshd - bastion, err := ssh.Dial("tcp", - net.JoinHostPort(_url.Hostname(), _url.Port()), - &ssh.ClientConfig{ - User: _url.User.Username(), - Auth: []ssh.AuthMethod{auth}, - HostKeyCallback: ssh.InsecureIgnoreHostKey(), - }, - ) - if err != nil { - die("Failed to build ssh tunnel") - } - defer bastion.Close() - - client.Transport = &http.Transport{ - DialContext: func(_ context.Context, _, _ string) (net.Conn, error) { - // Now we make the connection to the unix domain socket on the server using the ssh tunnel - return bastion.Dial("unix", _url.Path) - }, - } - } else { - client.Transport = &http.Transport{ - DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) { - d := net.Dialer{} - return d.DialContext(ctx, "unix", _url.Path) - }, - DisableCompression: true, - } - } - - resp, err := client.Get("http://localhost/v1.24/images/json") - if err != nil { - die(err.Error()) - } - defer resp.Body.Close() - body, _ := ioutil.ReadAll(resp.Body) - - var output bytes.Buffer - _ = json.Indent(&output, body, "", " ") - fmt.Printf("%s\n", output.String()) - os.Exit(0) -} - -func die(format string, a ...interface{}) { - fmt.Fprintf(os.Stderr, format, a...) - fmt.Fprintf(os.Stderr, "\n") - os.Exit(1) -} - -func publicKey(path string) (ssh.AuthMethod, error) { - key, err := ioutil.ReadFile(path) - if err != nil { - return nil, err - } - - signer, err := ssh.ParsePrivateKey(key) - if err != nil { - return nil, err - } - - return ssh.PublicKeys(signer), nil -} diff --git a/cmd/podman/build.go b/cmd/podman/build.go index 1fcb98a0e..12aedac37 100644 --- a/cmd/podman/build.go +++ b/cmd/podman/build.go @@ -84,7 +84,10 @@ func init() { } flag.DefValue = "true" - fromAndBugFlags := buildahcli.GetFromAndBudFlags(&fromAndBudValues, &userNSValues, &namespaceValues) + fromAndBugFlags, err := buildahcli.GetFromAndBudFlags(&fromAndBudValues, &userNSValues, &namespaceValues) + if err != nil { + logrus.Errorf("failed to setup podman build flags: %v", err) + } flags.AddFlagSet(&budFlags) flags.AddFlagSet(&fromAndBugFlags) diff --git a/cmd/podman/login.go b/cmd/podman/login.go index 369e0da16..e09117833 100644 --- a/cmd/podman/login.go +++ b/cmd/podman/login.go @@ -12,6 +12,7 @@ import ( "github.com/containers/image/v5/types" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/libpod/image" + "github.com/containers/libpod/pkg/registries" "github.com/docker/docker-credential-helpers/credentials" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -67,10 +68,23 @@ func loginCmd(c *cliconfig.LoginValues) error { if len(args) > 1 { return errors.Errorf("too many arguments, login takes only 1 argument") } + var server string if len(args) == 0 { - return errors.Errorf("please specify a registry to login to") + registriesFromFile, err := registries.GetRegistries() + if err != nil || len(registriesFromFile) == 0 { + return errors.Errorf("please specify a registry to login to") + } + + server = registriesFromFile[0] + logrus.Debugf("registry not specified, default to the first registry %q from registries.conf", server) + + } else { + server = registryFromFullName(scrubServer(args[0])) + } + + if c.Flag("password").Changed { + fmt.Fprintf(os.Stderr, "WARNING! Using --password via the cli is insecure. Please consider using --password-stdin\n") } - server := registryFromFullName(scrubServer(args[0])) sc := image.GetSystemContext("", c.Authfile, false) if c.Flag("tls-verify").Changed { diff --git a/cmd/podman/logout.go b/cmd/podman/logout.go index 4a113b1d0..dec6822cf 100644 --- a/cmd/podman/logout.go +++ b/cmd/podman/logout.go @@ -8,7 +8,9 @@ import ( "github.com/containers/image/v5/pkg/docker/config" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/shared" + "github.com/containers/libpod/pkg/registries" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -51,10 +53,16 @@ func logoutCmd(c *cliconfig.LogoutValues) error { if len(args) > 1 { return errors.Errorf("too many arguments, logout takes at most 1 argument") } + var server string if len(args) == 0 && !c.All { - return errors.Errorf("registry must be given") + registriesFromFile, err := registries.GetRegistries() + if err != nil || len(registriesFromFile) == 0 { + return errors.Errorf("no registries found in registries.conf, a registry must be provided") + } + + server = registriesFromFile[0] + logrus.Debugf("registry not specified, default to the first registry %q from registries.conf", server) } - var server string if len(args) == 1 { server = scrubServer(args[0]) } diff --git a/cmd/podman/logs.go b/cmd/podman/logs.go index a2594b5bf..ebc53ddf8 100644 --- a/cmd/podman/logs.go +++ b/cmd/podman/logs.go @@ -15,7 +15,7 @@ var ( logsCommand cliconfig.LogsValues logsDescription = `Retrieves logs for one or more containers. - This does not guarantee execution order when combined with podman run (i.e. your run may not have generated any logs at the time you execute podman logs. + This does not guarantee execution order when combined with podman run (i.e. your run may not have generated any logs at the time you execute podman logs). ` _logsCommand = &cobra.Command{ Use: "logs [flags] CONTAINER [CONTAINER...]", diff --git a/cmd/podman/pod_create.go b/cmd/podman/pod_create.go index 0f72780f9..810f62f02 100644 --- a/cmd/podman/pod_create.go +++ b/cmd/podman/pod_create.go @@ -45,19 +45,7 @@ func init() { podCreateCommand.SetUsageTemplate(UsageTemplate()) flags := podCreateCommand.Flags() flags.SetInterspersed(false) - // When we are ready to add the network options to the create commmand, we need to uncomment - // the following - - //flags.AddFlagSet(getNetFlags()) - - // Once this is uncommented, then the publish option below needs to be removed because it - // conflicts with the publish in getNetFlags. Upon removal, the c.Publish will not work - // anymore and needs to be cleaned up. I suggest starting with removing the Publish attribute - // from PodCreateValues structure. Running make should then expose all areas that need to be - // addressed. To get the value of publish (and other flags in getNetFlags, use the syntax: - // c.<type>("<flag_name") or c.Bool("publish") - // Remember to do this safely by checking len, etc. - + flags.AddFlagSet(getNetFlags()) flags.StringVar(&podCreateCommand.CgroupParent, "cgroup-parent", "", "Set parent cgroup for the pod") flags.BoolVar(&podCreateCommand.Infra, "infra", true, "Create an infra container associated with the pod to share namespaces with") flags.StringVar(&podCreateCommand.InfraImage, "infra-image", define.DefaultInfraImage, "The image of the infra container to associate with the pod") @@ -67,7 +55,6 @@ func init() { flags.StringVarP(&podCreateCommand.Name, "name", "n", "", "Assign a name to the pod") flags.StringVarP(&podCreateCommand.Hostname, "hostname", "", "", "Set a hostname to the pod") flags.StringVar(&podCreateCommand.PodIDFile, "pod-id-file", "", "Write the pod ID to the file") - flags.StringSliceVarP(&podCreateCommand.Publish, "publish", "p", []string{}, "Publish a container's port, or a range of ports, to the host (default [])") flags.StringVar(&podCreateCommand.Share, "share", shared.DefaultKernelNamespaces, "A comma delimited list of kernel namespaces the pod will share") } @@ -83,7 +70,7 @@ func podCreateCmd(c *cliconfig.PodCreateValues) error { } defer runtime.DeferredShutdown(false) - if len(c.Publish) > 0 { + if len(c.StringSlice("publish")) > 0 { if !c.Infra { return errors.Errorf("you must have an infra container to publish port bindings to the host") } diff --git a/cmd/podman/service.go b/cmd/podman/service.go index 4978b5d51..3e0ff927f 100644 --- a/cmd/podman/service.go +++ b/cmd/podman/service.go @@ -17,6 +17,7 @@ import ( "github.com/containers/libpod/pkg/adapter" api "github.com/containers/libpod/pkg/api/server" "github.com/containers/libpod/pkg/rootless" + "github.com/containers/libpod/pkg/systemd" "github.com/containers/libpod/pkg/util" "github.com/containers/libpod/pkg/varlinkapi" "github.com/containers/libpod/version" @@ -50,21 +51,52 @@ func init() { serviceCommand.SetHelpTemplate(HelpTemplate()) serviceCommand.SetUsageTemplate(UsageTemplate()) flags := serviceCommand.Flags() - flags.Int64VarP(&serviceCommand.Timeout, "timeout", "t", 1000, "Time until the service session expires in milliseconds. Use 0 to disable the timeout") + flags.Int64VarP(&serviceCommand.Timeout, "timeout", "t", 5, "Time until the service session expires in seconds. Use 0 to disable the timeout") flags.BoolVar(&serviceCommand.Varlink, "varlink", false, "Use legacy varlink service instead of REST") } func serviceCmd(c *cliconfig.ServiceValues) error { - // For V2, default to the REST socket - apiURI := adapter.DefaultAPIAddress + apiURI, err := resolveApiURI(c) + if err != nil { + return err + } + + // Create a single runtime api consumption + runtime, err := libpodruntime.GetRuntimeDisableFDs(getContext(), &c.PodmanCommand) + if err != nil { + return errors.Wrapf(err, "error creating libpod runtime") + } + defer func() { + if err := runtime.Shutdown(false); err != nil { + fmt.Fprintf(os.Stderr, "Failed to shutdown libpod runtime: %v", err) + } + }() + + timeout := time.Duration(c.Timeout) * time.Second if c.Varlink { - apiURI = adapter.DefaultVarlinkAddress + return runVarlink(runtime, apiURI, timeout, c) } + return runREST(runtime, apiURI, timeout) +} + +func resolveApiURI(c *cliconfig.ServiceValues) (string, error) { + var apiURI string - if rootless.IsRootless() { + // When determining _*THE*_ listening endpoint -- + // 1) User input wins always + // 2) systemd socket activation + // 3) rootless honors XDG_RUNTIME_DIR + // 4) if varlink -- adapter.DefaultVarlinkAddress + // 5) lastly adapter.DefaultAPIAddress + + if len(c.InputArgs) > 0 { + apiURI = c.InputArgs[0] + } else if ok := systemd.SocketActivated(); ok { + apiURI = "" + } else if rootless.IsRootless() { xdg, err := util.GetRuntimeDir() if err != nil { - return err + return "", err } socketName := "podman.sock" if c.Varlink { @@ -74,53 +106,59 @@ func serviceCmd(c *cliconfig.ServiceValues) error { if _, err := os.Stat(filepath.Dir(socketDir)); err != nil { if os.IsNotExist(err) { if err := os.Mkdir(filepath.Dir(socketDir), 0755); err != nil { - return err + return "", err } } else { - return err + return "", err } } - apiURI = fmt.Sprintf("unix:%s", socketDir) - } - - if len(c.InputArgs) > 0 { - apiURI = c.InputArgs[0] + apiURI = "unix:" + socketDir + } else if c.Varlink { + apiURI = adapter.DefaultVarlinkAddress + } else { + // For V2, default to the REST socket + apiURI = adapter.DefaultAPIAddress } - logrus.Infof("using API endpoint: %s", apiURI) - - // Create a single runtime api consumption - runtime, err := libpodruntime.GetRuntimeDisableFDs(getContext(), &c.PodmanCommand) - if err != nil { - return errors.Wrapf(err, "error creating libpod runtime") + if "" == apiURI { + logrus.Info("using systemd socket activation to determine API endpoint") + } else { + logrus.Infof("using API endpoint: %s", apiURI) } - defer runtime.DeferredShutdown(false) - - timeout := time.Duration(c.Timeout) * time.Millisecond - if c.Varlink { - return runVarlink(runtime, apiURI, timeout, c) - } - return runREST(runtime, apiURI, timeout) + return apiURI, nil } func runREST(r *libpod.Runtime, uri string, timeout time.Duration) error { logrus.Warn("This function is EXPERIMENTAL") fmt.Println("This function is EXPERIMENTAL.") - fields := strings.Split(uri, ":") - if len(fields) == 1 { - return errors.Errorf("%s is an invalid socket destination", uri) - } - address := strings.Join(fields[1:], ":") - l, err := net.Listen(fields[0], address) - if err != nil { - return errors.Wrapf(err, "unable to create socket %s", uri) + + var listener *net.Listener + if uri != "" { + fields := strings.Split(uri, ":") + if len(fields) == 1 { + return errors.Errorf("%s is an invalid socket destination", uri) + } + address := strings.Join(fields[1:], ":") + l, err := net.Listen(fields[0], address) + if err != nil { + return errors.Wrapf(err, "unable to create socket %s", uri) + } + defer l.Close() + listener = &l } - defer l.Close() - server, err := api.NewServerWithSettings(r, timeout, &l) + server, err := api.NewServerWithSettings(r, timeout, listener) if err != nil { return err } - return server.Serve() + defer func() { + if err := server.Shutdown(); err != nil { + fmt.Fprintf(os.Stderr, "Error when stopping service: %s", err) + } + }() + + err = server.Serve() + logrus.Debugf("%d/%d Active connections/Total connections\n", server.ActiveConnections, server.TotalConnections) + return err } func runVarlink(r *libpod.Runtime, uri string, timeout time.Duration, c *cliconfig.ServiceValues) error { diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go index ff3846e70..b5a1e7104 100644 --- a/cmd/podman/shared/container.go +++ b/cmd/podman/shared/container.go @@ -30,6 +30,7 @@ import ( const ( cidTruncLength = 12 podTruncLength = 12 + iidTruncLength = 12 cmdTruncLength = 17 ) @@ -66,6 +67,7 @@ type BatchContainerStruct struct { type PsContainerOutput struct { ID string Image string + ImageID string Command string Created string Ports string @@ -203,7 +205,7 @@ func NewBatchContainer(r *libpod.Runtime, ctr *libpod.Container, opts PsOptions) status = "Error" } - _, imageName := ctr.Image() + imageID, imageName := ctr.Image() cid := ctr.ID() podID := ctr.PodID() if !opts.NoTrunc { @@ -214,6 +216,9 @@ func NewBatchContainer(r *libpod.Runtime, ctr *libpod.Container, opts PsOptions) if len(command) > cmdTruncLength { command = command[0:cmdTruncLength] + "..." } + if len(imageID) > iidTruncLength { + imageID = imageID[0:iidTruncLength] + } } ports, err := ctr.PortMappings() @@ -223,6 +228,7 @@ func NewBatchContainer(r *libpod.Runtime, ctr *libpod.Container, opts PsOptions) pso.ID = cid pso.Image = imageName + pso.ImageID = imageID pso.Command = command pso.Created = created pso.Ports = portsToString(ports) diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go index 99538b3dc..5b244699c 100644 --- a/cmd/podman/shared/create.go +++ b/cmd/podman/shared/create.go @@ -701,9 +701,6 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod. Sysctl: sysctl, } - if err := secConfig.SetLabelOpts(runtime, pid, ipc); err != nil { - return nil, err - } if err := secConfig.SetSecurityOpts(runtime, c.StringArray("security-opt")); err != nil { return nil, err } diff --git a/cmd/podman/tree.go b/cmd/podman/tree.go index 69b42639d..28c770f0c 100644 --- a/cmd/podman/tree.go +++ b/cmd/podman/tree.go @@ -1,23 +1,14 @@ package main import ( - "context" "fmt" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/adapter" - "github.com/docker/go-units" "github.com/pkg/errors" "github.com/spf13/cobra" ) -const ( - middleItem = "├── " - continueItem = "│ " - lastItem = "└── " -) - var ( treeCommand cliconfig.TreeValues @@ -56,95 +47,11 @@ func treeCmd(c *cliconfig.TreeValues) error { return errors.Wrapf(err, "error creating libpod runtime") } defer runtime.DeferredShutdown(false) - imageInfo, layerInfoMap, img, err := runtime.Tree(c.InputArgs[0]) - if err != nil { - return err - } - return printTree(imageInfo, layerInfoMap, img, c.WhatRequires) -} -func printTree(imageInfo *image.InfoImage, layerInfoMap map[string]*image.LayerInfo, img *adapter.ContainerImage, whatRequires bool) error { - size, err := img.Size(context.Background()) + tree, err := runtime.ImageTree(c.InputArgs[0], c.WhatRequires) if err != nil { return err } - - fmt.Printf("Image ID: %s\n", imageInfo.ID[:12]) - fmt.Printf("Tags:\t %s\n", imageInfo.Tags) - fmt.Printf("Size:\t %v\n", units.HumanSizeWithPrecision(float64(*size), 4)) - if img.TopLayer() != "" { - fmt.Printf("Image Layers\n") - } else { - fmt.Printf("No Image Layers\n") - } - - if !whatRequires { - // fill imageInfo with layers associated with image. - // the layers will be filled such that - // (Start)RootLayer->...intermediate Parent Layer(s)-> TopLayer(End) - // Build output from imageInfo into buffer - printImageHierarchy(imageInfo) - - } else { - // fill imageInfo with layers associated with image. - // the layers will be filled such that - // (Start)TopLayer->...intermediate Child Layer(s)-> Child TopLayer(End) - // (Forks)... intermediate Child Layer(s) -> Child Top Layer(End) - return printImageChildren(layerInfoMap, img.TopLayer(), "", true) - } - return nil -} - -// Stores all children layers which are created using given Image. -// Layers are stored as follows -// (Start)TopLayer->...intermediate Child Layer(s)-> Child TopLayer(End) -// (Forks)... intermediate Child Layer(s) -> Child Top Layer(End) -func printImageChildren(layerMap map[string]*image.LayerInfo, layerID string, prefix string, last bool) error { - if layerID == "" { - return nil - } - ll, ok := layerMap[layerID] - if !ok { - return fmt.Errorf("lookup error: layerid %s, not found", layerID) - } - fmt.Print(prefix) - - //initialize intend with middleItem to reduce middleItem checks. - intend := middleItem - if !last { - // add continueItem i.e. '|' for next iteration prefix - prefix += continueItem - } else if len(ll.ChildID) > 1 || len(ll.ChildID) == 0 { - // The above condition ensure, alignment happens for node, which has more then 1 children. - // If node is last in printing hierarchy, it should not be printed as middleItem i.e. ├── - intend = lastItem - prefix += " " - } - - var tags string - if len(ll.RepoTags) > 0 { - tags = fmt.Sprintf(" Top Layer of: %s", ll.RepoTags) - } - fmt.Printf("%sID: %s Size: %7v%s\n", intend, ll.ID[:12], units.HumanSizeWithPrecision(float64(ll.Size), 4), tags) - for count, childID := range ll.ChildID { - if err := printImageChildren(layerMap, childID, prefix, count == len(ll.ChildID)-1); err != nil { - return err - } - } + fmt.Print(tree) return nil } - -// prints the layers info of image -func printImageHierarchy(imageInfo *image.InfoImage) { - for count, l := range imageInfo.Layers { - var tags string - intend := middleItem - if len(l.RepoTags) > 0 { - tags = fmt.Sprintf(" Top Layer of: %s", l.RepoTags) - } - if count == len(imageInfo.Layers)-1 { - intend = lastItem - } - fmt.Printf("%s ID: %s Size: %7v%s\n", intend, l.ID[:12], units.HumanSizeWithPrecision(float64(l.Size), 4), tags) - } -} diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink index a0227c48c..e9792fa8f 100644 --- a/cmd/podman/varlink/io.podman.varlink +++ b/cmd/podman/varlink/io.podman.varlink @@ -1188,6 +1188,16 @@ method GetPodsByStatus(statuses: []string) -> (pods: []string) # ~~~ method ImageExists(name: string) -> (exists: int) +# ImageTree returns the image tree for the provided image name or ID +# #### Example +# ~~~ +# $ varlink call -m unix:/run/podman/io.podman/io.podman.ImageTree '{"name": "alpine"}' +# { +# "tree": "Image ID: e7d92cdc71fe\nTags: [docker.io/library/alpine:latest]\nSize: 5.861MB\nImage Layers\n└── ID: 5216338b40a7 Size: 5.857MB Top Layer of: [docker.io/library/alpine:latest]\n" +# } +# ~~~ +method ImageTree(name: string, whatRequires: bool) -> (tree: string) + # ContainerExists takes a full or partial container ID or name and returns an int as to # whether the container exists in local storage. A result of 0 means the container does # exists; whereas a result of 1 means it could not be found. |