From 7feffb0f84560ff5af31b3ef752c87f7672b9559 Mon Sep 17 00:00:00 2001 From: kevinrizza Date: Tue, 24 Mar 2020 15:27:40 -0400 Subject: [PATCH 1/3] Bump operator-registry dependency *Update operator-registry dependency to 1.6.0 *Adds fix for generated dockerfiles *Adds optional output-directory parameter *Update cleanup funcs to handle new structure --- CHANGELOG.md | 2 ++ cmd/operator-sdk/bundle/cmd.go | 13 +++++++++++-- cmd/operator-sdk/bundle/create.go | 6 ++++-- doc/cli/operator-sdk_bundle_create.md | 1 + go.mod | 4 ++-- go.sum | 14 ++++++++------ test/test-framework/go.sum | 7 ++++--- 7 files changed, 32 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b7961cbbea..5bff74d8fdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,12 @@ - The methods `ctx.GetOperatorNamespace()` and `ctx.GetWatchNamespace()` was added `pkg/test` in order to replace `ctx.GetNamespace()` which is deprecated. ([#2617](https://github.com/operator-framework/operator-sdk/pull/2617)) - The `--crd-version` flag was added to the `new`, `add api`, `add crd`, and `generate crds` commands so that users can opt-in to `v1` CRDs. ([#2684](https://github.com/operator-framework/operator-sdk/pull/2684)) - The printout for the compatible Kubernetes Version [#2446](https://github.com/operator-framework/operator-sdk/pull/2446) +- Add the new flag `output-dir` to the command `operator-sdk bundle create`. ([#2662](https://github.com/operator-framework/operator-sdk/pull/2662)) ### Changed - The scorecard when creating a Custom Resource, will produce a message to the user if that CR already exists. ([#2683](https://github.com/operator-framework/operator-sdk/pull/2683)) +- Upgrade the `operator-registry` dependency version from `v1.5.7`to `v1.6.0` to update `bundle create` behaviour. ([#2662](https://github.com/operator-framework/operator-sdk/pull/2662)) ### Deprecated diff --git a/cmd/operator-sdk/bundle/cmd.go b/cmd/operator-sdk/bundle/cmd.go index 877f3b3c90b..1b8e452acbd 100644 --- a/cmd/operator-sdk/bundle/cmd.go +++ b/cmd/operator-sdk/bundle/cmd.go @@ -42,6 +42,7 @@ https://github.com/openshift/enhancements/blob/master/enhancements/olm/operator- type bundleCmd struct { directory string + outputDir string packageName string imageTag string imageBuilder string @@ -53,9 +54,17 @@ type bundleCmd struct { // cleanupFuncs returns a set of general funcs to clean up after a bundle // subcommand. func (c bundleCmd) cleanupFuncs() (fs []func()) { - metaDir := filepath.Join(c.directory, bundle.MetadataDir) - dockerFile := filepath.Join(c.directory, bundle.DockerFile) + manifestDir := c.outputDir + if manifestDir == "" { + manifestDir = c.directory + } + absManifestDir, _ := filepath.Abs(manifestDir) + manifestParent := filepath.Dir(absManifestDir) + metaDir := filepath.Join(manifestParent, bundle.MetadataDir) metaExists := isExist(metaDir) + + workingDir, _ := os.Getwd() + dockerFile := filepath.Join(workingDir, bundle.DockerFile) dockerFileExists := isExist(dockerFile) fs = append(fs, func() { diff --git a/cmd/operator-sdk/bundle/create.go b/cmd/operator-sdk/bundle/create.go index 574bb9e5466..5d9cd05d88b 100644 --- a/cmd/operator-sdk/bundle/create.go +++ b/cmd/operator-sdk/bundle/create.go @@ -78,7 +78,7 @@ $ operator-sdk bundle create \ if len(args) != 0 { return fmt.Errorf("command %s does not accept any arguments", cmd.CommandPath()) } - err := bundle.GenerateFunc(c.directory, c.packageName, channels, + err := bundle.GenerateFunc(c.directory, c.outputDir, c.packageName, channels, c.defaultChannel, true) if err != nil { log.Fatalf("Error generating bundle image files: %v", err) @@ -96,7 +96,7 @@ $ operator-sdk bundle create \ defer cleanup() } // Build but never overwrite existing metadata/Dockerfile. - err := bundle.BuildFunc(c.directory, c.imageTag, c.imageBuilder, + err := bundle.BuildFunc(c.directory, c.outputDir, c.imageTag, c.imageBuilder, c.packageName, channels, c.defaultChannel, false) if err != nil { log.Fatalf("Error building bundle image: %v", err) @@ -115,6 +115,8 @@ $ operator-sdk bundle create \ cmd.Flags().StringVarP(&c.directory, "directory", "d", defaultDir, "The directory where bundle manifests are located") + cmd.Flags().StringVarP(&c.outputDir, "output-dir", "o", "", + "Optional output directory for operator manifests") cmd.Flags().StringVarP(&c.packageName, "package", "p", projectName, "The name of the package that bundle image belongs to. Set if package name differs from project name") cmd.Flags().StringSliceVarP(&c.channels, "channels", "c", defaultChannels, diff --git a/doc/cli/operator-sdk_bundle_create.md b/doc/cli/operator-sdk_bundle_create.md index a1bd6e7a557..b93c980125c 100644 --- a/doc/cli/operator-sdk_bundle_create.md +++ b/doc/cli/operator-sdk_bundle_create.md @@ -59,6 +59,7 @@ $ operator-sdk bundle create \ -g, --generate-only Generate metadata and a Dockerfile on disk without building the bundle image -h, --help help for create -b, --image-builder string Tool to build container images. One of: [docker, podman, buildah] (default "docker") + -o, --output-dir string Optional output directory for operator manifests -p, --package string The name of the package that bundle image belongs to. Set if package name differs from project name (default "operator-sdk") ``` diff --git a/go.mod b/go.mod index ea209c2a537..6646ad2f29f 100644 --- a/go.mod +++ b/go.mod @@ -24,9 +24,9 @@ require ( github.com/mattn/go-isatty v0.0.8 github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/mapstructure v1.1.2 - github.com/operator-framework/api v0.0.0-20200120235816-80fd2f1a09c9 + github.com/operator-framework/api v0.1.0 github.com/operator-framework/operator-lifecycle-manager v0.0.0-20191115003340-16619cd27fa5 - github.com/operator-framework/operator-registry v1.5.7-0.20200121213444-d8e2ec52c19a + github.com/operator-framework/operator-registry v1.6.0 github.com/pborman/uuid v1.2.0 github.com/pkg/errors v0.8.1 github.com/prometheus/client_golang v1.2.1 diff --git a/go.sum b/go.sum index 5b522130628..7d5afb13e04 100644 --- a/go.sum +++ b/go.sum @@ -604,24 +604,28 @@ github.com/openshift/origin v0.0.0-20160503220234-8f127d736703/go.mod h1:0Rox5r9 github.com/openshift/prom-label-proxy v0.1.1-0.20191016113035-b8153a7f39f1/go.mod h1:p5MuxzsYP1JPsNGwtjtcgRHHlGziCJJfztff91nNixw= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/operator-framework/api v0.0.0-20200120235816-80fd2f1a09c9 h1:HfxMEPJ0djo/RNfrmli3kI2oKS6IeuIZWu1Q5Rewt/o= -github.com/operator-framework/api v0.0.0-20200120235816-80fd2f1a09c9/go.mod h1:S5IdlJvmKkF84K2tBvsrqJbI2FVy03P88R75snpRxJo= +github.com/operator-framework/api v0.1.0 h1:+GFEiyZAi+T4XNxm8/DR0Jo2+9oGSFaUEXNT0N6iHp0= +github.com/operator-framework/api v0.1.0/go.mod h1:/Jcpy9Ls8W1LK1hhEw30nCRBSBzbT8e/fE09TfRG0To= github.com/operator-framework/operator-lifecycle-manager v0.0.0-20191115003340-16619cd27fa5 h1:rjaihxY50c5C+kbQIK4s36R8zxByATYrgRbua4eiG6o= github.com/operator-framework/operator-lifecycle-manager v0.0.0-20191115003340-16619cd27fa5/go.mod h1:zL34MNy92LPutBH5gQK+gGhtgTUlZZX03I2G12vWHF4= github.com/operator-framework/operator-registry v1.5.1 h1:8ruUOG6IBDVTAXYWKsv6hwr4yv/0SFPFPAYGCpcv97E= github.com/operator-framework/operator-registry v1.5.1/go.mod h1:agrQlkWOo1q8U1SAaLSS2WQ+Z9vswNT2M2HFib9iuLY= github.com/operator-framework/operator-registry v1.5.3 h1:az83WDwgB+tHsmVn+tFq72yQBbaUAye8e4+KkDQmzLs= github.com/operator-framework/operator-registry v1.5.3/go.mod h1:agrQlkWOo1q8U1SAaLSS2WQ+Z9vswNT2M2HFib9iuLY= -github.com/operator-framework/operator-registry v1.5.7-0.20200121213444-d8e2ec52c19a h1:+Kxyr2Vp1PaPAF2yzrxLu0NcxbX9O5W+mHP6w+wQ5w8= -github.com/operator-framework/operator-registry v1.5.7-0.20200121213444-d8e2ec52c19a/go.mod h1:ekexcV4O8YMxdQuPb+Xco7MHfVmRIq7Jvj5e6NU7dHI= +github.com/operator-framework/operator-registry v1.6.0 h1:v/Gp33VNoR1QHZeHQagH7y6u4q+4reSEZ3rJTc+A7GE= +github.com/operator-framework/operator-registry v1.6.0/go.mod h1:6+zVeyLMgEJ4EC44VDbCtzQLtwtkmTVdlErBr+SaUiE= github.com/otiai10/copy v1.0.1 h1:gtBjD8aq4nychvRZ2CyJvFWAw0aja+VHazDdruZKGZA= github.com/otiai10/copy v1.0.1/go.mod h1:8bMCJrAqOtN/d9oyh5HR7HhLQMvcGMpGdwRDYsfOCHc= +github.com/otiai10/copy v1.0.2 h1:DDNipYy6RkIkjMwy+AWzgKiNTyj2RUI9yEMeETEpVyc= +github.com/otiai10/copy v1.0.2/go.mod h1:c7RpqBkwMom4bYTSkLSym4VSJz/XtncWRAj/J4PEIMY= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= github.com/otiai10/curr v0.0.0-20190513014714-f5a3d24e5776 h1:o59bHXu8Ejas8Kq6pjoVJQ9/neN66SM8AKh6wI42BBs= github.com/otiai10/curr v0.0.0-20190513014714-f5a3d24e5776/go.mod h1:3HNVkVOU7vZeFXocWuvtcS0XSFLcf2XUSDHkq9t1jU4= github.com/otiai10/mint v1.2.3/go.mod h1:YnfyPNhBvnY8bW4SGQHCs/aAFhkgySlMZbrF5U0bOVw= github.com/otiai10/mint v1.2.4 h1:DxYL0itZyPaR5Z9HILdxSoHx+gNs6Yx+neOGS3IVUk0= github.com/otiai10/mint v1.2.4/go.mod h1:d+b7n/0R3tdyUYYylALXpWQ/kTN+QobSq/4SRGBkR3M= +github.com/otiai10/mint v1.3.0 h1:Ady6MKVezQwHBkGzLFbrsywyp09Ah7rkmfjV3Bcr5uc= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -994,8 +998,6 @@ gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81 gotest.tools/gotestsum v0.3.5/go.mod h1:Mnf3e5FUzXbkCfynWBGOwLssY7gTQgCHObK9tMpAriY= helm.sh/helm/v3 v3.0.0 h1:or/9cs1GgfcTQeEnR2CVJNw893/rmqIG1KsNHmUiSFw= helm.sh/helm/v3 v3.0.0/go.mod h1:sI7B9yfvMgxtTPMWdk1jSKJ2aa59UyP9qhPydqW6mgo= -helm.sh/helm/v3 v3.0.1 h1:gEs30kweCOnLFK9Diq2S8b+VHmWQ2oi465GhqTc3ZxI= -helm.sh/helm/v3 v3.0.1/go.mod h1:sI7B9yfvMgxtTPMWdk1jSKJ2aa59UyP9qhPydqW6mgo= helm.sh/helm/v3 v3.0.2 h1:BggvLisIMrAc+Is5oAHVrlVxgwOOrMN8nddfQbm5gKo= helm.sh/helm/v3 v3.0.2/go.mod h1:KBxE6XWO57XSNA1PA9CvVLYRY0zWqYQTad84bNXp1lw= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/test/test-framework/go.sum b/test/test-framework/go.sum index 1c4e7ac3dd0..f0fdc0472b1 100644 --- a/test/test-framework/go.sum +++ b/test/test-framework/go.sum @@ -531,16 +531,18 @@ github.com/openshift/origin v0.0.0-20160503220234-8f127d736703/go.mod h1:0Rox5r9 github.com/openshift/prom-label-proxy v0.1.1-0.20191016113035-b8153a7f39f1/go.mod h1:p5MuxzsYP1JPsNGwtjtcgRHHlGziCJJfztff91nNixw= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/operator-framework/api v0.0.0-20200120235816-80fd2f1a09c9/go.mod h1:S5IdlJvmKkF84K2tBvsrqJbI2FVy03P88R75snpRxJo= +github.com/operator-framework/api v0.1.0/go.mod h1:/Jcpy9Ls8W1LK1hhEw30nCRBSBzbT8e/fE09TfRG0To= github.com/operator-framework/operator-lifecycle-manager v0.0.0-20191115003340-16619cd27fa5/go.mod h1:zL34MNy92LPutBH5gQK+gGhtgTUlZZX03I2G12vWHF4= github.com/operator-framework/operator-registry v1.5.1/go.mod h1:agrQlkWOo1q8U1SAaLSS2WQ+Z9vswNT2M2HFib9iuLY= github.com/operator-framework/operator-registry v1.5.3/go.mod h1:agrQlkWOo1q8U1SAaLSS2WQ+Z9vswNT2M2HFib9iuLY= -github.com/operator-framework/operator-registry v1.5.7-0.20200121213444-d8e2ec52c19a/go.mod h1:ekexcV4O8YMxdQuPb+Xco7MHfVmRIq7Jvj5e6NU7dHI= +github.com/operator-framework/operator-registry v1.6.0/go.mod h1:6+zVeyLMgEJ4EC44VDbCtzQLtwtkmTVdlErBr+SaUiE= github.com/otiai10/copy v1.0.1/go.mod h1:8bMCJrAqOtN/d9oyh5HR7HhLQMvcGMpGdwRDYsfOCHc= +github.com/otiai10/copy v1.0.2/go.mod h1:c7RpqBkwMom4bYTSkLSym4VSJz/XtncWRAj/J4PEIMY= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= github.com/otiai10/curr v0.0.0-20190513014714-f5a3d24e5776/go.mod h1:3HNVkVOU7vZeFXocWuvtcS0XSFLcf2XUSDHkq9t1jU4= github.com/otiai10/mint v1.2.3/go.mod h1:YnfyPNhBvnY8bW4SGQHCs/aAFhkgySlMZbrF5U0bOVw= github.com/otiai10/mint v1.2.4/go.mod h1:d+b7n/0R3tdyUYYylALXpWQ/kTN+QobSq/4SRGBkR3M= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -906,7 +908,6 @@ gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81 gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/gotestsum v0.3.5/go.mod h1:Mnf3e5FUzXbkCfynWBGOwLssY7gTQgCHObK9tMpAriY= helm.sh/helm/v3 v3.0.0/go.mod h1:sI7B9yfvMgxtTPMWdk1jSKJ2aa59UyP9qhPydqW6mgo= -helm.sh/helm/v3 v3.0.1/go.mod h1:sI7B9yfvMgxtTPMWdk1jSKJ2aa59UyP9qhPydqW6mgo= helm.sh/helm/v3 v3.0.2/go.mod h1:KBxE6XWO57XSNA1PA9CvVLYRY0zWqYQTad84bNXp1lw= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 73b294a6f4db39bcc4207745623d652ac8719313 Mon Sep 17 00:00:00 2001 From: Eric Stroczynski Date: Tue, 24 Mar 2020 22:17:07 -0700 Subject: [PATCH 2/3] bundle create: fix issue where manifests/ is expected by the operator-registry image builder but not generated by the SDK. In case deploy/olm-catalog//manifests doesn't exist, create one and delete it after the image is done building. If --generate-only is set, do not remove manifests/. --version lets a user specify which operator version they want to build an image for, and --latest uses the highest semver'd operator in the bundle parent dir. hack/tests: add 'bundle create' test cases doc,website: update generated CLI docs CHANGELOG.md: --output-dir addition and breaking change for bundle.Dockerfile location doc/migration: add breaking change to migration guide --- CHANGELOG.md | 3 +- Makefile | 1 + cmd/operator-sdk/bundle/cmd.go | 60 +--- cmd/operator-sdk/bundle/create.go | 317 ++++++++++++++---- cmd/operator-sdk/bundle/validate.go | 27 +- doc/cli/operator-sdk_bundle_create.md | 58 ++-- doc/cli/operator-sdk_bundle_validate.md | 25 +- doc/migration/version-upgrade-guide.md | 18 +- doc/user/olm-catalog/bundle-cli.md | 6 +- hack/tests/subcommand-bundle.sh | 83 +++++ .../en/docs/cli/operator-sdk_bundle_create.md | 59 ++-- .../docs/cli/operator-sdk_bundle_validate.md | 25 +- .../en/docs/golang/olm-catalog/bundle-cli.md | 6 +- .../docs/migration/version-upgrade-guide.md | 18 +- 14 files changed, 486 insertions(+), 220 deletions(-) create mode 100755 hack/tests/subcommand-bundle.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bff74d8fdb..b02760e5f1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,12 +6,13 @@ - The methods `ctx.GetOperatorNamespace()` and `ctx.GetWatchNamespace()` was added `pkg/test` in order to replace `ctx.GetNamespace()` which is deprecated. ([#2617](https://github.com/operator-framework/operator-sdk/pull/2617)) - The `--crd-version` flag was added to the `new`, `add api`, `add crd`, and `generate crds` commands so that users can opt-in to `v1` CRDs. ([#2684](https://github.com/operator-framework/operator-sdk/pull/2684)) - The printout for the compatible Kubernetes Version [#2446](https://github.com/operator-framework/operator-sdk/pull/2446) -- Add the new flag `output-dir` to the command `operator-sdk bundle create`. ([#2662](https://github.com/operator-framework/operator-sdk/pull/2662)) +- Add the new flag `--output-dir` to the command [`operator-sdk bundle create`](./doc/cli/operator-sdk_bundle_create.md). ([#2715](https://github.com/operator-framework/operator-sdk/pull/2715)) ### Changed - The scorecard when creating a Custom Resource, will produce a message to the user if that CR already exists. ([#2683](https://github.com/operator-framework/operator-sdk/pull/2683)) - Upgrade the `operator-registry` dependency version from `v1.5.7`to `v1.6.0` to update `bundle create` behaviour. ([#2662](https://github.com/operator-framework/operator-sdk/pull/2662)) +- **Breaking Change:** [`operator-sdk bundle create --generate-only`](./doc/cli/operator-sdk_bundle_create.md) now writes a Dockerfile to `/bundle.Dockerfile` and copies bundle manifests directly from the argument to `--directory`. ([#2715](https://github.com/operator-framework/operator-sdk/pull/2715)) ### Deprecated diff --git a/Makefile b/Makefile index f2325e68307..1d65b111683 100644 --- a/Makefile +++ b/Makefile @@ -218,6 +218,7 @@ test-ci: test-markdown test-sanity test-unit install test-subcommand test-e2e ## .PHONY: test-subcommand test-subcommand-local test-subcommand-scorecard test-subcommand-olm-install test-subcommand: test-subcommand-local test-subcommand-scorecard test-subcommand-olm-install + ./hack/tests/subcommand-bundle.sh test-subcommand-local: ./hack/tests/subcommand.sh diff --git a/cmd/operator-sdk/bundle/cmd.go b/cmd/operator-sdk/bundle/cmd.go index 1b8e452acbd..245b55c344a 100644 --- a/cmd/operator-sdk/bundle/cmd.go +++ b/cmd/operator-sdk/bundle/cmd.go @@ -15,13 +15,20 @@ package bundle import ( - "os" - "path/filepath" - - "github.com/operator-framework/operator-registry/pkg/lib/bundle" "github.com/spf13/cobra" ) +//nolint:structcheck +type bundleCmd struct { + directory string + packageName string + imageTag string + imageBuilder string + defaultChannel string + channels []string + generateOnly bool +} + func NewCmd() *cobra.Command { cmd := &cobra.Command{ Use: "bundle", @@ -39,48 +46,3 @@ https://github.com/openshift/enhancements/blob/master/enhancements/olm/operator- ) return cmd } - -type bundleCmd struct { - directory string - outputDir string - packageName string - imageTag string - imageBuilder string - defaultChannel string - channels []string - generateOnly bool -} - -// cleanupFuncs returns a set of general funcs to clean up after a bundle -// subcommand. -func (c bundleCmd) cleanupFuncs() (fs []func()) { - manifestDir := c.outputDir - if manifestDir == "" { - manifestDir = c.directory - } - absManifestDir, _ := filepath.Abs(manifestDir) - manifestParent := filepath.Dir(absManifestDir) - metaDir := filepath.Join(manifestParent, bundle.MetadataDir) - metaExists := isExist(metaDir) - - workingDir, _ := os.Getwd() - dockerFile := filepath.Join(workingDir, bundle.DockerFile) - dockerFileExists := isExist(dockerFile) - fs = append(fs, - func() { - if !metaExists { - _ = os.RemoveAll(metaDir) - } - }, - func() { - if !dockerFileExists { - _ = os.RemoveAll(dockerFile) - } - }) - return fs -} - -func isExist(path string) bool { - _, err := os.Stat(path) - return os.IsExist(err) -} diff --git a/cmd/operator-sdk/bundle/create.go b/cmd/operator-sdk/bundle/create.go index 5d9cd05d88b..f78f1ac99fa 100644 --- a/cmd/operator-sdk/bundle/create.go +++ b/cmd/operator-sdk/bundle/create.go @@ -17,22 +17,35 @@ package bundle import ( "errors" "fmt" + "io/ioutil" "os" "path/filepath" "strings" catalog "github.com/operator-framework/operator-sdk/internal/scaffold/olm-catalog" + "github.com/operator-framework/operator-sdk/internal/util/fileutil" "github.com/operator-framework/operator-sdk/internal/util/projutil" + "github.com/blang/semver" "github.com/operator-framework/operator-registry/pkg/lib/bundle" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "github.com/spf13/pflag" ) +type bundleCreateCmd struct { + bundleCmd + + outputDir string + version string + useLatestVersion bool +} + // newCreateCmd returns a command that will build operator bundle image or // generate metadata for them. func newCreateCmd() *cobra.Command { - c := &bundleCmd{} + c := &bundleCreateCmd{} + cmd := &cobra.Command{ Use: "create", Short: "Create an operator bundle image", @@ -41,92 +54,270 @@ bundle image containing operator metadata and manifests, tagged with the provided image tag. To write metadata and a bundle image Dockerfile to disk, set '--generate-only=true'. -Bundle metadata will be generated in /metadata, and the Dockerfile -in . This flag is useful if you want to build an operator's -bundle image manually or modify metadata before building an image. +Bundle metadata will be generated in /metadata, and a bundle Dockerfile +at /bundle.Dockerfile. Additionally a /manifests +directory will be created if one does not exist already for the specified +operator version (use --latest or --version=) This flag is useful if +you want to build an operator's bundle image manually, modify metadata before +building an image, or want to generate a 'manifests/' directory containing your +latest operator manifests for compatibility with other operator tooling. More information on operator bundle images and metadata: https://github.com/openshift/enhancements/blob/master/enhancements/olm/operator-bundle.md#docker -NOTE: bundle images are not runnable.`, - Example: `The following invocation will build a test-operator bundle image using Docker. +NOTE: bundle images are not runnable. +`, + Example: `The following invocation will build a test-operator 0.1.0 bundle image using Docker. This image will contain manifests for package channels 'stable' and 'beta': -$ operator-sdk bundle create quay.io/example/test-operator:v0.1.0 \ - --directory ./deploy/olm-catalog/test-operator \ - --package test-operator \ - --channels stable,beta \ - --default-channel stable + $ operator-sdk bundle create quay.io/example/test-operator:v0.1.0 \ + --version 0.1.0 \ + --directory ./deploy/olm-catalog/test-operator \ + --package test-operator \ + --channels stable,beta \ + --default-channel stable -Assuming your operator has the same name as your operator and the only channel -is 'stable', the above command can be abbreviated to: +Assuming your operator has the same name as your operator, the tag corresponds to +a bundle directory name, and the only channel is 'stable', the above command can +be abbreviated to: -$ operator-sdk bundle create quay.io/example/test-operator:v0.1.0 + $ operator-sdk bundle create quay.io/example/test-operator:v0.1.0 --version 0.1.0 -The following invocation will generate test-operator bundle metadata and -Dockerfile without building the image: +The following invocation will generate test-operator bundle metadata, a manifests +dir, and Dockerfile for your latest operator version without building the image: -$ operator-sdk bundle create \ - --generate-only \ - --directory ./deploy/olm-catalog/test-operator \ - --package test-operator \ - --channels stable,beta \ - --default-channel stable`, + $ operator-sdk bundle create \ + --generate-only \ + --latest \ + --directory ./deploy/olm-catalog/test-operator \ + --package test-operator \ + --channels stable,beta \ + --default-channel stable +`, RunE: func(cmd *cobra.Command, args []string) error { - channels := strings.Join(c.channels, ",") - if c.generateOnly { - if len(args) != 0 { - return fmt.Errorf("command %s does not accept any arguments", cmd.CommandPath()) - } - err := bundle.GenerateFunc(c.directory, c.outputDir, c.packageName, channels, - c.defaultChannel, true) - if err != nil { - log.Fatalf("Error generating bundle image files: %v", err) - } - return nil + if err := c.setDefaults(); err != nil { + return fmt.Errorf("error setting default args: %v", err) } - // An image tag is required for build only. - if len(args) != 1 { - return errors.New("a bundle image tag is a required argument, ex. example.com/test-operator:v0.1.0") + + if err := c.validate(args); err != nil { + return fmt.Errorf("error validating args: %v", err) } - c.imageTag = args[0] - // Clean up transient metadata and Dockerfile once the image is built, - // as they are no longer needed. - for _, cleanup := range c.cleanupFuncs() { - defer cleanup() + + if !c.generateOnly { + c.imageTag = args[0] } - // Build but never overwrite existing metadata/Dockerfile. - err := bundle.BuildFunc(c.directory, c.outputDir, c.imageTag, c.imageBuilder, - c.packageName, channels, c.defaultChannel, false) - if err != nil { - log.Fatalf("Error building bundle image: %v", err) + if err := c.run(); err != nil { + log.Fatal(err) } return nil }, } - // Set up default values. - projectName := filepath.Base(projutil.MustGetwd()) - defaultDir := "" - if _, err := os.Stat(catalog.OLMCatalogDir); err == nil || os.IsExist(err) { - defaultDir = filepath.Join(catalog.OLMCatalogDir, projectName) - } - defaultChannels := []string{"stable"} + c.addToFlagSet(cmd.Flags()) + + return cmd +} + +func (c *bundleCreateCmd) addToFlagSet(fs *pflag.FlagSet) { - cmd.Flags().StringVarP(&c.directory, "directory", "d", defaultDir, - "The directory where bundle manifests are located") - cmd.Flags().StringVarP(&c.outputDir, "output-dir", "o", "", + fs.StringVarP(&c.directory, "directory", "d", "", + "The directory where bundle manifests are located, ex. /deploy/olm-catalog/. "+ + "Set if package name differs from project name") + fs.StringVarP(&c.outputDir, "output-dir", "o", "", "Optional output directory for operator manifests") - cmd.Flags().StringVarP(&c.packageName, "package", "p", projectName, + fs.StringVarP(&c.version, "version", "v", "", + "Version of operator to build an image for. Must match a directory name of a bundle dir. "+ + "Set this if you do not have a 'manifests' directory at /deploy/olm-catalog//manifests") + fs.BoolVar(&c.useLatestVersion, "latest", false, + "Use the latest semantically versioned directory in /deploy/olm-catalog/") + fs.StringVarP(&c.imageTag, "tag", "t", "", + "The path of a registry to pull from, image name and its tag that present the bundle image "+ + "(e.g. quay.io/test/test-operator:v0.1.0)") + fs.StringVarP(&c.packageName, "package", "p", "", "The name of the package that bundle image belongs to. Set if package name differs from project name") - cmd.Flags().StringSliceVarP(&c.channels, "channels", "c", defaultChannels, + fs.StringSliceVarP(&c.channels, "channels", "c", []string{"stable"}, "The list of channels that bundle image belongs to") - cmd.Flags().BoolVarP(&c.generateOnly, "generate-only", "g", false, - "Generate metadata and a Dockerfile on disk without building the bundle image") - cmd.Flags().StringVarP(&c.imageBuilder, "image-builder", "b", "docker", + fs.BoolVarP(&c.generateOnly, "generate-only", "g", false, + "Generate metadata/, manifests/ and a Dockerfile on disk without building the bundle image") + fs.StringVarP(&c.imageBuilder, "image-builder", "b", "docker", "Tool to build container images. One of: [docker, podman, buildah]") - cmd.Flags().StringVarP(&c.defaultChannel, "default-channel", "e", "", + fs.StringVarP(&c.defaultChannel, "default-channel", "e", "", "The default channel for the bundle image") +} - return cmd +func (c bundleCreateCmd) setDefaults() (err error) { + projectName := filepath.Base(projutil.MustGetwd()) + if c.directory == "" { + c.directory = filepath.Join(catalog.OLMCatalogDir, projectName) + // Avoid discrepancy between packageName and directory if either is set + // by only assuming the operator dir is the packageName if directory isn't set. + c.packageName = projectName + } + return nil +} + +func (c bundleCreateCmd) validate(args []string) error { + if c.directory == "" { + return fmt.Errorf("--directory must be set") + } + if c.packageName == "" { + return fmt.Errorf("--package must be set") + } + if c.generateOnly { + if len(args) != 0 { + return errors.New("the command does not accept any arguments with --generate-only set") + } + } else { + if len(args) != 1 { + return errors.New("a bundle image tag is a required argument if --generate-only is not set") + } + } + // Validate semver if not latest + if c.version != "" { + if c.useLatestVersion { + return fmt.Errorf("cannot set both --latest and --version") + } + if _, err := semver.Parse(c.version); err != nil { + return fmt.Errorf("version %s is invalid: %v", c.version, err) + } + } + return nil +} + +func (c bundleCreateCmd) run() (err error) { + channels := strings.Join(c.channels, ",") + manifestsDir := filepath.Join(c.directory, bundle.ManifestsDir) + manifestsDirExisted := isExist(manifestsDir) + + // If the latest version is passed, find the highest semver in c.directory. + if c.useLatestVersion { + if c.version, err = findLatestSemverDir(c.directory); err != nil { + return fmt.Errorf("error finding latest operator bundle dir: %v", err) + } + } + + // version will be empty if neither useLatestVersion nor version were set + // by the user, so they want manifests/ left alone. Otherwise update it. + if c.version != "" { + versionedDir := filepath.Join(c.directory, c.version) + if err := copyDirShallow(versionedDir, manifestsDir); err != nil { + return fmt.Errorf("error updating manifests dir: %v", err) + } + } + + if c.generateOnly { + err := bundle.GenerateFunc(manifestsDir, c.outputDir, c.packageName, channels, c.defaultChannel, true) + if err != nil { + return fmt.Errorf("error generating bundle image files: %v", err) + } + return nil + } + + // Clean up transient files once the image is built, as they are no longer + // needed. + if !manifestsDirExisted { + defer func() { + if err := os.RemoveAll(manifestsDir); err != nil { + log.Fatal(err) + } + }() + } + for _, cleanup := range c.cleanupFuncs() { + defer cleanup() + } + + // Build but never overwrite existing metadata/Dockerfile. + err = bundle.BuildFunc(manifestsDir, c.outputDir, c.imageTag, c.imageBuilder, + c.packageName, channels, c.defaultChannel, false) + if err != nil { + return fmt.Errorf("error building bundle image: %v", err) + } + + return nil +} + +func findLatestSemverDir(operatorDir string) (latestVerStr string, err error) { + infos, err := ioutil.ReadDir(operatorDir) + if err != nil { + return "", err + } + versions := semver.Versions{} + for _, info := range infos { + if info.IsDir() { + childDir := filepath.Clean(info.Name()) + ver, err := semver.Parse(childDir) + if err != nil { + log.Debugf("Skipping non-semver dir %s: %v", childDir, err) + continue + } + versions = append(versions, ver) + } + } + if len(versions) == 0 { + return "", fmt.Errorf("no semver dirs found in %s", operatorDir) + } + semver.Sort(versions) + latestVerStr = versions[len(versions)-1].String() + return latestVerStr, nil +} + +func copyDirShallow(from, to string) error { + infos, err := ioutil.ReadDir(from) + if err != nil { + return err + } + if err = os.MkdirAll(to, fileutil.DefaultDirFileMode); err != nil { + return err + } + + for _, info := range infos { + fromPath := filepath.Join(from, info.Name()) + toPath := filepath.Join(to, info.Name()) + if !info.IsDir() { + b, err := ioutil.ReadFile(fromPath) + if err != nil { + return err + } + if err = ioutil.WriteFile(toPath, b, info.Mode()); err != nil { + return err + } + } else { + log.Debugf("Skipping copy %s to %s", fromPath, toPath) + } + } + + return nil +} + +// cleanupFuncs returns a set of funcs to clean up after 'bundle create'. +func (c bundleCreateCmd) cleanupFuncs() (fs []func()) { + rootDir := c.outputDir + if rootDir == "" { + rootDir = c.directory + } + + metaDir := filepath.Join(rootDir, bundle.MetadataDir) + metaExists := isExist(metaDir) + dockerFileExists := isExist(bundle.DockerFile) + fs = append(fs, + func() { + if !metaExists { + if err := os.RemoveAll(metaDir); err != nil { + log.Fatal(err) + } + } + }, + func() { + if !dockerFileExists { + if err := os.RemoveAll(bundle.DockerFile); err != nil { + log.Fatal(err) + } + } + }) + return fs +} + +func isExist(path string) bool { + _, err := os.Stat(path) + return err == nil || os.IsExist(err) } diff --git a/cmd/operator-sdk/bundle/validate.go b/cmd/operator-sdk/bundle/validate.go index 1ff87f013de..50651fe8dc4 100644 --- a/cmd/operator-sdk/bundle/validate.go +++ b/cmd/operator-sdk/bundle/validate.go @@ -39,22 +39,23 @@ Note: the image being validated must exist in a remote registry, not just locall Example: `The following command flow will generate test-operator bundle image manifests and validate that image: -$ cd ${HOME}/go/test-operator + $ cd ${HOME}/go/test-operator -# Generate manifests locally. -$ operator-sdk bundle create --generate-only + # Generate manifests locally. + $ operator-sdk bundle create --generate-only -# Modify the metadata and Dockerfile. -$ cd ./deploy/olm-catalog/test-operator -$ vim ./metadata/annotations.yaml -$ vim ./Dockerfile + # Modify the metadata and Dockerfile. + $ cd ./deploy/olm-catalog/test-operator + $ vim ./metadata/annotations.yaml + $ vim ./Dockerfile -# Build and push the image using the docker CLI. -$ docker build -t quay.io/example/test-operator:v0.1.0 . -$ docker push quay.io/example/test-operator:v0.1.0 + # Build and push the image using the docker CLI. + $ docker build -t quay.io/example/test-operator:v0.1.0 . + $ docker push quay.io/example/test-operator:v0.1.0 -# Ensure the image with modified metadata/Dockerfile is valid. -$ operator-sdk bundle validate quay.io/example/test-operator:v0.1.0`, + # Ensure the image with modified metadata/Dockerfile is valid. + $ operator-sdk bundle validate quay.io/example/test-operator:v0.1.0 +`, RunE: func(cmd *cobra.Command, args []string) error { if len(args) != 1 { return errors.New("a bundle image tag is a required argument, ex. example.com/test-operator:v0.1.0") @@ -70,11 +71,11 @@ $ operator-sdk bundle validate quay.io/example/test-operator:v0.1.0`, log.Error(err.Error()) } }() + logger := log.WithFields(log.Fields{ "container-tool": c.imageBuilder, "bundle-dir": dir, }) - log.SetLevel(log.DebugLevel) val := bundle.NewImageValidator(c.imageBuilder, logger) if err = val.PullBundleImage(c.imageTag, dir); err != nil { log.Fatalf("Error to unpacking image: %v", err) diff --git a/doc/cli/operator-sdk_bundle_create.md b/doc/cli/operator-sdk_bundle_create.md index b93c980125c..4d2ac62de0b 100644 --- a/doc/cli/operator-sdk_bundle_create.md +++ b/doc/cli/operator-sdk_bundle_create.md @@ -9,15 +9,20 @@ bundle image containing operator metadata and manifests, tagged with the provided image tag. To write metadata and a bundle image Dockerfile to disk, set '--generate-only=true'. -Bundle metadata will be generated in /metadata, and the Dockerfile -in . This flag is useful if you want to build an operator's -bundle image manually or modify metadata before building an image. +Bundle metadata will be generated in /metadata, and a bundle Dockerfile +at /bundle.Dockerfile. Additionally a /manifests +directory will be created if one does not exist already for the specified +operator version (use --latest or --version=) This flag is useful if +you want to build an operator's bundle image manually, modify metadata before +building an image, or want to generate a 'manifests/' directory containing your +latest operator manifests for compatibility with other operator tooling. More information on operator bundle images and metadata: https://github.com/openshift/enhancements/blob/master/enhancements/olm/operator-bundle.md#docker NOTE: bundle images are not runnable. + ``` operator-sdk bundle create [flags] ``` @@ -25,29 +30,33 @@ operator-sdk bundle create [flags] ### Examples ``` -The following invocation will build a test-operator bundle image using Docker. +The following invocation will build a test-operator 0.1.0 bundle image using Docker. This image will contain manifests for package channels 'stable' and 'beta': -$ operator-sdk bundle create quay.io/example/test-operator:v0.1.0 \ - --directory ./deploy/olm-catalog/test-operator \ - --package test-operator \ - --channels stable,beta \ - --default-channel stable + $ operator-sdk bundle create quay.io/example/test-operator:v0.1.0 \ + --version 0.1.0 \ + --directory ./deploy/olm-catalog/test-operator \ + --package test-operator \ + --channels stable,beta \ + --default-channel stable + +Assuming your operator has the same name as your operator, the tag corresponds to +a bundle directory name, and the only channel is 'stable', the above command can +be abbreviated to: -Assuming your operator has the same name as your operator and the only channel -is 'stable', the above command can be abbreviated to: + $ operator-sdk bundle create quay.io/example/test-operator:v0.1.0 --version 0.1.0 -$ operator-sdk bundle create quay.io/example/test-operator:v0.1.0 +The following invocation will generate test-operator bundle metadata, a manifests +dir, and Dockerfile for your latest operator version without building the image: -The following invocation will generate test-operator bundle metadata and -Dockerfile without building the image: + $ operator-sdk bundle create \ + --generate-only \ + --latest \ + --directory ./deploy/olm-catalog/test-operator \ + --package test-operator \ + --channels stable,beta \ + --default-channel stable -$ operator-sdk bundle create \ - --generate-only \ - --directory ./deploy/olm-catalog/test-operator \ - --package test-operator \ - --channels stable,beta \ - --default-channel stable ``` ### Options @@ -55,12 +64,15 @@ $ operator-sdk bundle create \ ``` -c, --channels strings The list of channels that bundle image belongs to (default [stable]) -e, --default-channel string The default channel for the bundle image - -d, --directory string The directory where bundle manifests are located - -g, --generate-only Generate metadata and a Dockerfile on disk without building the bundle image + -d, --directory string The directory where bundle manifests are located, ex. /deploy/olm-catalog/. Set if package name differs from project name + -g, --generate-only Generate metadata/, manifests/ and a Dockerfile on disk without building the bundle image -h, --help help for create -b, --image-builder string Tool to build container images. One of: [docker, podman, buildah] (default "docker") + --latest Use the latest semantically versioned directory in /deploy/olm-catalog/ -o, --output-dir string Optional output directory for operator manifests - -p, --package string The name of the package that bundle image belongs to. Set if package name differs from project name (default "operator-sdk") + -p, --package string The name of the package that bundle image belongs to. Set if package name differs from project name + -t, --tag string The path of a registry to pull from, image name and its tag that present the bundle image (e.g. quay.io/test/test-operator:v0.1.0) + -v, --version string Version of operator to build an image for. Must match a directory name of a bundle dir. Set this if you do not have a 'manifests' directory at /deploy/olm-catalog//manifests ``` ### SEE ALSO diff --git a/doc/cli/operator-sdk_bundle_validate.md b/doc/cli/operator-sdk_bundle_validate.md index a883f4193f6..1d7cf45cc42 100644 --- a/doc/cli/operator-sdk_bundle_validate.md +++ b/doc/cli/operator-sdk_bundle_validate.md @@ -20,22 +20,23 @@ operator-sdk bundle validate [flags] The following command flow will generate test-operator bundle image manifests and validate that image: -$ cd ${HOME}/go/test-operator + $ cd ${HOME}/go/test-operator -# Generate manifests locally. -$ operator-sdk bundle create --generate-only + # Generate manifests locally. + $ operator-sdk bundle create --generate-only -# Modify the metadata and Dockerfile. -$ cd ./deploy/olm-catalog/test-operator -$ vim ./metadata/annotations.yaml -$ vim ./Dockerfile + # Modify the metadata and Dockerfile. + $ cd ./deploy/olm-catalog/test-operator + $ vim ./metadata/annotations.yaml + $ vim ./Dockerfile -# Build and push the image using the docker CLI. -$ docker build -t quay.io/example/test-operator:v0.1.0 . -$ docker push quay.io/example/test-operator:v0.1.0 + # Build and push the image using the docker CLI. + $ docker build -t quay.io/example/test-operator:v0.1.0 . + $ docker push quay.io/example/test-operator:v0.1.0 + + # Ensure the image with modified metadata/Dockerfile is valid. + $ operator-sdk bundle validate quay.io/example/test-operator:v0.1.0 -# Ensure the image with modified metadata/Dockerfile is valid. -$ operator-sdk bundle validate quay.io/example/test-operator:v0.1.0 ``` ### Options diff --git a/doc/migration/version-upgrade-guide.md b/doc/migration/version-upgrade-guide.md index 6f942c045e1..551db602059 100644 --- a/doc/migration/version-upgrade-guide.md +++ b/doc/migration/version-upgrade-guide.md @@ -984,21 +984,21 @@ func serveCRMetrics(cfg *rest.Config, operatorNs string) error { ### Breaking changes #### `TestCtx` in `pkg/test` has been deprecated - + The type name `TestCtx` in `pkg/test` has been deprecated and renamed to `Context`. Users of the e2e framework should do the following: - + - Replace `TestCtx` with `Context` - Replace `NewTestCtx` with `NewContext` #### Scorecard only supports YAML config files - + The scorecard feature now only supports YAML config files. Config files with other extensions are no longer supported and should be changed to the YAML format. For further information see [`scorecard config file`](https://github.com/operator-framework/operator-sdk/blob/v0.16.x/doc/test-framework/scorecard.md#config-file) - -### Breaking Changes for Ansible -#### Remove Ansible container sidecar +### Breaking Changes for Ansible + +#### Remove Ansible container sidecar -The Ansible logs are now output in the operator container, so there is no longer a need for the Ansible container sidecar. To reflect this change, update the `deploy/operator.yaml` file as follows. +The Ansible logs are now output in the operator container, so there is no longer a need for the Ansible container sidecar. To reflect this change, update the `deploy/operator.yaml` file as follows. Remove: @@ -1068,13 +1068,13 @@ The methods `ctx.GetOperatorNamespace()` and `ctx.GetWatchNamespace()` was added This release contains breaking changes in some commands. -- The --namespace flag from `operator-sdk run --local` command, `operator-sdk test --local` command and `operator-sdk cleanup` command was deprecated and was replaced by --watch-namespace and --operator-namespace . +- The --namespace flag from `operator-sdk run --local` command, `operator-sdk test --local` command and `operator-sdk cleanup` command was deprecated and was replaced by --watch-namespace and --operator-namespace. [#2617](https://github.com/operator-framework/operator-sdk/pull/2617) Note that --watch-namespace can be used to set the namespace(s) which the operator will watch for changes. It will set the environment variable WATCH_NAMESPACE. Use explicitly an empty string to watch all namespaces or inform a List of namespaces such as "ns1,ns2" when the operator is cluster-scoped. If you use a List, then it needs contains the namespace where the operator is "deployed" in since the default metrics implementation will manage resources in the Operator's namespace. By default, it will be the Operator Namespace. Then, use the flag --operator-namespace to inform the namespace where the Operator will be "deployed" in and then, it will set the environment variable OPERATOR_NAMESPACE. If this value is not set, then it will be the namespace defined as default in the Kubeconfig. -NOTE: For more information check the PRs which are responsible for the above changes [#2617](https://github.com/operator-framework/operator-sdk/pull/2617). +- If you've run `operator-sdk bundle create --generate-only`, move your bundle Dockerfile at `/deploy/olm-catalog//Dockerfile` to `/bundle.Dockerfile` and update the first `COPY` from `COPY /*.yaml manifests/` to `COPY deploy/olm-catalog// manifests/`. [#2715](https://github.com/operator-framework/operator-sdk/pull/2715) [legacy-kubebuilder-doc-crd]: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html [v0.8.2-go-mod]: https://github.com/operator-framework/operator-sdk/blob/28bd2b0d4fd25aa68e15d928ae09d3c18c3b51da/internal/pkg/scaffold/go_mod.go#L40-L94 diff --git a/doc/user/olm-catalog/bundle-cli.md b/doc/user/olm-catalog/bundle-cli.md index 3dfa9f0d905..dd4c3e02ec2 100644 --- a/doc/user/olm-catalog/bundle-cli.md +++ b/doc/user/olm-catalog/bundle-cli.md @@ -7,14 +7,14 @@ This document gives an overview of using `operator-sdk` to work with Operator [b The following `operator-sdk` subcommands create or interact with Operator on-disk bundles and bundle images: * `generate csv`: creates a new or updates an existing CSV in a semantically versioned bundle directory, creates a package manifest if it does not exist, and optionally copies your CRDs to the versioned bundle directory. Read more about this command [here][sdk-generate-csv]. -* `bundle create`: creates an Operator bundle image from manifests on disk, or writes bundle image metadata to disk. This subcommand has corresponding functionality to `opm alpha bundle build`, and is stable. Output and underlying behavior between these commands is the same, except nothing is written to disk unless `--generate-only` is set (unset by default). Refer to [`opm alpha bundle build` docs][registry-opm-build] for more information. CLI differences between these commands: +* `bundle create`: creates an Operator bundle image from manifests on disk, or writes bundle image metadata to disk. This subcommand has corresponding functionality to `opm alpha bundle build`, and is stable. Output and underlying behavior between these commands is the same, except nothing is written to disk unless `--generate-only` is set (false by default). Refer to [`opm alpha bundle build` docs][registry-opm-build] for more information. CLI differences between these commands: | **operator-sdk** | **opm** | |--- |--- | | `operator-sdk bundle create --default=` | `opm alpha bundle build --default-channel=` | | `operator-sdk bundle create --generate-only` | `opm alpha bundle generate` | | `operator-sdk bundle create ` | `opm alpha bundle build --tag ` | - | no equivalent | `opm alpha bundle build --overwrite` | - | `operator-sdk bundle validate ` | `opm alpha bundle validate --tag ` | + | `operator-sdk bundle create --version=` | no equivalent | + | `operator-sdk bundle create --latest` | no equivalent | * `bundle validate`: validates an Operator bundle image. This subcommand has corresponding functionality to `opm alpha bundle validate`, and is stable. Refer to the [`opm alpha bundle validate` docs][registry-opm-validate] for more information. CLI differences between these commands: | **operator-sdk** | **opm** | |--- |--- | diff --git a/hack/tests/subcommand-bundle.sh b/hack/tests/subcommand-bundle.sh new file mode 100755 index 00000000000..067f61961c3 --- /dev/null +++ b/hack/tests/subcommand-bundle.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash + +source hack/lib/test_lib.sh + +function check_dir() { + if [[ $3 == 1 ]]; then + if [[ -d "$2" ]]; then + echo "${1}: directory ${2} should not exist" + exit 1 + fi + else + if [[ ! -d "$2" ]]; then + echo "${1}: directory ${2} should exist" + exit 1 + fi + fi +} + +function check_file() { + if [[ $3 == 1 ]]; then + if [[ -f "$2" ]]; then + echo "${1}: file ${2} should not exist" + exit 1 + fi + else + if [[ ! -f "$2" ]]; then + echo "${1}: file ${2} should exist" + exit 1 + fi + fi +} + +function cleanup() { + git clean -dfx test/test-framework +} + +OPERATOR_NAME="memcached-operator" +OPERATOR_VERSION="0.0.3" +OPERATOR_BUNDLE_IMAGE="quay.io/example/${OPERATOR_NAME}:${OPERATOR_VERSION}" +OPERATOR_BUNDLE_ROOT_DIR="deploy/olm-catalog/${OPERATOR_NAME}" +OPERATOR_BUNDLE_DIR="${OPERATOR_BUNDLE_ROOT_DIR}/${OPERATOR_VERSION}" +CREATE_CMD="operator-sdk bundle create $OPERATOR_BUNDLE_IMAGE" +GENERATE_CMD="operator-sdk bundle create --generate-only" + +pushd test/test-framework +trap_add "cleanup" EXIT +trap_add "popd" EXIT + +set -ex + +cp $(find deploy/crds/ -name *memcached*_crd.yaml) "${OPERATOR_BUNDLE_DIR}" + +TEST_NAME="create with version ${OPERATOR_VERSION}" +$CREATE_CMD --version $OPERATOR_VERSION --directory "$OPERATOR_BUNDLE_ROOT_DIR" --package $OPERATOR_NAME +check_dir "$TEST_NAME" "$OPERATOR_BUNDLE_ROOT_DIR/manifests" 1 +check_dir "$TEST_NAME" "$OPERATOR_BUNDLE_ROOT_DIR/metadata" 1 +check_file "$TEST_NAME" "bundle.Dockerfile" 1 + +TEST_NAME="create with latest" +$CREATE_CMD --latest --directory "$OPERATOR_BUNDLE_ROOT_DIR" --package $OPERATOR_NAME +check_dir "$TEST_NAME" "$OPERATOR_BUNDLE_ROOT_DIR/manifests" 1 +check_dir "$TEST_NAME" "$OPERATOR_BUNDLE_ROOT_DIR/metadata" 1 +check_file "$TEST_NAME" "bundle.Dockerfile" 1 + +TEST_NAME="generate with version ${OPERATOR_VERSION}" +$GENERATE_CMD --version $OPERATOR_VERSION --directory "$OPERATOR_BUNDLE_ROOT_DIR" --package $OPERATOR_NAME +check_dir "$TEST_NAME" "$OPERATOR_BUNDLE_ROOT_DIR/manifests" 0 +check_dir "$TEST_NAME" "$OPERATOR_BUNDLE_ROOT_DIR/metadata" 0 +check_file "$TEST_NAME" "bundle.Dockerfile" 0 +cleanup + +TEST_NAME="create with version ${OPERATOR_VERSION} with manifests dir" +$GENERATE_CMD --version $OPERATOR_VERSION --directory "$OPERATOR_BUNDLE_ROOT_DIR" --package $OPERATOR_NAME +rm -rf "$OPERATOR_BUNDLE_ROOT_DIR/metadata" "bundle.Dockerfile" +$CREATE_CMD --directory "$OPERATOR_BUNDLE_ROOT_DIR" --package $OPERATOR_NAME +check_dir "$TEST_NAME" "$OPERATOR_BUNDLE_ROOT_DIR/manifests" 0 +check_dir "$TEST_NAME" "$OPERATOR_BUNDLE_ROOT_DIR/metadata" 1 +check_file "$TEST_NAME" "bundle.Dockerfile" 1 +cleanup + +# TODO(estroz): add validate steps after each 'create' test to validate dirs +# once the following is merged: +# https://github.com/operator-framework/operator-sdk/pull/2737 diff --git a/website/content/en/docs/cli/operator-sdk_bundle_create.md b/website/content/en/docs/cli/operator-sdk_bundle_create.md index a1bd6e7a557..4d2ac62de0b 100644 --- a/website/content/en/docs/cli/operator-sdk_bundle_create.md +++ b/website/content/en/docs/cli/operator-sdk_bundle_create.md @@ -9,15 +9,20 @@ bundle image containing operator metadata and manifests, tagged with the provided image tag. To write metadata and a bundle image Dockerfile to disk, set '--generate-only=true'. -Bundle metadata will be generated in /metadata, and the Dockerfile -in . This flag is useful if you want to build an operator's -bundle image manually or modify metadata before building an image. +Bundle metadata will be generated in /metadata, and a bundle Dockerfile +at /bundle.Dockerfile. Additionally a /manifests +directory will be created if one does not exist already for the specified +operator version (use --latest or --version=) This flag is useful if +you want to build an operator's bundle image manually, modify metadata before +building an image, or want to generate a 'manifests/' directory containing your +latest operator manifests for compatibility with other operator tooling. More information on operator bundle images and metadata: https://github.com/openshift/enhancements/blob/master/enhancements/olm/operator-bundle.md#docker NOTE: bundle images are not runnable. + ``` operator-sdk bundle create [flags] ``` @@ -25,29 +30,33 @@ operator-sdk bundle create [flags] ### Examples ``` -The following invocation will build a test-operator bundle image using Docker. +The following invocation will build a test-operator 0.1.0 bundle image using Docker. This image will contain manifests for package channels 'stable' and 'beta': -$ operator-sdk bundle create quay.io/example/test-operator:v0.1.0 \ - --directory ./deploy/olm-catalog/test-operator \ - --package test-operator \ - --channels stable,beta \ - --default-channel stable + $ operator-sdk bundle create quay.io/example/test-operator:v0.1.0 \ + --version 0.1.0 \ + --directory ./deploy/olm-catalog/test-operator \ + --package test-operator \ + --channels stable,beta \ + --default-channel stable + +Assuming your operator has the same name as your operator, the tag corresponds to +a bundle directory name, and the only channel is 'stable', the above command can +be abbreviated to: -Assuming your operator has the same name as your operator and the only channel -is 'stable', the above command can be abbreviated to: + $ operator-sdk bundle create quay.io/example/test-operator:v0.1.0 --version 0.1.0 -$ operator-sdk bundle create quay.io/example/test-operator:v0.1.0 +The following invocation will generate test-operator bundle metadata, a manifests +dir, and Dockerfile for your latest operator version without building the image: -The following invocation will generate test-operator bundle metadata and -Dockerfile without building the image: + $ operator-sdk bundle create \ + --generate-only \ + --latest \ + --directory ./deploy/olm-catalog/test-operator \ + --package test-operator \ + --channels stable,beta \ + --default-channel stable -$ operator-sdk bundle create \ - --generate-only \ - --directory ./deploy/olm-catalog/test-operator \ - --package test-operator \ - --channels stable,beta \ - --default-channel stable ``` ### Options @@ -55,11 +64,15 @@ $ operator-sdk bundle create \ ``` -c, --channels strings The list of channels that bundle image belongs to (default [stable]) -e, --default-channel string The default channel for the bundle image - -d, --directory string The directory where bundle manifests are located - -g, --generate-only Generate metadata and a Dockerfile on disk without building the bundle image + -d, --directory string The directory where bundle manifests are located, ex. /deploy/olm-catalog/. Set if package name differs from project name + -g, --generate-only Generate metadata/, manifests/ and a Dockerfile on disk without building the bundle image -h, --help help for create -b, --image-builder string Tool to build container images. One of: [docker, podman, buildah] (default "docker") - -p, --package string The name of the package that bundle image belongs to. Set if package name differs from project name (default "operator-sdk") + --latest Use the latest semantically versioned directory in /deploy/olm-catalog/ + -o, --output-dir string Optional output directory for operator manifests + -p, --package string The name of the package that bundle image belongs to. Set if package name differs from project name + -t, --tag string The path of a registry to pull from, image name and its tag that present the bundle image (e.g. quay.io/test/test-operator:v0.1.0) + -v, --version string Version of operator to build an image for. Must match a directory name of a bundle dir. Set this if you do not have a 'manifests' directory at /deploy/olm-catalog//manifests ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_bundle_validate.md b/website/content/en/docs/cli/operator-sdk_bundle_validate.md index a883f4193f6..1d7cf45cc42 100644 --- a/website/content/en/docs/cli/operator-sdk_bundle_validate.md +++ b/website/content/en/docs/cli/operator-sdk_bundle_validate.md @@ -20,22 +20,23 @@ operator-sdk bundle validate [flags] The following command flow will generate test-operator bundle image manifests and validate that image: -$ cd ${HOME}/go/test-operator + $ cd ${HOME}/go/test-operator -# Generate manifests locally. -$ operator-sdk bundle create --generate-only + # Generate manifests locally. + $ operator-sdk bundle create --generate-only -# Modify the metadata and Dockerfile. -$ cd ./deploy/olm-catalog/test-operator -$ vim ./metadata/annotations.yaml -$ vim ./Dockerfile + # Modify the metadata and Dockerfile. + $ cd ./deploy/olm-catalog/test-operator + $ vim ./metadata/annotations.yaml + $ vim ./Dockerfile -# Build and push the image using the docker CLI. -$ docker build -t quay.io/example/test-operator:v0.1.0 . -$ docker push quay.io/example/test-operator:v0.1.0 + # Build and push the image using the docker CLI. + $ docker build -t quay.io/example/test-operator:v0.1.0 . + $ docker push quay.io/example/test-operator:v0.1.0 + + # Ensure the image with modified metadata/Dockerfile is valid. + $ operator-sdk bundle validate quay.io/example/test-operator:v0.1.0 -# Ensure the image with modified metadata/Dockerfile is valid. -$ operator-sdk bundle validate quay.io/example/test-operator:v0.1.0 ``` ### Options diff --git a/website/content/en/docs/golang/olm-catalog/bundle-cli.md b/website/content/en/docs/golang/olm-catalog/bundle-cli.md index 3dfa9f0d905..dd4c3e02ec2 100644 --- a/website/content/en/docs/golang/olm-catalog/bundle-cli.md +++ b/website/content/en/docs/golang/olm-catalog/bundle-cli.md @@ -7,14 +7,14 @@ This document gives an overview of using `operator-sdk` to work with Operator [b The following `operator-sdk` subcommands create or interact with Operator on-disk bundles and bundle images: * `generate csv`: creates a new or updates an existing CSV in a semantically versioned bundle directory, creates a package manifest if it does not exist, and optionally copies your CRDs to the versioned bundle directory. Read more about this command [here][sdk-generate-csv]. -* `bundle create`: creates an Operator bundle image from manifests on disk, or writes bundle image metadata to disk. This subcommand has corresponding functionality to `opm alpha bundle build`, and is stable. Output and underlying behavior between these commands is the same, except nothing is written to disk unless `--generate-only` is set (unset by default). Refer to [`opm alpha bundle build` docs][registry-opm-build] for more information. CLI differences between these commands: +* `bundle create`: creates an Operator bundle image from manifests on disk, or writes bundle image metadata to disk. This subcommand has corresponding functionality to `opm alpha bundle build`, and is stable. Output and underlying behavior between these commands is the same, except nothing is written to disk unless `--generate-only` is set (false by default). Refer to [`opm alpha bundle build` docs][registry-opm-build] for more information. CLI differences between these commands: | **operator-sdk** | **opm** | |--- |--- | | `operator-sdk bundle create --default=` | `opm alpha bundle build --default-channel=` | | `operator-sdk bundle create --generate-only` | `opm alpha bundle generate` | | `operator-sdk bundle create ` | `opm alpha bundle build --tag ` | - | no equivalent | `opm alpha bundle build --overwrite` | - | `operator-sdk bundle validate ` | `opm alpha bundle validate --tag ` | + | `operator-sdk bundle create --version=` | no equivalent | + | `operator-sdk bundle create --latest` | no equivalent | * `bundle validate`: validates an Operator bundle image. This subcommand has corresponding functionality to `opm alpha bundle validate`, and is stable. Refer to the [`opm alpha bundle validate` docs][registry-opm-validate] for more information. CLI differences between these commands: | **operator-sdk** | **opm** | |--- |--- | diff --git a/website/content/en/docs/migration/version-upgrade-guide.md b/website/content/en/docs/migration/version-upgrade-guide.md index 6f942c045e1..551db602059 100644 --- a/website/content/en/docs/migration/version-upgrade-guide.md +++ b/website/content/en/docs/migration/version-upgrade-guide.md @@ -984,21 +984,21 @@ func serveCRMetrics(cfg *rest.Config, operatorNs string) error { ### Breaking changes #### `TestCtx` in `pkg/test` has been deprecated - + The type name `TestCtx` in `pkg/test` has been deprecated and renamed to `Context`. Users of the e2e framework should do the following: - + - Replace `TestCtx` with `Context` - Replace `NewTestCtx` with `NewContext` #### Scorecard only supports YAML config files - + The scorecard feature now only supports YAML config files. Config files with other extensions are no longer supported and should be changed to the YAML format. For further information see [`scorecard config file`](https://github.com/operator-framework/operator-sdk/blob/v0.16.x/doc/test-framework/scorecard.md#config-file) - -### Breaking Changes for Ansible -#### Remove Ansible container sidecar +### Breaking Changes for Ansible + +#### Remove Ansible container sidecar -The Ansible logs are now output in the operator container, so there is no longer a need for the Ansible container sidecar. To reflect this change, update the `deploy/operator.yaml` file as follows. +The Ansible logs are now output in the operator container, so there is no longer a need for the Ansible container sidecar. To reflect this change, update the `deploy/operator.yaml` file as follows. Remove: @@ -1068,13 +1068,13 @@ The methods `ctx.GetOperatorNamespace()` and `ctx.GetWatchNamespace()` was added This release contains breaking changes in some commands. -- The --namespace flag from `operator-sdk run --local` command, `operator-sdk test --local` command and `operator-sdk cleanup` command was deprecated and was replaced by --watch-namespace and --operator-namespace . +- The --namespace flag from `operator-sdk run --local` command, `operator-sdk test --local` command and `operator-sdk cleanup` command was deprecated and was replaced by --watch-namespace and --operator-namespace. [#2617](https://github.com/operator-framework/operator-sdk/pull/2617) Note that --watch-namespace can be used to set the namespace(s) which the operator will watch for changes. It will set the environment variable WATCH_NAMESPACE. Use explicitly an empty string to watch all namespaces or inform a List of namespaces such as "ns1,ns2" when the operator is cluster-scoped. If you use a List, then it needs contains the namespace where the operator is "deployed" in since the default metrics implementation will manage resources in the Operator's namespace. By default, it will be the Operator Namespace. Then, use the flag --operator-namespace to inform the namespace where the Operator will be "deployed" in and then, it will set the environment variable OPERATOR_NAMESPACE. If this value is not set, then it will be the namespace defined as default in the Kubeconfig. -NOTE: For more information check the PRs which are responsible for the above changes [#2617](https://github.com/operator-framework/operator-sdk/pull/2617). +- If you've run `operator-sdk bundle create --generate-only`, move your bundle Dockerfile at `/deploy/olm-catalog//Dockerfile` to `/bundle.Dockerfile` and update the first `COPY` from `COPY /*.yaml manifests/` to `COPY deploy/olm-catalog// manifests/`. [#2715](https://github.com/operator-framework/operator-sdk/pull/2715) [legacy-kubebuilder-doc-crd]: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html [v0.8.2-go-mod]: https://github.com/operator-framework/operator-sdk/blob/28bd2b0d4fd25aa68e15d928ae09d3c18c3b51da/internal/pkg/scaffold/go_mod.go#L40-L94 From accf2bffab1fff91b0e4d93b60a9b1be53c303e1 Mon Sep 17 00:00:00 2001 From: Eric Stroczynski Date: Mon, 30 Mar 2020 13:42:45 -0700 Subject: [PATCH 3/3] [WIP] change behavior of create back to original --- cmd/operator-sdk/bundle/create.go | 232 ++++++++++++++---------------- hack/tests/subcommand-bundle.sh | 105 ++++++++++---- 2 files changed, 178 insertions(+), 159 deletions(-) diff --git a/cmd/operator-sdk/bundle/create.go b/cmd/operator-sdk/bundle/create.go index f78f1ac99fa..0a1dbfab072 100644 --- a/cmd/operator-sdk/bundle/create.go +++ b/cmd/operator-sdk/bundle/create.go @@ -26,7 +26,6 @@ import ( "github.com/operator-framework/operator-sdk/internal/util/fileutil" "github.com/operator-framework/operator-sdk/internal/util/projutil" - "github.com/blang/semver" "github.com/operator-framework/operator-registry/pkg/lib/bundle" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -36,9 +35,7 @@ import ( type bundleCreateCmd struct { bundleCmd - outputDir string - version string - useLatestVersion bool + outputDir string } // newCreateCmd returns a command that will build operator bundle image or @@ -71,8 +68,7 @@ NOTE: bundle images are not runnable. This image will contain manifests for package channels 'stable' and 'beta': $ operator-sdk bundle create quay.io/example/test-operator:v0.1.0 \ - --version 0.1.0 \ - --directory ./deploy/olm-catalog/test-operator \ + --directory ./deploy/olm-catalog/test-operator/0.1.0 \ --package test-operator \ --channels stable,beta \ --default-channel stable @@ -81,15 +77,15 @@ Assuming your operator has the same name as your operator, the tag corresponds t a bundle directory name, and the only channel is 'stable', the above command can be abbreviated to: - $ operator-sdk bundle create quay.io/example/test-operator:v0.1.0 --version 0.1.0 + $ operator-sdk bundle create quay.io/example/test-operator:v0.1.0 \ + --directory The following invocation will generate test-operator bundle metadata, a manifests dir, and Dockerfile for your latest operator version without building the image: $ operator-sdk bundle create \ --generate-only \ - --latest \ - --directory ./deploy/olm-catalog/test-operator \ + --directory ./deploy/olm-catalog/test-operator/0.1.0 \ --package test-operator \ --channels stable,beta \ --default-channel stable @@ -103,11 +99,58 @@ dir, and Dockerfile for your latest operator version without building the image: return fmt.Errorf("error validating args: %v", err) } - if !c.generateOnly { + channels := strings.Join(c.channels, ",") + + if c.generateOnly { + err := bundle.GenerateFunc(c.directory, c.outputDir, c.packageName, channels, c.defaultChannel, true) + if err != nil { + log.Fatal(fmt.Errorf("error generating bundle image files: %v", err)) + } + if c.outputDir != "" { + outputManifestsDir := filepath.Join(c.outputDir, bundle.ManifestsDir) + if err := copyDirShallow(c.directory, outputManifestsDir); err != nil { + return fmt.Errorf("error updating manifests dir: %v", err) + } + } + } else { + // if c.outputDir != "" { + // outputManifestsDir := filepath.Join(c.outputDir, bundle.ManifestsDir) + // if err := copyDirShallow(c.directory, outputManifestsDir); err != nil { + // return fmt.Errorf("error updating manifests dir: %v", err) + // } + // } c.imageTag = args[0] - } - if err := c.run(); err != nil { - log.Fatal(err) + rootDir := filepath.Dir(c.directory) + metadataDir := filepath.Join(rootDir, bundle.MetadataDir) + metadataDirExisted := isExist(metadataDir) + dockerfileExisted := isExist(bundle.DockerFile) + + // Clean up transient files once the image is built, as they are no longer + // needed. + if !metadataDirExisted { + defer func() { + if err := os.RemoveAll(metadataDir); err != nil { + log.Fatal(err) + } + }() + } + if !dockerfileExisted { + defer func() { + if err := os.RemoveAll(bundle.DockerFile); err != nil { + log.Fatal(err) + } + }() + } + // for _, cleanup := range c.cleanupFuncs() { + // defer cleanup() + // } + + // Build but never overwrite existing metadata/Dockerfile. + err := bundle.BuildFunc(c.directory, c.outputDir, c.imageTag, c.imageBuilder, + c.packageName, channels, c.defaultChannel, false) + if err != nil { + log.Fatal(fmt.Errorf("error building bundle image: %v", err)) + } } return nil }, @@ -121,15 +164,9 @@ dir, and Dockerfile for your latest operator version without building the image: func (c *bundleCreateCmd) addToFlagSet(fs *pflag.FlagSet) { fs.StringVarP(&c.directory, "directory", "d", "", - "The directory where bundle manifests are located, ex. /deploy/olm-catalog/. "+ - "Set if package name differs from project name") + "The directory where bundle manifests are located, ex. /deploy/olm-catalog/test-operator/0.1.0") fs.StringVarP(&c.outputDir, "output-dir", "o", "", "Optional output directory for operator manifests") - fs.StringVarP(&c.version, "version", "v", "", - "Version of operator to build an image for. Must match a directory name of a bundle dir. "+ - "Set this if you do not have a 'manifests' directory at /deploy/olm-catalog//manifests") - fs.BoolVar(&c.useLatestVersion, "latest", false, - "Use the latest semantically versioned directory in /deploy/olm-catalog/") fs.StringVarP(&c.imageTag, "tag", "t", "", "The path of a registry to pull from, image name and its tag that present the bundle image "+ "(e.g. quay.io/test/test-operator:v0.1.0)") @@ -172,93 +209,30 @@ func (c bundleCreateCmd) validate(args []string) error { return errors.New("a bundle image tag is a required argument if --generate-only is not set") } } - // Validate semver if not latest - if c.version != "" { - if c.useLatestVersion { - return fmt.Errorf("cannot set both --latest and --version") - } - if _, err := semver.Parse(c.version); err != nil { - return fmt.Errorf("version %s is invalid: %v", c.version, err) - } - } return nil } -func (c bundleCreateCmd) run() (err error) { - channels := strings.Join(c.channels, ",") - manifestsDir := filepath.Join(c.directory, bundle.ManifestsDir) - manifestsDirExisted := isExist(manifestsDir) - - // If the latest version is passed, find the highest semver in c.directory. - if c.useLatestVersion { - if c.version, err = findLatestSemverDir(c.directory); err != nil { - return fmt.Errorf("error finding latest operator bundle dir: %v", err) - } - } - - // version will be empty if neither useLatestVersion nor version were set - // by the user, so they want manifests/ left alone. Otherwise update it. - if c.version != "" { - versionedDir := filepath.Join(c.directory, c.version) - if err := copyDirShallow(versionedDir, manifestsDir); err != nil { - return fmt.Errorf("error updating manifests dir: %v", err) - } - } - - if c.generateOnly { - err := bundle.GenerateFunc(manifestsDir, c.outputDir, c.packageName, channels, c.defaultChannel, true) - if err != nil { - return fmt.Errorf("error generating bundle image files: %v", err) - } - return nil - } - - // Clean up transient files once the image is built, as they are no longer - // needed. - if !manifestsDirExisted { - defer func() { - if err := os.RemoveAll(manifestsDir); err != nil { - log.Fatal(err) - } - }() - } - for _, cleanup := range c.cleanupFuncs() { - defer cleanup() - } - - // Build but never overwrite existing metadata/Dockerfile. - err = bundle.BuildFunc(manifestsDir, c.outputDir, c.imageTag, c.imageBuilder, - c.packageName, channels, c.defaultChannel, false) - if err != nil { - return fmt.Errorf("error building bundle image: %v", err) - } +// Scenarios: +// Generate: +// - no manifests, no outputDir - create manifests normally +// - manifests, no outputDir - do not create manifests +// - no manifests, outputDir - create manifests in outputDir +// - manifests, outputDir - create manifests in outputDir +func (c bundleCreateCmd) runGenerate() (err error) { return nil } -func findLatestSemverDir(operatorDir string) (latestVerStr string, err error) { - infos, err := ioutil.ReadDir(operatorDir) - if err != nil { - return "", err - } - versions := semver.Versions{} - for _, info := range infos { - if info.IsDir() { - childDir := filepath.Clean(info.Name()) - ver, err := semver.Parse(childDir) - if err != nil { - log.Debugf("Skipping non-semver dir %s: %v", childDir, err) - continue - } - versions = append(versions, ver) - } - } - if len(versions) == 0 { - return "", fmt.Errorf("no semver dirs found in %s", operatorDir) - } - semver.Sort(versions) - latestVerStr = versions[len(versions)-1].String() - return latestVerStr, nil +// Build: +// - no manifests, no metadata, no outputDir +// - no manifests, metadata, no outputDir +// - manifests, no metadata, no outputDir +// - no manifests, no metadata, outputDir +// - no manifests, metadata, outputDir +// - manifests, no metadata, outputDir +func (c bundleCreateCmd) runBuild() (err error) { + + return nil } func copyDirShallow(from, to string) error { @@ -278,7 +252,12 @@ func copyDirShallow(from, to string) error { if err != nil { return err } - if err = ioutil.WriteFile(toPath, b, info.Mode()); err != nil { + data := "(empty)" + if len(b) > 20 { + data = string(b[:20]) + } + fmt.Printf("writing %s to %s: %s\n", fromPath, toPath, data) + if err = ioutil.WriteFile(toPath, b, fileutil.DefaultFileMode); err != nil { return err } } else { @@ -289,33 +268,30 @@ func copyDirShallow(from, to string) error { return nil } -// cleanupFuncs returns a set of funcs to clean up after 'bundle create'. -func (c bundleCreateCmd) cleanupFuncs() (fs []func()) { - rootDir := c.outputDir - if rootDir == "" { - rootDir = c.directory - } - - metaDir := filepath.Join(rootDir, bundle.MetadataDir) - metaExists := isExist(metaDir) - dockerFileExists := isExist(bundle.DockerFile) - fs = append(fs, - func() { - if !metaExists { - if err := os.RemoveAll(metaDir); err != nil { - log.Fatal(err) - } - } - }, - func() { - if !dockerFileExists { - if err := os.RemoveAll(bundle.DockerFile); err != nil { - log.Fatal(err) - } - } - }) - return fs -} +// // cleanupFuncs returns a set of funcs to clean up after 'bundle create'. +// func (c bundleCreateCmd) cleanupFuncs() (fs []func()) { +// // If output-dir is set we don't want to remove files, since the user has +// // specified they want a directory generated. +// metaDir := filepath.Join(c.directory, bundle.MetadataDir) +// metaExists := isExist(metaDir) +// dockerFileExists := isExist(bundle.DockerFile) +// fs = append(fs, +// func() { +// if !metaExists { +// if err := os.RemoveAll(metaDir); err != nil { +// log.Fatal(err) +// } +// } +// }, +// func() { +// if !dockerFileExists { +// if err := os.RemoveAll(bundle.DockerFile); err != nil { +// log.Fatal(err) +// } +// } +// }) +// return fs +// } func isExist(path string) bool { _, err := os.Stat(path) diff --git a/hack/tests/subcommand-bundle.sh b/hack/tests/subcommand-bundle.sh index 067f61961c3..633bd806695 100755 --- a/hack/tests/subcommand-bundle.sh +++ b/hack/tests/subcommand-bundle.sh @@ -3,7 +3,7 @@ source hack/lib/test_lib.sh function check_dir() { - if [[ $3 == 1 ]]; then + if [[ $3 == 0 ]]; then if [[ -d "$2" ]]; then echo "${1}: directory ${2} should not exist" exit 1 @@ -17,7 +17,7 @@ function check_dir() { } function check_file() { - if [[ $3 == 1 ]]; then + if [[ $3 == 0 ]]; then if [[ -f "$2" ]]; then echo "${1}: file ${2} should not exist" exit 1 @@ -30,53 +30,96 @@ function check_file() { fi } -function cleanup() { - git clean -dfx test/test-framework +function cleanup_case() { + git clean -dfx . } +function cp_crds() { + cp $(find deploy/crds/ -name *memcached*_crd.yaml) "$OPERATOR_BUNDLE_DIR" +} + +TEST_DIR="test/test-framework" OPERATOR_NAME="memcached-operator" OPERATOR_VERSION="0.0.3" OPERATOR_BUNDLE_IMAGE="quay.io/example/${OPERATOR_NAME}:${OPERATOR_VERSION}" OPERATOR_BUNDLE_ROOT_DIR="deploy/olm-catalog/${OPERATOR_NAME}" OPERATOR_BUNDLE_DIR="${OPERATOR_BUNDLE_ROOT_DIR}/${OPERATOR_VERSION}" -CREATE_CMD="operator-sdk bundle create $OPERATOR_BUNDLE_IMAGE" -GENERATE_CMD="operator-sdk bundle create --generate-only" +OUTPUT_DIR="foo" +CREATE_CMD="operator-sdk bundle create $OPERATOR_BUNDLE_IMAGE --directory "$OPERATOR_BUNDLE_DIR" --package $OPERATOR_NAME" +GENERATE_CMD="operator-sdk bundle create --generate-only --directory "$OPERATOR_BUNDLE_DIR" --package $OPERATOR_NAME" -pushd test/test-framework -trap_add "cleanup" EXIT +pushd "$TEST_DIR" +# trap_add "git clean -dfx $TEST_DIR" EXIT trap_add "popd" EXIT set -ex -cp $(find deploy/crds/ -name *memcached*_crd.yaml) "${OPERATOR_BUNDLE_DIR}" - TEST_NAME="create with version ${OPERATOR_VERSION}" -$CREATE_CMD --version $OPERATOR_VERSION --directory "$OPERATOR_BUNDLE_ROOT_DIR" --package $OPERATOR_NAME -check_dir "$TEST_NAME" "$OPERATOR_BUNDLE_ROOT_DIR/manifests" 1 -check_dir "$TEST_NAME" "$OPERATOR_BUNDLE_ROOT_DIR/metadata" 1 +cp_crds +$CREATE_CMD +check_dir "$TEST_NAME" "${OUTPUT_DIR}" 0 +check_dir "$TEST_NAME" "$OPERATOR_BUNDLE_DIR/metadata" 0 +check_file "$TEST_NAME" "bundle.Dockerfile" 0 +cleanup_case + +TEST_NAME="create with version ${OPERATOR_VERSION} and output-dir" +cp_crds +$CREATE_CMD --output-dir "$OUTPUT_DIR" +check_dir "$TEST_NAME" "${OUTPUT_DIR}/manifests" 1 +check_dir "$TEST_NAME" "${OUTPUT_DIR}/metadata" 1 +check_dir "$TEST_NAME" "${OPERATOR_BUNDLE_ROOT_DIR}/metadata" 0 +check_file "$TEST_NAME" "bundle.Dockerfile" 0 +cleanup_case + +TEST_NAME="generate with version ${OPERATOR_VERSION}" +cp_crds +$GENERATE_CMD +check_dir "$TEST_NAME" "${OUTPUT_DIR}" 0 +check_dir "$TEST_NAME" "${OPERATOR_BUNDLE_ROOT_DIR}/metadata" 1 check_file "$TEST_NAME" "bundle.Dockerfile" 1 +cleanup_case -TEST_NAME="create with latest" -$CREATE_CMD --latest --directory "$OPERATOR_BUNDLE_ROOT_DIR" --package $OPERATOR_NAME -check_dir "$TEST_NAME" "$OPERATOR_BUNDLE_ROOT_DIR/manifests" 1 -check_dir "$TEST_NAME" "$OPERATOR_BUNDLE_ROOT_DIR/metadata" 1 +TEST_NAME="generate with version ${OPERATOR_VERSION} and output-dir" +cp_crds +$GENERATE_CMD --output-dir "$OUTPUT_DIR" +ls -alR "$OPERATOR_BUNDLE_DIR" +ls -alR "$OUTPUT_DIR" +check_dir "$TEST_NAME" "${OUTPUT_DIR}/manifests" 1 +check_dir "$TEST_NAME" "${OUTPUT_DIR}/metadata" 1 +check_dir "$TEST_NAME" "${OPERATOR_BUNDLE_ROOT_DIR}/metadata" 0 check_file "$TEST_NAME" "bundle.Dockerfile" 1 +cleanup_case -TEST_NAME="generate with version ${OPERATOR_VERSION}" -$GENERATE_CMD --version $OPERATOR_VERSION --directory "$OPERATOR_BUNDLE_ROOT_DIR" --package $OPERATOR_NAME -check_dir "$TEST_NAME" "$OPERATOR_BUNDLE_ROOT_DIR/manifests" 0 -check_dir "$TEST_NAME" "$OPERATOR_BUNDLE_ROOT_DIR/metadata" 0 -check_file "$TEST_NAME" "bundle.Dockerfile" 0 -cleanup - -TEST_NAME="create with version ${OPERATOR_VERSION} with manifests dir" -$GENERATE_CMD --version $OPERATOR_VERSION --directory "$OPERATOR_BUNDLE_ROOT_DIR" --package $OPERATOR_NAME -rm -rf "$OPERATOR_BUNDLE_ROOT_DIR/metadata" "bundle.Dockerfile" -$CREATE_CMD --directory "$OPERATOR_BUNDLE_ROOT_DIR" --package $OPERATOR_NAME -check_dir "$TEST_NAME" "$OPERATOR_BUNDLE_ROOT_DIR/manifests" 0 -check_dir "$TEST_NAME" "$OPERATOR_BUNDLE_ROOT_DIR/metadata" 1 +TEST_NAME="create with version ${OPERATOR_VERSION} with existing metadata" +cp_crds +$GENERATE_CMD +$CREATE_CMD +check_dir "$TEST_NAME" "${OPERATOR_BUNDLE_ROOT_DIR}/manifests" 0 +check_dir "$TEST_NAME" "${OPERATOR_BUNDLE_ROOT_DIR}/metadata" 1 +check_file "$TEST_NAME" "bundle.Dockerfile" 1 +cleanup_case + +TEST_NAME="create with version ${OPERATOR_VERSION} with existing metadata and output-dir" +cp_crds +$GENERATE_CMD +$CREATE_CMD --output-dir "$OUTPUT_DIR" +check_dir "$TEST_NAME" "${OPERATOR_BUNDLE_ROOT_DIR}/manifests" 0 +check_dir "$TEST_NAME" "${OPERATOR_BUNDLE_ROOT_DIR}/metadata" 1 +check_dir "$TEST_NAME" "${OUTPUT_DIR}/manifests" 1 +check_dir "$TEST_NAME" "${OUTPUT_DIR}/metadata" 1 +check_file "$TEST_NAME" "bundle.Dockerfile" 1 +cleanup_case + +TEST_NAME="create with version ${OPERATOR_VERSION} from output-dir and output-dir" +cp_crds +$GENERATE_CMD --output-dir "$OUTPUT_DIR" +operator-sdk bundle create $OPERATOR_BUNDLE_IMAGE --package $OPERATOR_NAME --directory "${OUTPUT_DIR}/manifests" +check_dir "$TEST_NAME" "${OPERATOR_BUNDLE_ROOT_DIR}/manifests" 0 +check_dir "$TEST_NAME" "${OPERATOR_BUNDLE_ROOT_DIR}/metadata" 0 +check_dir "$TEST_NAME" "${OUTPUT_DIR}/manifests" 1 +check_dir "$TEST_NAME" "${OUTPUT_DIR}/metadata" 1 check_file "$TEST_NAME" "bundle.Dockerfile" 1 -cleanup +cleanup_case # TODO(estroz): add validate steps after each 'create' test to validate dirs # once the following is merged: