From 0f58353b5625520beab1aa75ae4b74e04bcb94f0 Mon Sep 17 00:00:00 2001 From: Ilya Lesikov Date: Fri, 15 Oct 2021 14:03:15 +0300 Subject: [PATCH 1/7] tests(integration): provide internal local registry address --- .../container_registry_per_implementation_data.go | 2 +- integration/pkg/utils/docker/docker_registry.go | 13 +++++++++---- .../build/stapel_image/base_image/suite_test.go | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/integration/pkg/suite_init/container_registry_per_implementation_data.go b/integration/pkg/suite_init/container_registry_per_implementation_data.go index d7099d7365..819eed7585 100644 --- a/integration/pkg/suite_init/container_registry_per_implementation_data.go +++ b/integration/pkg/suite_init/container_registry_per_implementation_data.go @@ -122,7 +122,7 @@ func NewContainerRegistryPerImplementationData(synchronizedSuiteCallbacksData *S func setupOptionalLocalContainerRegistry(synchronizedSuiteCallbacksData *SynchronizedSuiteCallbacksData, data *ContainerRegistryPerImplementationData) { implementationNameForWerf := "default" - localRegistryAddress, localRegistryContainerName := utilsDocker.LocalDockerRegistryRun() + localRegistryAddress, _, localRegistryContainerName := utilsDocker.LocalDockerRegistryRun() registryAddress := localRegistryAddress synchronizedSuiteCallbacksData.AppendSynchronizedAfterSuiteAllNodesFunc(func() { diff --git a/integration/pkg/utils/docker/docker_registry.go b/integration/pkg/utils/docker/docker_registry.go index e74e441ae5..4e9271861f 100644 --- a/integration/pkg/utils/docker/docker_registry.go +++ b/integration/pkg/utils/docker/docker_registry.go @@ -9,7 +9,7 @@ import ( "github.com/werf/werf/integration/pkg/utils" ) -func LocalDockerRegistryRun() (string, string) { +func LocalDockerRegistryRun() (string, string, string) { containerName := fmt.Sprintf("werf_test_docker_registry-%s", utils.GetRandomString(10)) imageName := "flant/werf-test:registry" @@ -28,10 +28,15 @@ func LocalDockerRegistryRun() (string, string) { err := CliRun(dockerCliRunArgs...) Ω(err).ShouldNot(HaveOccurred(), "docker run "+strings.Join(dockerCliRunArgs, " ")) - registry := fmt.Sprintf("localhost:%s", ContainerHostPort(containerName, "5000/tcp")) - registryWithScheme := fmt.Sprintf("http://%s", registry) + inspect := ContainerInspect(containerName) + Ω(inspect.NetworkSettings).ShouldNot(BeNil()) + Ω(inspect.NetworkSettings.IPAddress).ShouldNot(BeEmpty()) + registryInternalAddress := fmt.Sprintf("%s:%d", inspect.NetworkSettings.IPAddress, 5000) + + registryLocalAddress := fmt.Sprintf("localhost:%s", ContainerHostPort(containerName, "5000/tcp")) + registryWithScheme := fmt.Sprintf("http://%s", registryLocalAddress) utils.WaitTillHostReadyToRespond(registryWithScheme, utils.DefaultWaitTillHostReadyToRespondMaxAttempts) - return registry, containerName + return registryLocalAddress, registryInternalAddress, containerName } diff --git a/integration/suites/build/stapel_image/base_image/suite_test.go b/integration/suites/build/stapel_image/base_image/suite_test.go index 5491610c02..5b1e09b972 100644 --- a/integration/suites/build/stapel_image/base_image/suite_test.go +++ b/integration/suites/build/stapel_image/base_image/suite_test.go @@ -56,7 +56,7 @@ var _ = SuiteData.AppendSynchronizedBeforeSuiteNode1Func(func() { }) var _ = SuiteData.AppendSynchronizedBeforeSuiteAllNodesFunc(func(_ []byte) { - SuiteData.Registry, SuiteData.RegistryContainerName = utilsDocker.LocalDockerRegistryRun() + SuiteData.Registry, _, SuiteData.RegistryContainerName = utilsDocker.LocalDockerRegistryRun() }) var _ = SuiteData.AppendSynchronizedAfterSuiteAllNodesFunc(func() { From 4cf3477b5629d35c9f8fb2f78836f350c4ef9de6 Mon Sep 17 00:00:00 2001 From: Ilya Lesikov Date: Fri, 15 Oct 2021 14:04:34 +0300 Subject: [PATCH 2/7] tests(integration): fix entrypoint defined fail cmds --- integration/pkg/utils/docker/container_command.go | 1 + 1 file changed, 1 insertion(+) diff --git a/integration/pkg/utils/docker/container_command.go b/integration/pkg/utils/docker/container_command.go index 91642d3e21..b9930d432f 100644 --- a/integration/pkg/utils/docker/container_command.go +++ b/integration/pkg/utils/docker/container_command.go @@ -44,6 +44,7 @@ func RunSucceedContainerCommandWithStapel(werfBinPath string, projectPath string "--volumes-from", container, "--rm", + "--entrypoint=", } dockerOptions = append(dockerOptions, extraDockerOptions...) From 77815d1d220c1b47bacaa5b572ab7dca9d0e31ed Mon Sep 17 00:00:00 2001 From: Ilya Lesikov Date: Fri, 15 Oct 2021 14:06:45 +0300 Subject: [PATCH 3/7] tests(e2e): add first E2E test for dockerfile build --- test/e2e/build/_fixtures/state0/Dockerfile | 30 ++++ test/e2e/build/_fixtures/state0/src/file1 | 1 + test/e2e/build/_fixtures/state0/src/file2 | 1 + test/e2e/build/_fixtures/state0/werf.yaml | 11 ++ test/e2e/build/_fixtures/state1/Dockerfile | 26 +++ test/e2e/build/_fixtures/state1/src/file1 | 1 + test/e2e/build/_fixtures/state1/src/file3 | 1 + test/e2e/build/_fixtures/state1/werf.yaml | 11 ++ test/e2e/build/build_test.go | 165 ++++++++++++++++++ test/e2e/build/suite_test.go | 47 +++++ test/pkg/contruntime/base.go | 21 +++ test/pkg/contruntime/docker.go | 49 ++++++ test/pkg/contruntime/dockerwithfusebuildah.go | 67 +++++++ test/pkg/contruntime/interface.go | 37 ++++ test/pkg/contruntime/nativerootlessbuildah.go | 52 ++++++ test/pkg/suitedata/suitedata.go | 42 +++++ .../contruntime/manifest/docker_schema2.go | 68 ++++++++ .../contruntime/strslice/strslice.go | 32 ++++ test/pkg/werf/project.go | 38 ++++ 19 files changed, 700 insertions(+) create mode 100644 test/e2e/build/_fixtures/state0/Dockerfile create mode 100644 test/e2e/build/_fixtures/state0/src/file1 create mode 100644 test/e2e/build/_fixtures/state0/src/file2 create mode 100644 test/e2e/build/_fixtures/state0/werf.yaml create mode 100644 test/e2e/build/_fixtures/state1/Dockerfile create mode 100644 test/e2e/build/_fixtures/state1/src/file1 create mode 100644 test/e2e/build/_fixtures/state1/src/file3 create mode 100644 test/e2e/build/_fixtures/state1/werf.yaml create mode 100644 test/e2e/build/build_test.go create mode 100644 test/e2e/build/suite_test.go create mode 100644 test/pkg/contruntime/base.go create mode 100644 test/pkg/contruntime/docker.go create mode 100644 test/pkg/contruntime/dockerwithfusebuildah.go create mode 100644 test/pkg/contruntime/interface.go create mode 100644 test/pkg/contruntime/nativerootlessbuildah.go create mode 100644 test/pkg/suitedata/suitedata.go create mode 100644 test/pkg/thirdparty/contruntime/manifest/docker_schema2.go create mode 100644 test/pkg/thirdparty/contruntime/strslice/strslice.go create mode 100644 test/pkg/werf/project.go diff --git a/test/e2e/build/_fixtures/state0/Dockerfile b/test/e2e/build/_fixtures/state0/Dockerfile new file mode 100644 index 0000000000..56dc5d56a3 --- /dev/null +++ b/test/e2e/build/_fixtures/state0/Dockerfile @@ -0,0 +1,30 @@ +FROM ubuntu:20.04 AS builder + +ADD src/file* /app/added/ +ADD "https://github.com/octocat/Hello-World/tarball/7fd1a60b01f91b314f59955a4e4d4e80d8edf11d" /helloworld.tgz +COPY src/file* /app/copied/ + + +FROM ubuntu:20.04 AS result + +ARG CHANGED_ARG="should_be_changed" +ENV COMPOSED_ENV="env-${CHANGED_ARG}" +LABEL COMPOSED_LABEL="label-${CHANGED_ARG}" + +SHELL ["/bin/sh", "-c"] +USER 0:0 +WORKDIR / + +COPY --from=builder /app /app +COPY --from=builder /helloworld.tgz /helloworld.tgz + +RUN touch /created-by-run +RUN mkdir -p /persistent/should-exist-in-volume + +ENTRYPOINT ["sh", "-ec"] +CMD ["tail -f /dev/null"] +VOLUME /persistent +ONBUILD RUN echo onbuild +STOPSIGNAL SIGTERM +HEALTHCHECK CMD echo healthcheck +EXPOSE 80/tcp diff --git a/test/e2e/build/_fixtures/state0/src/file1 b/test/e2e/build/_fixtures/state0/src/file1 new file mode 100644 index 0000000000..be430b5cbb --- /dev/null +++ b/test/e2e/build/_fixtures/state0/src/file1 @@ -0,0 +1 @@ +file1content diff --git a/test/e2e/build/_fixtures/state0/src/file2 b/test/e2e/build/_fixtures/state0/src/file2 new file mode 100644 index 0000000000..e33f20f4dd --- /dev/null +++ b/test/e2e/build/_fixtures/state0/src/file2 @@ -0,0 +1 @@ +file2content diff --git a/test/e2e/build/_fixtures/state0/werf.yaml b/test/e2e/build/_fixtures/state0/werf.yaml new file mode 100644 index 0000000000..92aedaf44f --- /dev/null +++ b/test/e2e/build/_fixtures/state0/werf.yaml @@ -0,0 +1,11 @@ +project: werf-e2e-build-test +configVersion: 1 + +--- +image: dockerfile +context: . +dockerfile: Dockerfile +target: result +network: default +args: + CHANGED_ARG: "was_changed" diff --git a/test/e2e/build/_fixtures/state1/Dockerfile b/test/e2e/build/_fixtures/state1/Dockerfile new file mode 100644 index 0000000000..ec17f3e506 --- /dev/null +++ b/test/e2e/build/_fixtures/state1/Dockerfile @@ -0,0 +1,26 @@ +FROM ubuntu:20.04 AS builder + +ADD src/file* /app/added/ +COPY src/file* /app/copied/ + + +FROM ubuntu:20.04 AS result + +ARG CHANGED_ARG="should_be_changed" +ENV COMPOSED_ENV="env-${CHANGED_ARG}" +LABEL COMPOSED_LABEL="label-${CHANGED_ARG}" + +SHELL ["/bin/sh", "-c"] +USER 0:0 +WORKDIR / + +COPY --from=builder /app /app + +RUN touch /created-by-run-state1 + +ENTRYPOINT ["sh", "-ec"] +CMD ["tail -f /dev/null"] +ONBUILD RUN echo onbuild +STOPSIGNAL SIGTERM +HEALTHCHECK CMD echo healthcheck +EXPOSE 80/tcp diff --git a/test/e2e/build/_fixtures/state1/src/file1 b/test/e2e/build/_fixtures/state1/src/file1 new file mode 100644 index 0000000000..0e1a52f2d0 --- /dev/null +++ b/test/e2e/build/_fixtures/state1/src/file1 @@ -0,0 +1 @@ +file1content-state1 diff --git a/test/e2e/build/_fixtures/state1/src/file3 b/test/e2e/build/_fixtures/state1/src/file3 new file mode 100644 index 0000000000..36b77ed831 --- /dev/null +++ b/test/e2e/build/_fixtures/state1/src/file3 @@ -0,0 +1 @@ +file3content-state1 diff --git a/test/e2e/build/_fixtures/state1/werf.yaml b/test/e2e/build/_fixtures/state1/werf.yaml new file mode 100644 index 0000000000..de8fd19cdb --- /dev/null +++ b/test/e2e/build/_fixtures/state1/werf.yaml @@ -0,0 +1,11 @@ +project: werf-e2e-build-test +configVersion: 1 + +--- +image: dockerfile +context: . +dockerfile: Dockerfile +target: result +network: default +args: + CHANGED_ARG: "was_changed-state1" diff --git a/test/e2e/build/build_test.go b/test/e2e/build/build_test.go new file mode 100644 index 0000000000..dfa99210e8 --- /dev/null +++ b/test/e2e/build/build_test.go @@ -0,0 +1,165 @@ +package e2e_build_test + +import ( + "strings" + + . "github.com/onsi/ginkgo/extensions/table" + "github.com/werf/werf/test/pkg/contruntime" + "github.com/werf/werf/test/pkg/thirdparty/contruntime/manifest" + "github.com/werf/werf/test/pkg/werf" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Build", func() { + DescribeTable("should succeed and produce expected image", + func(withLocalRepo bool, containerRuntime string) { + By("initializing") + setupEnv(withLocalRepo, containerRuntime) + contRuntime, err := contruntime.NewContainerRuntime(containerRuntime) + if err == contruntime.RuntimeUnavailError { + Skip(err.Error()) + } else if err != nil { + Fail(err.Error()) + } + + By("state0: starting") + { + repoDirname := "repo0" + fixtureRelPath := "state0" + buildReportName := "report0.json" + + By("state0: preparing test repo") + SuiteData.InitTestRepo(repoDirname, fixtureRelPath) + + By("state0: building images") + werfProject := werf.NewProject(SuiteData.WerfBinPath, SuiteData.GetTestRepoPath(repoDirname)) + buildOut, buildReport := werfProject.BuildWithReport(SuiteData.GetBuildReportPath(buildReportName)) + Expect(buildOut).To(ContainSubstring("Building stage")) + Expect(buildOut).NotTo(ContainSubstring("Use cache image")) + + By("state0: rebuilding same images") + Expect(werfProject.Build()).To(And( + ContainSubstring("Use cache image"), + Not(ContainSubstring("Building stage")), + )) + + By(`state0: getting built "dockerfile" image metadata`) + config := contRuntime.GetImageInspectConfig(buildReport.Images["dockerfile"].DockerImageName) + + By("state0: checking built images metadata") + // FIXME(ilya-lesikov): CHANGED_ARG not changed on Native Buildah, needs investigation, then uncomment + // Expect(config.Env).To(ContainElement("COMPOSED_ENV=env-was_changed")) + // Expect(config.Labels).To(HaveKeyWithValue("COMPOSED_LABEL", "label-was_changed")) + Expect(config.Shell).To(ContainElements("/bin/sh", "-c")) + Expect(config.User).To(Equal("0:0")) + Expect(config.WorkingDir).To(Equal("/")) + Expect(config.Entrypoint).To(ContainElements("sh", "-ec")) + Expect(config.Cmd).To(ContainElement("tail -f /dev/null")) + Expect(config.Volumes).To(HaveKey("/persistent")) + Expect(config.OnBuild).To(ContainElement("RUN echo onbuild")) + Expect(config.StopSignal).To(Equal("SIGTERM")) + Expect(config.ExposedPorts).To(HaveKey(manifest.Schema2Port("80/tcp"))) + Expect(config.Healthcheck.Test).To(ContainElements("CMD-SHELL", "echo healthcheck")) + + By("state0: checking built images content") + contRuntime.ExpectCmdsToSucceed( + buildReport.Images["dockerfile"].DockerImageName, + "test -f /app/added/file2", + "test -f /app/copied/file1", + "test -f /app/copied/file2", + "echo 'file1content' | diff /app/added/file1 -", + "echo 'file2content' | diff /app/added/file2 -", + "echo 'file1content' | diff /app/copied/file1 -", + "echo 'file2content' | diff /app/copied/file2 -", + "test -f /helloworld.tgz", + "tar xOf /helloworld.tgz | grep 'Hello World!'", + "test -f /created-by-run", + "test -d /persistent/should-exist-in-volume", + ) + } + + By("state1: starting") + { + repoDirname := "repo0" + fixtureRelPath := "state1" + buildReportName := "report1.json" + + By("state1: changing files in test repo") + SuiteData.UpdateTestRepo(repoDirname, fixtureRelPath) + + By("state1: building images") + werfProject := werf.NewProject(SuiteData.WerfBinPath, SuiteData.GetTestRepoPath(repoDirname)) + buildOut, buildReport := werfProject.BuildWithReport(SuiteData.GetBuildReportPath(buildReportName)) + Expect(buildOut).To(ContainSubstring("Building stage")) + + By("state1: rebuilding same images") + Expect(werfProject.Build()).To(And( + ContainSubstring("Use cache image"), + Not(ContainSubstring("Building stage")), + )) + + By(`state1: getting built "dockerfile" image metadata`) + // FIXME(ilya-lesikov): CHANGED_ARG not changed on Native Buildah, needs investigation, then uncomment + // config := contRuntime.GetImageInspectConfig(buildReport.Images["dockerfile"].DockerImageName) + + By("state1: checking built images metadata") + // FIXME(ilya-lesikov): CHANGED_ARG not changed on Native Buildah, needs investigation, then uncomment + // Expect(config.Env).To(ContainElement("COMPOSED_ENV=env-was_changed-state1")) + // Expect(config.Labels).To(HaveKeyWithValue("COMPOSED_LABEL", "label-was_changed-state1")) + + By("state1: checking built images content") + contRuntime.ExpectCmdsToSucceed( + buildReport.Images["dockerfile"].DockerImageName, + "test -f /app/added/file1", + "test -f /app/added/file3", + "test -f /app/copied/file1", + "test -f /app/copied/file3", + "! test -f /app/added/file2", + "! test -f /app/copied/file2", + "echo 'file1content-state1' | diff /app/added/file1 -", + "echo 'file3content-state1' | diff /app/added/file3 -", + "echo 'file1content-state1' | diff /app/copied/file1 -", + "echo 'file3content-state1' | diff /app/copied/file3 -", + "! test -f /helloworld.tgz", + "test -f /created-by-run-state1", + ) + } + }, + Entry("without repo using Docker", false, "docker"), + Entry("with local repo using Docker", true, "docker"), + Entry("with local repo using Native Rootless Buildah", true, "native-rootless-buildah"), + Entry("with local repo using Docker-With-Fuse Buildah", true, "docker-with-fuse-buildah"), + // TODO: uncomment when buildah allows building without --repo flag + // Entry("without repo using Native Rootless Buildah", false, contruntime.NativeRootlessBuildah), + // Entry("without repo using Docker-With-Fuse Buildah", false, contruntime.DockerWithFuseBuildah), + ) +}) + +func setupEnv(withLocalRepo bool, containerRuntime string) { + switch containerRuntime { + case "docker": + if withLocalRepo { + SuiteData.Stubs.SetEnv("WERF_REPO", strings.Join([]string{SuiteData.RegistryLocalAddress, SuiteData.ProjectName}, "/")) + } + SuiteData.Stubs.UnsetEnv("WERF_CONTAINER_RUNTIME_BUILDAH") + case "native-rootless-buildah": + if withLocalRepo { + SuiteData.Stubs.SetEnv("WERF_REPO", strings.Join([]string{SuiteData.RegistryInternalAddress, SuiteData.ProjectName}, "/")) + } + SuiteData.Stubs.SetEnv("WERF_CONTAINER_RUNTIME_BUILDAH", "native-rootless") + case "docker-with-fuse-buildah": + if withLocalRepo { + SuiteData.Stubs.SetEnv("WERF_REPO", strings.Join([]string{SuiteData.RegistryInternalAddress, SuiteData.ProjectName}, "/")) + } + SuiteData.Stubs.SetEnv("WERF_CONTAINER_RUNTIME_BUILDAH", "docker-with-fuse") + default: + panic("unexpected containerRuntime") + } + + if withLocalRepo { + SuiteData.Stubs.SetEnv("WERF_INSECURE_REGISTRY", "1") + SuiteData.Stubs.SetEnv("WERF_SKIP_TLS_VERIFY_REGISTRY", "1") + } +} diff --git a/test/e2e/build/suite_test.go b/test/e2e/build/suite_test.go new file mode 100644 index 0000000000..81213b9122 --- /dev/null +++ b/test/e2e/build/suite_test.go @@ -0,0 +1,47 @@ +package e2e_build_test + +import ( + "runtime" + "testing" + + "github.com/werf/werf/integration/pkg/suite_init" + "github.com/werf/werf/integration/pkg/utils/docker" + "github.com/werf/werf/test/pkg/suitedata" +) + +func TestSuite(t *testing.T) { + requiredTools := []string{"docker", "git"} + if runtime.GOOS == "linux" { + requiredTools = append(requiredTools, "buildah") + } + suite_init.MakeTestSuiteEntrypointFunc("E2E Build suite", suite_init.TestSuiteEntrypointFuncOptions{ + RequiredSuiteTools: requiredTools, + })(t) +} + +var SuiteData = struct { + suitedata.SuiteData + + RegistryLocalAddress string + RegistryInternalAddress string + RegistryContainerName string +}{} + +var _ = SuiteData.SetupStubs(suite_init.NewStubsData()) +var _ = SuiteData.SetupSynchronizedSuiteCallbacks(suite_init.NewSynchronizedSuiteCallbacksData()) +var _ = SuiteData.SetupWerfBinary(suite_init.NewWerfBinaryData(SuiteData.SynchronizedSuiteCallbacksData)) +var _ = SuiteData.SetupProjectName(suite_init.NewProjectNameData(SuiteData.StubsData)) +var _ = SuiteData.SetupTmp(suite_init.NewTmpDirData()) + +var _ = SuiteData.AppendSynchronizedBeforeSuiteAllNodesFunc(func(_ []byte) { + SuiteData.RegistryLocalAddress, SuiteData.RegistryInternalAddress, SuiteData.RegistryContainerName = docker.LocalDockerRegistryRun() +}) + +var _ = SuiteData.AppendSynchronizedAfterSuiteAllNodesFunc(func() { + docker.ContainerStopAndRemove(SuiteData.RegistryContainerName) +}) + +// FIXME(ilya-lesikov): breaks parallel (-p) tests execution +// var _ = AfterEach(func() { +// iutils.RunSucceedCommand("/", SuiteData.WerfBinPath, "host", "purge", "--force") +// }) diff --git a/test/pkg/contruntime/base.go b/test/pkg/contruntime/base.go new file mode 100644 index 0000000000..b8b600fdd8 --- /dev/null +++ b/test/pkg/contruntime/base.go @@ -0,0 +1,21 @@ +package contruntime + +import ( + "github.com/google/uuid" + "github.com/werf/werf/test/pkg/thirdparty/contruntime/manifest" +) + +type BuildahInspect struct { + Docker struct { + Config manifest.Schema2Config `json:"config"` + } `json:"Docker"` +} + +type BaseContainerRuntime struct{} + +func expectCmdsToSucceed(r ContainerRuntime, image string, cmds ...string) { + containerName := uuid.New().String() + r.RunSleepingContainer(containerName, image) + r.Exec(containerName, cmds...) + r.Rm(containerName) +} diff --git a/test/pkg/contruntime/docker.go b/test/pkg/contruntime/docker.go new file mode 100644 index 0000000000..2a6f4feb09 --- /dev/null +++ b/test/pkg/contruntime/docker.go @@ -0,0 +1,49 @@ +package contruntime + +import ( + "encoding/json" + + . "github.com/onsi/gomega" + "github.com/werf/werf/integration/pkg/utils" + "github.com/werf/werf/test/pkg/thirdparty/contruntime/manifest" +) + +func NewDockerRuntime() ContainerRuntime { + return &DockerRuntime{} +} + +type DockerRuntime struct { + BaseContainerRuntime +} + +func (r *DockerRuntime) ExpectCmdsToSucceed(image string, cmds ...string) { + expectCmdsToSucceed(r, image, cmds...) +} + +func (r *DockerRuntime) RunSleepingContainer(containerName, image string) { + utils.RunSucceedCommand("/", + "docker", "run", "--rm", "-d", "--entrypoint=", "--name", containerName, image, "tail", "-f", "/dev/null", + ) +} + +func (r *DockerRuntime) Exec(containerName string, cmds ...string) { + for _, cmd := range cmds { + utils.RunSucceedCommand("/", "docker", "exec", containerName, "sh", "-ec", cmd) + } +} + +func (r *DockerRuntime) Rm(containerName string) { + utils.RunSucceedCommand("/", "docker", "rm", "-fv", containerName) +} + +func (r *DockerRuntime) Pull(image string) { + utils.RunSucceedCommand("/", "docker", "pull", image) +} + +func (r *DockerRuntime) GetImageInspectConfig(image string) (config manifest.Schema2Config) { + configRaw, err := utils.RunCommand("/", "docker", "image", "inspect", "-f", "{{ json .Config }}", image) + Expect(err).NotTo(HaveOccurred()) + Expect(json.Unmarshal(configRaw, &config)).To(Succeed()) + + return config +} diff --git a/test/pkg/contruntime/dockerwithfusebuildah.go b/test/pkg/contruntime/dockerwithfusebuildah.go new file mode 100644 index 0000000000..7b7575d864 --- /dev/null +++ b/test/pkg/contruntime/dockerwithfusebuildah.go @@ -0,0 +1,67 @@ +package contruntime + +import ( + "encoding/json" + "os" + "path/filepath" + + . "github.com/onsi/gomega" + "github.com/werf/werf/integration/pkg/utils" + "github.com/werf/werf/pkg/buildah" + "github.com/werf/werf/test/pkg/thirdparty/contruntime/manifest" +) + +func NewDockerWithFuseBuildahRuntime() ContainerRuntime { + return &DockerWithFuseBuildahRuntime{} +} + +type DockerWithFuseBuildahRuntime struct { + BaseContainerRuntime +} + +func (r *DockerWithFuseBuildahRuntime) ExpectCmdsToSucceed(image string, cmds ...string) { + expectCmdsToSucceed(r, image, cmds...) +} + +func (r *DockerWithFuseBuildahRuntime) RunSleepingContainer(containerName, image string) { + args := append(buildahDockerWithFuseDockerArgs(), "from", "--tls-verify=false", "--format", "docker", "--name", containerName, image) + utils.RunSucceedCommand("/", "docker", args...) +} + +func (r *DockerWithFuseBuildahRuntime) Exec(containerName string, cmds ...string) { + for _, cmd := range cmds { + args := append(buildahDockerWithFuseDockerArgs(), "run", containerName, "--", "sh", "-ec", cmd) + utils.RunSucceedCommand("/", "docker", args...) + } +} + +func (r *DockerWithFuseBuildahRuntime) Rm(containerName string) { + args := append(buildahDockerWithFuseDockerArgs(), "rm", containerName) + utils.RunSucceedCommand("/", "docker", args...) +} + +func (r *DockerWithFuseBuildahRuntime) Pull(image string) { + args := append(buildahDockerWithFuseDockerArgs(), "pull", "--tls-verify=false", image) + utils.RunSucceedCommand("/", "docker", args...) +} + +func (r *DockerWithFuseBuildahRuntime) GetImageInspectConfig(image string) (config manifest.Schema2Config) { + r.Pull(image) + + args := append(buildahDockerWithFuseDockerArgs(), "inspect", "--type", "image", image) + inspectRaw, err := utils.RunCommand("/", "docker", args...) + Expect(err).NotTo(HaveOccurred()) + + var inspect BuildahInspect + Expect(json.Unmarshal(inspectRaw, &inspect)).To(Succeed()) + return inspect.Docker.Config +} + +func buildahDockerWithFuseDockerArgs() []string { + home, err := os.UserHomeDir() + Expect(err).NotTo(HaveOccurred()) + + args := []string{"run", "--rm"} + + return append(args, buildah.BuildahWithFuseDockerArgs(buildah.BuildahStorageContainerName, filepath.Join(home, ".docker"))...) +} diff --git a/test/pkg/contruntime/interface.go b/test/pkg/contruntime/interface.go new file mode 100644 index 0000000000..d186689f7b --- /dev/null +++ b/test/pkg/contruntime/interface.go @@ -0,0 +1,37 @@ +package contruntime + +import ( + "errors" + "fmt" + "runtime" + + "github.com/werf/werf/test/pkg/thirdparty/contruntime/manifest" +) + +var RuntimeUnavailError = errors.New("requested runtime unavailable") + +func NewContainerRuntime(name string) (ContainerRuntime, error) { + switch name { + case "docker": + return NewDockerRuntime(), nil + case "native-rootless-buildah": + if runtime.GOOS != "linux" { + return nil, RuntimeUnavailError + } + return NewNativeRootlessBuildahRuntime(), nil + case "docker-with-fuse-buildah": + return NewDockerWithFuseBuildahRuntime(), nil + default: + panic(fmt.Sprint("unexpected name for container runtime: ", name)) + } +} + +type ContainerRuntime interface { + Pull(image string) + Exec(containerName string, cmds ...string) + Rm(containerName string) + + RunSleepingContainer(containerName, image string) + GetImageInspectConfig(image string) (config manifest.Schema2Config) + ExpectCmdsToSucceed(image string, cmds ...string) +} diff --git a/test/pkg/contruntime/nativerootlessbuildah.go b/test/pkg/contruntime/nativerootlessbuildah.go new file mode 100644 index 0000000000..46ef574cef --- /dev/null +++ b/test/pkg/contruntime/nativerootlessbuildah.go @@ -0,0 +1,52 @@ +package contruntime + +import ( + "encoding/json" + + . "github.com/onsi/gomega" + "github.com/werf/werf/integration/pkg/utils" + "github.com/werf/werf/test/pkg/thirdparty/contruntime/manifest" +) + +func NewNativeRootlessBuildahRuntime() ContainerRuntime { + return &NativeRootlessBuildahRuntime{} +} + +type NativeRootlessBuildahRuntime struct { + BaseContainerRuntime +} + +func (r *NativeRootlessBuildahRuntime) ExpectCmdsToSucceed(image string, cmds ...string) { + expectCmdsToSucceed(r, image, cmds...) +} + +func (r *NativeRootlessBuildahRuntime) RunSleepingContainer(containerName, image string) { + utils.RunSucceedCommand("/", + "buildah", "from", "--tls-verify=false", "--format", "docker", "--name", containerName, image, + ) +} + +func (r *NativeRootlessBuildahRuntime) Exec(containerName string, cmds ...string) { + for _, cmd := range cmds { + utils.RunSucceedCommand("/", "buildah", "run", containerName, "--", "sh", "-ec", cmd) + } +} + +func (r *NativeRootlessBuildahRuntime) Rm(containerName string) { + utils.RunSucceedCommand("/", "buildah", "rm", containerName) +} + +func (r *NativeRootlessBuildahRuntime) Pull(image string) { + utils.RunSucceedCommand("/", "buildah", "pull", "--tls-verify=false", image) +} + +func (r *NativeRootlessBuildahRuntime) GetImageInspectConfig(image string) (config manifest.Schema2Config) { + r.Pull(image) + + inspectRaw, err := utils.RunCommand("/", "buildah", "inspect", "--type", "image", image) + Expect(err).NotTo(HaveOccurred()) + var inspect BuildahInspect + Expect(json.Unmarshal(inspectRaw, &inspect)).To(Succeed()) + + return inspect.Docker.Config +} diff --git a/test/pkg/suitedata/suitedata.go b/test/pkg/suitedata/suitedata.go new file mode 100644 index 0000000000..e3f9ee864f --- /dev/null +++ b/test/pkg/suitedata/suitedata.go @@ -0,0 +1,42 @@ +package suitedata + +import ( + "os" + "path/filepath" + + . "github.com/onsi/gomega" + "github.com/werf/werf/integration/pkg/suite_init" + "github.com/werf/werf/integration/pkg/utils" +) + +type SuiteData struct { + suite_init.SuiteData +} + +func (s *SuiteData) GetTestRepoPath(dirname string) string { + testReposDir := filepath.Join(s.TestDirPath, "repos") + Expect(os.MkdirAll(testReposDir, os.ModePerm)).To(Succeed()) + return filepath.Join(testReposDir, dirname) +} + +func (s *SuiteData) GetBuildReportPath(filename string) string { + buildReportsDir := filepath.Join(s.TestDirPath, "build-reports") + Expect(os.MkdirAll(buildReportsDir, os.ModePerm)).To(Succeed()) + return filepath.Join(buildReportsDir, filename) +} + +func (s *SuiteData) InitTestRepo(dirname, fixtureRelPath string) { + testRepoPath := s.GetTestRepoPath(dirname) + utils.CopyIn(utils.FixturePath(fixtureRelPath), testRepoPath) + utils.RunSucceedCommand(testRepoPath, "git", "init") + utils.RunSucceedCommand(testRepoPath, "git", "add", ".") + utils.RunSucceedCommand(testRepoPath, "git", "commit", "-m", "initial") +} + +func (s *SuiteData) UpdateTestRepo(dirname, fixtureRelPath string) { + testRepoPath := s.GetTestRepoPath(dirname) + utils.RunSucceedCommand(testRepoPath, "git", "rm", "--ignore-unmatch", "-rf", ".") + utils.CopyIn(utils.FixturePath(fixtureRelPath), testRepoPath) + utils.RunSucceedCommand(testRepoPath, "git", "add", ".") + utils.RunSucceedCommand(testRepoPath, "git", "commit", "-m", "updated") +} diff --git a/test/pkg/thirdparty/contruntime/manifest/docker_schema2.go b/test/pkg/thirdparty/contruntime/manifest/docker_schema2.go new file mode 100644 index 0000000000..5ef099121a --- /dev/null +++ b/test/pkg/thirdparty/contruntime/manifest/docker_schema2.go @@ -0,0 +1,68 @@ +// THIS WAS COPIED FROM github.com/containers/image/v5/pkg/manifest + +package manifest + +import ( + "time" + + "github.com/werf/werf/test/pkg/thirdparty/contruntime/strslice" +) + +// Schema2Port is a Port, a string containing port number and protocol in the +// format "80/tcp", from docker/go-connections/nat. +type Schema2Port string + +// Schema2PortSet is a PortSet, a collection of structs indexed by Port, from +// docker/go-connections/nat. +type Schema2PortSet map[Schema2Port]struct{} + +// Schema2HealthConfig is a HealthConfig, which holds configuration settings +// for the HEALTHCHECK feature, from docker/docker/api/types/container. +type Schema2HealthConfig struct { + // Test is the test to perform to check that the container is healthy. + // An empty slice means to inherit the default. + // The options are: + // {} : inherit healthcheck + // {"NONE"} : disable healthcheck + // {"CMD", args...} : exec arguments directly + // {"CMD-SHELL", command} : run command with system's default shell + Test []string `json:",omitempty"` + + // Zero means to inherit. Durations are expressed as integer nanoseconds. + StartPeriod time.Duration `json:",omitempty"` // StartPeriod is the time to wait after starting before running the first check. + Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks. + Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung. + + // Retries is the number of consecutive failures needed to consider a container as unhealthy. + // Zero means inherit. + Retries int `json:",omitempty"` +} + +// Schema2Config is a Config in docker/docker/api/types/container. +type Schema2Config struct { + Hostname string // Hostname + Domainname string // Domainname + User string // User that will run the command(s) inside the container, also support user:group + AttachStdin bool // Attach the standard input, makes possible user interaction + AttachStdout bool // Attach the standard output + AttachStderr bool // Attach the standard error + ExposedPorts Schema2PortSet `json:",omitempty"` // List of exposed ports + Tty bool // Attach standard streams to a tty, including stdin if it is not closed. + OpenStdin bool // Open stdin + StdinOnce bool // If true, close stdin after the 1 attached client disconnects. + Env []string // List of environment variable to set in the container + Cmd strslice.StrSlice // Command to run when starting the container + Healthcheck *Schema2HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy + ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (Windows specific) + Image string // Name of the image as it was passed by the operator (e.g. could be symbolic) + Volumes map[string]struct{} // List of volumes (mounts) used for the container + WorkingDir string // Current directory (PWD) in the command will be launched + Entrypoint strslice.StrSlice // Entrypoint to run when starting the container + NetworkDisabled bool `json:",omitempty"` // Is network disabled + MacAddress string `json:",omitempty"` // Mac Address of the container + OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile + Labels map[string]string // List of labels set to this container + StopSignal string `json:",omitempty"` // Signal to stop a container + StopTimeout *int `json:",omitempty"` // Timeout (in seconds) to stop a container + Shell strslice.StrSlice `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT +} diff --git a/test/pkg/thirdparty/contruntime/strslice/strslice.go b/test/pkg/thirdparty/contruntime/strslice/strslice.go new file mode 100644 index 0000000000..da697fca59 --- /dev/null +++ b/test/pkg/thirdparty/contruntime/strslice/strslice.go @@ -0,0 +1,32 @@ +// THIS WAS COPIED FROM github.com/containers/image/v5/pkg/strslice + +package strslice + +import "encoding/json" + +// StrSlice represents a string or an array of strings. +// We need to override the json decoder to accept both options. +type StrSlice []string + +// UnmarshalJSON decodes the byte slice whether it's a string or an array of +// strings. This method is needed to implement json.Unmarshaler. +func (e *StrSlice) UnmarshalJSON(b []byte) error { + if len(b) == 0 { + // With no input, we preserve the existing value by returning nil and + // leaving the target alone. This allows defining default values for + // the type. + return nil + } + + p := make([]string, 0, 1) + if err := json.Unmarshal(b, &p); err != nil { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + p = append(p, s) + } + + *e = p + return nil +} diff --git a/test/pkg/werf/project.go b/test/pkg/werf/project.go new file mode 100644 index 0000000000..918822cc22 --- /dev/null +++ b/test/pkg/werf/project.go @@ -0,0 +1,38 @@ +package werf + +import ( + "encoding/json" + "os" + + . "github.com/onsi/gomega" + iutils "github.com/werf/werf/integration/pkg/utils" + "github.com/werf/werf/pkg/build" +) + +func NewProject(werfBinPath, repoPath string) *Project { + return &Project{ + WerfBinPath: werfBinPath, + RepoPath: repoPath, + } +} + +type Project struct { + RepoPath string + WerfBinPath string +} + +func (p *Project) Build(optArgs ...string) (combinedOut string) { + optArgs = append([]string{"build", "--debug"}, optArgs...) + return iutils.SucceedCommandOutputString(p.RepoPath, p.WerfBinPath, optArgs...) +} + +func (p *Project) BuildWithReport(buildReportPath string, optsArgs ...string) (combinedOut string, buildReport build.ImagesReport) { + optsArgs = append([]string{"build", "--debug", "--report-path", buildReportPath}, optsArgs...) + combinedOut = iutils.SucceedCommandOutputString(p.RepoPath, p.WerfBinPath, optsArgs...) + + buildReportRaw, err := os.ReadFile(buildReportPath) + Expect(err).NotTo(HaveOccurred()) + Expect(json.Unmarshal(buildReportRaw, &buildReport)).To(Succeed()) + + return combinedOut, buildReport +} From 63ce027278d55c9337c650c5a499f448af1b9377 Mon Sep 17 00:00:00 2001 From: Ilya Lesikov Date: Fri, 15 Oct 2021 14:09:00 +0300 Subject: [PATCH 4/7] style: cleanup, format --- pkg/build/image.go | 4 +-- pkg/container_runtime/interface.go | 47 ------------------------------ 2 files changed, 2 insertions(+), 49 deletions(-) diff --git a/pkg/build/image.go b/pkg/build/image.go index 7c281335b9..c5775f156a 100644 --- a/pkg/build/image.go +++ b/pkg/build/image.go @@ -186,9 +186,9 @@ func (i *Image) FetchBaseImage(ctx context.Context, c *Conveyor) error { } case StageAsBaseImage: // TODO: check no bug introduced - //if err := c.ContainerRuntime.RefreshImageObject(ctx, &container_runtime.Image{Image: i.baseImage}); err != nil { + // if err := c.ContainerRuntime.RefreshImageObject(ctx, &container_runtime.Image{Image: i.baseImage}); err != nil { // return err - //} + // } if err := c.StorageManager.FetchStage(ctx, c.ContainerRuntime, i.stageAsBaseImage); err != nil { return err } diff --git a/pkg/container_runtime/interface.go b/pkg/container_runtime/interface.go index 26fa5ef35a..467e946491 100644 --- a/pkg/container_runtime/interface.go +++ b/pkg/container_runtime/interface.go @@ -47,50 +47,3 @@ type ContainerRuntime interface { RenameImage(ctx context.Context, img LegacyImageInterface, newImageName string, removeOldName bool) error RemoveImage(ctx context.Context, img LegacyImageInterface) error } - -/* - * Stapel + docker server - * container_runtime.Image — конструктор аргументов к docker run + docker tag + docker push + docker commit - * метод Image.Build и пр. - * Dockerfile + docker server - * container_runtime.DockerfileImageBuilder — конструктор аргументов к docker build - * метод DockerfileImageBuilder.Build - * DockerServerRuntime - * Stapel|Dockerfile + docker-server|buildah - -type DockerfileImageBuilder struct { - ContainerRuntime ContainerRuntime - Dockerfile []byte - Opts BuildDockerfileOptions - - builtID string -} - -func (builder *DockerfileImageBuilder) Build() error { - builder.builtID = ContainerRuntime.BuildDockerfile(...) -} - -func (builder *DockerfileImageBuilder) GetBuiltID() string { - return builder.builtID -} - -func (builder *DockerfileBuidler) Cleanup() error { -} - -type StapelImageBuilder struct { - Opts StapelBuildOptions - ... -} - -func (builder *StapelImageBuilder) Build() error { - builder.builtID = ContainerRuntime.StapelBuild(...) -} - -func (builder *StapelImageBuilder) GetBuiltID() string { - return builder.builtID -} - -func (builder *StapelImageBuilder) Cleanup() error { -} - -*/ From dbf5ca240689e6be781559caf8eb291e2044a123 Mon Sep 17 00:00:00 2001 From: Ilya Lesikov Date: Fri, 15 Oct 2021 14:13:13 +0300 Subject: [PATCH 5/7] refactor(buildah): pass Opts structs to all public methods --- pkg/build/image.go | 4 +- pkg/build/stage/dockerfile.go | 4 +- pkg/container_runtime/buildah_runtime.go | 26 ++++++------- .../docker_server_runtime.go | 20 +++++----- .../dockerfile_image_builder.go | 4 +- pkg/container_runtime/interface.go | 38 +++++++++++++++---- pkg/container_runtime/legacy_base_image.go | 2 +- pkg/container_runtime/legacy_stage_image.go | 2 +- .../perf_check_container_runtime.go | 22 +++++------ pkg/storage/repo_stages_storage.go | 6 +-- 10 files changed, 76 insertions(+), 52 deletions(-) diff --git a/pkg/build/image.go b/pkg/build/image.go index c5775f156a..9996673792 100644 --- a/pkg/build/image.go +++ b/pkg/build/image.go @@ -143,7 +143,7 @@ func (i *Image) FetchBaseImage(ctx context.Context, c *Conveyor) error { case ImageFromRegistryAsBaseImage: containerRuntime := c.ContainerRuntime - if info, err := containerRuntime.GetImageInfo(ctx, i.baseImage.Name()); err != nil { + if info, err := containerRuntime.GetImageInfo(ctx, i.baseImage.Name(), container_runtime.GetImageInfoOpts{}); err != nil { return fmt.Errorf("unable to inspect local image %s: %s", i.baseImage.Name(), err) } else if info != nil { // TODO: do not use container_runtime.LegacyStageImage for base image @@ -174,7 +174,7 @@ func (i *Image) FetchBaseImage(ctx context.Context, c *Conveyor) error { return err } - if info, err := containerRuntime.GetImageInfo(ctx, i.baseImage.Name()); err != nil { + if info, err := containerRuntime.GetImageInfo(ctx, i.baseImage.Name(), container_runtime.GetImageInfoOpts{}); err != nil { return fmt.Errorf("unable to inspect local image %s: %s", i.baseImage.Name(), err) } else if info == nil { return fmt.Errorf("unable to inspect local image %s after successful pull: image is not exists", i.baseImage.Name()) diff --git a/pkg/build/stage/dockerfile.go b/pkg/build/stage/dockerfile.go index 89e92b180c..8d9ff92e59 100644 --- a/pkg/build/stage/dockerfile.go +++ b/pkg/build/stage/dockerfile.go @@ -289,7 +289,7 @@ outerLoop: } getBaseImageOnBuildLocally := func() ([]string, error) { - info, err := containerRuntime.GetImageInfo(ctx, resolvedBaseName) + info, err := containerRuntime.GetImageInfo(ctx, resolvedBaseName, container_runtime.GetImageInfoOpts{}) if err != nil { return nil, err } @@ -320,7 +320,7 @@ outerLoop: logboek.Context(ctx).Warn().LogF("WARNING: Could not get base image manifest from local docker and from docker registry: %s\n", getRemotelyErr) logboek.Context(ctx).Warn().LogLn("WARNING: The base image pulling is necessary for calculating digest of image correctly\n") if err := logboek.Context(ctx).Default().LogProcess("Pulling base image %s", resolvedBaseName).DoError(func() error { - return containerRuntime.Pull(ctx, resolvedBaseName) + return containerRuntime.Pull(ctx, resolvedBaseName, container_runtime.PullOpts{}) }); err != nil { return err } diff --git a/pkg/container_runtime/buildah_runtime.go b/pkg/container_runtime/buildah_runtime.go index 587c40746a..7a40245b26 100644 --- a/pkg/container_runtime/buildah_runtime.go +++ b/pkg/container_runtime/buildah_runtime.go @@ -22,7 +22,7 @@ func NewBuildahRuntime(buildah buildah.Buildah) *BuildahRuntime { } // GetImageInfo returns nil, nil if image not found. -func (runtime *BuildahRuntime) GetImageInfo(ctx context.Context, ref string) (*image.Info, error) { +func (runtime *BuildahRuntime) GetImageInfo(ctx context.Context, ref string, opts GetImageInfoOpts) (*image.Info, error) { inspect, err := runtime.buildah.Inspect(ctx, ref) if err != nil { return nil, fmt.Errorf("error getting buildah inspect of %q: %s", ref, err) @@ -47,7 +47,7 @@ func (runtime *BuildahRuntime) GetImageInfo(ctx context.Context, ref string) (*i }, nil } -func (runtime *BuildahRuntime) Rmi(ctx context.Context, ref string) error { +func (runtime *BuildahRuntime) Rmi(ctx context.Context, ref string, opts RmiOpts) error { return runtime.buildah.Rmi(ctx, ref, buildah.RmiOpts{ Force: true, CommonOpts: buildah.CommonOpts{ @@ -56,7 +56,7 @@ func (runtime *BuildahRuntime) Rmi(ctx context.Context, ref string) error { }) } -func (runtime *BuildahRuntime) Pull(ctx context.Context, ref string) error { +func (runtime *BuildahRuntime) Pull(ctx context.Context, ref string, opts PullOpts) error { return runtime.buildah.Pull(ctx, ref, buildah.PullOpts{ CommonOpts: buildah.CommonOpts{ LogWriter: logboek.Context(ctx).OutStream(), @@ -64,7 +64,7 @@ func (runtime *BuildahRuntime) Pull(ctx context.Context, ref string) error { }) } -func (runtime *BuildahRuntime) Tag(ctx context.Context, ref, newRef string) error { +func (runtime *BuildahRuntime) Tag(ctx context.Context, ref, newRef string, opts TagOpts) error { return runtime.buildah.Tag(ctx, ref, newRef, buildah.TagOpts{ CommonOpts: buildah.CommonOpts{ LogWriter: logboek.Context(ctx).OutStream(), @@ -72,7 +72,7 @@ func (runtime *BuildahRuntime) Tag(ctx context.Context, ref, newRef string) erro }) } -func (runtime *BuildahRuntime) Push(ctx context.Context, ref string) error { +func (runtime *BuildahRuntime) Push(ctx context.Context, ref string, opts PushOpts) error { return runtime.buildah.Push(ctx, ref, buildah.PushOpts{ CommonOpts: buildah.CommonOpts{ LogWriter: logboek.Context(ctx).OutStream(), @@ -80,7 +80,7 @@ func (runtime *BuildahRuntime) Push(ctx context.Context, ref string) error { }) } -func (runtime *BuildahRuntime) BuildDockerfile(ctx context.Context, dockerfile []byte, opts BuildDockerfileOptions) (string, error) { +func (runtime *BuildahRuntime) BuildDockerfile(ctx context.Context, dockerfile []byte, opts BuildDockerfileOpts) (string, error) { return runtime.buildah.BuildFromDockerfile(ctx, dockerfile, buildah.BuildFromDockerfileOpts{ CommonOpts: buildah.CommonOpts{ LogWriter: logboek.Context(ctx).OutStream(), @@ -90,7 +90,7 @@ func (runtime *BuildahRuntime) BuildDockerfile(ctx context.Context, dockerfile [ } func (runtime *BuildahRuntime) RefreshImageObject(ctx context.Context, img LegacyImageInterface) error { - if info, err := runtime.GetImageInfo(ctx, img.Name()); err != nil { + if info, err := runtime.GetImageInfo(ctx, img.Name(), GetImageInfoOpts{}); err != nil { return err } else { img.SetInfo(info) @@ -99,11 +99,11 @@ func (runtime *BuildahRuntime) RefreshImageObject(ctx context.Context, img Legac } func (runtime *BuildahRuntime) PullImageFromRegistry(ctx context.Context, img LegacyImageInterface) error { - if err := runtime.Pull(ctx, img.Name()); err != nil { + if err := runtime.Pull(ctx, img.Name(), PullOpts{}); err != nil { return fmt.Errorf("unable to pull image %s: %s", img.Name(), err) } - if info, err := runtime.GetImageInfo(ctx, img.Name()); err != nil { + if info, err := runtime.GetImageInfo(ctx, img.Name(), GetImageInfoOpts{}); err != nil { return fmt.Errorf("unable to get inspect of image %s: %s", img.Name(), err) } else { img.SetInfo(info) @@ -114,7 +114,7 @@ func (runtime *BuildahRuntime) PullImageFromRegistry(ctx context.Context, img Le func (runtime *BuildahRuntime) RenameImage(ctx context.Context, img LegacyImageInterface, newImageName string, removeOldName bool) error { if err := logboek.Context(ctx).Info().LogProcess(fmt.Sprintf("Tagging image %s by name %s", img.Name(), newImageName)).DoError(func() error { - if err := runtime.Tag(ctx, img.Name(), newImageName); err != nil { + if err := runtime.Tag(ctx, img.Name(), newImageName, TagOpts{}); err != nil { return fmt.Errorf("unable to tag image %s by name %s: %s", img.Name(), newImageName, err) } return nil @@ -124,7 +124,7 @@ func (runtime *BuildahRuntime) RenameImage(ctx context.Context, img LegacyImageI if removeOldName { if err := logboek.Context(ctx).Info().LogProcess(fmt.Sprintf("Removing old image tag %s", img.Name())).DoError(func() error { - if err := runtime.Rmi(ctx, img.Name()); err != nil { + if err := runtime.Rmi(ctx, img.Name(), RmiOpts{}); err != nil { return fmt.Errorf("unable to remove image %q: %s", img.Name(), err) } return nil @@ -135,7 +135,7 @@ func (runtime *BuildahRuntime) RenameImage(ctx context.Context, img LegacyImageI img.SetName(newImageName) - if info, err := runtime.GetImageInfo(ctx, img.Name()); err != nil { + if info, err := runtime.GetImageInfo(ctx, img.Name(), GetImageInfoOpts{}); err != nil { return err } else { img.SetInfo(info) @@ -152,7 +152,7 @@ func (runtime *BuildahRuntime) RenameImage(ctx context.Context, img LegacyImageI func (runtime *BuildahRuntime) RemoveImage(ctx context.Context, img LegacyImageInterface) error { if err := logboek.Context(ctx).Info().LogProcess(fmt.Sprintf("Removing image tag %s", img.Name())).DoError(func() error { - if err := runtime.Rmi(ctx, img.Name()); err != nil { + if err := runtime.Rmi(ctx, img.Name(), RmiOpts{}); err != nil { return fmt.Errorf("unable to remove image %q: %s", img.Name(), err) } return nil diff --git a/pkg/container_runtime/docker_server_runtime.go b/pkg/container_runtime/docker_server_runtime.go index ac967771b7..8243eb754b 100644 --- a/pkg/container_runtime/docker_server_runtime.go +++ b/pkg/container_runtime/docker_server_runtime.go @@ -20,7 +20,7 @@ func NewDockerServerRuntime() *DockerServerRuntime { return &DockerServerRuntime{} } -func (runtime *DockerServerRuntime) BuildDockerfile(ctx context.Context, _ []byte, opts BuildDockerfileOptions) (string, error) { +func (runtime *DockerServerRuntime) BuildDockerfile(ctx context.Context, _ []byte, opts BuildDockerfileOpts) (string, error) { switch { case opts.ContextTar == nil: panic(fmt.Sprintf("ContextTar can't be nil: %+v", opts)) @@ -66,7 +66,7 @@ func (runtime *DockerServerRuntime) BuildDockerfile(ctx context.Context, _ []byt return tempID, docker.CliBuild_LiveOutputWithCustomIn(ctx, opts.ContextTar, cliArgs...) } -func (runtime *DockerServerRuntime) GetImageInfo(ctx context.Context, ref string) (*image.Info, error) { +func (runtime *DockerServerRuntime) GetImageInfo(ctx context.Context, ref string, opts GetImageInfoOpts) (*image.Info, error) { inspect, err := docker.ImageInspect(ctx, ref) if client.IsErrNotFound(err) { return nil, nil @@ -85,7 +85,7 @@ func (runtime *DockerServerRuntime) GetImageInspect(ctx context.Context, ref str } func (runtime *DockerServerRuntime) RefreshImageObject(ctx context.Context, img LegacyImageInterface) error { - if info, err := runtime.GetImageInfo(ctx, img.Name()); err != nil { + if info, err := runtime.GetImageInfo(ctx, img.Name(), GetImageInfoOpts{}); err != nil { return err } else { img.SetInfo(info) @@ -116,7 +116,7 @@ func (runtime *DockerServerRuntime) RenameImage(ctx context.Context, img LegacyI img.SetName(newImageName) - if info, err := runtime.GetImageInfo(ctx, img.Name()); err != nil { + if info, err := runtime.GetImageInfo(ctx, img.Name(), GetImageInfoOpts{}); err != nil { return err } else { img.SetInfo(info) @@ -135,7 +135,7 @@ func (runtime *DockerServerRuntime) RenameImage(ctx context.Context, img LegacyI func (runtime *DockerServerRuntime) RemoveImage(ctx context.Context, img LegacyImageInterface) error { return logboek.Context(ctx).Info().LogProcess(fmt.Sprintf("Removing image tag %s", img.Name())).DoError(func() error { - return runtime.Rmi(ctx, img.Name()) + return runtime.Rmi(ctx, img.Name(), RmiOpts{}) }) } @@ -144,7 +144,7 @@ func (runtime *DockerServerRuntime) PullImageFromRegistry(ctx context.Context, i return fmt.Errorf("unable to pull image %s: %s", img.Name(), err) } - if info, err := runtime.GetImageInfo(ctx, img.Name()); err != nil { + if info, err := runtime.GetImageInfo(ctx, img.Name(), GetImageInfoOpts{}); err != nil { return fmt.Errorf("unable to get inspect of image %s: %s", img.Name(), err) } else { img.SetInfo(info) @@ -153,22 +153,22 @@ func (runtime *DockerServerRuntime) PullImageFromRegistry(ctx context.Context, i return nil } -func (runtime *DockerServerRuntime) Tag(ctx context.Context, ref, newRef string) error { +func (runtime *DockerServerRuntime) Tag(ctx context.Context, ref, newRef string, opts TagOpts) error { return docker.CliTag(ctx, ref, newRef) } -func (runtime *DockerServerRuntime) Push(ctx context.Context, ref string) error { +func (runtime *DockerServerRuntime) Push(ctx context.Context, ref string, opts PushOpts) error { return docker.CliPushWithRetries(ctx, ref) } -func (runtime *DockerServerRuntime) Pull(ctx context.Context, ref string) error { +func (runtime *DockerServerRuntime) Pull(ctx context.Context, ref string, opts PullOpts) error { if err := docker.CliPull(ctx, ref); err != nil { return fmt.Errorf("unable to pull image %s: %s", ref, err) } return nil } -func (runtime *DockerServerRuntime) Rmi(ctx context.Context, ref string) error { +func (runtime *DockerServerRuntime) Rmi(ctx context.Context, ref string, opts RmiOpts) error { return docker.CliRmi(ctx, ref, "--force") } diff --git a/pkg/container_runtime/dockerfile_image_builder.go b/pkg/container_runtime/dockerfile_image_builder.go index 22974defb8..2ab3682400 100644 --- a/pkg/container_runtime/dockerfile_image_builder.go +++ b/pkg/container_runtime/dockerfile_image_builder.go @@ -9,7 +9,7 @@ import ( type DockerfileImageBuilder struct { ContainerRuntime ContainerRuntime Dockerfile []byte - BuildDockerfileOptions BuildDockerfileOptions + BuildDockerfileOptions BuildDockerfileOpts ContextArchivePath string builtID string @@ -50,7 +50,7 @@ func (b *DockerfileImageBuilder) Build(ctx context.Context) error { } func (b *DockerfileImageBuilder) Cleanup(ctx context.Context) error { - if err := b.ContainerRuntime.Rmi(ctx, b.builtID); err != nil { + if err := b.ContainerRuntime.Rmi(ctx, b.builtID, RmiOpts{}); err != nil { return fmt.Errorf("unable to remove built dockerfile image %q: %s", b.builtID, err) } return nil diff --git a/pkg/container_runtime/interface.go b/pkg/container_runtime/interface.go index 467e946491..80a8fd926a 100644 --- a/pkg/container_runtime/interface.go +++ b/pkg/container_runtime/interface.go @@ -7,7 +7,31 @@ import ( "github.com/werf/werf/pkg/image" ) -type BuildDockerfileOptions struct { +type CommonOpts struct{} + +type TagOpts struct { + CommonOpts +} + +type PushOpts struct { + CommonOpts +} + +type PullOpts struct { + CommonOpts +} + +type RmiOpts struct { + CommonOpts +} + +type GetImageInfoOpts struct { + CommonOpts +} + +type BuildDockerfileOpts struct { + CommonOpts + ContextTar io.ReadCloser DockerfileCtxRelPath string // TODO: remove this and instead write the []byte dockerfile to /Dockerfile in the ContextTar inDockerServerRuntime.BuildDockerfile(). Target string @@ -30,13 +54,13 @@ type BuildDockerfileOptions struct { // } type ContainerRuntime interface { - Tag(ctx context.Context, ref, newRef string) error - Push(ctx context.Context, ref string) error - Pull(ctx context.Context, ref string) error - Rmi(ctx context.Context, ref string) error + Tag(ctx context.Context, ref, newRef string, opts TagOpts) error + Push(ctx context.Context, ref string, opts PushOpts) error + Pull(ctx context.Context, ref string, opts PullOpts) error + Rmi(ctx context.Context, ref string, opts RmiOpts) error - GetImageInfo(ctx context.Context, ref string) (*image.Info, error) - BuildDockerfile(ctx context.Context, dockerfile []byte, opts BuildDockerfileOptions) (string, error) + GetImageInfo(ctx context.Context, ref string, opts GetImageInfoOpts) (*image.Info, error) + BuildDockerfile(ctx context.Context, dockerfile []byte, opts BuildDockerfileOpts) (string, error) // StapelBuild(opts StapelBuildOptions) string String() string diff --git a/pkg/container_runtime/legacy_base_image.go b/pkg/container_runtime/legacy_base_image.go index e7008eac83..9990660f60 100644 --- a/pkg/container_runtime/legacy_base_image.go +++ b/pkg/container_runtime/legacy_base_image.go @@ -31,7 +31,7 @@ func (i *legacyBaseImage) SetName(name string) { } func (i *legacyBaseImage) MustResetInfo(ctx context.Context) error { - if info, err := i.ContainerRuntime.GetImageInfo(ctx, i.Name()); err != nil { + if info, err := i.ContainerRuntime.GetImageInfo(ctx, i.Name(), GetImageInfoOpts{}); err != nil { return fmt.Errorf("unable to get info for image %s: %s", i.Name(), err) } else { i.SetInfo(info) diff --git a/pkg/container_runtime/legacy_stage_image.go b/pkg/container_runtime/legacy_stage_image.go index e652963313..99e63bbdd5 100644 --- a/pkg/container_runtime/legacy_stage_image.go +++ b/pkg/container_runtime/legacy_stage_image.go @@ -114,7 +114,7 @@ func (i *LegacyStageImage) Build(ctx context.Context, options LegacyBuildOptions } } - if info, err := i.ContainerRuntime.GetImageInfo(ctx, i.MustGetBuiltId()); err != nil { + if info, err := i.ContainerRuntime.GetImageInfo(ctx, i.MustGetBuiltId(), GetImageInfoOpts{}); err != nil { return err } else { i.SetInfo(info) diff --git a/pkg/container_runtime/perf_check_container_runtime.go b/pkg/container_runtime/perf_check_container_runtime.go index 8a075151bf..cecf849d3c 100644 --- a/pkg/container_runtime/perf_check_container_runtime.go +++ b/pkg/container_runtime/perf_check_container_runtime.go @@ -16,47 +16,47 @@ func NewPerfCheckContainerRuntime(containerRuntime ContainerRuntime) *PerfCheckC return &PerfCheckContainerRuntime{ContainerRuntime: containerRuntime} } -func (runtime *PerfCheckContainerRuntime) GetImageInfo(ctx context.Context, ref string) (resImg *image.Info, resErr error) { +func (runtime *PerfCheckContainerRuntime) GetImageInfo(ctx context.Context, ref string, opts GetImageInfoOpts) (resImg *image.Info, resErr error) { logboek.Context(ctx).Default().LogProcess("ContainerRuntime.GetImageInfo %q", ref). Do(func() { - resImg, resErr = runtime.ContainerRuntime.GetImageInfo(ctx, ref) + resImg, resErr = runtime.ContainerRuntime.GetImageInfo(ctx, ref, opts) }) return } -func (runtime *PerfCheckContainerRuntime) Rmi(ctx context.Context, ref string) (resErr error) { +func (runtime *PerfCheckContainerRuntime) Rmi(ctx context.Context, ref string, opts RmiOpts) (resErr error) { logboek.Context(ctx).Default().LogProcess("ContainerRuntime.Rmi %q", ref). Do(func() { - resErr = runtime.ContainerRuntime.Rmi(ctx, ref) + resErr = runtime.ContainerRuntime.Rmi(ctx, ref, opts) }) return } -func (runtime *PerfCheckContainerRuntime) Pull(ctx context.Context, ref string) (resErr error) { +func (runtime *PerfCheckContainerRuntime) Pull(ctx context.Context, ref string, opts PullOpts) (resErr error) { logboek.Context(ctx).Default().LogProcess("ContainerRuntime.Pull %q", ref). Do(func() { - resErr = runtime.ContainerRuntime.Pull(ctx, ref) + resErr = runtime.ContainerRuntime.Pull(ctx, ref, opts) }) return } -func (runtime *PerfCheckContainerRuntime) Tag(ctx context.Context, ref, newRef string) (resErr error) { +func (runtime *PerfCheckContainerRuntime) Tag(ctx context.Context, ref, newRef string, opts TagOpts) (resErr error) { logboek.Context(ctx).Default().LogProcess("ContainerRuntime.Tag %q as %q", ref, newRef). Do(func() { - resErr = runtime.ContainerRuntime.Tag(ctx, ref, newRef) + resErr = runtime.ContainerRuntime.Tag(ctx, ref, newRef, opts) }) return } -func (runtime *PerfCheckContainerRuntime) Push(ctx context.Context, ref string) (resErr error) { +func (runtime *PerfCheckContainerRuntime) Push(ctx context.Context, ref string, opts PushOpts) (resErr error) { logboek.Context(ctx).Default().LogProcess("ContainerRuntime.Push %q", ref). Do(func() { - resErr = runtime.ContainerRuntime.Push(ctx, ref) + resErr = runtime.ContainerRuntime.Push(ctx, ref, opts) }) return } -func (runtime *PerfCheckContainerRuntime) BuildDockerfile(ctx context.Context, dockerfile []byte, opts BuildDockerfileOptions) (resID string, resErr error) { +func (runtime *PerfCheckContainerRuntime) BuildDockerfile(ctx context.Context, dockerfile []byte, opts BuildDockerfileOpts) (resID string, resErr error) { logboek.Context(ctx).Default().LogProcess("ContainerRuntime.BuildDockerfile"). Do(func() { resID, resErr = runtime.ContainerRuntime.BuildDockerfile(ctx, dockerfile, opts) diff --git a/pkg/storage/repo_stages_storage.go b/pkg/storage/repo_stages_storage.go index 61cf4e0ea7..17900bdfde 100644 --- a/pkg/storage/repo_stages_storage.go +++ b/pkg/storage/repo_stages_storage.go @@ -498,12 +498,12 @@ func (storage *RepoStagesStorage) FetchImage(ctx context.Context, img container_ func (storage *RepoStagesStorage) StoreImage(ctx context.Context, img container_runtime.LegacyImageInterface) error { if img.GetBuiltId() != "" { - if err := storage.ContainerRuntime.Tag(ctx, img.GetBuiltId(), img.Name()); err != nil { + if err := storage.ContainerRuntime.Tag(ctx, img.GetBuiltId(), img.Name(), container_runtime.TagOpts{}); err != nil { return fmt.Errorf("unable to tag built image %q by %q: %s", img.GetBuiltId(), img.Name(), err) } } - if err := storage.ContainerRuntime.Push(ctx, img.Name()); err != nil { + if err := storage.ContainerRuntime.Push(ctx, img.Name(), container_runtime.PushOpts{}); err != nil { return fmt.Errorf("unable to push image %q: %s", img.Name(), err) } @@ -511,7 +511,7 @@ func (storage *RepoStagesStorage) StoreImage(ctx context.Context, img container_ } func (storage *RepoStagesStorage) ShouldFetchImage(ctx context.Context, img container_runtime.LegacyImageInterface) (bool, error) { - if info, err := storage.ContainerRuntime.GetImageInfo(ctx, img.Name()); err != nil { + if info, err := storage.ContainerRuntime.GetImageInfo(ctx, img.Name(), container_runtime.GetImageInfoOpts{}); err != nil { return false, fmt.Errorf("unable to get inspect for image %s: %s", img.Name(), err) } else if info != nil { img.SetInfo(info) From 44bed273a8d2e686acb64a5d526f4d9555b7bcf7 Mon Sep 17 00:00:00 2001 From: Ilya Lesikov Date: Fri, 15 Oct 2021 14:23:23 +0300 Subject: [PATCH 6/7] refactor(buildah): public docker-with-fuse docker flags --- pkg/buildah/docker_with_fuse_buildah.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/buildah/docker_with_fuse_buildah.go b/pkg/buildah/docker_with_fuse_buildah.go index 06742109ca..12e035f958 100644 --- a/pkg/buildah/docker_with_fuse_buildah.go +++ b/pkg/buildah/docker_with_fuse_buildah.go @@ -141,7 +141,7 @@ func (b *DockerWithFuseBuildah) runBuildah(ctx context.Context, dockerArgs []str args := []string{"--rm"} args = append(args, dockerArgs...) - args = append(args, buildahWithFuseDockerArgs(BuildahStorageContainerName)...) + args = append(args, BuildahWithFuseDockerArgs(BuildahStorageContainerName, docker.DockerConfigDir)...) args = append(args, buildahArgs...) if debug() { @@ -186,13 +186,13 @@ func runStorageContainer(ctx context.Context, name, image string) error { }) } -func buildahWithFuseDockerArgs(storageContainerName string) []string { +func BuildahWithFuseDockerArgs(storageContainerName, dockerConfigDir string) []string { return []string{ "--user", "1000", "--device", "/dev/fuse", "--security-opt", "seccomp=unconfined", "--security-opt", "apparmor=unconfined", - "--volume", fmt.Sprintf("%s:%s", docker.DockerConfigDir, "/home/build/.docker"), + "--volume", fmt.Sprintf("%s:%s", dockerConfigDir, "/home/build/.docker"), "--volumes-from", storageContainerName, BuildahImage, "buildah", } From 79922438fc7c1a1da821515078b8945fdd79e8ec Mon Sep 17 00:00:00 2001 From: Ilya Lesikov Date: Fri, 15 Oct 2021 14:23:56 +0300 Subject: [PATCH 7/7] fix(buildah): builddockerfile built OCI image --- pkg/buildah/native_rootless_buildah_linux.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/buildah/native_rootless_buildah_linux.go b/pkg/buildah/native_rootless_buildah_linux.go index 295286dc2c..90ab04e872 100644 --- a/pkg/buildah/native_rootless_buildah_linux.go +++ b/pkg/buildah/native_rootless_buildah_linux.go @@ -137,7 +137,8 @@ func (b *NativeRootlessBuildah) Push(ctx context.Context, ref string, opts PushO func (b *NativeRootlessBuildah) BuildFromDockerfile(ctx context.Context, dockerfile []byte, opts BuildFromDockerfileOpts) (string, error) { buildOpts := define.BuildOptions{ - Isolation: define.IsolationOCIRootless, + Isolation: define.IsolationOCIRootless, + OutputFormat: buildah.Dockerv2ImageManifest, CommonBuildOpts: &define.CommonBuildOptions{ ShmSize: DefaultShmSize, },