diff options
Diffstat (limited to 'pkg/adapter/runtime_remote.go')
-rw-r--r-- | pkg/adapter/runtime_remote.go | 1108 |
1 files changed, 0 insertions, 1108 deletions
diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go deleted file mode 100644 index c511b70f1..000000000 --- a/pkg/adapter/runtime_remote.go +++ /dev/null @@ -1,1108 +0,0 @@ -// +build remoteclient - -package adapter - -import ( - "bufio" - "context" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "text/template" - "time" - - "github.com/containers/buildah/imagebuildah" - "github.com/containers/buildah/pkg/formats" - "github.com/containers/common/pkg/config" - "github.com/containers/image/v5/docker/reference" - "github.com/containers/image/v5/types" - "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/cmd/podman/remoteclientconfig" - "github.com/containers/libpod/libpod" - "github.com/containers/libpod/libpod/define" - "github.com/containers/libpod/libpod/events" - "github.com/containers/libpod/libpod/image" - "github.com/containers/libpod/pkg/util" - iopodman "github.com/containers/libpod/pkg/varlink" - "github.com/containers/libpod/utils" - "github.com/containers/storage/pkg/archive" - "github.com/opencontainers/go-digest" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "github.com/varlink/go/varlink" - v1 "k8s.io/api/core/v1" -) - -// ImageRuntime is wrapper for image runtime -type RemoteImageRuntime struct{} - -// RemoteRuntime describes a wrapper runtime struct -type RemoteRuntime struct { - Conn *varlink.Connection - Remote bool - cmd cliconfig.MainFlags - config io.Reader -} - -// LocalRuntime describes a typical libpod runtime -type LocalRuntime struct { - *RemoteRuntime -} - -// GetRuntimeNoStore returns a LocalRuntime struct with the actual runtime embedded in it -// The nostore is ignored -func GetRuntimeNoStore(ctx context.Context, c *cliconfig.PodmanCommand) (*LocalRuntime, error) { - return GetRuntime(ctx, c) -} - -// GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it -func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*LocalRuntime, error) { - var ( - customConfig bool - err error - f *os.File - ) - runtime := RemoteRuntime{ - Remote: true, - cmd: c.GlobalFlags, - } - configPath := remoteclientconfig.GetConfigFilePath() - // Check if the basedir for configPath exists and if not, create it. - if _, err := os.Stat(filepath.Dir(configPath)); os.IsNotExist(err) { - if mkdirErr := os.MkdirAll(filepath.Dir(configPath), 0750); mkdirErr != nil { - return nil, mkdirErr - } - } - if len(c.GlobalFlags.RemoteConfigFilePath) > 0 { - configPath = c.GlobalFlags.RemoteConfigFilePath - customConfig = true - } - - f, err = os.Open(configPath) - if err != nil { - // If user does not explicitly provide a configuration file path and we cannot - // find a default, no error should occur. - if os.IsNotExist(err) && !customConfig { - logrus.Debugf("unable to load configuration file at %s", configPath) - runtime.config = nil - } else { - return nil, errors.Wrapf(err, "unable to load configuration file at %s", configPath) - } - } else { - // create the io reader for the remote client - runtime.config = bufio.NewReader(f) - } - conn, err := runtime.Connect() - if err != nil { - return nil, err - } - runtime.Conn = conn - return &LocalRuntime{ - &runtime, - }, nil -} - -// DeferredShutdown is a bogus wrapper for compaat with the libpod -// runtime and should only be run when a defer is being used -func (r RemoteRuntime) DeferredShutdown(force bool) { - if err := r.Shutdown(force); err != nil { - logrus.Error("unable to shutdown runtime") - } -} - -// Containers is a bogus wrapper for compat with the libpod runtime -type ContainersConfig struct { - // CGroupManager is the CGroup Manager to use - // Valid values are "cgroupfs" and "systemd" - CgroupManager string -} - -// RuntimeConfig is a bogus wrapper for compat with the libpod runtime -type RuntimeConfig struct { - Containers ContainersConfig -} - -// Shutdown is a bogus wrapper for compat with the libpod runtime -func (r *RemoteRuntime) GetConfig() (*config.Config, error) { - return nil, 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 - Digests []digest.Digest - isParent bool - Runtime *LocalRuntime - TopLayer string - ReadOnly bool - NamesHistory []string -} - -// Container ... -type Container struct { - remoteContainer -} - -// remoteContainer .... -type remoteContainer struct { - Runtime *LocalRuntime - config *libpod.ContainerConfig - state *libpod.ContainerState -} - -// Pod ... -type Pod struct { - remotepod -} - -type remotepod struct { - config *libpod.PodConfig - state *libpod.PodInspectState - containers []libpod.PodContainerInfo // nolint: structcheck - Runtime *LocalRuntime -} - -type VolumeFilter func(*Volume) bool - -// Volume is embed for libpod volumes -type Volume struct { - remoteVolume -} - -type remoteVolume struct { - Runtime *LocalRuntime - config *libpod.VolumeConfig -} - -// GetImages returns a slice of containerimages over a varlink connection -func (r *LocalRuntime) GetImages() ([]*ContainerImage, error) { - return r.getImages(false) -} - -// GetRWImages returns a slice of read/write containerimages over a varlink connection -func (r *LocalRuntime) GetRWImages() ([]*ContainerImage, error) { - return r.getImages(true) -} - -func (r *LocalRuntime) GetFilteredImages(filters []string, rwOnly bool) ([]*ContainerImage, error) { - if len(filters) > 0 { - return nil, errors.Wrap(define.ErrNotImplemented, "filtering images is not supported on the remote client") - } - var newImages []*ContainerImage - images, err := iopodman.ListImages().Call(r.Conn) - if err != nil { - return nil, err - } - for _, i := range images { - if rwOnly && i.ReadOnly { - continue - } - 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 (r *LocalRuntime) getImages(rwOnly bool) ([]*ContainerImage, error) { - var newImages []*ContainerImage - images, err := iopodman.ListImages().Call(r.Conn) - if err != nil { - return nil, err - } - for _, i := range images { - if rwOnly && i.ReadOnly { - continue - } - 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.Image, name string, runtime *LocalRuntime) (*ContainerImage, error) { - created, err := time.ParseInLocation(time.RFC3339, i.Created, time.UTC) - if err != nil { - return nil, err - } - var digests []digest.Digest - for _, d := range i.Digests { - digests = append(digests, digest.Digest(d)) - } - ri := remoteImage{ - InputName: name, - ID: i.Id, - Digest: digest.Digest(i.Digest), - Digests: digests, - 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, - TopLayer: i.TopLayer, - ReadOnly: i.ReadOnly, - NamesHistory: i.History, - } - 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) { - var iid string - creds := iopodman.AuthConfig{} - reply, err := iopodman.PullImage().Send(r.Conn, varlink.More, srcRef.DockerReference().String(), creds) - if err != nil { - return nil, err - } - - for { - responses, flags, err := reply() - if err != nil { - return nil, err - } - for _, line := range responses.Logs { - fmt.Print(line) - } - iid = responses.Id - if flags&varlink.Continues == 0 { - break - } - } - - newImage, err := r.NewImageFromLocal(iid) - 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, label *string, pullType util.PullType) (*ContainerImage, error) { - var iid string - if label != nil { - return nil, errors.New("the remote client function does not support checking a remote image for a label") - } - creds := iopodman.AuthConfig{} - if dockeroptions.DockerRegistryCreds != nil { - creds.Username = dockeroptions.DockerRegistryCreds.Username - creds.Password = dockeroptions.DockerRegistryCreds.Password - } - reply, err := iopodman.PullImage().Send(r.Conn, varlink.More, name, creds) - if err != nil { - return nil, err - } - for { - responses, flags, err := reply() - if err != nil { - return nil, err - } - for _, line := range responses.Logs { - fmt.Print(line) - } - iid = responses.Id - if flags&varlink.Continues == 0 { - break - } - } - newImage, err := r.NewImageFromLocal(iid) - if err != nil { - return nil, err - } - return newImage, nil -} - -func (r *LocalRuntime) ImageTree(imageOrID string, whatRequires bool) (string, error) { - return iopodman.ImageTree().Call(r.Conn, imageOrID, whatRequires) -} - -// 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(context.Context) (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 -} - -// NamesHistory returns a string array of names previously associated with the image -func (ci *ContainerImage) NamesHistory() []string { - return ci.remoteImage.NamesHistory -} - -// Created returns the time the image was created -func (ci *ContainerImage) Created() time.Time { - return ci.remoteImage.Created -} - -// IsReadOnly returns whether the image is ReadOnly -func (ci *ContainerImage) IsReadOnly() bool { - return ci.remoteImage.ReadOnly -} - -// 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 -} - -// Digests returns the image's digests -func (ci *ContainerImage) Digests() []digest.Digest { - return append([]digest.Digest{}, ci.remoteImage.Digests...) -} - -// 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 -} - -// TopLayer returns an images top layer as a string -func (ci *ContainerImage) TopLayer() string { - return ci.remoteImage.TopLayer -} - -// TagImage ... -func (ci *ContainerImage) TagImage(tag string) error { - _, err := iopodman.TagImage().Call(ci.Runtime.Conn, ci.ID(), tag) - return err -} - -// UntagImage removes a single tag from an image -func (ci *ContainerImage) UntagImage(tag string) error { - _, err := iopodman.UntagImage().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) (*image.ImageDeleteResponse, error) { - ir := image.ImageDeleteResponse{} - response, err := iopodman.RemoveImageWithResponse().Call(r.Conn, img.InputName, force) - if err != nil { - return nil, err - } - ir.Deleted = response.Deleted - ir.Untagged = append(ir.Untagged, response.Untagged...) - return &ir, nil -} - -// 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 := time.ParseInLocation(time.RFC3339, h.Created, time.UTC) - 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 -} - -// PruneImages is the wrapper call for a remote-client to prune images -func (r *LocalRuntime) PruneImages(ctx context.Context, all bool, filter []string) ([]string, error) { - return iopodman.ImagesPrune().Call(r.Conn, all, filter) -} - -// Export is a wrapper to container export to a tarfile -func (r *LocalRuntime) Export(name string, path string) error { - tempPath, err := iopodman.ExportContainer().Call(r.Conn, name, "") - if err != nil { - return err - } - return r.GetFileFromRemoteHost(tempPath, path, true) -} - -func (r *LocalRuntime) GetFileFromRemoteHost(remoteFilePath, outputPath string, delete bool) error { - outputFile, err := os.Create(outputPath) - if err != nil { - return err - } - defer outputFile.Close() - - writer := bufio.NewWriter(outputFile) - defer writer.Flush() - - reply, err := iopodman.ReceiveFile().Send(r.Conn, varlink.Upgrade, remoteFilePath, delete) - if err != nil { - return err - } - - length, _, err := reply() - if err != nil { - return errors.Wrap(err, "unable to get file length for transfer") - } - - reader := r.Conn.Reader - if _, err := io.CopyN(writer, reader, length); err != nil { - return errors.Wrap(err, "file transfer failed") - } - return nil -} - -// Import implements the remote calls required to import a container image to the store -func (r *LocalRuntime) Import(ctx context.Context, source, reference string, changes []string, history string, quiet bool) (string, error) { - // First we send the file to the host - tempFile, err := r.SendFileOverVarlink(source) - if err != nil { - return "", err - } - return iopodman.ImportImage().Call(r.Conn, strings.TrimRight(tempFile, ":"), reference, history, changes, true) -} - -func (r *LocalRuntime) Build(ctx context.Context, c *cliconfig.BuildValues, options imagebuildah.BuildOptions, dockerfiles []string) (string, reference.Canonical, error) { - buildOptions := iopodman.BuildOptions{ - AddHosts: options.CommonBuildOpts.AddHost, - CgroupParent: options.CommonBuildOpts.CgroupParent, - CpuPeriod: int64(options.CommonBuildOpts.CPUPeriod), - CpuQuota: options.CommonBuildOpts.CPUQuota, - CpuShares: int64(options.CommonBuildOpts.CPUShares), - CpusetCpus: options.CommonBuildOpts.CPUSetMems, - CpusetMems: options.CommonBuildOpts.CPUSetMems, - Memory: options.CommonBuildOpts.Memory, - MemorySwap: options.CommonBuildOpts.MemorySwap, - ShmSize: options.CommonBuildOpts.ShmSize, - Ulimit: options.CommonBuildOpts.Ulimit, - Volume: options.CommonBuildOpts.Volumes, - } - buildinfo := iopodman.BuildInfo{ - // Err: string(options.Err), - // Out: - // ReportWriter: - Architecture: options.Architecture, - AddCapabilities: options.AddCapabilities, - AdditionalTags: options.AdditionalTags, - Annotations: options.Annotations, - BuildArgs: options.Args, - BuildOptions: buildOptions, - CniConfigDir: options.CNIConfigDir, - CniPluginDir: options.CNIPluginPath, - Compression: string(options.Compression), - Devices: options.Devices, - DefaultsMountFilePath: options.DefaultMountsFilePath, - Dockerfiles: dockerfiles, - DropCapabilities: options.DropCapabilities, - ForceRmIntermediateCtrs: options.ForceRmIntermediateCtrs, - Iidfile: options.IIDFile, - Label: options.Labels, - Layers: options.Layers, - // NamespaceOptions: options.NamespaceOptions, - Nocache: options.NoCache, - Os: options.OS, - Output: options.Output, - OutputFormat: options.OutputFormat, - PullPolicy: options.PullPolicy.String(), - Quiet: options.Quiet, - RemoteIntermediateCtrs: options.RemoveIntermediateCtrs, - RuntimeArgs: options.RuntimeArgs, - SignBy: options.SignBy, - Squash: options.Squash, - Target: options.Target, - TransientMounts: options.TransientMounts, - } - // tar the file - outputFile, err := ioutil.TempFile("", "varlink_tar_send") - if err != nil { - return "", nil, err - } - defer outputFile.Close() - defer os.Remove(outputFile.Name()) - - // Create the tarball of the context dir to a tempfile - if err := utils.TarToFilesystem(options.ContextDirectory, outputFile); err != nil { - return "", nil, err - } - // Send the context dir tarball over varlink. - tempFile, err := r.SendFileOverVarlink(outputFile.Name()) - if err != nil { - return "", nil, err - } - buildinfo.ContextDir = tempFile - - reply, err := iopodman.BuildImage().Send(r.Conn, varlink.More, buildinfo) - if err != nil { - return "", nil, err - } - - for { - responses, flags, err := reply() - if err != nil { - return "", nil, err - } - for _, line := range responses.Logs { - fmt.Print(line) - } - if flags&varlink.Continues == 0 { - break - } - } - return "", nil, err -} - -// SendFileOverVarlink sends a file over varlink in an upgraded connection -func (r *LocalRuntime) SendFileOverVarlink(source string) (string, error) { - fs, err := os.Open(source) - if err != nil { - return "", err - } - - fileInfo, err := fs.Stat() - if err != nil { - return "", err - } - logrus.Debugf("sending %s over varlink connection", source) - reply, err := iopodman.SendFile().Send(r.Conn, varlink.Upgrade, "", fileInfo.Size()) - if err != nil { - return "", err - } - _, _, err = reply() - if err != nil { - return "", err - } - - reader := bufio.NewReader(fs) - _, err = reader.WriteTo(r.Conn.Writer) - if err != nil { - return "", err - } - logrus.Debugf("file transfer complete for %s", source) - r.Conn.Writer.Flush() - - // All was sent, wait for the ACK from the server - tempFile, err := r.Conn.Reader.ReadString(':') - if err != nil { - return "", err - } - - // r.Conn is kaput at this point due to the upgrade - if err := r.RemoteRuntime.RefreshConnection(); err != nil { - return "", err - - } - - return strings.Replace(tempFile, ":", "", -1), nil -} - -// GetAllVolumes retrieves all the volumes -func (r *LocalRuntime) GetAllVolumes() ([]*libpod.Volume, error) { - return nil, define.ErrNotImplemented -} - -// RemoveVolume removes a volumes -func (r *LocalRuntime) RemoveVolume(ctx context.Context, v *libpod.Volume, force, prune bool) error { - return define.ErrNotImplemented -} - -// GetContainers retrieves all containers from the state -// Filters can be provided which will determine what containers are included in -// the output. Multiple filters are handled by ANDing their output, so only -// containers matching all filters are returned -func (r *LocalRuntime) GetContainers(filters ...libpod.ContainerFilter) ([]*libpod.Container, error) { - return nil, define.ErrNotImplemented -} - -// RemoveContainer removes the given container -// If force is specified, the container will be stopped first -// Otherwise, RemoveContainer will return an error if the container is running -func (r *LocalRuntime) RemoveContainer(ctx context.Context, c *libpod.Container, force, volumes bool) error { - return define.ErrNotImplemented -} - -// CreateVolume creates a volume over a varlink connection for the remote client -func (r *LocalRuntime) CreateVolume(ctx context.Context, c *cliconfig.VolumeCreateValues, labels, opts map[string]string) (string, error) { - cvOpts := iopodman.VolumeCreateOpts{ - Options: opts, - Labels: labels, - } - if len(c.InputArgs) > 0 { - cvOpts.VolumeName = c.InputArgs[0] - } - - if c.Flag("driver").Changed { - cvOpts.Driver = c.Driver - } - - return iopodman.VolumeCreate().Call(r.Conn, cvOpts) -} - -// RemoveVolumes removes volumes over a varlink connection for the remote client -func (r *LocalRuntime) RemoveVolumes(ctx context.Context, c *cliconfig.VolumeRmValues) ([]string, map[string]error, error) { - rmOpts := iopodman.VolumeRemoveOpts{ - All: c.All, - Force: c.Force, - Volumes: c.InputArgs, - } - success, failures, err := iopodman.VolumeRemove().Call(r.Conn, rmOpts) - stringsToErrors := make(map[string]error) - for k, v := range failures { - stringsToErrors[k] = errors.New(v) - } - return success, stringsToErrors, err -} - -func (r *LocalRuntime) Push(ctx context.Context, srcName, destination, manifestMIMEType, authfile, digestfile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions image.SigningOptions, dockerRegistryOptions *image.DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error { - - reply, err := iopodman.PushImage().Send(r.Conn, varlink.More, srcName, destination, forceCompress, manifestMIMEType, signingOptions.RemoveSignatures, signingOptions.SignBy) - if err != nil { - return err - } - for { - responses, flags, err := reply() - if err != nil { - return err - } - for _, line := range responses.Logs { - fmt.Print(line) - } - if flags&varlink.Continues == 0 { - break - } - } - - return err -} - -// InspectVolumes returns a slice of volumes based on an arg list or --all -func (r *LocalRuntime) InspectVolumes(ctx context.Context, c *cliconfig.VolumeInspectValues) ([]*libpod.InspectVolumeData, error) { - var ( - inspectData []*libpod.InspectVolumeData - volumes []string - ) - - if c.All { - allVolumes, err := r.Volumes(ctx) - if err != nil { - return nil, err - } - for _, vol := range allVolumes { - volumes = append(volumes, vol.Name()) - } - } else { - volumes = append(volumes, c.InputArgs...) - } - - for _, vol := range volumes { - jsonString, err := iopodman.InspectVolume().Call(r.Conn, vol) - if err != nil { - return nil, err - } - inspectJSON := new(libpod.InspectVolumeData) - if err := json.Unmarshal([]byte(jsonString), inspectJSON); err != nil { - return nil, errors.Wrapf(err, "error unmarshalling inspect JSON for volume %s", vol) - } - inspectData = append(inspectData, inspectJSON) - } - - return inspectData, nil -} - -// Volumes returns a slice of adapter.volumes based on information about libpod -// volumes over a varlink connection -func (r *LocalRuntime) Volumes(ctx context.Context) ([]*Volume, error) { - reply, err := iopodman.GetVolumes().Call(r.Conn, []string{}, true) - if err != nil { - return nil, err - } - return varlinkVolumeToVolume(r, reply), nil -} - -func varlinkVolumeToVolume(r *LocalRuntime, volumes []iopodman.Volume) []*Volume { - var vols []*Volume - for _, v := range volumes { - volumeConfig := libpod.VolumeConfig{ - Name: v.Name, - Labels: v.Labels, - MountPoint: v.MountPoint, - Driver: v.Driver, - Options: v.Options, - } - n := remoteVolume{ - Runtime: r, - config: &volumeConfig, - } - newVol := Volume{ - n, - } - vols = append(vols, &newVol) - } - return vols -} - -// PruneVolumes removes all unused volumes from the remote system -func (r *LocalRuntime) PruneVolumes(ctx context.Context) ([]string, []error) { - var errs []error - prunedNames, prunedErrors, err := iopodman.VolumesPrune().Call(r.Conn) - if err != nil { - return []string{}, []error{err} - } - // We need to transform the string results of the error into actual error types - for _, e := range prunedErrors { - errs = append(errs, errors.New(e)) - } - return prunedNames, errs -} - -// SaveImage is a wrapper function for saving an image to the local filesystem -func (r *LocalRuntime) SaveImage(ctx context.Context, c *cliconfig.SaveValues) error { - source := c.InputArgs[0] - additionalTags := c.InputArgs[1:] - - options := iopodman.ImageSaveOptions{ - Name: source, - Format: c.Format, - Output: c.Output, - MoreTags: additionalTags, - Quiet: c.Quiet, - Compress: c.Compress, - } - reply, err := iopodman.ImageSave().Send(r.Conn, varlink.More, options) - if err != nil { - return err - } - - var fetchfile string - for { - responses, flags, err := reply() - if err != nil { - return err - } - if len(responses.Id) > 0 { - fetchfile = responses.Id - } - for _, line := range responses.Logs { - fmt.Print(line) - } - if flags&varlink.Continues == 0 { - break - } - - } - if err != nil { // nolint: govet - return err - } - - outputToDir := false - outfile := c.Output - var outputFile *os.File - // If the result is supposed to be a dir, then we need to put the tarfile - // from the host in a temporary file - if options.Format != "oci-archive" && options.Format != "docker-archive" { - outputToDir = true - outputFile, err = ioutil.TempFile("", "saveimage_tempfile") - if err != nil { - return err - } - outfile = outputFile.Name() - defer outputFile.Close() - defer os.Remove(outputFile.Name()) - } - // We now need to fetch the tarball result back to the more system - if err := r.GetFileFromRemoteHost(fetchfile, outfile, true); err != nil { - return err - } - - // If the result is a tarball, we're done - // If it is a dir, we need to untar the temporary file into the dir - if outputToDir { - if err := utils.UntarToFileSystem(c.Output, outputFile, &archive.TarOptions{}); err != nil { - return err - } - } - return nil -} - -// LoadImage loads a container image from a remote client's filesystem -func (r *LocalRuntime) LoadImage(ctx context.Context, name string, cli *cliconfig.LoadValues) (string, error) { - var names string - remoteTempFile, err := r.SendFileOverVarlink(cli.Input) - if err != nil { - return "", nil - } - more := varlink.More - if cli.Quiet { - more = 0 - } - reply, err := iopodman.LoadImage().Send(r.Conn, uint64(more), name, remoteTempFile, cli.Quiet, true) - if err != nil { - return "", err - } - - for { - responses, flags, err := reply() - if err != nil { - logrus.Error(err) - return "", err - } - for _, line := range responses.Logs { - fmt.Print(line) - } - names = responses.Id - if flags&varlink.Continues == 0 { - break - } - } - return names, nil -} - -// IsImageNotFound checks if the error indicates that no image was found. -func IsImageNotFound(err error) bool { - if errors.Cause(err) == image.ErrNoSuchImage { - return true - } - switch err.(type) { // nolint: gocritic - case *iopodman.ImageNotFound: - return true - } - return false -} - -// HealthCheck executes a container's healthcheck over a varlink connection -func (r *LocalRuntime) HealthCheck(c *cliconfig.HealthCheckValues) (string, error) { - return iopodman.HealthCheckRun().Call(r.Conn, c.InputArgs[0]) -} - -// Events monitors libpod/podman events over a varlink connection -func (r *LocalRuntime) Events(c *cliconfig.EventValues) error { - var more uint64 - if c.Stream { - more = uint64(varlink.More) - } - reply, err := iopodman.GetEvents().Send(r.Conn, more, c.Filter, c.Since, c.Until) - if err != nil { - return errors.Wrapf(err, "unable to obtain events") - } - - w := bufio.NewWriter(os.Stdout) - var tmpl *template.Template - if c.Format != formats.JSONString { - template, err := template.New("events").Parse(c.Format) - if err != nil { - return err - } - tmpl = template - } - - for { - returnedEvent, flags, err := reply() - if err != nil { - // When the error handling is back into podman, we can flip this to a better way to check - // for problems. For now, this works. - return err - } - if returnedEvent.Time == "" && returnedEvent.Status == "" && returnedEvent.Type == "" { - // We got a blank event return, signals end of stream in certain cases - break - } - eTime, err := time.Parse(time.RFC3339Nano, returnedEvent.Time) - if err != nil { - return errors.Wrapf(err, "unable to parse time of event %s", returnedEvent.Time) - } - eType, err := events.StringToType(returnedEvent.Type) - if err != nil { - return err - } - eStatus, err := events.StringToStatus(returnedEvent.Status) - if err != nil { - return err - } - event := events.Event{ - ID: returnedEvent.Id, - Image: returnedEvent.Image, - Name: returnedEvent.Name, - Status: eStatus, - Time: eTime, - Type: eType, - } - if c.Format == formats.JSONString { // nolint: gocritic - jsonStr, err := event.ToJSONString() - if err != nil { - return errors.Wrapf(err, "unable to format json") - } - if _, err := w.Write([]byte(jsonStr)); err != nil { - return err - } - } else if len(c.Format) > 0 { - if err := tmpl.Execute(w, event); err != nil { - return err - } - } else { - if _, err := w.Write([]byte(event.ToHumanReadable())); err != nil { - return err - } - } - - if _, err := w.Write([]byte("\n")); err != nil { - return err - } - if err := w.Flush(); err != nil { - return err - } - if flags&varlink.Continues == 0 { - break - } - } - return nil -} - -// Diff ... -func (r *LocalRuntime) Diff(c *cliconfig.DiffValues, to string) ([]archive.Change, error) { - var changes []archive.Change - reply, err := iopodman.Diff().Call(r.Conn, to) - if err != nil { - return nil, err - } - for _, change := range reply { - changes = append(changes, archive.Change{Path: change.Path, Kind: stringToChangeType(change.ChangeType)}) - } - return changes, nil -} - -func stringToChangeType(change string) archive.ChangeType { - switch change { - case "A": - return archive.ChangeAdd - case "D": - return archive.ChangeDelete - default: // nolint: gocritic,stylecheck - logrus.Errorf("'%s' is unknown archive type", change) - fallthrough - case "C": - return archive.ChangeModify - } -} - -// GenerateKube creates kubernetes email from containers and pods -func (r *LocalRuntime) GenerateKube(c *cliconfig.GenerateKubeValues) (*v1.Pod, *v1.Service, error) { - var ( - pod v1.Pod - service v1.Service - ) - reply, err := iopodman.GenerateKube().Call(r.Conn, c.InputArgs[0], c.Service) - if err != nil { - return nil, nil, errors.Wrap(err, "unable to create kubernetes YAML") - } - if err := json.Unmarshal([]byte(reply.Pod), &pod); err != nil { - return nil, nil, err - } - err = json.Unmarshal([]byte(reply.Service), &service) - return &pod, &service, err -} - -// GetContainersByContext looks up containers based on the cli input of all, latest, or a list -func (r *LocalRuntime) GetContainersByContext(all bool, latest bool, namesOrIDs []string) ([]*Container, error) { - var containers []*Container - cids, err := iopodman.GetContainersByContext().Call(r.Conn, all, latest, namesOrIDs) - if err != nil { - return nil, err - } - for _, cid := range cids { - ctr, err := r.LookupContainer(cid) - if err != nil { - return nil, err - } - containers = append(containers, ctr) - } - return containers, nil -} - -// GetVersion returns version information from service -func (r *LocalRuntime) GetVersion() (define.Version, error) { - version, goVersion, gitCommit, built, osArch, apiVersion, err := iopodman.GetVersion().Call(r.Conn) - if err != nil { - return define.Version{}, errors.Wrapf(err, "Unable to obtain server version information") - } - - var buildTime int64 - if built != "" { - t, err := time.Parse(time.RFC3339, built) - if err != nil { - return define.Version{}, nil - } - buildTime = t.Unix() - } - - return define.Version{ - RemoteAPIVersion: apiVersion, - Version: version, - GoVersion: goVersion, - GitCommit: gitCommit, - Built: buildTime, - OsArch: osArch, - }, nil -} |