diff options
Diffstat (limited to 'pkg/varlinkapi/images.go')
-rw-r--r-- | pkg/varlinkapi/images.go | 1037 |
1 files changed, 0 insertions, 1037 deletions
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go deleted file mode 100644 index af6c43fec..000000000 --- a/pkg/varlinkapi/images.go +++ /dev/null @@ -1,1037 +0,0 @@ -// +build varlink - -package varlinkapi - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "time" - - "github.com/containers/buildah" - "github.com/containers/buildah/imagebuildah" - dockerarchive "github.com/containers/image/v5/docker/archive" - "github.com/containers/image/v5/manifest" - "github.com/containers/image/v5/transports/alltransports" - "github.com/containers/image/v5/types" - "github.com/containers/podman/v2/libpod" - "github.com/containers/podman/v2/libpod/define" - "github.com/containers/podman/v2/libpod/image" - "github.com/containers/podman/v2/pkg/channel" - "github.com/containers/podman/v2/pkg/util" - iopodman "github.com/containers/podman/v2/pkg/varlink" - "github.com/containers/podman/v2/utils" - "github.com/containers/storage/pkg/archive" - v1 "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -// ListImagesWithFilters returns a list of images that have been filtered -func (i *VarlinkAPI) ListImagesWithFilters(call iopodman.VarlinkCall, filters []string) error { - images, err := i.Runtime.ImageRuntime().GetImagesWithFilters(filters) - if err != nil { - return call.ReplyErrorOccurred(fmt.Sprintf("unable to get list of images %q", err)) - } - imageList, err := imagesToImageList(images) - if err != nil { - return call.ReplyErrorOccurred("unable to parse response " + err.Error()) - } - return call.ReplyListImagesWithFilters(imageList) -} - -// imagesToImageList converts a slice of Images to an imagelist for varlink responses -func imagesToImageList(images []*image.Image) ([]iopodman.Image, error) { - var imageList []iopodman.Image - for _, img := range images { - labels, _ := img.Labels(getContext()) - containers, _ := img.Containers() - repoDigests, err := img.RepoDigests() - if err != nil { - return nil, err - } - - size, _ := img.Size(getContext()) - isParent, err := img.IsParent(context.TODO()) - if err != nil { - return nil, err - } - - i := iopodman.Image{ - Id: img.ID(), - Digest: string(img.Digest()), - ParentId: img.Parent, - RepoTags: img.Names(), - RepoDigests: repoDigests, - Created: img.Created().Format(time.RFC3339), - Size: int64(*size), - VirtualSize: img.VirtualSize, - Containers: int64(len(containers)), - Labels: labels, - IsParent: isParent, - ReadOnly: img.IsReadOnly(), - History: img.NamesHistory(), - } - imageList = append(imageList, i) - } - return imageList, nil -} - -// ListImages lists all the images in the store -// It requires no inputs. -func (i *VarlinkAPI) ListImages(call iopodman.VarlinkCall) error { - images, err := i.Runtime.ImageRuntime().GetImages() - if err != nil { - return call.ReplyErrorOccurred("unable to get list of images " + err.Error()) - } - imageList, err := imagesToImageList(images) - if err != nil { - return call.ReplyErrorOccurred("unable to parse response " + err.Error()) - } - return call.ReplyListImages(imageList) -} - -// GetImage returns a single image in the form of a Image -func (i *VarlinkAPI) GetImage(call iopodman.VarlinkCall, id string) error { - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(id) - if err != nil { - return call.ReplyImageNotFound(id, err.Error()) - } - labels, err := newImage.Labels(getContext()) - if err != nil { - return err - } - containers, err := newImage.Containers() - if err != nil { - return err - } - repoDigests, err := newImage.RepoDigests() - if err != nil { - return err - } - size, err := newImage.Size(getContext()) - if err != nil { - return err - } - - il := iopodman.Image{ - Id: newImage.ID(), - ParentId: newImage.Parent, - RepoTags: newImage.Names(), - RepoDigests: repoDigests, - Created: newImage.Created().Format(time.RFC3339), - Size: int64(*size), - VirtualSize: newImage.VirtualSize, - Containers: int64(len(containers)), - Labels: labels, - TopLayer: newImage.TopLayer(), - ReadOnly: newImage.IsReadOnly(), - History: newImage.NamesHistory(), - } - return call.ReplyGetImage(il) -} - -// BuildImage ... -func (i *VarlinkAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildInfo) error { - var ( - namespace []buildah.NamespaceOption - imageID string - err error - ) - - contextDir := config.ContextDir - - newContextDir, err := ioutil.TempDir("", "buildTarball") - if err != nil { - call.ReplyErrorOccurred("unable to create tempdir") - } - logrus.Debugf("created new context dir at %s", newContextDir) - - reader, err := os.Open(contextDir) - if err != nil { - logrus.Errorf("failed to open the context dir tar file") - return call.ReplyErrorOccurred(fmt.Sprintf("unable to open context dir tar file %s", contextDir)) - } - defer reader.Close() - if err := archive.Untar(reader, newContextDir, &archive.TarOptions{}); err != nil { - logrus.Errorf("fail to untar the context dir tarball (%s) to the context dir (%s)", contextDir, newContextDir) - return call.ReplyErrorOccurred(fmt.Sprintf("unable to untar context dir %s", contextDir)) - } - logrus.Debugf("untar of %s successful", contextDir) - defer func() { - if err := os.Remove(contextDir); err != nil { - logrus.Error(err) - } - if err := os.RemoveAll(newContextDir); err != nil { - logrus.Errorf("unable to delete directory '%s': %q", newContextDir, err) - } - }() - - systemContext := types.SystemContext{} - // All output (stdout, stderr) is captured in output as well - var output bytes.Buffer - - commonOpts := &buildah.CommonBuildOptions{ - AddHost: config.BuildOptions.AddHosts, - CgroupParent: config.BuildOptions.CgroupParent, - CPUPeriod: uint64(config.BuildOptions.CpuPeriod), - CPUQuota: config.BuildOptions.CpuQuota, - CPUSetCPUs: config.BuildOptions.CpusetCpus, - CPUSetMems: config.BuildOptions.CpusetMems, - Memory: config.BuildOptions.Memory, - MemorySwap: config.BuildOptions.MemorySwap, - ShmSize: config.BuildOptions.ShmSize, - Ulimit: config.BuildOptions.Ulimit, - Volumes: config.BuildOptions.Volume, - } - - options := imagebuildah.BuildOptions{ - AddCapabilities: config.AddCapabilities, - AdditionalTags: config.AdditionalTags, - Annotations: config.Annotations, - Architecture: config.Architecture, - Args: config.BuildArgs, - CNIConfigDir: config.CniConfigDir, - CNIPluginPath: config.CniPluginDir, - CommonBuildOpts: commonOpts, - Compression: stringCompressionToArchiveType(config.Compression), - ContextDirectory: newContextDir, - DefaultMountsFilePath: config.DefaultsMountFilePath, - Devices: config.Devices, - Err: &output, - ForceRmIntermediateCtrs: config.ForceRmIntermediateCtrs, - IIDFile: config.Iidfile, - Labels: config.Label, - Layers: config.Layers, - NamespaceOptions: namespace, - NoCache: config.Nocache, - OS: config.Os, - Out: &output, - Output: config.Output, - OutputFormat: config.OutputFormat, - PullPolicy: stringPullPolicyToType(config.PullPolicy), - Quiet: config.Quiet, - RemoveIntermediateCtrs: config.RemoteIntermediateCtrs, - ReportWriter: &output, - RuntimeArgs: config.RuntimeArgs, - SignBy: config.SignBy, - Squash: config.Squash, - SystemContext: &systemContext, - Target: config.Target, - TransientMounts: config.TransientMounts, - } - - if call.WantsMore() { - call.Continues = true - } else { - return call.ReplyErrorOccurred("endpoint requires a more connection") - } - - var newPathDockerFiles []string - - for _, d := range config.Dockerfiles { - if strings.HasPrefix(d, "http://") || - strings.HasPrefix(d, "https://") || - strings.HasPrefix(d, "git://") || - strings.HasPrefix(d, "github.com/") { - newPathDockerFiles = append(newPathDockerFiles, d) - continue - } - base := filepath.Base(d) - newPathDockerFiles = append(newPathDockerFiles, filepath.Join(newContextDir, base)) - } - - c := make(chan error) - go func() { - iid, _, err := i.Runtime.Build(getContext(), options, newPathDockerFiles...) - imageID = iid - c <- err - close(c) - }() - - var log []string - done := false - for { - outputLine, err := output.ReadString('\n') - if err == nil { - log = append(log, outputLine) - if call.WantsMore() { - // we want to reply with what we have - br := iopodman.MoreResponse{ - Logs: log, - } - call.ReplyBuildImage(br) - log = []string{} - } - continue - } else if err == io.EOF { - select { - case err := <-c: - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - done = true - default: - if call.WantsMore() { - time.Sleep(1 * time.Second) - break - } - } - } else { - return call.ReplyErrorOccurred(err.Error()) - } - if done { - break - } - } - call.Continues = false - - br := iopodman.MoreResponse{ - Logs: log, - Id: imageID, - } - return call.ReplyBuildImage(br) -} - -// InspectImage returns an image's inspect information as a string that can be serialized. -// Requires an image ID or name -func (i *VarlinkAPI) InspectImage(call iopodman.VarlinkCall, name string) error { - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - return call.ReplyImageNotFound(name, err.Error()) - } - inspectInfo, err := newImage.Inspect(getContext()) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - b, err := json.Marshal(inspectInfo) - if err != nil { - return call.ReplyErrorOccurred(fmt.Sprintf("unable to serialize")) - } - return call.ReplyInspectImage(string(b)) -} - -// HistoryImage returns the history of the image's layers -// Requires an image or name -func (i *VarlinkAPI) HistoryImage(call iopodman.VarlinkCall, name string) error { - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - return call.ReplyImageNotFound(name, err.Error()) - } - history, err := newImage.History(getContext()) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - var histories []iopodman.ImageHistory - for _, hist := range history { - imageHistory := iopodman.ImageHistory{ - Id: hist.ID, - Created: hist.Created.Format(time.RFC3339), - CreatedBy: hist.CreatedBy, - Tags: newImage.Names(), - Size: hist.Size, - Comment: hist.Comment, - } - histories = append(histories, imageHistory) - } - return call.ReplyHistoryImage(histories) -} - -// PushImage pushes an local image to registry -func (i *VarlinkAPI) PushImage(call iopodman.VarlinkCall, name, tag string, compress bool, format string, removeSignatures bool, signBy string) error { - var ( - manifestType string - ) - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - return call.ReplyImageNotFound(name, err.Error()) - } - destname := name - if tag != "" { - destname = tag - } - dockerRegistryOptions := image.DockerRegistryOptions{} - 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, - } - - if call.WantsMore() { - call.Continues = true - } - - output := bytes.NewBuffer([]byte{}) - c := make(chan error) - go func() { - writer := bytes.NewBuffer([]byte{}) - err := newImage.PushImageToHeuristicDestination(getContext(), destname, manifestType, "", "", "", writer, compress, so, &dockerRegistryOptions, nil) - if err != nil { - c <- err - } - _, err = io.CopyBuffer(output, writer, nil) - c <- err - close(c) - }() - - // TODO When pull output gets fixed for the remote client, we need to look into how we can turn below - // into something re-usable. it is in build too - var log []string - done := false - for { - line, err := output.ReadString('\n') - if err == nil { - log = append(log, line) - continue - } else if err == io.EOF { - select { - case err := <-c: - if err != nil { - logrus.Errorf("reading of output during push failed for %s", newImage.ID()) - return call.ReplyErrorOccurred(err.Error()) - } - done = true - default: - if !call.WantsMore() { - break - } - br := iopodman.MoreResponse{ - Logs: log, - Id: newImage.ID(), - } - call.ReplyPushImage(br) - log = []string{} - } - } else { - return call.ReplyErrorOccurred(err.Error()) - } - if done { - break - } - } - call.Continues = false - - br := iopodman.MoreResponse{ - Logs: log, - Id: newImage.ID(), - } - return call.ReplyPushImage(br) -} - -// TagImage accepts an image name and tag as strings and tags an image in the local store. -func (i *VarlinkAPI) TagImage(call iopodman.VarlinkCall, name, tag string) error { - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - return call.ReplyImageNotFound(name, err.Error()) - } - if err := newImage.TagImage(tag); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyTagImage(newImage.ID()) -} - -// UntagImage accepts an image name and tag as strings and removes the tag from the local store. -func (i *VarlinkAPI) UntagImage(call iopodman.VarlinkCall, name, tag string) error { - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - return call.ReplyImageNotFound(name, err.Error()) - } - if err := newImage.UntagImage(tag); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyUntagImage(newImage.ID()) -} - -// 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 *VarlinkAPI) RemoveImage(call iopodman.VarlinkCall, name string, force bool) error { - ctx := getContext() - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - return call.ReplyImageNotFound(name, err.Error()) - } - _, err = i.Runtime.RemoveImage(ctx, newImage, force) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyRemoveImage(newImage.ID()) -} - -// RemoveImageWithResponse accepts an image name and force bool. It returns details about what -// was done in removeimageresponse struct. -func (i *VarlinkAPI) RemoveImageWithResponse(call iopodman.VarlinkCall, name string, force bool) error { - ir := iopodman.RemoveImageResponse{} - ctx := getContext() - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - return call.ReplyImageNotFound(name, err.Error()) - } - response, err := i.Runtime.RemoveImage(ctx, newImage, force) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - ir.Untagged = append(ir.Untagged, response.Untagged...) - ir.Deleted = response.Deleted - return call.ReplyRemoveImageWithResponse(ir) -} - -// SearchImages searches all registries configured in /etc/containers/registries.conf for an image -// Requires an image name and a search limit as int -func (i *VarlinkAPI) SearchImages(call iopodman.VarlinkCall, query string, limit *int64, filter iopodman.ImageSearchFilter) error { - // Transform all arguments to proper types first - argLimit := 0 - argIsOfficial := types.OptionalBoolUndefined - argIsAutomated := types.OptionalBoolUndefined - if limit != nil { - argLimit = int(*limit) - } - if filter.Is_official != nil { - argIsOfficial = types.NewOptionalBool(*filter.Is_official) - } - if filter.Is_automated != nil { - argIsAutomated = types.NewOptionalBool(*filter.Is_automated) - } - - // Transform a SearchFilter the backend can deal with - sFilter := image.SearchFilter{ - IsOfficial: argIsOfficial, - IsAutomated: argIsAutomated, - Stars: int(filter.Star_count), - } - - searchOptions := image.SearchOptions{ - Limit: argLimit, - Filter: sFilter, - } - results, err := image.SearchImages(query, searchOptions) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - var imageResults []iopodman.ImageSearchResult - for _, result := range results { - i := iopodman.ImageSearchResult{ - Registry: result.Index, - Description: result.Description, - Is_official: result.Official == "[OK]", - Is_automated: result.Automated == "[OK]", - Name: result.Name, - Star_count: int64(result.Stars), - } - imageResults = append(imageResults, i) - } - return call.ReplySearchImages(imageResults) -} - -// DeleteUnusedImages deletes any images that do not have containers associated with it. -// TODO Filters are not implemented -func (i *VarlinkAPI) DeleteUnusedImages(call iopodman.VarlinkCall) error { - images, err := i.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(context.TODO(), false); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - deletedImages = append(deletedImages, img.ID()) - } - } - return call.ReplyDeleteUnusedImages(deletedImages) -} - -// Commit ... -func (i *VarlinkAPI) Commit(call iopodman.VarlinkCall, name, imageName string, changes []string, author, message string, pause bool, manifestType string) error { - var ( - newImage *image.Image - log []string - mimeType string - ) - output := channel.NewWriter(make(chan []byte)) - channelClose := func() { - if err := output.Close(); err != nil { - logrus.Errorf("failed to close channel writer: %q", err) - } - } - defer channelClose() - - ctr, err := i.Runtime.LookupContainer(name) - if err != nil { - return call.ReplyContainerNotFound(name, err.Error()) - } - rtc, err := i.Runtime.GetConfig() - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false) - switch manifestType { - case "oci", "": // nolint - mimeType = buildah.OCIv1ImageManifest - case "docker": - mimeType = manifest.DockerV2Schema2MediaType - default: - return call.ReplyErrorOccurred(fmt.Sprintf("unrecognized image format %q", manifestType)) - } - coptions := buildah.CommitOptions{ - SignaturePolicyPath: rtc.Engine.SignaturePolicyPath, - ReportWriter: output, - SystemContext: sc, - PreferredManifestType: mimeType, - } - options := libpod.ContainerCommitOptions{ - CommitOptions: coptions, - Pause: pause, - Message: message, - Changes: changes, - Author: author, - } - - if call.WantsMore() { - call.Continues = true - } - - c := make(chan error) - - go func() { - newImage, err = ctr.Commit(getContext(), imageName, options) - if err != nil { - c <- err - } - c <- nil - close(c) - }() - - // reply is the func being sent to the output forwarder. in this case it is replying - // with a more response struct - reply := func(br iopodman.MoreResponse) error { - return call.ReplyCommit(br) - } - log, err = forwardOutput(log, c, call.WantsMore(), output, reply) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - call.Continues = false - br := iopodman.MoreResponse{ - Logs: log, - Id: newImage.ID(), - } - return call.ReplyCommit(br) -} - -// ImportImage imports an image from a tarball to the image store -func (i *VarlinkAPI) ImportImage(call iopodman.VarlinkCall, source, reference, message string, changes []string, delete bool) error { - configChanges, err := util.GetImageConfig(changes) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - history := []v1.History{ - {Comment: message}, - } - config := v1.Image{ - Config: configChanges.ImageConfig, - History: history, - } - newImage, err := i.Runtime.ImageRuntime().Import(getContext(), source, reference, nil, image.SigningOptions{}, config) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if delete { - if err := os.Remove(source); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - } - - return call.ReplyImportImage(newImage.ID()) -} - -// ExportImage exports an image to the provided destination -// destination must have the transport type!! -func (i *VarlinkAPI) ExportImage(call iopodman.VarlinkCall, name, destination string, compress bool, tags []string) error { - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - return call.ReplyImageNotFound(name, err.Error()) - } - - additionalTags, err := image.GetAdditionalTags(tags) - if err != nil { - return err - } - - if err := newImage.PushImageToHeuristicDestination(getContext(), destination, "", "", "", "", nil, compress, image.SigningOptions{}, &image.DockerRegistryOptions{}, additionalTags); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyExportImage(newImage.ID()) -} - -// PullImage pulls an image from a registry to the image store. -func (i *VarlinkAPI) PullImage(call iopodman.VarlinkCall, name string, creds iopodman.AuthConfig) error { - var ( - imageID string - err error - ) - dockerRegistryOptions := image.DockerRegistryOptions{ - DockerRegistryCreds: &types.DockerAuthConfig{ - Username: creds.Username, - Password: creds.Password, - }, - } - - so := image.SigningOptions{} - - if call.WantsMore() { - call.Continues = true - } - output := channel.NewWriter(make(chan []byte)) - channelClose := func() { - if err := output.Close(); err != nil { - logrus.Errorf("failed to close channel writer: %q", err) - } - } - defer channelClose() - c := make(chan error) - defer close(c) - - go func() { - var foundError bool - if strings.HasPrefix(name, dockerarchive.Transport.Name()+":") { - srcRef, err := alltransports.ParseImageName(name) - if err != nil { - c <- errors.Wrapf(err, "error parsing %q", name) - } - newImage, err := i.Runtime.ImageRuntime().LoadFromArchiveReference(getContext(), srcRef, "", output) - if err != nil { - foundError = true - c <- errors.Wrapf(err, "error pulling image from %q", name) - } else { - imageID = newImage[0].ID() - } - } else { - newImage, err := i.Runtime.ImageRuntime().New(getContext(), name, "", "", output, &dockerRegistryOptions, so, nil, util.PullImageMissing) - if err != nil { - foundError = true - c <- errors.Wrapf(err, "unable to pull %s", name) - } else { - imageID = newImage.ID() - } - } - if !foundError { - c <- nil - } - }() - - var log []string - reply := func(br iopodman.MoreResponse) error { - return call.ReplyPullImage(br) - } - log, err = forwardOutput(log, c, call.WantsMore(), output, reply) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - call.Continues = false - br := iopodman.MoreResponse{ - Logs: log, - Id: imageID, - } - return call.ReplyPullImage(br) -} - -// ImageExists returns bool as to whether the input image exists in local storage -func (i *VarlinkAPI) ImageExists(call iopodman.VarlinkCall, name string) error { - _, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if errors.Cause(err) == image.ErrNoSuchImage { - return call.ReplyImageExists(1) - } - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyImageExists(0) -} - -// ContainerRunlabel ... -func (i *VarlinkAPI) ContainerRunlabel(call iopodman.VarlinkCall, input iopodman.Runlabel) error { - ctx := getContext() - dockerRegistryOptions := image.DockerRegistryOptions{} - stdErr := os.Stderr - stdOut := os.Stdout - stdIn := os.Stdin - - runLabel, imageName, err := GetRunlabel(input.Label, input.Image, ctx, i.Runtime, input.Pull, "", dockerRegistryOptions, input.Authfile, "", nil) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if runLabel == "" { - return call.ReplyErrorOccurred(fmt.Sprintf("%s does not contain the label %s", input.Image, input.Label)) - } - - cmd, env, err := GenerateRunlabelCommand(runLabel, imageName, input.Name, input.Opts, input.ExtraArgs, "") - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if err := utils.ExecCmdWithStdStreams(stdIn, stdOut, stdErr, env, cmd[0], cmd[1:]...); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyContainerRunlabel() -} - -// ImagesPrune .... -func (i *VarlinkAPI) ImagesPrune(call iopodman.VarlinkCall, all bool, filter []string) error { - prunedImages, err := i.Runtime.ImageRuntime().PruneImages(context.TODO(), all, []string{}) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyImagesPrune(prunedImages) -} - -// ImageSave .... -func (i *VarlinkAPI) ImageSave(call iopodman.VarlinkCall, options iopodman.ImageSaveOptions) error { - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(options.Name) - if err != nil { - if errors.Cause(err) == define.ErrNoSuchImage { - return call.ReplyImageNotFound(options.Name, err.Error()) - } - return call.ReplyErrorOccurred(err.Error()) - } - - // Determine if we are dealing with a tarball or dir - var output string - outputToDir := false - if options.Format == "oci-archive" || options.Format == "docker-archive" { - tempfile, err := ioutil.TempFile("", "varlink_send") - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - output = tempfile.Name() - tempfile.Close() - } else { - var err error - outputToDir = true - output, err = ioutil.TempDir("", "varlink_send") - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - } - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if call.WantsMore() { - call.Continues = true - } - - saveOutput := bytes.NewBuffer([]byte{}) - c := make(chan error) - go func() { - err := newImage.Save(getContext(), options.Name, options.Format, output, options.MoreTags, options.Quiet, options.Compress, true) - c <- err - close(c) - }() - var log []string - done := false - for { - line, err := saveOutput.ReadString('\n') - if err == nil { - log = append(log, line) - continue - } else if err == io.EOF { - select { - case err := <-c: - if err != nil { - logrus.Errorf("reading of output during save failed for %s", newImage.ID()) - return call.ReplyErrorOccurred(err.Error()) - } - done = true - default: - if !call.WantsMore() { - break - } - br := iopodman.MoreResponse{ - Logs: log, - } - call.ReplyImageSave(br) - log = []string{} - } - } else { - return call.ReplyErrorOccurred(err.Error()) - } - if done { - break - } - } - call.Continues = false - - sendfile := output - // Image has been saved to `output` - if outputToDir { - // If the output is a directory, we need to tar up the directory to send it back - // Create a tempfile for the directory tarball - outputFile, err := ioutil.TempFile("", "varlink_save_dir") - if err != nil { - return err - } - defer outputFile.Close() - if err := utils.TarToFilesystem(output, outputFile); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - sendfile = outputFile.Name() - } - br := iopodman.MoreResponse{ - Logs: log, - Id: sendfile, - } - return call.ReplyPushImage(br) -} - -// LoadImage ... -func (i *VarlinkAPI) LoadImage(call iopodman.VarlinkCall, name, inputFile string, deleteInputFile, quiet bool) error { - var ( - names string - writer io.Writer - err error - ) - if !quiet { - writer = os.Stderr - } - - if call.WantsMore() { - call.Continues = true - } - output := bytes.NewBuffer([]byte{}) - - c := make(chan error) - go func() { - names, err = i.Runtime.LoadImage(getContext(), name, inputFile, writer, "") - c <- err - close(c) - }() - - var log []string - done := false - for { - line, err := output.ReadString('\n') - if err == nil { - log = append(log, line) - continue - } else if err == io.EOF { - select { - case err := <-c: - if err != nil { - logrus.Error(err) - return call.ReplyErrorOccurred(err.Error()) - } - done = true - default: - if !call.WantsMore() { - break - } - br := iopodman.MoreResponse{ - Logs: log, - } - call.ReplyLoadImage(br) - log = []string{} - } - } else { - return call.ReplyErrorOccurred(err.Error()) - } - if done { - break - } - } - call.Continues = false - - br := iopodman.MoreResponse{ - Logs: log, - Id: names, - } - if deleteInputFile { - if err := os.Remove(inputFile); err != nil { - logrus.Errorf("unable to delete input file %s", inputFile) - } - } - return call.ReplyLoadImage(br) -} - -// Diff ... -func (i *VarlinkAPI) Diff(call iopodman.VarlinkCall, name string) error { - var response []iopodman.DiffInfo - changes, err := i.Runtime.GetDiff("", name) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - for _, change := range changes { - response = append(response, iopodman.DiffInfo{Path: change.Path, ChangeType: change.Kind.String()}) - } - return call.ReplyDiff(response) -} - -// GetLayersMapWithImageInfo is a development only endpoint to obtain layer information for an image. -func (i *VarlinkAPI) GetLayersMapWithImageInfo(call iopodman.VarlinkCall) error { - layerInfo, err := image.GetLayersMapWithImageInfo(i.Runtime.ImageRuntime()) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - b, err := json.Marshal(layerInfo) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyGetLayersMapWithImageInfo(string(b)) -} - -// BuildImageHierarchyMap ... -func (i *VarlinkAPI) BuildImageHierarchyMap(call iopodman.VarlinkCall, name string) error { - img, err := i.Runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - imageInfo := &image.InfoImage{ - ID: img.ID(), - Tags: img.Names(), - } - layerInfo, err := image.GetLayersMapWithImageInfo(i.Runtime.ImageRuntime()) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - if err := image.BuildImageHierarchyMap(imageInfo, layerInfo, img.TopLayer()); err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - b, err := json.Marshal(imageInfo) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyBuildImageHierarchyMap(string(b)) -} - -// ImageTree returns the image tree string for the provided image name or ID -func (i *VarlinkAPI) ImageTree(call iopodman.VarlinkCall, nameOrID string, whatRequires bool) error { - img, err := i.Runtime.ImageRuntime().NewFromLocal(nameOrID) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - - tree, err := img.GenerateTree(whatRequires) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } - return call.ReplyImageTree(tree) -} |