diff options
Diffstat (limited to 'libpod/adapter')
-rw-r--r-- | libpod/adapter/client.go | 36 | ||||
-rw-r--r-- | libpod/adapter/containers_remote.go | 50 | ||||
-rw-r--r-- | libpod/adapter/images_remote.go | 24 | ||||
-rw-r--r-- | libpod/adapter/info_remote.go | 56 | ||||
-rw-r--r-- | libpod/adapter/runtime.go | 101 | ||||
-rw-r--r-- | libpod/adapter/runtime_remote.go | 322 |
6 files changed, 589 insertions, 0 deletions
diff --git a/libpod/adapter/client.go b/libpod/adapter/client.go new file mode 100644 index 000000000..b3bb9acae --- /dev/null +++ b/libpod/adapter/client.go @@ -0,0 +1,36 @@ +// +build remoteclient + +package adapter + +import ( + "os" + + "github.com/sirupsen/logrus" + "github.com/varlink/go/varlink" +) + +// DefaultAddress is the default address of the varlink socket +const DefaultAddress = "unix:/run/podman/io.podman" + +// Connect provides a varlink connection +func (r RemoteRuntime) Connect() (*varlink.Connection, error) { + var err error + var connection *varlink.Connection + if bridge := os.Getenv("PODMAN_VARLINK_BRIDGE"); bridge != "" { + logrus.Infof("Connecting with varlink bridge") + logrus.Debugf("%s", bridge) + connection, err = varlink.NewBridge(bridge) + } else { + address := os.Getenv("PODMAN_VARLINK_ADDRESS") + if address == "" { + address = DefaultAddress + } + logrus.Infof("Connecting with varlink address") + logrus.Debugf("%s", address) + connection, err = varlink.NewConnection(address) + } + if err != nil { + return nil, err + } + return connection, nil +} diff --git a/libpod/adapter/containers_remote.go b/libpod/adapter/containers_remote.go new file mode 100644 index 000000000..9623304e5 --- /dev/null +++ b/libpod/adapter/containers_remote.go @@ -0,0 +1,50 @@ +// +build remoteclient + +package adapter + +import ( + "encoding/json" + + iopodman "github.com/containers/libpod/cmd/podman/varlink" + "github.com/containers/libpod/libpod" + "github.com/containers/libpod/pkg/inspect" +) + +// Inspect returns an inspect struct from varlink +func (c *Container) Inspect(size bool) (*inspect.ContainerInspectData, error) { + reply, err := iopodman.ContainerInspectData().Call(c.Runtime.Conn, c.ID()) + if err != nil { + return nil, err + } + data := inspect.ContainerInspectData{} + if err := json.Unmarshal([]byte(reply), &data); err != nil { + return nil, err + } + return &data, err +} + +// ID returns the ID of the container +func (c *Container) ID() string { + return c.config.ID +} + +// GetArtifact returns a container's artifacts +func (c *Container) GetArtifact(name string) ([]byte, error) { + var data []byte + reply, err := iopodman.ContainerArtifacts().Call(c.Runtime.Conn, c.ID(), name) + if err != nil { + return nil, err + } + if err := json.Unmarshal([]byte(reply), &data); err != nil { + return nil, err + } + return data, err +} + +// Config returns a container's Config ... same as ctr.Config() +func (c *Container) Config() *libpod.ContainerConfig { + if c.config != nil { + return c.config + } + return c.Runtime.Config(c.ID()) +} diff --git a/libpod/adapter/images_remote.go b/libpod/adapter/images_remote.go new file mode 100644 index 000000000..e7b38dccc --- /dev/null +++ b/libpod/adapter/images_remote.go @@ -0,0 +1,24 @@ +// +build remoteclient + +package adapter + +import ( + "context" + "encoding/json" + + iopodman "github.com/containers/libpod/cmd/podman/varlink" + "github.com/containers/libpod/pkg/inspect" +) + +// Inspect returns returns an ImageData struct from over a varlink connection +func (i *ContainerImage) Inspect(ctx context.Context) (*inspect.ImageData, error) { + reply, err := iopodman.InspectImage().Call(i.Runtime.Conn, i.ID()) + if err != nil { + return nil, err + } + data := inspect.ImageData{} + if err := json.Unmarshal([]byte(reply), &data); err != nil { + return nil, err + } + return &data, nil +} diff --git a/libpod/adapter/info_remote.go b/libpod/adapter/info_remote.go new file mode 100644 index 000000000..3b691ed17 --- /dev/null +++ b/libpod/adapter/info_remote.go @@ -0,0 +1,56 @@ +// +build remoteclient + +package adapter + +import ( + "encoding/json" + + "github.com/containers/libpod/cmd/podman/varlink" + "github.com/containers/libpod/libpod" +) + +// Info returns information for the host system and its components +func (r RemoteRuntime) Info() ([]libpod.InfoData, error) { + // TODO the varlink implementation for info should be updated to match the output for regular info + var ( + reply []libpod.InfoData + hostInfo map[string]interface{} + store map[string]interface{} + ) + + registries := make(map[string]interface{}) + insecureRegistries := make(map[string]interface{}) + conn, err := r.Connect() + if err != nil { + return nil, err + } + defer conn.Close() + info, err := iopodman.GetInfo().Call(conn) + if err != nil { + return nil, err + } + + // info.host -> map[string]interface{} + h, err := json.Marshal(info.Host) + if err != nil { + return nil, err + } + json.Unmarshal(h, &hostInfo) + + // info.store -> map[string]interface{} + s, err := json.Marshal(info.Store) + if err != nil { + return nil, err + } + json.Unmarshal(s, &store) + + registries["registries"] = info.Registries + insecureRegistries["registries"] = info.Insecure_registries + + // Add everything to the reply + reply = append(reply, libpod.InfoData{Type: "host", Data: hostInfo}) + reply = append(reply, libpod.InfoData{Type: "registries", Data: registries}) + reply = append(reply, libpod.InfoData{Type: "insecure registries", Data: insecureRegistries}) + reply = append(reply, libpod.InfoData{Type: "store", Data: store}) + return reply, nil +} diff --git a/libpod/adapter/runtime.go b/libpod/adapter/runtime.go new file mode 100644 index 000000000..1f3599082 --- /dev/null +++ b/libpod/adapter/runtime.go @@ -0,0 +1,101 @@ +// +build !remoteclient + +package adapter + +import ( + "context" + "io" + + "github.com/containers/image/types" + "github.com/containers/libpod/cmd/podman/libpodruntime" + "github.com/containers/libpod/libpod" + "github.com/containers/libpod/libpod/image" + "github.com/urfave/cli" +) + +// LocalRuntime describes a typical libpod runtime +type LocalRuntime struct { + *libpod.Runtime + Remote bool +} + +// ContainerImage ... +type ContainerImage struct { + *image.Image +} + +// Container ... +type Container struct { + *libpod.Container +} + +// GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it +func GetRuntime(c *cli.Context) (*LocalRuntime, error) { + runtime, err := libpodruntime.GetRuntime(c) + if err != nil { + return nil, err + } + return &LocalRuntime{ + Runtime: runtime, + }, nil +} + +// GetImages returns a slice of images in containerimages +func (r *LocalRuntime) GetImages() ([]*ContainerImage, error) { + var containerImages []*ContainerImage + images, err := r.Runtime.ImageRuntime().GetImages() + if err != nil { + return nil, err + } + for _, i := range images { + containerImages = append(containerImages, &ContainerImage{i}) + } + return containerImages, nil + +} + +// NewImageFromLocal returns a containerimage representation of a image from local storage +func (r *LocalRuntime) NewImageFromLocal(name string) (*ContainerImage, error) { + img, err := r.Runtime.ImageRuntime().NewFromLocal(name) + if err != nil { + return nil, err + } + return &ContainerImage{img}, nil +} + +// LoadFromArchiveReference calls into local storage to load an image from an archive +func (r *LocalRuntime) LoadFromArchiveReference(ctx context.Context, srcRef types.ImageReference, signaturePolicyPath string, writer io.Writer) ([]*ContainerImage, error) { + var containerImages []*ContainerImage + imgs, err := r.Runtime.ImageRuntime().LoadFromArchiveReference(ctx, srcRef, signaturePolicyPath, writer) + if err != nil { + return nil, err + } + for _, i := range imgs { + ci := ContainerImage{i} + containerImages = append(containerImages, &ci) + } + return containerImages, nil +} + +// New calls into local storage to look for an image in local storage or to pull it +func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *image.DockerRegistryOptions, signingoptions image.SigningOptions, forcePull bool) (*ContainerImage, error) { + img, err := r.Runtime.ImageRuntime().New(ctx, name, signaturePolicyPath, authfile, writer, dockeroptions, signingoptions, forcePull) + if err != nil { + return nil, err + } + return &ContainerImage{img}, nil +} + +// RemoveImage calls into local storage and removes an image +func (r *LocalRuntime) RemoveImage(ctx context.Context, img *ContainerImage, force bool) (string, error) { + return r.Runtime.RemoveImage(ctx, img.Image, force) +} + +// LookupContainer ... +func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) { + ctr, err := r.Runtime.LookupContainer(idOrName) + if err != nil { + return nil, err + } + return &Container{ctr}, nil +} diff --git a/libpod/adapter/runtime_remote.go b/libpod/adapter/runtime_remote.go new file mode 100644 index 000000000..7189348bc --- /dev/null +++ b/libpod/adapter/runtime_remote.go @@ -0,0 +1,322 @@ +// +build remoteclient + +package adapter + +import ( + "context" + "encoding/json" + "fmt" + "io" + "strings" + "time" + + "github.com/containers/image/types" + "github.com/containers/libpod/cmd/podman/varlink" + "github.com/containers/libpod/libpod" + "github.com/containers/libpod/libpod/image" + "github.com/opencontainers/go-digest" + "github.com/sirupsen/logrus" + "github.com/urfave/cli" + "github.com/varlink/go/varlink" +) + +// ImageRuntime is wrapper for image runtime +type RemoteImageRuntime struct{} + +// RemoteRuntime describes a wrapper runtime struct +type RemoteRuntime struct { + Conn *varlink.Connection + Remote bool +} + +// LocalRuntime describes a typical libpod runtime +type LocalRuntime struct { + *RemoteRuntime +} + +// GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it +func GetRuntime(c *cli.Context) (*LocalRuntime, error) { + runtime := RemoteRuntime{} + conn, err := runtime.Connect() + if err != nil { + return nil, err + } + rr := RemoteRuntime{ + Conn: conn, + Remote: true, + } + foo := LocalRuntime{ + &rr, + } + return &foo, nil +} + +// Shutdown is a bogus wrapper for compat with the libpod runtime +func (r RemoteRuntime) Shutdown(force bool) error { + return nil +} + +// ContainerImage +type ContainerImage struct { + remoteImage +} + +type remoteImage struct { + ID string + Labels map[string]string + RepoTags []string + RepoDigests []string + Parent string + Size int64 + Created time.Time + InputName string + Names []string + Digest digest.Digest + isParent bool + Runtime *LocalRuntime +} + +// Container ... +type Container struct { + remoteContainer +} + +// remoteContainer .... +type remoteContainer struct { + Runtime *LocalRuntime + config *libpod.ContainerConfig + state *libpod.ContainerState +} + +// GetImages returns a slice of containerimages over a varlink connection +func (r *LocalRuntime) GetImages() ([]*ContainerImage, error) { + var newImages []*ContainerImage + images, err := iopodman.ListImages().Call(r.Conn) + if err != nil { + return nil, err + } + for _, i := range images { + name := i.Id + if len(i.RepoTags) > 1 { + name = i.RepoTags[0] + } + newImage, err := imageInListToContainerImage(i, name, r) + if err != nil { + return nil, err + } + newImages = append(newImages, newImage) + } + return newImages, nil +} + +func imageInListToContainerImage(i iopodman.ImageInList, name string, runtime *LocalRuntime) (*ContainerImage, error) { + created, err := splitStringDate(i.Created) + if err != nil { + return nil, err + } + ri := remoteImage{ + InputName: name, + ID: i.Id, + Labels: i.Labels, + RepoTags: i.RepoTags, + RepoDigests: i.RepoTags, + Parent: i.ParentId, + Size: i.Size, + Created: created, + Names: i.RepoTags, + isParent: i.IsParent, + Runtime: runtime, + } + return &ContainerImage{ri}, nil +} + +// NewImageFromLocal returns a container image representation of a image over varlink +func (r *LocalRuntime) NewImageFromLocal(name string) (*ContainerImage, error) { + img, err := iopodman.GetImage().Call(r.Conn, name) + if err != nil { + return nil, err + } + return imageInListToContainerImage(img, name, r) + +} + +// LoadFromArchiveReference creates an image from a local archive +func (r *LocalRuntime) LoadFromArchiveReference(ctx context.Context, srcRef types.ImageReference, signaturePolicyPath string, writer io.Writer) ([]*ContainerImage, error) { + // TODO We need to find a way to leak certDir, creds, and the tlsverify into this function, normally this would + // come from cli options but we don't want want those in here either. + imageID, err := iopodman.PullImage().Call(r.Conn, srcRef.DockerReference().String(), "", "", signaturePolicyPath, true) + if err != nil { + return nil, err + } + newImage, err := r.NewImageFromLocal(imageID) + if err != nil { + return nil, err + } + return []*ContainerImage{newImage}, nil +} + +// New calls into local storage to look for an image in local storage or to pull it +func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *image.DockerRegistryOptions, signingoptions image.SigningOptions, forcePull bool) (*ContainerImage, error) { + // TODO Creds needs to be figured out here too, like above + tlsBool := dockeroptions.DockerInsecureSkipTLSVerify + // Remember SkipTlsVerify is the opposite of tlsverify + // If tlsBook is true or undefined, we do not skip + SkipTlsVerify := false + if tlsBool == types.OptionalBoolFalse { + SkipTlsVerify = true + } + imageID, err := iopodman.PullImage().Call(r.Conn, name, dockeroptions.DockerCertPath, "", signaturePolicyPath, SkipTlsVerify) + if err != nil { + return nil, err + } + newImage, err := r.NewImageFromLocal(imageID) + if err != nil { + return nil, err + } + return newImage, nil +} + +func splitStringDate(d string) (time.Time, error) { + fields := strings.Fields(d) + t := fmt.Sprintf("%sT%sZ", fields[0], fields[1]) + return time.ParseInLocation(time.RFC3339Nano, t, time.UTC) +} + +// IsParent goes through the layers in the store and checks if i.TopLayer is +// the parent of any other layer in store. Double check that image with that +// layer exists as well. +func (ci *ContainerImage) IsParent() (bool, error) { + return ci.remoteImage.isParent, nil +} + +// ID returns the image ID as a string +func (ci *ContainerImage) ID() string { + return ci.remoteImage.ID +} + +// Names returns a string array of names associated with the image +func (ci *ContainerImage) Names() []string { + return ci.remoteImage.Names +} + +// Created returns the time the image was created +func (ci *ContainerImage) Created() time.Time { + return ci.remoteImage.Created +} + +// Size returns the size of the image +func (ci *ContainerImage) Size(ctx context.Context) (*uint64, error) { + usize := uint64(ci.remoteImage.Size) + return &usize, nil +} + +// Digest returns the image's digest +func (ci *ContainerImage) Digest() digest.Digest { + return ci.remoteImage.Digest +} + +// Labels returns a map of the image's labels +func (ci *ContainerImage) Labels(ctx context.Context) (map[string]string, error) { + return ci.remoteImage.Labels, nil +} + +// Dangling returns a bool if the image is "dangling" +func (ci *ContainerImage) Dangling() bool { + return len(ci.Names()) == 0 +} + +// TagImage ... +func (ci *ContainerImage) TagImage(tag string) error { + _, err := iopodman.TagImage().Call(ci.Runtime.Conn, ci.ID(), tag) + return err +} + +// RemoveImage calls varlink to remove an image +func (r *LocalRuntime) RemoveImage(ctx context.Context, img *ContainerImage, force bool) (string, error) { + return iopodman.RemoveImage().Call(r.Conn, img.InputName, force) +} + +// History returns the history of an image and its layers +func (ci *ContainerImage) History(ctx context.Context) ([]*image.History, error) { + var imageHistories []*image.History + + reply, err := iopodman.HistoryImage().Call(ci.Runtime.Conn, ci.InputName) + if err != nil { + return nil, err + } + for _, h := range reply { + created, err := splitStringDate(h.Created) + if err != nil { + return nil, err + } + ih := image.History{ + ID: h.Id, + Created: &created, + CreatedBy: h.CreatedBy, + Size: h.Size, + Comment: h.Comment, + } + imageHistories = append(imageHistories, &ih) + } + return imageHistories, nil +} + +// LookupContainer gets basic information about container over a varlink +// connection and then translates it to a *Container +func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) { + state, err := r.ContainerState(idOrName) + if err != nil { + return nil, err + } + config := r.Config(idOrName) + if err != nil { + return nil, err + } + + rc := remoteContainer{ + r, + config, + state, + } + + c := Container{ + rc, + } + return &c, nil +} + +func (r *LocalRuntime) GetLatestContainer() (*Container, error) { + return nil, libpod.ErrNotImplemented +} + +// ContainerState returns the "state" of the container. +func (r *LocalRuntime) ContainerState(name string) (*libpod.ContainerState, error) { //no-lint + reply, err := iopodman.ContainerStateData().Call(r.Conn, name) + if err != nil { + return nil, err + } + data := libpod.ContainerState{} + if err := json.Unmarshal([]byte(reply), &data); err != nil { + return nil, err + } + return &data, err + +} + +// Config returns a container config +func (r *LocalRuntime) Config(name string) *libpod.ContainerConfig { + // TODO the Spec being returned is not populated. Matt and I could not figure out why. Will defer + // further looking into it for after devconf. + // The libpod function for this has no errors so we are kind of in a tough + // spot here. Logging the errors for now. + reply, err := iopodman.ContainerConfig().Call(r.Conn, name) + if err != nil { + logrus.Error("call to container.config failed") + } + data := libpod.ContainerConfig{} + if err := json.Unmarshal([]byte(reply), &data); err != nil { + logrus.Error("failed to unmarshal container inspect data") + } + return &data + +} |