diff options
Diffstat (limited to 'pkg/varlinkapi/images.go')
-rw-r--r-- | pkg/varlinkapi/images.go | 282 |
1 files changed, 160 insertions, 122 deletions
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go index 5e0889645..534419f6f 100644 --- a/pkg/varlinkapi/images.go +++ b/pkg/varlinkapi/images.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "io" + "io/ioutil" "os" "path/filepath" "strings" @@ -24,10 +25,11 @@ import ( sysreg "github.com/containers/libpod/pkg/registries" "github.com/containers/libpod/pkg/util" "github.com/containers/libpod/utils" - "github.com/docker/go-units" + "github.com/containers/storage/pkg/archive" "github.com/opencontainers/image-spec/specs-go/v1" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) // ListImages lists all the images in the store @@ -37,7 +39,7 @@ func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error { if err != nil { return call.ReplyErrorOccurred(fmt.Sprintf("unable to get list of images %q", err)) } - var imageList []iopodman.ImageInList + var imageList []iopodman.Image for _, image := range images { labels, _ := image.Labels(getContext()) containers, _ := image.Containers() @@ -52,12 +54,12 @@ func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error { return call.ReplyErrorOccurred(err.Error()) } - i := iopodman.ImageInList{ + i := iopodman.Image{ Id: image.ID(), ParentId: image.Parent, RepoTags: image.Names(), RepoDigests: repoDigests, - Created: image.Created().String(), + Created: image.Created().Format(time.RFC3339), Size: int64(*size), VirtualSize: image.VirtualSize, Containers: int64(len(containers)), @@ -69,11 +71,11 @@ func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error { return call.ReplyListImages(imageList) } -// GetImage returns a single image in the form of a ImageInList -func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, name string) error { - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) +// GetImage returns a single image in the form of a Image +func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, id string) error { + newImage, err := i.Runtime.ImageRuntime().NewFromLocal(id) if err != nil { - return call.ReplyImageNotFound(err.Error()) + return call.ReplyImageNotFound(id) } labels, err := newImage.Labels(getContext()) if err != nil { @@ -92,12 +94,12 @@ func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, name string) error { return err } - il := iopodman.ImageInList{ + il := iopodman.Image{ Id: newImage.ID(), ParentId: newImage.Parent, RepoTags: newImage.Names(), RepoDigests: repoDigests, - Created: newImage.Created().String(), + Created: newImage.Created().Format(time.RFC3339), Size: int64(*size), VirtualSize: newImage.VirtualSize, Containers: int64(len(containers)), @@ -109,83 +111,46 @@ func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, name string) error { // BuildImage ... func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildInfo) error { var ( - memoryLimit int64 - memorySwap int64 - namespace []buildah.NamespaceOption - err error + namespace []buildah.NamespaceOption + err error ) systemContext := types.SystemContext{} - dockerfiles := config.Dockerfile - contextDir := "" - - for i := range dockerfiles { - if strings.HasPrefix(dockerfiles[i], "http://") || - strings.HasPrefix(dockerfiles[i], "https://") || - strings.HasPrefix(dockerfiles[i], "git://") || - strings.HasPrefix(dockerfiles[i], "github.com/") { - continue - } - absFile, err := filepath.Abs(dockerfiles[i]) - if err != nil { - return errors.Wrapf(err, "error determining path to file %q", dockerfiles[i]) - } - contextDir = filepath.Dir(absFile) - dockerfiles[i], err = filepath.Rel(contextDir, absFile) - if err != nil { - return errors.Wrapf(err, "error determining path to file %q", dockerfiles[i]) - } - break - } + contextDir := config.ContextDir - pullPolicy := imagebuildah.PullNever - if config.Pull { - pullPolicy = imagebuildah.PullIfMissing - } - - if config.Pull_always { - pullPolicy = imagebuildah.PullAlways - } - manifestType := "oci" //nolint - if config.Image_format != "" { - manifestType = config.Image_format - } - - if strings.HasPrefix(manifestType, "oci") { - manifestType = buildah.OCIv1ImageManifest - } else if strings.HasPrefix(manifestType, "docker") { - manifestType = buildah.Dockerv2ImageManifest - } else { - return call.ReplyErrorOccurred(fmt.Sprintf("unrecognized image type %q", manifestType)) + newContextDir, err := ioutil.TempDir("", "buildTarball") + if err != nil { + call.ReplyErrorOccurred("unable to create tempdir") } + logrus.Debugf("created new context dir at %s", newContextDir) - if config.Memory != "" { - memoryLimit, err = units.RAMInBytes(config.Memory) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } + reader, err := os.Open(contextDir) + if err != nil { + logrus.Errorf("failed to open the context dir tar file %s", contextDir) + return call.ReplyErrorOccurred(fmt.Sprintf("unable to open context dir tar file %s", contextDir)) } - - if config.Memory_swap != "" { - memorySwap, err = units.RAMInBytes(config.Memory_swap) - if err != nil { - return call.ReplyErrorOccurred(err.Error()) - } + 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) + // All output (stdout, stderr) is captured in output as well output := bytes.NewBuffer([]byte{}) + commonOpts := &buildah.CommonBuildOptions{ - AddHost: config.Add_hosts, - CgroupParent: config.Cgroup_parent, - CPUPeriod: uint64(config.Cpu_period), - CPUQuota: config.Cpu_quota, - CPUSetCPUs: config.Cpuset_cpus, - CPUSetMems: config.Cpuset_mems, - Memory: memoryLimit, - MemorySwap: memorySwap, - ShmSize: config.Shm_size, - Ulimit: config.Ulimit, - Volumes: config.Volume, + 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, } hostNetwork := buildah.NamespaceOption{ @@ -196,37 +161,68 @@ func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildI namespace = append(namespace, hostNetwork) options := imagebuildah.BuildOptions{ - ContextDirectory: contextDir, - PullPolicy: pullPolicy, - Compression: imagebuildah.Gzip, - Quiet: false, - //SignaturePolicyPath: - Args: config.Build_args, - //Output: - AdditionalTags: config.Tags, - //Runtime: runtime. - //RuntimeArgs: , - OutputFormat: manifestType, - SystemContext: &systemContext, - CommonBuildOpts: commonOpts, - Squash: config.Squash, - Labels: config.Label, - Annotations: config.Annotations, - ReportWriter: output, - NamespaceOptions: namespace, + CommonBuildOpts: commonOpts, + AdditionalTags: config.AdditionalTags, + Annotations: config.Annotations, + Args: config.BuildArgs, + CNIConfigDir: config.CniConfigDir, + CNIPluginPath: config.CniPluginDir, + Compression: stringCompressionToArchiveType(config.Compression), + ContextDirectory: newContextDir, + DefaultMountsFilePath: config.DefaultsMountFilePath, + Err: output, + ForceRmIntermediateCtrs: config.ForceRmIntermediateCtrs, + IIDFile: config.Iidfile, + Labels: config.Label, + Layers: config.Layers, + NoCache: config.Nocache, + Out: output, + Output: config.Output, + NamespaceOptions: namespace, + OutputFormat: config.OutputFormat, + PullPolicy: stringPullPolicyToType(config.PullPolicy), + Quiet: config.Quiet, + RemoveIntermediateCtrs: config.RemoteIntermediateCtrs, + ReportWriter: output, + RuntimeArgs: config.RuntimeArgs, + SignaturePolicyPath: config.SignaturePolicyPath, + Squash: config.Squash, + SystemContext: &systemContext, } if call.WantsMore() { call.Continues = true } - c := build(i.Runtime, options, config.Dockerfile) + 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 := build(i.Runtime, options, newPathDockerFiles) var log []string done := false for { - line, err := output.ReadString('\n') + outputLine, err := output.ReadString('\n') if err == nil { - log = append(log, line) + 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 { @@ -236,15 +232,10 @@ func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildI } done = true default: - if !call.WantsMore() { + if call.WantsMore() { time.Sleep(1 * time.Second) break } - br := iopodman.BuildResponse{ - Logs: log, - } - call.ReplyBuildImage(br) - log = []string{} } } else { return call.ReplyErrorOccurred(err.Error()) @@ -254,11 +245,12 @@ func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildI } } call.Continues = false - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(config.Tags[0]) + + newImage, err := i.Runtime.ImageRuntime().NewFromLocal(config.Output) if err != nil { return call.ReplyErrorOccurred(err.Error()) } - br := iopodman.BuildResponse{ + br := iopodman.MoreResponse{ Logs: log, Id: newImage.ID(), } @@ -276,12 +268,6 @@ func build(runtime *libpod.Runtime, options imagebuildah.BuildOptions, dockerfil return c } -// CreateImage ... -// TODO With Pull being added, should we skip Create? -func (i *LibpodAPI) CreateImage(call iopodman.VarlinkCall) error { - return call.ReplyMethodNotImplemented("CreateImage") -} - // 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 iopodman.VarlinkCall, name string) error { @@ -315,7 +301,7 @@ func (i *LibpodAPI) HistoryImage(call iopodman.VarlinkCall, name string) error { for _, hist := range history { imageHistory := iopodman.ImageHistory{ Id: hist.ID, - Created: hist.Created.String(), + Created: hist.Created.Format(time.RFC3339), CreatedBy: hist.CreatedBy, Tags: newImage.Names(), Size: hist.Size, @@ -332,7 +318,6 @@ func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, tlsVe registryCreds *types.DockerAuthConfig manifestType string ) - newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) if err != nil { return call.ReplyImageNotFound(err.Error()) @@ -372,10 +357,59 @@ func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, tlsVe SignBy: signBy, } - if err := newImage.PushImageToHeuristicDestination(getContext(), destname, manifestType, "", signaturePolicy, nil, compress, so, &dockerRegistryOptions, nil); err != nil { - return call.ReplyErrorOccurred(err.Error()) + if call.WantsMore() { + call.Continues = true + } + + output := bytes.NewBuffer([]byte{}) + c := make(chan error) + go func() { + err := newImage.PushImageToHeuristicDestination(getContext(), destname, manifestType, "", signaturePolicy, output, compress, so, &dockerRegistryOptions, 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() { + time.Sleep(1 * time.Second) + break + } + br := iopodman.MoreResponse{ + Logs: log, + } + call.ReplyPushImage(br) + log = []string{} + } + } else { + return call.ReplyErrorOccurred(err.Error()) + } + if done { + break + } } - return call.ReplyPushImage(newImage.ID()) + call.Continues = false + + br := iopodman.MoreResponse{ + Logs: log, + } + return call.ReplyPushImage(br) } // TagImage accepts an image name and tag as strings and tags an image in the local store. @@ -405,17 +439,21 @@ func (i *LibpodAPI) RemoveImage(call iopodman.VarlinkCall, name string, force bo return call.ReplyRemoveImage(newImage.ID()) } -// SearchImage searches all registries configured in /etc/containers/registries.conf for an image +// 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 *LibpodAPI) SearchImage(call iopodman.VarlinkCall, name string, limit int64) error { +func (i *LibpodAPI) SearchImages(call iopodman.VarlinkCall, query 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 []iopodman.ImageSearch + var imageResults []iopodman.ImageSearchResult for _, reg := range registries { - results, err := docker.SearchRegistry(getContext(), sc, reg, name, int(limit)) + var lim = 1000 + if limit != nil { + lim = int(*limit) + } + results, err := docker.SearchRegistry(getContext(), sc, reg, query, lim) if err != nil { // If we are searching multiple registries, don't make something like an // auth error fatal. Unfortunately we cannot differentiate between auth @@ -426,7 +464,7 @@ func (i *LibpodAPI) SearchImage(call iopodman.VarlinkCall, name string, limit in return call.ReplyErrorOccurred(err.Error()) } for _, result := range results { - i := iopodman.ImageSearch{ + i := iopodman.ImageSearchResult{ Description: result.Description, Is_official: result.IsOfficial, Is_automated: result.IsAutomated, @@ -436,7 +474,7 @@ func (i *LibpodAPI) SearchImage(call iopodman.VarlinkCall, name string, limit in imageResults = append(imageResults, i) } } - return call.ReplySearchImage(imageResults) + return call.ReplySearchImages(imageResults) } // DeleteUnusedImages deletes any images that do not have containers associated with it. |