diff options
author | Brent Baude <bbaude@redhat.com> | 2020-05-21 13:58:51 -0500 |
---|---|---|
committer | Brent Baude <bbaude@redhat.com> | 2020-05-21 14:22:11 -0500 |
commit | 845a795a7a1666fb8af2abc6ce93c7152f06a9b9 (patch) | |
tree | 781967bb1056e841ab2533b78958330193aa8d0a | |
parent | 9d3b46624b4eb3b6eeea38b5b1057914a9ff2baf (diff) | |
download | podman-845a795a7a1666fb8af2abc6ce93c7152f06a9b9.tar.gz podman-845a795a7a1666fb8af2abc6ce93c7152f06a9b9.tar.bz2 podman-845a795a7a1666fb8af2abc6ce93c7152f06a9b9.zip |
v2 podman-remote build
this is a very basic implementation of build. some of the more advanced options need to be included still as well. i think the endpoints for compat and libpod will have to split given buildahs more advanced set of options. that should probably be done by someone more experienced with build internals.
Signed-off-by: Brent Baude <bbaude@redhat.com>
-rw-r--r-- | pkg/api/handlers/compat/images_build.go | 1 | ||||
-rw-r--r-- | pkg/api/server/register_images.go | 209 | ||||
-rw-r--r-- | pkg/bindings/images/images.go | 107 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/images.go | 11 |
4 files changed, 326 insertions, 2 deletions
diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go index e208e6ddc..e9d8fd719 100644 --- a/pkg/api/handlers/compat/images_build.go +++ b/pkg/api/handlers/compat/images_build.go @@ -226,6 +226,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { id, _, err := runtime.Build(r.Context(), buildOptions, query.Dockerfile) if err != nil { utils.InternalServerError(w, err) + return } // Find image ID that was built... diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index 01854b9c4..c885dc81a 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -1188,5 +1188,214 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/libpod/images/{name}/changes"), s.APIHandler(compat.Changes)).Methods(http.MethodGet) + // swagger:operation POST /libpod/build libpod libpodBuildImage + // --- + // tags: + // - images + // summary: Create image + // description: Build an image from the given Dockerfile(s) + // parameters: + // - in: query + // name: dockerfile + // type: string + // default: Dockerfile + // description: | + // Path within the build context to the `Dockerfile`. + // This is ignored if remote is specified and points to an external `Dockerfile`. + // - in: query + // name: t + // type: string + // default: latest + // description: A name and optional tag to apply to the image in the `name:tag` format. + // - in: query + // name: extrahosts + // type: string + // default: + // description: | + // TBD Extra hosts to add to /etc/hosts + // (As of version 1.xx) + // - in: query + // name: remote + // type: string + // default: + // description: | + // A Git repository URI or HTTP/HTTPS context URI. + // If the URI points to a single text file, the file’s contents are placed + // into a file called Dockerfile and the image is built from that file. If + // the URI points to a tarball, the file is downloaded by the daemon and the + // contents therein used as the context for the build. If the URI points to a + // tarball and the dockerfile parameter is also specified, there must be a file + // with the corresponding path inside the tarball. + // (As of version 1.xx) + // - in: query + // name: q + // type: boolean + // default: false + // description: | + // Suppress verbose build output + // - in: query + // name: nocache + // type: boolean + // default: false + // description: | + // Do not use the cache when building the image + // (As of version 1.xx) + // - in: query + // name: cachefrom + // type: string + // default: + // description: | + // JSON array of images used to build cache resolution + // (As of version 1.xx) + // - in: query + // name: pull + // type: boolean + // default: false + // description: | + // Attempt to pull the image even if an older image exists locally + // (As of version 1.xx) + // - in: query + // name: rm + // type: boolean + // default: true + // description: | + // Remove intermediate containers after a successful build + // (As of version 1.xx) + // - in: query + // name: forcerm + // type: boolean + // default: false + // description: | + // Always remove intermediate containers, even upon failure + // (As of version 1.xx) + // - in: query + // name: memory + // type: integer + // description: | + // Memory is the upper limit (in bytes) on how much memory running containers can use + // (As of version 1.xx) + // - in: query + // name: memswap + // type: integer + // description: | + // MemorySwap limits the amount of memory and swap together + // (As of version 1.xx) + // - in: query + // name: cpushares + // type: integer + // description: | + // CPUShares (relative weight + // (As of version 1.xx) + // - in: query + // name: cpusetcpus + // type: string + // description: | + // CPUSetCPUs in which to allow execution (0-3, 0,1) + // (As of version 1.xx) + // - in: query + // name: cpuperiod + // type: integer + // description: | + // CPUPeriod limits the CPU CFS (Completely Fair Scheduler) period + // (As of version 1.xx) + // - in: query + // name: cpuquota + // type: integer + // description: | + // CPUQuota limits the CPU CFS (Completely Fair Scheduler) quota + // (As of version 1.xx) + // - in: query + // name: buildargs + // type: string + // default: + // description: | + // JSON map of string pairs denoting build-time variables. + // For example, the build argument `Foo` with the value of `bar` would be encoded in JSON as `["Foo":"bar"]`. + // + // For example, buildargs={"Foo":"bar"}. + // + // Note(s): + // * This should not be used to pass secrets. + // * The value of buildargs should be URI component encoded before being passed to the API. + // + // (As of version 1.xx) + // - in: query + // name: shmsize + // type: integer + // default: 67108864 + // description: | + // ShmSize is the "size" value to use when mounting an shmfs on the container's /dev/shm directory. + // Default is 64MB + // (As of version 1.xx) + // - in: query + // name: squash + // type: boolean + // default: false + // description: | + // Silently ignored. + // Squash the resulting images layers into a single layer + // (As of version 1.xx) + // - in: query + // name: labels + // type: string + // default: + // description: | + // JSON map of key, value pairs to set as labels on the new image + // (As of version 1.xx) + // - in: query + // name: networkmode + // type: string + // default: bridge + // description: | + // Sets the networking mode for the run commands during build. + // Supported standard values are: + // * `bridge` limited to containers within a single host, port mapping required for external access + // * `host` no isolation between host and containers on this network + // * `none` disable all networking for this container + // * container:<nameOrID> share networking with given container + // ---All other values are assumed to be a custom network's name + // (As of version 1.xx) + // - in: query + // name: platform + // type: string + // default: + // description: | + // Platform format os[/arch[/variant]] + // (As of version 1.xx) + // - in: query + // name: target + // type: string + // default: + // description: | + // Target build stage + // (As of version 1.xx) + // - in: query + // name: outputs + // type: string + // default: + // description: | + // output configuration TBD + // (As of version 1.xx) + // produces: + // - application/json + // responses: + // 200: + // description: OK (As of version 1.xx) + // schema: + // type: object + // required: + // - stream + // properties: + // stream: + // type: string + // description: output from build process + // example: | + // (build details...) + // Successfully built 8ba084515c724cbf90d447a63600c0a6 + // 400: + // $ref: "#/responses/BadParamError" + // 500: + // $ref: "#/responses/InternalError" + r.Handle(VersionedPath("/libpod/build"), s.APIHandler(compat.BuildImage)).Methods(http.MethodPost) return nil } diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go index 69b9e9bbf..f9c02d199 100644 --- a/pkg/bindings/images/images.go +++ b/pkg/bindings/images/images.go @@ -1,6 +1,7 @@ package images import ( + "bytes" "context" "fmt" "io" @@ -8,10 +9,13 @@ import ( "net/url" "strconv" + "github.com/containers/buildah" "github.com/containers/image/v5/types" "github.com/containers/libpod/pkg/api/handlers" "github.com/containers/libpod/pkg/bindings" "github.com/containers/libpod/pkg/domain/entities" + "github.com/docker/go-units" + jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" ) @@ -209,7 +213,108 @@ func Untag(ctx context.Context, nameOrID, tag, repo string) error { return response.Process(nil) } -func Build(nameOrId string) {} +// Build creates an image using a containerfile reference +func Build(ctx context.Context, containerFiles []string, options entities.BuildOptions, tarfile io.Reader) (*entities.BuildReport, error) { + var ( + platform string + report entities.BuildReport + ) + conn, err := bindings.GetClient(ctx) + if err != nil { + return nil, err + } + params := url.Values{} + params.Set("dockerfile", containerFiles[0]) + if t := options.Output; len(t) > 0 { + params.Set("t", t) + } + // TODO Remote, Quiet + if options.NoCache { + params.Set("nocache", "1") + } + // TODO cachefrom + if options.PullPolicy == buildah.PullAlways { + params.Set("pull", "1") + } + if options.RemoveIntermediateCtrs { + params.Set("rm", "1") + } + if options.ForceRmIntermediateCtrs { + params.Set("forcerm", "1") + } + if mem := options.CommonBuildOpts.Memory; mem > 0 { + params.Set("memory", strconv.Itoa(int(mem))) + } + if memSwap := options.CommonBuildOpts.MemorySwap; memSwap > 0 { + params.Set("memswap", strconv.Itoa(int(memSwap))) + } + if cpuShares := options.CommonBuildOpts.CPUShares; cpuShares > 0 { + params.Set("cpushares", strconv.Itoa(int(cpuShares))) + } + if cpuSetCpus := options.CommonBuildOpts.CPUSetCPUs; len(cpuSetCpus) > 0 { + params.Set("cpusetcpues", cpuSetCpus) + } + if cpuPeriod := options.CommonBuildOpts.CPUPeriod; cpuPeriod > 0 { + params.Set("cpuperiod", strconv.Itoa(int(cpuPeriod))) + } + if cpuQuota := options.CommonBuildOpts.CPUQuota; cpuQuota > 0 { + params.Set("cpuquota", strconv.Itoa(int(cpuQuota))) + } + if buildArgs := options.Args; len(buildArgs) > 0 { + bArgs, err := jsoniter.MarshalToString(buildArgs) + if err != nil { + return nil, err + } + params.Set("buildargs", bArgs) + } + if shmSize := options.CommonBuildOpts.ShmSize; len(shmSize) > 0 { + shmBytes, err := units.RAMInBytes(shmSize) + if err != nil { + return nil, err + } + params.Set("shmsize", strconv.Itoa(int(shmBytes))) + } + if options.Squash { + params.Set("squash", "1") + } + if labels := options.Labels; len(labels) > 0 { + l, err := jsoniter.MarshalToString(labels) + if err != nil { + return nil, err + } + params.Set("labels", l) + } + + // TODO network? + if OS := options.OS; len(OS) > 0 { + platform += OS + } + if arch := options.Architecture; len(arch) > 0 { + platform += "/" + arch + } + if len(platform) > 0 { + params.Set("platform", platform) + } + // TODO outputs? + + response, err := conn.DoRequest(tarfile, http.MethodPost, "/build", params) + if err != nil { + return nil, err + } + var streamReponse []byte + bb := bytes.NewBuffer(streamReponse) + if _, err = io.Copy(bb, response.Body); err != nil { + return nil, err + } + var s struct { + Stream string `json:"stream"` + } + if err := jsoniter.UnmarshalFromString(bb.String(), &s); err != nil { + return nil, err + } + fmt.Print(s.Stream) + return &report, nil +} // Imports adds the given image to the local image store. This can be done by file and the given reader // or via the url parameter. Additional metadata can be associated with the image by using the changes and diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index 3d5626c45..c300e74d0 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -4,6 +4,7 @@ import ( "context" "io/ioutil" "os" + "path" "strings" "github.com/containers/common/pkg/config" @@ -13,6 +14,7 @@ import ( "github.com/containers/libpod/pkg/domain/entities" "github.com/containers/libpod/pkg/domain/utils" utils2 "github.com/containers/libpod/utils" + "github.com/containers/storage/pkg/archive" "github.com/pkg/errors" ) @@ -265,7 +267,14 @@ func (ir *ImageEngine) Config(_ context.Context) (*config.Config, error) { } func (ir *ImageEngine) Build(ctx context.Context, containerFiles []string, opts entities.BuildOptions) (*entities.BuildReport, error) { - return nil, errors.New("not implemented yet") + if len(containerFiles) > 1 { + return nil, errors.New("something") + } + tarfile, err := archive.Tar(path.Base(containerFiles[0]), 0) + if err != nil { + return nil, err + } + return images.Build(ir.ClientCxt, containerFiles, opts, tarfile) } func (ir *ImageEngine) Tree(ctx context.Context, nameOrId string, opts entities.ImageTreeOptions) (*entities.ImageTreeReport, error) { |