summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authorbaude <bbaude@redhat.com>2018-04-23 13:32:41 -0500
committerAtomic Bot <atomic-devel@projectatomic.io>2018-04-26 19:14:44 +0000
commit39a7a773a653176e294382bc6301275fd57aff6b (patch)
tree334db314ef5681bd6979e2be91dd39640f8e00ff /pkg
parent0ccfd7dc20c11bc2f9d646c98cc67fb399cd9013 (diff)
downloadpodman-39a7a773a653176e294382bc6301275fd57aff6b.tar.gz
podman-39a7a773a653176e294382bc6301275fd57aff6b.tar.bz2
podman-39a7a773a653176e294382bc6301275fd57aff6b.zip
varlink images
implement varlink image functions for working with libpod with the exception of a couple due to incompletions on the libpod side of things (build). also, created a first pass at a libpodpy package which will stand as a client to working with libpod's varlink methods using python. Signed-off-by: baude <bbaude@redhat.com> Closes: #669 Approved by: baude
Diffstat (limited to 'pkg')
-rw-r--r--pkg/util/utils.go66
-rw-r--r--pkg/varlinkapi/config.go16
-rw-r--r--pkg/varlinkapi/containers.go2
-rw-r--r--pkg/varlinkapi/images.go274
-rw-r--r--pkg/varlinkapi/system.go2
-rw-r--r--pkg/varlinkapi/util.go10
6 files changed, 330 insertions, 40 deletions
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index edcf63f80..1bbfe30d3 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -5,6 +5,7 @@ import (
"strings"
"github.com/containers/image/types"
+ "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"golang.org/x/crypto/ssh/terminal"
)
@@ -54,3 +55,68 @@ func StringInSlice(s string, sl []string) bool {
}
return false
}
+
+// GetImageConfig converts the --change flag values in the format "CMD=/bin/bash USER=example"
+// to a type v1.ImageConfig
+func GetImageConfig(changes []string) (v1.ImageConfig, error) {
+ // USER=value | EXPOSE=value | ENV=value | ENTRYPOINT=value |
+ // CMD=value | VOLUME=value | WORKDIR=value | LABEL=key=value | STOPSIGNAL=value
+
+ var (
+ user string
+ env []string
+ entrypoint []string
+ cmd []string
+ workingDir string
+ stopSignal string
+ )
+
+ exposedPorts := make(map[string]struct{})
+ volumes := make(map[string]struct{})
+ labels := make(map[string]string)
+
+ for _, ch := range changes {
+ pair := strings.Split(ch, "=")
+ if len(pair) == 1 {
+ return v1.ImageConfig{}, errors.Errorf("no value given for instruction %q", ch)
+ }
+ switch pair[0] {
+ case "USER":
+ user = pair[1]
+ case "EXPOSE":
+ var st struct{}
+ exposedPorts[pair[1]] = st
+ case "ENV":
+ env = append(env, pair[1])
+ case "ENTRYPOINT":
+ entrypoint = append(entrypoint, pair[1])
+ case "CMD":
+ cmd = append(cmd, pair[1])
+ case "VOLUME":
+ var st struct{}
+ volumes[pair[1]] = st
+ case "WORKDIR":
+ workingDir = pair[1]
+ case "LABEL":
+ if len(pair) == 3 {
+ labels[pair[1]] = pair[2]
+ } else {
+ labels[pair[1]] = ""
+ }
+ case "STOPSIGNAL":
+ stopSignal = pair[1]
+ }
+ }
+
+ return v1.ImageConfig{
+ User: user,
+ ExposedPorts: exposedPorts,
+ Env: env,
+ Entrypoint: entrypoint,
+ Cmd: cmd,
+ Volumes: volumes,
+ WorkingDir: workingDir,
+ Labels: labels,
+ StopSignal: stopSignal,
+ }, nil
+}
diff --git a/pkg/varlinkapi/config.go b/pkg/varlinkapi/config.go
index 167270f09..3c6a3311c 100644
--- a/pkg/varlinkapi/config.go
+++ b/pkg/varlinkapi/config.go
@@ -1,14 +1,18 @@
package varlinkapi
-import "github.com/projectatomic/libpod/cmd/podman/ioprojectatomicpodman"
+import (
+ ioprojectatomicpodman "github.com/projectatomic/libpod/cmd/podman/varlink"
+ "github.com/urfave/cli"
+)
// LibpodAPI is the basic varlink struct for libpod
type LibpodAPI struct {
+ Cli *cli.Context
ioprojectatomicpodman.VarlinkInterface
}
-var (
- lp = LibpodAPI{}
- // VarlinkLibpod instantiation
- VarlinkLibpod = ioprojectatomicpodman.VarlinkNew(&lp)
-)
+// New creates a new varlink client
+func New(cli *cli.Context) *ioprojectatomicpodman.VarlinkInterface {
+ lp := LibpodAPI{Cli: cli}
+ return ioprojectatomicpodman.VarlinkNew(&lp)
+}
diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go
index e58cab497..bd406dda2 100644
--- a/pkg/varlinkapi/containers.go
+++ b/pkg/varlinkapi/containers.go
@@ -1,7 +1,7 @@
package varlinkapi
import (
- "github.com/projectatomic/libpod/cmd/podman/ioprojectatomicpodman"
+ ioprojectatomicpodman "github.com/projectatomic/libpod/cmd/podman/varlink"
)
// ListContainers ...
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index 1de54e43b..29fe803ae 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -1,75 +1,285 @@
package varlinkapi
import (
- "github.com/projectatomic/libpod/cmd/podman/ioprojectatomicpodman"
+ "encoding/json"
+ "fmt"
+
+ "github.com/containers/image/docker"
+ "github.com/opencontainers/image-spec/specs-go/v1"
+ "github.com/projectatomic/libpod/cmd/podman/libpodruntime"
+ ioprojectatomicpodman "github.com/projectatomic/libpod/cmd/podman/varlink"
+ "github.com/projectatomic/libpod/libpod/image"
+ sysreg "github.com/projectatomic/libpod/pkg/registries"
+ "github.com/projectatomic/libpod/pkg/util"
)
-// ListImages ...
+// ListImages lists all the images in the store
+// It requires no inputs.
func (i *LibpodAPI) ListImages(call ioprojectatomicpodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("ListImages")
+ runtime, err := libpodruntime.GetRuntime(i.Cli)
+ if err != nil {
+ return call.ReplyRuntimeError(err.Error())
+ }
+ images, err := runtime.ImageRuntime().GetImages()
+ if err != nil {
+ return call.ReplyErrorOccurred(fmt.Sprintf("unable to get list of images %q", err))
+ }
+ var imageList []ioprojectatomicpodman.ImageInList
+ for _, image := range images {
+ //size, _:= image.Size(getContext())
+ labels, _ := image.Labels(getContext())
+ containers, _ := image.Containers()
+
+ i := ioprojectatomicpodman.ImageInList{
+ Id: image.ID(),
+ ParentId: image.Parent,
+ RepoTags: image.Names(),
+ RepoDigests: image.RepoDigests(),
+ Created: image.Created().String(),
+ //Size: size,
+ VirtualSize: image.VirtualSize,
+ Containers: int64(len(containers)),
+ Labels: labels,
+ }
+ imageList = append(imageList, i)
+ }
+ return call.ReplyListImages(imageList)
}
// BuildImage ...
+// TODO Waiting for buildah to be vendored into libpod to do this only one
func (i *LibpodAPI) BuildImage(call ioprojectatomicpodman.VarlinkCall) error {
return call.ReplyMethodNotImplemented("BuildImage")
}
// CreateImage ...
+// TODO With Pull being added, should we skip Create?
func (i *LibpodAPI) CreateImage(call ioprojectatomicpodman.VarlinkCall) error {
return call.ReplyMethodNotImplemented("CreateImage")
}
-// InspectImage ...
-func (i *LibpodAPI) InspectImage(call ioprojectatomicpodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("InspectImage")
+// InspectImage returns an image's inspect information as a string that can be serialized.
+// Requires an image ID or name
+func (i *LibpodAPI) InspectImage(call ioprojectatomicpodman.VarlinkCall, name string) error {
+ runtime, err := libpodruntime.GetRuntime(i.Cli)
+ if err != nil {
+ return call.ReplyRuntimeError(err.Error())
+ }
+ newImage, err := runtime.ImageRuntime().NewFromLocal(name)
+ if err != nil {
+ return call.ReplyImageNotFound(name)
+ }
+ inspectInfo, err := newImage.Inspect(getContext())
+ b, err := json.Marshal(inspectInfo)
+ if err != nil {
+ return call.ReplyErrorOccurred(fmt.Sprintf("unable to serialize"))
+ }
+ return call.ReplyInspectImage(string(b))
}
-// HistoryImage ...
-func (i *LibpodAPI) HistoryImage(call ioprojectatomicpodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("HistoryImage")
+// HistoryImage returns the history of the image's layers
+// Requires an image or name
+func (i *LibpodAPI) HistoryImage(call ioprojectatomicpodman.VarlinkCall, name string) error {
+ runtime, err := libpodruntime.GetRuntime(i.Cli)
+ if err != nil {
+ return call.ReplyRuntimeError(err.Error())
+ }
+ newImage, err := runtime.ImageRuntime().NewFromLocal(name)
+ if err != nil {
+ return call.ReplyImageNotFound(name)
+ }
+ history, layerInfos, err := newImage.History(getContext())
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ var histories []ioprojectatomicpodman.ImageHistory
+ for i, h := range history {
+ imageHistory := ioprojectatomicpodman.ImageHistory{
+ Id: newImage.ID(),
+ Created: h.Created.String(),
+ CreatedBy: h.CreatedBy,
+ Tags: newImage.Names(),
+ Size: layerInfos[i].Size,
+ Comment: h.Comment,
+ }
+ histories = append(histories, imageHistory)
+ }
+ return call.ReplyHistoryImage(histories)
}
-// PushImage ...
-func (i *LibpodAPI) PushImage(call ioprojectatomicpodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("PushImage")
+// PushImage pushes an local image to registry
+// TODO We need to add options for signing, credentials, and tls
+func (i *LibpodAPI) PushImage(call ioprojectatomicpodman.VarlinkCall, name, tag string, tlsVerify bool) error {
+ runtime, err := libpodruntime.GetRuntime(i.Cli)
+ if err != nil {
+ return call.ReplyRuntimeError(err.Error())
+ }
+ newImage, err := runtime.ImageRuntime().NewFromLocal(name)
+ if err != nil {
+ return call.ReplyImageNotFound(err.Error())
+ }
+ destname := name
+ if tag != "" {
+ destname = tag
+ }
+
+ dockerRegistryOptions := image.DockerRegistryOptions{
+ DockerInsecureSkipTLSVerify: !tlsVerify,
+ }
+
+ so := image.SigningOptions{}
+
+ if err := newImage.PushImage(getContext(), destname, "", "", "", nil, false, so, &dockerRegistryOptions); err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ return call.ReplyPushImage()
}
-// TagImage ...
-func (i *LibpodAPI) TagImage(call ioprojectatomicpodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("TagImage")
+// TagImage accepts an image name and tag as strings and tags an image in the local store.
+func (i *LibpodAPI) TagImage(call ioprojectatomicpodman.VarlinkCall, name, tag string) error {
+ runtime, err := libpodruntime.GetRuntime(i.Cli)
+ if err != nil {
+ return call.ReplyRuntimeError(err.Error())
+ }
+ newImage, err := runtime.ImageRuntime().NewFromLocal(name)
+ if err != nil {
+ return call.ReplyImageNotFound(name)
+ }
+ if err := newImage.TagImage(tag); err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ return call.ReplyTagImage()
}
-// RemoveImage ...
-func (i *LibpodAPI) RemoveImage(call ioprojectatomicpodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("RemoveImage")
+// RemoveImage accepts a image name or ID as a string and force bool to determine if it should
+// remove the image even if being used by stopped containers
+func (i *LibpodAPI) RemoveImage(call ioprojectatomicpodman.VarlinkCall, name string, force bool) error {
+ runtime, err := libpodruntime.GetRuntime(i.Cli)
+ if err != nil {
+ return call.ReplyRuntimeError(err.Error())
+ }
+ newImage, err := runtime.ImageRuntime().NewFromLocal(name)
+ if err != nil {
+ return call.ReplyImageNotFound(name)
+ }
+ if err := newImage.Remove(force); err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ return call.ReplyRemoveImage()
}
-// SearchImage ...
-func (i *LibpodAPI) SearchImage(call ioprojectatomicpodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("SearchImage")
+// SearchImage searches all registries configured in /etc/containers/registries.conf for an image
+// Requires an image name and a search limit as int
+func (i *LibpodAPI) SearchImage(call ioprojectatomicpodman.VarlinkCall, name string, limit int64) error {
+ sc := image.GetSystemContext("", "", false)
+ registries, err := sysreg.GetRegistries()
+ if err != nil {
+ return call.ReplyErrorOccurred(fmt.Sprintf("unable to get system registries: %q", err))
+ }
+ var imageResults []ioprojectatomicpodman.ImageSearch
+ for _, reg := range registries {
+ results, err := docker.SearchRegistry(getContext(), sc, reg, name, int(limit))
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ for _, result := range results {
+ i := ioprojectatomicpodman.ImageSearch{
+ Description: result.Description,
+ Is_official: result.IsOfficial,
+ Is_automated: result.IsAutomated,
+ Name: result.Name,
+ Star_count: int64(result.StarCount),
+ }
+ imageResults = append(imageResults, i)
+ }
+ }
+ return call.ReplySearchImage(imageResults)
}
-// DeleteUnusedImages ...
+// DeleteUnusedImages deletes any images that do not have containers associated with it.
+// TODO Filters are not implemented
func (i *LibpodAPI) DeleteUnusedImages(call ioprojectatomicpodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("DeleteUnusedImages")
+ runtime, err := libpodruntime.GetRuntime(i.Cli)
+ if err != nil {
+ return call.ReplyRuntimeError(err.Error())
+ }
+ images, err := runtime.ImageRuntime().GetImages()
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ var deletedImages []string
+ for _, img := range images {
+ containers, err := img.Containers()
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ if len(containers) == 0 {
+ if err := img.Remove(false); err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ deletedImages = append(deletedImages, img.ID())
+ }
+ }
+ return call.ReplyDeleteUnusedImages(deletedImages)
}
// CreateFromContainer ...
+// TODO This must wait until buildah is properly vendored into libpod
func (i *LibpodAPI) CreateFromContainer(call ioprojectatomicpodman.VarlinkCall) error {
return call.ReplyMethodNotImplemented("CreateFromContainer")
}
-// ImportImage ...
-func (i *LibpodAPI) ImportImage(call ioprojectatomicpodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("ImportImage")
+// ImportImage imports an image from a tarball to the image store
+func (i *LibpodAPI) ImportImage(call ioprojectatomicpodman.VarlinkCall, source, reference, message string, changes []string) error {
+ runtime, err := libpodruntime.GetRuntime(i.Cli)
+ if err != nil {
+ return call.ReplyRuntimeError(err.Error())
+ }
+ configChanges, err := util.GetImageConfig(changes)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ history := []v1.History{
+ {Comment: message},
+ }
+ config := v1.Image{
+ Config: configChanges,
+ History: history,
+ }
+ newImage, err := runtime.ImageRuntime().Import(getContext(), source, reference, nil, image.SigningOptions{}, config)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ return call.ReplyImportImage(newImage.ID())
}
-// ExportImage ...
-func (i *LibpodAPI) ExportImage(call ioprojectatomicpodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("ExportImage")
+// ExportImage exports an image to the provided destination
+// destination must have the transport type!!
+func (i *LibpodAPI) ExportImage(call ioprojectatomicpodman.VarlinkCall, name, destination string, compress bool) error {
+ runtime, err := libpodruntime.GetRuntime(i.Cli)
+ if err != nil {
+ return call.ReplyRuntimeError(err.Error())
+ }
+ newImage, err := runtime.ImageRuntime().NewFromLocal(name)
+ if err != nil {
+ return call.ReplyImageNotFound(name)
+ }
+ if err := newImage.PushImage(getContext(), destination, "", "", "", nil, compress, image.SigningOptions{}, &image.DockerRegistryOptions{}); err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ return call.ReplyExportImage()
}
-// PullImage ...
-func (i *LibpodAPI) PullImage(call ioprojectatomicpodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("PullImage")
+// PullImage pulls an image from a registry to the image store.
+// TODO This implementation is incomplete
+func (i *LibpodAPI) PullImage(call ioprojectatomicpodman.VarlinkCall, name string) error {
+ runtime, err := libpodruntime.GetRuntime(i.Cli)
+ if err != nil {
+ return call.ReplyRuntimeError(err.Error())
+ }
+ newImage, err := runtime.ImageRuntime().New(getContext(), name, "", "", nil, &image.DockerRegistryOptions{}, image.SigningOptions{}, true, false)
+ if err != nil {
+ return call.ReplyErrorOccurred(fmt.Sprintf("unable to pull %s", name))
+ }
+ return call.ReplyPullImage(newImage.ID())
}
diff --git a/pkg/varlinkapi/system.go b/pkg/varlinkapi/system.go
index c343f1245..976dfc682 100644
--- a/pkg/varlinkapi/system.go
+++ b/pkg/varlinkapi/system.go
@@ -1,7 +1,7 @@
package varlinkapi
import (
- "github.com/projectatomic/libpod/cmd/podman/ioprojectatomicpodman"
+ ioprojectatomicpodman "github.com/projectatomic/libpod/cmd/podman/varlink"
"github.com/projectatomic/libpod/libpod"
)
diff --git a/pkg/varlinkapi/util.go b/pkg/varlinkapi/util.go
new file mode 100644
index 000000000..ff0fb6ecb
--- /dev/null
+++ b/pkg/varlinkapi/util.go
@@ -0,0 +1,10 @@
+package varlinkapi
+
+import (
+ "context"
+)
+
+// getContext returns a non-nil, empty context
+func getContext() context.Context {
+ return context.TODO()
+}