From 8e2595e8a8dedae88d34febd7f10a35490253b0f Mon Sep 17 00:00:00 2001 From: Arjun Raja Yogidas Date: Mon, 27 Jan 2025 06:39:27 +0000 Subject: [PATCH] feat: add additional options to image build Signed-off-by: Arjun Raja Yogidas --- api/handlers/builder/build.go | 47 ++++++++++++++++++----- api/handlers/builder/build_test.go | 61 ++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 9 deletions(-) diff --git a/api/handlers/builder/build.go b/api/handlers/builder/build.go index e624ec12..480f28c9 100644 --- a/api/handlers/builder/build.go +++ b/api/handlers/builder/build.go @@ -53,6 +53,22 @@ func (h *handler) getBuildOptions(w http.ResponseWriter, r *http.Request, stream h.logger.Warnf("Failed to get buildkit host: %v", err.Error()) return nil, err } + + buildArgs, err := getQueryParamMap(r, "buildargs", []string{}) + if err != nil { + return nil, fmt.Errorf("unable to parse buildargs query: %s", err) + } + + labels, err := getQueryParamMap(r, "labels", []string{}) + if err != nil { + return nil, fmt.Errorf("unable to parse labels query: %s", err) + } + + cacheFrom, err := getQueryParamMap(r, "cachefrom", []string{}) + if err != nil { + return nil, fmt.Errorf("unable to parse cacheFrom query: %s", err) + } + options := types.BuilderBuildOptions{ // TODO: investigate - interestingly nerdctl prints all the build log in stderr for some reason. Stdout: stream, @@ -73,17 +89,15 @@ func (h *handler) getBuildOptions(w http.ResponseWriter, r *http.Request, stream Platform: getQueryParamList(r, "platform", []string{}), Rm: getQueryParamBool(r, "rm", true), Progress: "auto", + Quiet: getQueryParamBool(r, "q", true), + NoCache: getQueryParamBool(r, "nocache", false), + CacheFrom: cacheFrom, + BuildArgs: buildArgs, + Label: labels, + NetworkMode: getQueryParamStr(r, "networkmode", ""), + Output: getQueryParamStr(r, "output", ""), } - argsQuery := r.URL.Query().Get("buildargs") - if argsQuery != "" { - buildargs := make(map[string]string) - err := json.Unmarshal([]byte(argsQuery), &buildargs) - if err != nil { - return nil, fmt.Errorf("unable to parse buildargs query: %s", err) - } - options.BuildArgs = maputility.Flatten(buildargs, maputility.KeyEqualsValueFormat) - } return &options, nil } @@ -117,3 +131,18 @@ func getQueryParamList(r *http.Request, paramName string, defaultValue []string) } return params[paramName] } + +func getQueryParamMap(r *http.Request, paramName string, defaultValue []string) ([]string, error) { + query := r.URL.Query().Get(paramName) + if query == "" { + return defaultValue, nil + } + + var parsedMap map[string]string + err := json.Unmarshal([]byte(query), &parsedMap) + if err != nil { + return nil, fmt.Errorf("unable to parse %s query: %s", paramName, err) + } + + return maputility.Flatten(parsedMap, maputility.KeyEqualsValueFormat), nil +} diff --git a/api/handlers/builder/build_test.go b/api/handlers/builder/build_test.go index 2ab80003..b4ba07ab 100644 --- a/api/handlers/builder/build_test.go +++ b/api/handlers/builder/build_test.go @@ -153,6 +153,60 @@ var _ = Describe("Build API", func() { Expect(err).Should(BeNil()) Expect(buildOption.Rm).Should(BeTrue()) }) + It("should set the q query param", func() { + ncBuildSvc.EXPECT().GetBuildkitHost().Return("mocked-value", nil).AnyTimes() + req = httptest.NewRequest(http.MethodPost, "/build?q=false", nil) + buildOption, err := h.getBuildOptions(rr, req, stream) + Expect(err).Should(BeNil()) + Expect(buildOption.Quiet).Should(BeFalse()) + }) + It("should set the nocache query param", func() { + ncBuildSvc.EXPECT().GetBuildkitHost().Return("mocked-value", nil).AnyTimes() + req = httptest.NewRequest(http.MethodPost, "/build?nocache=true", nil) + buildOption, err := h.getBuildOptions(rr, req, stream) + Expect(err).Should(BeNil()) + Expect(buildOption.NoCache).Should(BeTrue()) + }) + It("should set the CacheFrom query param", func() { + ncBuildSvc.EXPECT().GetBuildkitHost().Return("mocked-value", nil).AnyTimes() + req = httptest.NewRequest(http.MethodPost, "/build?cachefrom={\"image1\":\"tag1\",\"image2\":\"tag2\"}", nil) + buildOption, err := h.getBuildOptions(rr, req, stream) + Expect(err).Should(BeNil()) + Expect(buildOption.CacheFrom).Should(ContainElements("image1=tag1", "image2=tag2")) + }) + + It("should set the BuildArgs query param", func() { + ncBuildSvc.EXPECT().GetBuildkitHost().Return("mocked-value", nil).AnyTimes() + req = httptest.NewRequest(http.MethodPost, "/build?buildargs={\"ARG1\":\"value1\",\"ARG2\":\"value2\"}", nil) + buildOption, err := h.getBuildOptions(rr, req, stream) + Expect(err).Should(BeNil()) + Expect(buildOption.BuildArgs).Should(ContainElements("ARG1=value1", "ARG2=value2")) + }) + + It("should set the Label query param", func() { + ncBuildSvc.EXPECT().GetBuildkitHost().Return("mocked-value", nil).AnyTimes() + req = httptest.NewRequest(http.MethodPost, "/build?labels={\"LABEL1\":\"value1\",\"LABEL2\":\"value2\"}", nil) + buildOption, err := h.getBuildOptions(rr, req, stream) + Expect(err).Should(BeNil()) + Expect(buildOption.Label).Should(ContainElements("LABEL1=value1", "LABEL2=value2")) + }) + + It("should set the NetworkMode query param", func() { + ncBuildSvc.EXPECT().GetBuildkitHost().Return("mocked-value", nil).AnyTimes() + req = httptest.NewRequest(http.MethodPost, "/build?networkmode=host", nil) + buildOption, err := h.getBuildOptions(rr, req, stream) + Expect(err).Should(BeNil()) + Expect(buildOption.NetworkMode).Should(Equal("host")) + }) + + It("should set the Output query param", func() { + ncBuildSvc.EXPECT().GetBuildkitHost().Return("mocked-value", nil).AnyTimes() + req = httptest.NewRequest(http.MethodPost, "/build?output=type=docker", nil) + buildOption, err := h.getBuildOptions(rr, req, stream) + Expect(err).Should(BeNil()) + Expect(buildOption.Output).Should(Equal("type=docker")) + }) + It("should set all the default value for the query param", func() { ncBuildSvc.EXPECT().GetBuildkitHost().Return("mocked-value", nil).AnyTimes() req = httptest.NewRequest(http.MethodPost, "/build", nil) @@ -162,6 +216,13 @@ var _ = Describe("Build API", func() { Expect(buildOption.Platform).Should(HaveLen(0)) Expect(buildOption.File).Should(Equal("Dockerfile")) Expect(buildOption.Rm).Should(BeTrue()) + Expect(buildOption.Quiet).Should(BeTrue()) + Expect(buildOption.NoCache).Should(BeFalse()) + Expect(buildOption.CacheFrom).Should(BeEmpty()) + Expect(buildOption.BuildArgs).Should(BeEmpty()) + Expect(buildOption.Label).Should(BeEmpty()) + Expect(buildOption.NetworkMode).Should(BeEmpty()) + Expect(buildOption.Output).Should(BeEmpty()) }) }) })