Clean up some existing varlink endpoints

Going through and adding options (like tls-verify, signature option, etc)
to some varlink endpoints (like push/pull) many of which had not been
updated since their original authoring.

Signed-off-by: baude <bbaude@redhat.com>
This commit is contained in:
baude
2018-12-11 13:44:55 -06:00
parent 8645df84db
commit 06d763d964
6 changed files with 156 additions and 65 deletions

19
API.md
View File

@ -87,9 +87,9 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func Ping() StringResponse](#Ping) [func Ping() StringResponse](#Ping)
[func PullImage(name: string) string](#PullImage) [func PullImage(name: string, certDir: string, creds: string, signaturePolicy: string, tlsVerify: bool) string](#PullImage)
[func PushImage(name: string, tag: string, tlsverify: bool) string](#PushImage) [func PushImage(name: string, tag: string, tlsverify: bool, signaturePolicy: string, creds: string, certDir: string, compress: bool, format: string, removeSignatures: bool, signBy: string) string](#PushImage)
[func RemoveContainer(name: string, force: bool) string](#RemoveContainer) [func RemoveContainer(name: string, force: bool) string](#RemoveContainer)
@ -739,7 +739,7 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.Ping
### <a name="PullImage"></a>func PullImage ### <a name="PullImage"></a>func PullImage
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
method PullImage(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div> method PullImage(name: [string](https://godoc.org/builtin#string), certDir: [string](https://godoc.org/builtin#string), creds: [string](https://godoc.org/builtin#string), signaturePolicy: [string](https://godoc.org/builtin#string), tlsVerify: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div>
PullImage pulls an image from a repository to local storage. After the pull is successful, the ID of the image PullImage pulls an image from a repository to local storage. After the pull is successful, the ID of the image
is returned. is returned.
#### Example #### Example
@ -752,7 +752,7 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.PullImage '{"name": "regi
### <a name="PushImage"></a>func PushImage ### <a name="PushImage"></a>func PushImage
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
method PushImage(name: [string](https://godoc.org/builtin#string), tag: [string](https://godoc.org/builtin#string), tlsverify: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div> method PushImage(name: [string](https://godoc.org/builtin#string), tag: [string](https://godoc.org/builtin#string), tlsverify: [bool](https://godoc.org/builtin#bool), signaturePolicy: [string](https://godoc.org/builtin#string), creds: [string](https://godoc.org/builtin#string), certDir: [string](https://godoc.org/builtin#string), compress: [bool](https://godoc.org/builtin#bool), format: [string](https://godoc.org/builtin#string), removeSignatures: [bool](https://godoc.org/builtin#bool), signBy: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div>
PushImage takes three input arguments: the name or ID of an image, the fully-qualified destination name of the image, PushImage takes three input arguments: the name or ID of an image, the fully-qualified destination name of the image,
and a boolean as to whether tls-verify should be used (with false disabling TLS, not affecting the default behavior). and a boolean as to whether tls-verify should be used (with false disabling TLS, not affecting the default behavior).
It will return an [ImageNotFound](#ImageNotFound) error if It will return an [ImageNotFound](#ImageNotFound) error if
@ -1499,9 +1499,8 @@ reason [string](https://godoc.org/builtin#string)
### <a name="PodCreate"></a>type PodCreate ### <a name="PodCreate"></a>type PodCreate
PodCreate is an input structure for creating pods. PodCreate is an input structure for creating pods.
It emulates options to podman pod create, however It emulates options to podman pod create. The infraCommand and
changing pause image name and pause container infraImage options are currently NotSupported.
is not currently supported
name [string](https://godoc.org/builtin#string) name [string](https://godoc.org/builtin#string)
@ -1512,6 +1511,12 @@ labels [map[string]](#map[string])
share [[]string](#[]string) share [[]string](#[]string)
infra [bool](https://godoc.org/builtin#bool) infra [bool](https://godoc.org/builtin#bool)
infraCommand [string](https://godoc.org/builtin#string)
infraImage [string](https://godoc.org/builtin#string)
publish [[]string](#[]string)
### <a name="PodmanInfo"></a>type PodmanInfo ### <a name="PodmanInfo"></a>type PodmanInfo
PodmanInfo describes the Podman host and build PodmanInfo describes the Podman host and build

View File

@ -3,15 +3,12 @@ package main
import ( import (
"fmt" "fmt"
"os" "os"
"strconv"
"strings" "strings"
"github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/pkg/rootless"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/docker/go-connections/nat"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
@ -150,7 +147,7 @@ func podCreateCmd(c *cli.Context) error {
} }
if len(c.StringSlice("publish")) > 0 { if len(c.StringSlice("publish")) > 0 {
portBindings, err := CreatePortBindings(c.StringSlice("publish")) portBindings, err := shared.CreatePortBindings(c.StringSlice("publish"))
if err != nil { if err != nil {
return err return err
} }
@ -178,36 +175,3 @@ func podCreateCmd(c *cli.Context) error {
return nil return nil
} }
// CreatePortBindings iterates ports mappings and exposed ports into a format CNI understands
func CreatePortBindings(ports []string) ([]ocicni.PortMapping, error) {
var portBindings []ocicni.PortMapping
// The conversion from []string to natBindings is temporary while mheon reworks the port
// deduplication code. Eventually that step will not be required.
_, natBindings, err := nat.ParsePortSpecs(ports)
if err != nil {
return nil, err
}
for containerPb, hostPb := range natBindings {
var pm ocicni.PortMapping
pm.ContainerPort = int32(containerPb.Int())
for _, i := range hostPb {
var hostPort int
var err error
pm.HostIP = i.HostIP
if i.HostPort == "" {
hostPort = containerPb.Int()
} else {
hostPort, err = strconv.Atoi(i.HostPort)
if err != nil {
return nil, errors.Wrapf(err, "unable to convert host port to integer")
}
}
pm.HostPort = int32(hostPort)
pm.Protocol = containerPb.Proto()
portBindings = append(portBindings, pm)
}
}
return portBindings, nil
}

View File

@ -1,7 +1,11 @@
package shared package shared
import ( import (
"strconv"
"github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/docker/go-connections/nat"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -95,3 +99,36 @@ func GetNamespaceOptions(ns []string) ([]libpod.PodCreateOption, error) {
} }
return options, nil return options, nil
} }
// CreatePortBindings iterates ports mappings and exposed ports into a format CNI understands
func CreatePortBindings(ports []string) ([]ocicni.PortMapping, error) {
var portBindings []ocicni.PortMapping
// The conversion from []string to natBindings is temporary while mheon reworks the port
// deduplication code. Eventually that step will not be required.
_, natBindings, err := nat.ParsePortSpecs(ports)
if err != nil {
return nil, err
}
for containerPb, hostPb := range natBindings {
var pm ocicni.PortMapping
pm.ContainerPort = int32(containerPb.Int())
for _, i := range hostPb {
var hostPort int
var err error
pm.HostIP = i.HostIP
if i.HostPort == "" {
hostPort = containerPb.Int()
} else {
hostPort, err = strconv.Atoi(i.HostPort)
if err != nil {
return nil, errors.Wrapf(err, "unable to convert host port to integer")
}
}
pm.HostPort = int32(hostPort)
pm.Protocol = containerPb.Proto()
portBindings = append(portBindings, pm)
}
}
return portBindings, nil
}

View File

@ -343,15 +343,17 @@ type ListPodContainerInfo (
) )
# PodCreate is an input structure for creating pods. # PodCreate is an input structure for creating pods.
# It emulates options to podman pod create, however # It emulates options to podman pod create. The infraCommand and
# changing pause image name and pause container # infraImage options are currently NotSupported.
# is not currently supported
type PodCreate ( type PodCreate (
name: string, name: string,
cgroupParent: string, cgroupParent: string,
labels: [string]string, labels: [string]string,
share: []string, share: []string,
infra: bool infra: bool,
infraCommand: string,
infraImage: string,
publish: []string
) )
# ListPodData is the returned struct for an individual pod # ListPodData is the returned struct for an individual pod
@ -632,7 +634,7 @@ method HistoryImage(name: string) -> (history: []ImageHistory)
# and a boolean as to whether tls-verify should be used (with false disabling TLS, not affecting the default behavior). # and a boolean as to whether tls-verify should be used (with false disabling TLS, not affecting the default behavior).
# It will return an [ImageNotFound](#ImageNotFound) error if # It will return an [ImageNotFound](#ImageNotFound) error if
# the image cannot be found in local storage; otherwise the ID of the image will be returned on success. # the image cannot be found in local storage; otherwise the ID of the image will be returned on success.
method PushImage(name: string, tag: string, tlsverify: bool) -> (image: string) method PushImage(name: string, tag: string, tlsverify: bool, signaturePolicy: string, creds: string, certDir: string, compress: bool, format: string, removeSignatures: bool, signBy: string) -> (image: string)
# TagImage takes the name or ID of an image in local storage as well as the desired tag name. If the image cannot # TagImage takes the name or ID of an image in local storage as well as the desired tag name. If the image cannot
# be found, an [ImageNotFound](#ImageNotFound) error will be returned; otherwise, the ID of the image is returned on success. # be found, an [ImageNotFound](#ImageNotFound) error will be returned; otherwise, the ID of the image is returned on success.
@ -700,7 +702,7 @@ method ExportImage(name: string, destination: string, compress: bool, tags: []st
# "id": "426866d6fa419873f97e5cbd320eeb22778244c1dfffa01c944db3114f55772e" # "id": "426866d6fa419873f97e5cbd320eeb22778244c1dfffa01c944db3114f55772e"
# } # }
# ~~~ # ~~~
method PullImage(name: string) -> (id: string) method PullImage(name: string, certDir: string, creds: string, signaturePolicy: string, tlsVerify: bool) -> (id: string)
# CreatePod creates a new empty pod. It uses a [PodCreate](#PodCreate) type for input. # CreatePod creates a new empty pod. It uses a [PodCreate](#PodCreate) type for input.
# On success, the ID of the newly created pod will be returned. # On success, the ID of the newly created pod will be returned.

View File

@ -13,7 +13,9 @@ import (
"github.com/containers/buildah" "github.com/containers/buildah"
"github.com/containers/buildah/imagebuildah" "github.com/containers/buildah/imagebuildah"
"github.com/containers/image/docker" "github.com/containers/image/docker"
dockerarchive "github.com/containers/image/docker/archive"
"github.com/containers/image/manifest" "github.com/containers/image/manifest"
"github.com/containers/image/transports/alltransports"
"github.com/containers/image/types" "github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/cmd/podman/varlink" "github.com/containers/libpod/cmd/podman/varlink"
@ -130,7 +132,7 @@ func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildI
if config.Pull_always { if config.Pull_always {
pullPolicy = imagebuildah.PullAlways pullPolicy = imagebuildah.PullAlways
} }
manifestType := "oci" manifestType := "oci" //nolint
if config.Image_format != "" { if config.Image_format != "" {
manifestType = config.Image_format manifestType = config.Image_format
} }
@ -311,8 +313,12 @@ func (i *LibpodAPI) HistoryImage(call iopodman.VarlinkCall, name string) error {
} }
// PushImage pushes an local image to registry // PushImage pushes an local image to registry
// TODO We need to add options for signing, credentials, tls, and multi-tag func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, tlsVerify bool, signaturePolicy, creds, certDir string, compress bool, format string, removeSignatures bool, signBy string) error {
func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, tlsVerify bool) error { var (
registryCreds *types.DockerAuthConfig
manifestType string
)
newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
if err != nil { if err != nil {
return call.ReplyImageNotFound(err.Error()) return call.ReplyImageNotFound(err.Error())
@ -321,15 +327,38 @@ func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, tlsVe
if tag != "" { if tag != "" {
destname = tag destname = tag
} }
if creds != "" {
dockerRegistryOptions := image.DockerRegistryOptions{} creds, err := util.ParseRegistryCreds(creds)
if err != nil {
return err
}
registryCreds = creds
}
dockerRegistryOptions := image.DockerRegistryOptions{
DockerRegistryCreds: registryCreds,
DockerCertPath: certDir,
}
if !tlsVerify { if !tlsVerify {
dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.OptionalBoolTrue dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.OptionalBoolTrue
} }
if format != "" {
switch format {
case "oci": //nolint
manifestType = v1.MediaTypeImageManifest
case "v2s1":
manifestType = manifest.DockerV2Schema1SignedMediaType
case "v2s2", "docker":
manifestType = manifest.DockerV2Schema2MediaType
default:
return call.ReplyErrorOccurred(fmt.Sprintf("unknown format %q. Choose on of the supported formats: 'oci', 'v2s1', or 'v2s2'", format))
}
}
so := image.SigningOptions{
RemoveSignatures: removeSignatures,
SignBy: signBy,
}
so := image.SigningOptions{} if err := newImage.PushImageToHeuristicDestination(getContext(), destname, manifestType, "", signaturePolicy, nil, compress, so, &dockerRegistryOptions, nil); err != nil {
if err := newImage.PushImageToHeuristicDestination(getContext(), destname, "", "", "", nil, false, so, &dockerRegistryOptions, nil); err != nil {
return call.ReplyErrorOccurred(err.Error()) return call.ReplyErrorOccurred(err.Error())
} }
return call.ReplyPushImage(newImage.ID()) return call.ReplyPushImage(newImage.ID())
@ -428,7 +457,7 @@ func (i *LibpodAPI) Commit(call iopodman.VarlinkCall, name, imageName string, ch
sc := image.GetSystemContext(i.Runtime.GetConfig().SignaturePolicyPath, "", false) sc := image.GetSystemContext(i.Runtime.GetConfig().SignaturePolicyPath, "", false)
var mimeType string var mimeType string
switch manifestType { switch manifestType {
case "oci", "": case "oci", "": //nolint
mimeType = buildah.OCIv1ImageManifest mimeType = buildah.OCIv1ImageManifest
case "docker": case "docker":
mimeType = manifest.DockerV2Schema2MediaType mimeType = manifest.DockerV2Schema2MediaType
@ -496,13 +525,47 @@ func (i *LibpodAPI) ExportImage(call iopodman.VarlinkCall, name, destination str
} }
// PullImage pulls an image from a registry to the image store. // PullImage pulls an image from a registry to the image store.
// TODO This implementation is incomplete func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string, certDir, creds, signaturePolicy string, tlsVerify bool) error {
func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string) error { var (
newImage, err := i.Runtime.ImageRuntime().New(getContext(), name, "", "", nil, &image.DockerRegistryOptions{}, image.SigningOptions{}, true) registryCreds *types.DockerAuthConfig
if err != nil { imageID string
return call.ReplyErrorOccurred(fmt.Sprintf("unable to pull %s: %s", name, err.Error())) )
if creds != "" {
creds, err := util.ParseRegistryCreds(creds)
if err != nil {
return err
}
registryCreds = creds
} }
return call.ReplyPullImage(newImage.ID())
dockerRegistryOptions := image.DockerRegistryOptions{
DockerRegistryCreds: registryCreds,
DockerCertPath: certDir,
}
if tlsVerify {
dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!tlsVerify)
}
so := image.SigningOptions{}
if strings.HasPrefix(name, dockerarchive.Transport.Name()+":") {
srcRef, err := alltransports.ParseImageName(name)
if err != nil {
return errors.Wrapf(err, "error parsing %q", name)
}
newImage, err := i.Runtime.ImageRuntime().LoadFromArchiveReference(getContext(), srcRef, signaturePolicy, nil)
if err != nil {
return errors.Wrapf(err, "error pulling image from %q", name)
}
imageID = newImage[0].ID()
} else {
newImage, err := i.Runtime.ImageRuntime().New(getContext(), name, signaturePolicy, "", nil, &dockerRegistryOptions, so, false)
if err != nil {
return call.ReplyErrorOccurred(fmt.Sprintf("unable to pull %s: %s", name, err.Error()))
}
imageID = newImage.ID()
}
return call.ReplyPullImage(imageID)
} }
// ImageExists returns bool as to whether the input image exists in local storage // ImageExists returns bool as to whether the input image exists in local storage

View File

@ -2,6 +2,7 @@ package varlinkapi
import ( import (
"encoding/json" "encoding/json"
"github.com/containers/libpod/pkg/rootless"
"syscall" "syscall"
"github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/cmd/podman/shared"
@ -12,6 +13,10 @@ import (
// CreatePod ... // CreatePod ...
func (i *LibpodAPI) CreatePod(call iopodman.VarlinkCall, create iopodman.PodCreate) error { func (i *LibpodAPI) CreatePod(call iopodman.VarlinkCall, create iopodman.PodCreate) error {
var options []libpod.PodCreateOption var options []libpod.PodCreateOption
if create.InfraCommand != "" || create.InfraImage != "" {
return call.ReplyErrorOccurred("the infra-command and infra-image options are not supported yet")
}
if create.CgroupParent != "" { if create.CgroupParent != "" {
options = append(options, libpod.WithPodCgroupParent(create.CgroupParent)) options = append(options, libpod.WithPodCgroupParent(create.CgroupParent))
} }
@ -27,6 +32,21 @@ func (i *LibpodAPI) CreatePod(call iopodman.VarlinkCall, create iopodman.PodCrea
if len(create.Share) == 0 && create.Infra { if len(create.Share) == 0 && create.Infra {
return call.ReplyErrorOccurred("You must share kernel namespaces to run an infra container") return call.ReplyErrorOccurred("You must share kernel namespaces to run an infra container")
} }
if len(create.Publish) > 0 {
if !create.Infra {
return call.ReplyErrorOccurred("you must have an infra container to publish port bindings to the host")
}
if rootless.IsRootless() {
return call.ReplyErrorOccurred("rootless networking does not allow port binding to the host")
}
portBindings, err := shared.CreatePortBindings(create.Publish)
if err != nil {
return err
}
options = append(options, libpod.WithInfraContainerPorts(portBindings))
}
if create.Infra { if create.Infra {
options = append(options, libpod.WithInfraContainer()) options = append(options, libpod.WithInfraContainer())
nsOptions, err := shared.GetNamespaceOptions(create.Share) nsOptions, err := shared.GetNamespaceOptions(create.Share)