diff --git a/Makefile b/Makefile index 8630684499..23e45ee0e8 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ ifeq (, $(wildcard $(KUBEBUILDER_ASSETS)/kube-apiserver)) $(error kube-apiserver $(KUBEBUILDER_ASSETS_ERR)) endif -build: $(REGISTRY_CMDS) $(OLM_CMDS) $(OPM) ## build opm and olm binaries +build: $(REGISTRY_CMDS) $(OLM_CMDS) $(OPM) bin/copy-content ## build opm and olm binaries build/opm: $(MAKE) $(OPM) @@ -64,7 +64,7 @@ build/registry: $(MAKE) $(REGISTRY_CMDS) $(OPM) build/olm: - $(MAKE) $(PSM_CMD) $(OLM_CMDS) $(COLLECT_PROFILES_CMD) + $(MAKE) $(PSM_CMD) $(OLM_CMDS) $(COLLECT_PROFILES_CMD) bin/copy-content $(OPM): version_flags=-ldflags "-X '$(REGISTRY_PKG)/cmd/opm/version.gitCommit=$(GIT_COMMIT)' -X '$(REGISTRY_PKG)/cmd/opm/version.opmVersion=$(OPM_VERSION)' -X '$(REGISTRY_PKG)/cmd/opm/version.buildDate=$(BUILD_DATE)'" $(OPM): @@ -104,6 +104,9 @@ bin/kubebuilder: bin/cpb: FORCE CGO_ENABLED=0 go build $(GO_BUILD_OPTS) -ldflags '-extldflags "-static"' -o $@ github.com/operator-framework/operator-lifecycle-manager/util/cpb +bin/copy-content: FORCE + CGO_ENABLED=0 go build $(GO_BUILD_OPTS) -ldflags '-extldflags "-static"' -o $@ github.com/operator-framework/operator-lifecycle-manager/cmd/copy-content + unit/olm: bin/kubebuilder @echo "Running the OLM unit tests" $(MAKE) unit WHAT=operator-lifecycle-manager diff --git a/cmds.go b/cmds.go index 110cc62007..32ccbb03d0 100644 --- a/cmds.go +++ b/cmds.go @@ -2,6 +2,7 @@ package cmds import ( _ "github.com/operator-framework/operator-lifecycle-manager/cmd/catalog" + _ "github.com/operator-framework/operator-lifecycle-manager/cmd/copy-content" _ "github.com/operator-framework/operator-lifecycle-manager/cmd/olm" _ "github.com/operator-framework/operator-lifecycle-manager/cmd/package-server" _ "github.com/operator-framework/operator-lifecycle-manager/util/cpb" diff --git a/go.mod b/go.mod index bd4cd3fa94..7db37fd2b5 100644 --- a/go.mod +++ b/go.mod @@ -13,9 +13,9 @@ require ( github.com/mikefarah/yq/v3 v3.0.0-20201202084205-8846255d1c37 github.com/onsi/ginkgo/v2 v2.9.5 github.com/openshift/api v3.9.0+incompatible - github.com/operator-framework/api v0.17.8-0.20230803152844-704ae942c4a9 + github.com/operator-framework/api v0.17.8-0.20230908201838-28c6773d2b74 github.com/operator-framework/operator-lifecycle-manager v0.0.0-00010101000000-000000000000 - github.com/operator-framework/operator-registry v1.27.1 + github.com/operator-framework/operator-registry v1.29.0 github.com/sirupsen/logrus v1.9.2 github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.3 @@ -63,7 +63,7 @@ require ( github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/cyphar/filepath-securejoin v0.2.3 // indirect + github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/distribution/distribution v2.7.1+incompatible // indirect github.com/docker/cli v23.0.1+incompatible // indirect @@ -73,7 +73,7 @@ require ( github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/emicklei/go-restful/v3 v3.10.1 // indirect + github.com/emicklei/go-restful/v3 v3.10.2 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect @@ -162,7 +162,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect github.com/openshift/client-go v0.0.0-20220525160904-9e1acff93e4a // indirect - github.com/otiai10/copy v1.2.0 // indirect + github.com/otiai10/copy v1.12.0 // indirect github.com/pbnjay/strptime v0.0.0-20140226051138-5c05b0d668c9 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect diff --git a/go.sum b/go.sum index 7bcffd9de7..b5472ec762 100644 --- a/go.sum +++ b/go.sum @@ -167,8 +167,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHH github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= -github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -205,8 +205,8 @@ github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4 github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ= -github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= +github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= @@ -700,13 +700,9 @@ github.com/openshift/api v0.0.0-20210517065120-b325f58df679/go.mod h1:dZ4kytOo3s github.com/openshift/build-machinery-go v0.0.0-20210209125900-0da259a2c359/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE= github.com/openshift/client-go v0.0.0-20200326155132-2a6cd50aedd0 h1:kMiuiZXH1GdfbiMwsuAQOqGaMxlo9NCUk0wT4XAdfNM= github.com/openshift/client-go v0.0.0-20200326155132-2a6cd50aedd0/go.mod h1:uUQ4LClRO+fg5MF/P6QxjMCb1C9f7Oh4RKepftDnEJE= -github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k= -github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= -github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= -github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= -github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= -github.com/otiai10/mint v1.3.1 h1:BCmzIS3n71sGfHB5NMNDB3lHYPz8fWSkCAErHed//qc= -github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= +github.com/otiai10/copy v1.12.0 h1:cLMgSQnXBs1eehF0Wy/FAGsgDTDmAqFR7rQylBb1nDY= +github.com/otiai10/copy v1.12.0/go.mod h1:rSaLseMUsZFFbsFGc7wCJnnkTAvdc5L6VWxPE4308Ww= +github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pbnjay/strptime v0.0.0-20140226051138-5c05b0d668c9 h1:4lfz0keanz7/gAlvJ7lAe9zmE08HXxifBZJC0AdeGKo= github.com/pbnjay/strptime v0.0.0-20140226051138-5c05b0d668c9/go.mod h1:6Hr+C/olSdkdL3z68MlyXWzwhvwmwN7KuUFXGb3PoOk= diff --git a/manifests/0000_50_olm_00-catalogsources.crd.yaml b/manifests/0000_50_olm_00-catalogsources.crd.yaml index 8b6a6a6888..618d0972f9 100644 --- a/manifests/0000_50_olm_00-catalogsources.crd.yaml +++ b/manifests/0000_50_olm_00-catalogsources.crd.yaml @@ -534,8 +534,21 @@ spec: topologyKey: description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. type: string + extractContent: + description: ExtractContent configures the gRPC catalog Pod to extract catalog metadata from the provided index image and use a well-known version of the `opm` server to expose it. The catalog index image that this CatalogSource is configured to use *must* be using the file-based catalogs in order to utilize this feature. + type: object + required: + - cacheDir + - catalogDir + properties: + cacheDir: + description: CacheDir is the directory storing the pre-calculated API cache. + type: string + catalogDir: + description: CatalogDir is the directory storing the file-based catalog contents. + type: string memoryTarget: - description: "MemoryTarget configures the $GOMEMLIMIT value for the gRPC catalog Pod. This is a soft memory limit for the server, which the runtime will attempt to meet but makes no guarantees that it will do so. If this value is set, the Pod will have the following modifications made to the container running the server: - the $GOMEMLIMIT environment variable will be set to this value in bytes - the memory request will be set to this value - the memory limit will be set to 200% of this value \n This field should be set if it's desired to reduce the footprint of a catalog server as much as possible, or if a catalog being served is very large and needs more than the default allocation. If your index image has a file- system cache, determine a good approximation for this value by doubling the size of the package cache at /tmp/cache/cache/packages.json in the index image. \n This field is best-effort; if unset, no default will be used and no Pod memory limit or $GOMEMLIMIT value will be set." + description: "MemoryTarget configures the $GOMEMLIMIT value for the gRPC catalog Pod. This is a soft memory limit for the server, which the runtime will attempt to meet but makes no guarantees that it will do so. If this value is set, the Pod will have the following modifications made to the container running the server: - the $GOMEMLIMIT environment variable will be set to this value in bytes - the memory request will be set to this value \n This field should be set if it's desired to reduce the footprint of a catalog server as much as possible, or if a catalog being served is very large and needs more than the default allocation. If your index image has a file- system cache, determine a good approximation for this value by doubling the size of the package cache at /tmp/cache/cache/packages.json in the index image. \n This field is best-effort; if unset, no default will be used and no Pod memory limit or $GOMEMLIMIT value will be set." pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ anyOf: - type: integer diff --git a/manifests/0000_90_olm_01-prometheus-rule.yaml b/manifests/0000_90_olm_01-prometheus-rule.yaml index 89c1b354f1..a9eeeb4fe1 100644 --- a/manifests/0000_90_olm_01-prometheus-rule.yaml +++ b/manifests/0000_90_olm_01-prometheus-rule.yaml @@ -36,7 +36,7 @@ spec: - name: olm.installplan.rules rules: - alert: InstallPlanStepAppliedWithWarnings - expr: sum(increase(installplan_warnings_total[5m])) > 0 + expr: sum by(namespace) (increase(installplan_warnings_total[5m])) > 0 labels: severity: warning annotations: diff --git a/operator-lifecycle-manager.Dockerfile b/operator-lifecycle-manager.Dockerfile index cb39ca570e..47ff6d716b 100644 --- a/operator-lifecycle-manager.Dockerfile +++ b/operator-lifecycle-manager.Dockerfile @@ -4,9 +4,9 @@ ENV GO111MODULE auto ENV GOPATH /go ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH -# Permit the cpb binary to be compiled statically. The Red Hat compiler +# Permit the cpb and copy-content binaries to be compiled statically. The Red Hat compiler # provided by ART will otherwise force FIPS compliant dynamic compilation. -ENV GO_COMPLIANCE_EXCLUDE="build.*operator-lifecycle-manager/util/cpb" +ENV GO_COMPLIANCE_EXCLUDE="build.*operator-lifecycle-manager/(util/cpb|cmd/copy-content)" WORKDIR /build @@ -30,6 +30,7 @@ COPY --from=builder /build/bin/collect-profiles /bin/collect-profiles COPY --from=builder /build/bin/package-server /bin/package-server COPY --from=builder /build/bin/cpb /bin/cpb COPY --from=builder /build/bin/psm /bin/psm +COPY --from=builder /build/bin/copy-content /bin/copy-content # This image doesn't need to run as root user. USER 1001 diff --git a/scripts/bumper/main.go b/scripts/bumper/main.go index 9517c61acd..6fa4bf9914 100644 --- a/scripts/bumper/main.go +++ b/scripts/bumper/main.go @@ -199,7 +199,7 @@ func main() { } for i, commit := range missingCommits { commitLogger := logger.WithField("commit", commit.Hash) - commitLogger.Infof("cherry-picking commit %d/%d", i+1, len(commits)) + commitLogger.Infof("cherry-picking commit %d/%d", i+1, len(missingCommits)) if err := cherryPick(ctx, commitLogger, commit, opts.GitCommitArgs()); err != nil { logger.WithError(err).Fatal("failed to cherry-pick commit") } diff --git a/staging/api/crds/operators.coreos.com_catalogsources.yaml b/staging/api/crds/operators.coreos.com_catalogsources.yaml index c3e2f6ce18..6b3b81cb77 100644 --- a/staging/api/crds/operators.coreos.com_catalogsources.yaml +++ b/staging/api/crds/operators.coreos.com_catalogsources.yaml @@ -532,8 +532,21 @@ spec: topologyKey: description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. type: string + extractContent: + description: ExtractContent configures the gRPC catalog Pod to extract catalog metadata from the provided index image and use a well-known version of the `opm` server to expose it. The catalog index image that this CatalogSource is configured to use *must* be using the file-based catalogs in order to utilize this feature. + type: object + required: + - cacheDir + - catalogDir + properties: + cacheDir: + description: CacheDir is the directory storing the pre-calculated API cache. + type: string + catalogDir: + description: CatalogDir is the directory storing the file-based catalog contents. + type: string memoryTarget: - description: "MemoryTarget configures the $GOMEMLIMIT value for the gRPC catalog Pod. This is a soft memory limit for the server, which the runtime will attempt to meet but makes no guarantees that it will do so. If this value is set, the Pod will have the following modifications made to the container running the server: - the $GOMEMLIMIT environment variable will be set to this value in bytes - the memory request will be set to this value - the memory limit will be set to 200% of this value \n This field should be set if it's desired to reduce the footprint of a catalog server as much as possible, or if a catalog being served is very large and needs more than the default allocation. If your index image has a file- system cache, determine a good approximation for this value by doubling the size of the package cache at /tmp/cache/cache/packages.json in the index image. \n This field is best-effort; if unset, no default will be used and no Pod memory limit or $GOMEMLIMIT value will be set." + description: "MemoryTarget configures the $GOMEMLIMIT value for the gRPC catalog Pod. This is a soft memory limit for the server, which the runtime will attempt to meet but makes no guarantees that it will do so. If this value is set, the Pod will have the following modifications made to the container running the server: - the $GOMEMLIMIT environment variable will be set to this value in bytes - the memory request will be set to this value \n This field should be set if it's desired to reduce the footprint of a catalog server as much as possible, or if a catalog being served is very large and needs more than the default allocation. If your index image has a file- system cache, determine a good approximation for this value by doubling the size of the package cache at /tmp/cache/cache/packages.json in the index image. \n This field is best-effort; if unset, no default will be used and no Pod memory limit or $GOMEMLIMIT value will be set." pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ anyOf: - type: integer diff --git a/staging/api/crds/zz_defs.go b/staging/api/crds/zz_defs.go index a391fce34b..6ce922fa00 100644 --- a/staging/api/crds/zz_defs.go +++ b/staging/api/crds/zz_defs.go @@ -85,7 +85,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _operatorsCoreosCom_catalogsourcesYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x7d\x69\x73\xdc\x36\x16\xe0\x77\xff\x8a\x57\xda\xd9\x92\x94\x74\x53\x76\x32\x95\x9d\x68\x72\x94\x46\x3e\x56\x15\x1f\x2a\x4b\xc9\xd4\x8e\xe5\xdd\xa0\xc9\xd7\xdd\x88\x48\x80\x01\x40\x49\x9d\xe3\xbf\x6f\xbd\x07\x80\x64\xdf\x87\xec\xd8\xae\x21\x3f\x24\x6a\x12\xe7\xbb\x2f\xc0\xa2\x94\x3f\xa1\xb1\x52\xab\x63\x10\xa5\xc4\x3b\x87\x8a\x7e\xd9\xe4\xfa\x1f\x36\x91\xfa\xe8\xe6\xd1\x83\x6b\xa9\xb2\x63\x38\xad\xac\xd3\xc5\x6b\xb4\xba\x32\x29\x3e\xc6\xa1\x54\xd2\x49\xad\x1e\x14\xe8\x44\x26\x9c\x38\x7e\x00\x20\x94\xd2\x4e\xd0\x6b\x4b\x3f\x01\x52\xad\x9c\xd1\x79\x8e\xa6\x3f\x42\x95\x5c\x57\x03\x1c\x54\x32\xcf\xd0\xf0\xe0\x71\xea\x9b\x87\xc9\xd7\xc9\xc3\x07\x00\xa9\x41\xee\x7e\x29\x0b\xb4\x4e\x14\xe5\x31\xa8\x2a\xcf\x1f\x00\x28\x51\xe0\x31\xa4\xc2\x89\x5c\x8f\xfc\x22\x6c\xa2\x4b\x34\xc2\x69\x63\x93\x54\x1b\xd4\xf4\xbf\xe2\x81\x2d\x31\xa5\xd9\x47\x46\x57\xe5\x31\x2c\x6c\xe3\xc7\x8b\x8b\x14\x0e\x47\xda\xc8\xf8\x1b\xa0\x0f\x3a\x2f\xf8\xef\xb0\x79\x3f\xed\x05\x4f\xcb\xef\x73\x69\xdd\x0f\xf3\xdf\x9e\x4b\xeb\xf8\x7b\x99\x57\x46\xe4\xb3\x0b\xe6\x4f\x76\xac\x8d\x7b\xd9\x4c\x4f\xd3\xa5\xc2\x59\x93\xfa\xcf\x52\x8d\xaa\x5c\x98\x99\xbe\x0f\x00\x6c\xaa\x4b\x3c\x06\xee\x5a\x8a\x14\xb3\x07\x00\x01\x84\x61\xa8\x3e\x88\x2c\x63\xb4\x88\xfc\xdc\x48\xe5\xd0\x9c\xea\xbc\x2a\x54\x3d\x15\xb5\xc9\xd0\xa6\x46\x96\x8e\x41\x7f\x39\x46\x28\x0d\x3a\x37\x61\x90\x80\x1e\x82\x1b\x63\x9c\xbb\xee\x05\xf0\x8b\xd5\xea\x5c\xb8\xf1\x31\x24\x04\xe1\x24\x93\xb6\xcc\xc5\x84\x56\xd3\x6a\xe5\xd1\xf4\xd8\x7f\x6b\xbd\x77\x13\x5a\xba\x75\x46\xaa\xd1\xaa\xa5\x50\xbb\xcd\xd7\xe0\x41\x73\x39\x29\xe7\x97\x30\xf3\x72\xd3\xf9\xcb\x6a\x90\x4b\x3b\x46\xb3\xf9\x22\xea\x2e\x73\x6b\x38\x5f\xf0\x65\xc9\x42\x5a\x83\x46\x86\x4a\xe6\x98\x61\x6e\x82\x93\xd1\xfc\x1e\x33\xe1\xe2\x4b\xdf\xe8\xe6\x91\xc8\xcb\xb1\x78\x14\x5e\xda\x74\x8c\x85\x68\xe8\x41\x97\xa8\x4e\xce\xcf\x7e\xfa\xf2\x62\xe6\x03\x4c\x43\x67\x8a\xce\x41\x5a\x10\x60\xb0\xd4\x56\x3a\x6d\x26\x04\xad\xd3\x8b\x9f\x6c\x0f\x4e\x5f\x3f\xb6\x3d\x10\x2a\xab\x19\x0f\x4a\x91\x5e\x8b\x11\xda\x64\x6e\xad\x7a\xf0\x0b\xa6\xae\xf5\xda\xe0\xaf\x95\x34\x98\xb5\x57\x41\xe0\x89\x30\x99\x79\x4d\xf0\x6f\xbd\x2a\x0d\xcd\xe9\x5a\x8c\xec\x9f\x96\x94\x9b\x7a\x3f\xb3\xc3\x7d\x02\x83\x6f\x07\x19\x09\x38\xb4\x4c\x02\x81\xc7\x30\x0b\xb0\xf3\xa4\x21\x2d\xed\xdf\xa0\x45\xe5\x45\x1e\xbd\x16\x2a\xec\x29\x81\x0b\x34\xd4\x91\xd8\xbd\xca\x33\x92\x84\x37\x68\x1c\x18\x4c\xf5\x48\xc9\xdf\xea\xd1\x2c\x38\xcd\xd3\xe4\xc2\xa1\x75\xc0\x5c\xab\x44\x0e\x37\x22\xaf\xd0\x83\xb2\x10\x13\x30\x48\xe3\x42\xa5\x5a\x23\x70\x13\x9b\xc0\x0b\x6d\x10\xa4\x1a\xea\x63\x18\x3b\x57\xda\xe3\xa3\xa3\x91\x74\x51\x86\xa7\xba\x28\x2a\x25\xdd\xe4\x88\xc5\xb1\x1c\x54\x24\x0e\x8f\x32\xbc\xc1\xfc\xc8\xca\x51\x5f\x98\x74\x2c\x1d\xa6\xae\x32\x78\x24\x4a\xd9\xe7\xc5\x2a\x96\xe3\x49\x91\xfd\x0f\x13\xa4\xbe\xdd\x9f\x01\xdf\x42\x62\x86\x28\x36\x57\xc2\x9a\x84\xa7\xa7\x22\xdf\xdd\xef\xa5\x01\x29\xbd\x22\xa8\xbc\x7e\x72\x71\x09\x71\x01\x1e\xec\x1e\xc2\x4d\x53\xdb\x00\x9b\x00\x25\xd5\x10\x8d\x6f\x39\x34\xba\xe0\x51\x50\x65\xa5\x96\xca\x79\x96\xce\x25\x2a\x07\xb6\x1a\x14\xd2\x59\xa6\x39\xb4\x8e\xf0\x90\xc0\x29\xab\x30\x18\x20\x54\x25\x71\x52\x96\xc0\x99\x82\x53\x51\x60\x7e\x2a\x2c\xbe\x77\x50\x13\x44\x6d\x9f\xc0\xb7\x39\xb0\xdb\x1a\x78\xbe\xc3\x1c\x8f\x01\x44\x0d\xb9\x51\xe3\x65\x4c\x09\x9e\x03\x17\x49\x60\x58\xc1\x8b\xf4\x88\x2c\x33\x68\x17\x7c\x98\x63\x48\xdf\xd0\xd3\xc9\x58\x5b\xc2\x9f\x70\xf0\xea\xf9\x0b\x48\x85\x82\xca\x22\x31\x4f\xaa\x95\x22\x82\x70\x1a\x04\xe9\xb2\x3e\xde\x49\xcb\x04\x64\x70\x24\xad\x33\x93\x04\x9e\x6a\x53\x08\x77\x0c\xdf\xc4\x57\x7d\x1e\x4e\x1b\x90\xe5\x77\xc7\xdf\x94\xda\xb8\xef\xe0\x95\xca\x27\x34\x68\x06\xb7\x63\x54\x70\x51\xef\x0d\xbe\x6d\xfd\x78\x66\xca\x34\x81\xb3\x91\xd2\x26\xb6\x24\xaa\x3a\x2b\xc4\x08\x61\x28\x31\x67\xba\xb6\xe8\x92\x59\x0c\xae\xc4\x22\x78\x73\x69\x28\x47\x2f\x44\xb9\x16\x34\xa7\xb1\x25\xcd\x45\xd3\xb7\x95\x77\xf3\xd1\x69\x26\x65\xda\x12\xfd\x29\xd2\x6b\x10\x61\x96\x42\x94\x7d\xcb\x6c\xd3\x02\xd3\x66\x10\x38\x8d\x03\x10\xfc\x9a\xd7\x67\x41\x72\x25\xdb\x6e\xbb\xbd\xb3\xad\xfb\x36\x66\xc8\x5a\xa0\xbd\x58\xa4\x45\x36\x98\x63\x64\xca\xf4\x5c\x67\x7e\xdb\x6b\x67\x79\xd6\x6e\x0d\x78\x57\x6a\x8b\x16\x32\x39\x1c\xa2\x21\xb9\xa3\x6f\xd0\x18\x99\xa1\x85\xa1\x36\x8c\xaf\x52\x67\xcc\x93\x35\xfe\xa6\x54\xed\xb9\xce\x36\x45\x0c\x4d\xcd\x0a\xc3\x13\x63\x20\xc3\xa5\xdb\x5d\xc8\xed\xb0\x86\x79\xe9\x11\x43\x36\xff\x27\x8b\xbf\xce\xc0\xe3\x24\x34\x8e\x94\x1a\x2c\xaa\x20\x3a\xf6\x2d\x6d\x7f\xdf\xd6\x63\x2e\x5a\xee\x06\x4b\xde\x64\xd9\xf4\x28\x9d\xe1\xc9\x9a\xe5\xcf\x6d\xe1\x31\xff\x18\xa0\xe5\xee\xf5\x52\x59\x83\x67\x55\xce\xa2\xa6\xca\xa7\x31\xba\x6c\x1f\x1b\xee\x65\xd3\xfd\xf8\x76\x38\x44\x63\x30\x7b\x5c\x11\xfd\x5e\xd4\xab\x0a\x42\xca\xbf\x7e\x72\x87\x69\xb5\x8c\xc7\x96\x6e\x9d\x8c\xe2\xb0\x4d\x34\x70\x2b\xf3\x3c\x4c\x47\x02\x25\x7e\xa0\xfd\xb2\x1d\x43\xe0\xb1\x5e\x48\x5b\xe1\xa4\x1d\x4e\x18\x1c\x35\xc0\xf0\x8e\x74\x36\x7b\x2c\x4c\xf1\x72\x28\x31\x83\xc1\x24\xa8\x6b\x12\x9e\x3d\x18\x54\x0e\xa4\x63\x5d\x9e\x8e\xb5\xb6\x08\xc2\xc3\x9d\xc7\xbd\x91\x9a\x2d\x25\xd0\x0a\x49\xfe\x14\xa4\x90\x03\xe3\xb4\x86\x4f\x78\xe5\x4d\x37\x69\xa1\x20\x89\x5f\xc3\x2a\x92\x23\x0d\x73\x2b\xdd\x98\x7f\x8c\xc8\xe4\x26\x2b\xcc\x56\x05\x0d\x7a\x8b\x72\x34\x76\xb6\x07\x32\xc1\x84\xb1\x8b\x22\x1d\xb7\x86\x2d\x10\x9d\x05\x91\xe7\x71\x09\x6d\x92\xf0\x7a\xb3\x20\x13\x05\x0e\x6a\x1b\x26\xd8\x1b\xbd\x5a\xaf\xce\x62\x6d\x21\xb8\x7a\x80\x2e\x4d\x0e\x7b\x90\xea\xa2\xac\x1c\xc1\x84\xd6\x38\x98\x80\x74\x64\x67\x7b\x7b\xc9\xe8\x6a\xe4\x77\x82\x79\x98\x38\x1a\xab\x5e\x33\x91\x70\x20\x1f\x51\x8d\x60\xcf\x6f\x6e\x2f\xda\x9f\x34\x9c\xf4\x9b\xe0\xfd\x15\xc2\xa5\xe3\x60\x02\xa7\xda\x18\xb4\xa5\x56\xdc\x93\xbf\x3c\x69\xd6\xf6\xcf\xba\xd3\x81\x3d\x6c\x80\x39\x96\xa3\x71\x84\xa5\x30\xc8\xef\xa6\x71\xb0\x8a\x47\x1a\x3e\x11\xc6\x4c\xf9\x92\x8b\x1e\xe9\xb0\x58\xc3\x25\x73\xa4\x7d\xa2\x00\x8b\xd2\x4d\x5a\x34\xd1\xc2\x9e\x43\x53\xd4\x30\x60\x04\x33\xbb\x5a\xbf\x3f\x59\x94\xb9\x4c\xa5\x0b\x14\x02\x0f\xe1\x80\x49\x44\x3a\x12\x65\xa0\x74\x5f\x97\x87\x09\x9c\x70\xf8\x62\x83\x09\x94\xae\xc7\x0f\x03\xd1\xa4\x56\x37\x63\xad\xdd\xdb\x86\x42\xc5\x3f\xcb\x6d\xba\xf9\xa7\x1f\xd6\x8f\x2a\x9d\xb5\xf2\x16\x37\xf7\x30\x59\xdb\x74\x53\xf1\x16\x5b\xc7\x35\x6c\xd2\x7a\x16\xd5\x9e\xa4\x2d\xe6\x98\x92\x4b\x4a\xb0\xef\x81\xb0\x56\xa7\x92\xac\xfc\x86\x68\xa7\x29\xdd\xef\x64\x3d\xec\x61\x5b\xf8\xc3\xd6\xfb\xa7\x67\x96\xf1\x36\xed\x37\x07\x8d\x5c\x92\xf1\x3b\x9c\x81\xca\x94\xc0\x1a\x4c\xf8\xeb\xbe\x85\x5c\x0c\x30\xb7\x9b\x01\x01\xb6\xe2\xda\xe6\xd9\x90\x7f\x97\x6e\x68\xe9\x46\x82\x8f\x59\x23\x9e\x84\x36\xf9\x66\x42\x2a\x1b\xfc\xe7\x1e\x08\xb8\xc6\x89\x77\xb5\xc9\x83\x8f\x81\x0b\x6e\x6c\xd0\xab\x1b\x22\x8e\x6b\x9c\x70\xa3\xe0\x77\x6f\xb1\xdc\xad\x89\xc3\x3f\xdb\xb0\x69\xf3\xf4\x69\xa1\x5b\xf6\x88\x9b\xde\xa2\xdb\xf6\xf4\xeb\x9f\x6b\x5c\x69\x79\x2d\x7a\xe6\x4c\x12\xa6\x49\xc6\x07\x23\x89\xf5\x57\xc4\xb1\x28\xcb\x5c\x22\xfb\xf3\x5b\x4e\xb3\xd2\x0b\x58\xf5\x44\xe8\xdd\x6b\x5f\xaf\xeb\x80\x86\x27\xc8\x7d\xeb\x89\x8f\x38\x7d\x2c\x4b\xef\xdf\x5a\x64\xc6\x8d\x91\x9f\x9f\x44\x2e\x9b\x50\x9b\x65\x3d\x7b\xa6\x7a\xf0\x52\x3b\xfa\xdf\x13\xf2\x84\x6d\x0f\x1e\x6b\xb4\x2f\xb5\xe3\x9f\x09\x3c\x73\x9e\xd6\x9f\x6f\x28\xd9\xde\x01\x80\xfc\x7a\xef\x05\x9e\x13\xe5\x65\x0a\x6d\xbf\x1d\x33\xb2\x09\x9c\x79\xb3\xa5\x66\x5c\x69\xe1\x4c\x91\x71\x18\xc0\xc0\x51\x3c\x6e\x1b\x86\x28\x2a\xcb\x41\x1e\xa5\x55\x9f\x6d\x80\x85\x63\x78\xe8\xd1\x38\x6d\xf8\xad\x18\x6e\xf9\x50\xcf\x38\xd6\xf0\x7c\x69\xe7\xb1\xb8\x61\x93\x4e\xaa\x51\x5e\x1b\x6f\x3d\xb8\x1d\xcb\x74\xec\xad\xee\x01\xfa\xd0\x60\x69\x90\x14\x96\xb0\x24\xaa\xe8\xcd\x08\x0d\x19\xbb\x32\x8e\xe7\x03\x93\xb9\x48\x31\x83\x8c\x4d\x4b\x1f\x64\x13\x0e\x47\x32\x85\x02\xcd\x08\xa1\x24\x4d\xb2\x1b\xf6\xb7\x13\xec\xfe\xd9\x5a\xbc\xb7\x27\xdc\x8a\xdc\x58\x45\x3e\x25\x5b\xf7\x2f\xd2\x8e\x6c\x57\x77\xda\xb1\xd3\x8e\x33\x4f\xa7\x1d\xeb\xa7\xd3\x8e\x6b\x9e\x4e\x3b\x76\xda\xf1\xbd\x6b\x47\xef\xcb\xee\xe0\x3c\xff\xdb\x87\x38\x66\xbd\x65\xd6\xb4\x31\x4d\x37\xed\x36\x93\xbe\xb9\x08\x02\xe7\x92\x5d\x6d\xe9\x93\x24\x46\xa8\x11\xc2\xa3\xfe\xa3\x87\x0f\xb7\x71\xaa\x03\x22\x37\xea\x31\x0c\x99\x1e\xa9\xdc\x97\x5f\xac\xec\xb1\x2c\xfe\xf6\x0e\xa2\xa6\x81\xc6\xeb\x40\xde\x94\xed\xb0\x24\xf0\xc9\xd2\x49\x69\x07\x05\x3a\x10\x6e\x2a\x54\x24\x0b\xec\xd5\xa9\x02\x26\xf8\x90\xa5\x8c\x11\xd8\x0c\xb4\x0a\x71\x3c\x02\x7e\xb2\xdb\x0a\x52\x14\x3e\xa5\x36\xc0\x7a\x15\xba\xa0\x59\xa5\x72\x91\x5d\x68\x09\x18\xa1\x02\x07\x98\x8c\x12\xc8\x2a\xee\x26\x54\x48\x9b\x1e\xfa\xd5\xda\x89\x75\x58\x70\x24\x57\x1b\xfe\x1f\x2d\xdb\x99\x09\x35\xc6\x1b\x54\xae\x12\x79\x3e\x01\xbc\x91\xa9\xab\xf7\xc7\x59\x5b\xe9\x7c\xb0\x7d\xb3\x10\xe1\x46\xa6\xc3\xe6\xe6\x42\x7f\x8e\x82\xed\x9a\x3e\xdb\x68\xfb\xb9\xb1\x37\xe1\xc9\x19\x5d\xe8\x77\x92\x2c\x35\x56\x1d\x8d\xeb\x63\xe0\xfc\x27\x13\xd7\xab\xd7\xeb\x43\xae\xb0\xb5\x24\xdb\x42\x7a\xcd\x9a\xa5\x55\x9e\x13\x61\xf8\x28\xec\xfc\x06\x16\x44\x47\xfd\x96\xa6\x88\xd9\x07\xde\x7d\x88\xf9\xe4\xe5\x63\x82\x0a\xb5\xb9\xd4\xa5\xce\xf5\x68\xd2\x86\xb4\x2f\x2f\x92\x45\x19\x83\xe3\x02\x6c\x35\x08\x46\x03\x91\xdf\xcb\x19\xd4\x74\x91\xbf\x2e\xf2\xd7\xf9\x36\x73\x4f\xe7\xdb\xd4\x4f\xe7\xdb\xac\x79\x3a\xdf\xa6\xf3\x6d\xba\xc8\x1f\x74\xda\x71\x05\x4c\x3a\xed\x08\x9d\x76\x5c\xba\xaf\x4e\x3b\xae\x04\x4f\xa7\x1d\x3b\xed\xb8\xe8\x29\x75\x76\x8f\x42\xc7\x52\x67\x2b\xea\x1c\x7d\xd4\x27\xd5\xfd\x5c\xa7\xc2\x85\xba\x7c\xea\x12\xe2\x7c\x56\x14\x3e\x10\xd5\x83\xdf\xb4\x42\x5f\xbc\x46\xb8\xe1\x70\x92\x76\x63\x34\xd4\xfc\xc0\x1e\xae\x2c\x6c\xea\xea\x24\xbb\x3a\xc9\x8f\xbe\x4e\x72\x2c\xac\xc7\xab\x17\x4a\xcb\xcb\x26\x5b\x0c\x79\x89\xa6\xf8\x44\xab\x26\x89\x5c\x02\xba\xf9\xc4\x53\x83\x52\xbf\xf3\x2c\xe4\x0b\x30\x3b\x9f\xde\x6f\xb0\x97\x79\x53\x22\xcb\x30\x83\x12\x4d\xdf\x93\x88\x86\xa1\x54\xd9\x82\xbd\x46\xf8\x7c\xd0\xea\xc7\xe9\x7d\x7c\xc0\x12\xc8\xe9\x85\xec\x10\x73\x6d\x07\x8e\xa7\x24\xfc\x47\x51\x10\xb9\xad\x55\xdf\x07\x17\x82\xbc\x3f\x6c\x68\xd7\x6f\x6f\x9a\xb3\x41\x1d\x43\xc2\xbb\xfb\x95\x6c\x96\xff\x5a\xa1\x99\xf0\xf9\x8f\xc6\x60\xad\xcf\xd6\x85\x1c\x99\xb4\x90\x0a\xeb\x35\xc5\xb6\xae\xe5\x96\x6e\xd4\x6e\x7e\xca\xee\x91\x68\x98\x85\xcb\xec\x50\xde\x27\x8d\x3e\xb8\x87\xd9\x42\x27\x7c\x41\x16\xa0\x89\xfe\x6f\xb5\x9e\x5d\x4d\xb7\x9d\x0c\xb7\x85\x44\xf1\x11\x3b\xe7\xb0\xbb\x83\x0e\x3b\x3b\xe9\xb0\x93\xa3\x0e\xbb\x3a\xeb\x70\x0f\x87\x1d\x76\x73\xda\x61\x96\x14\x08\x43\xc1\xca\x7a\x3f\xfe\x3b\xdc\xc7\x45\x85\x7b\xf8\xf1\x30\xbb\xd5\x9a\x4c\xcd\xfb\x72\xea\x99\xd6\xa7\xfc\xfa\xbf\x1a\x58\xbb\xf9\xf4\x30\x0b\xaa\xe0\x0c\x4b\x76\x68\x3f\x11\x0f\xff\x2f\x71\xb7\xe1\x5e\x2e\x37\xec\xee\x76\xc3\xee\x94\xc1\xaa\xee\x39\xa7\x53\xef\xab\x30\xfd\x28\x5e\x45\xf0\x19\xdc\x21\xfc\x4e\x9a\x80\xf1\xf2\x27\x94\x42\x1a\x4b\xf6\x5d\x88\x99\xb4\xbf\x05\xef\xbc\x3d\x4c\xe1\x8f\x10\x93\xa8\xbe\x11\x39\xe9\x1e\x5f\xc7\x11\xfc\x22\x1a\x7d\x56\x4d\xf7\xe0\x76\x4c\xde\x26\x49\xa9\xfa\xbc\xf3\xde\x35\x4e\xf6\x7a\x73\x84\xb4\x77\xa6\xf6\xbc\x8e\x9a\x23\x9d\x5a\xa1\x69\x95\x4f\x60\x8f\xbf\xed\xbd\x6b\xcd\xbe\x83\xe2\x6a\x5f\xa1\xb2\xab\x5e\xd8\x81\x4a\x54\xbc\xd6\xe5\xdd\x1b\x9b\x5e\x8b\xf8\xc4\x46\x9c\xc5\x36\x0a\x86\x4b\x2d\x5a\xca\xa5\xae\x1a\x61\x1a\xe3\xf7\x59\x74\x7e\x2b\x15\x6e\xba\x88\x67\xce\xc3\x60\x5e\x49\xcd\x97\x34\x05\xc4\x6b\x85\x96\x0d\x3b\xac\x43\x44\xad\xce\xdc\x36\xf1\xe5\x20\x8d\xb6\x53\xd9\x6c\x81\x48\xd3\x83\x6d\xc4\x02\x85\xb2\xb0\x17\x63\x4f\xfb\xb6\x69\xb1\x97\x34\xa7\xfb\xea\x11\x0f\x7e\xff\xf3\x70\xea\x44\x5f\x33\x60\x67\x69\x77\x96\x76\x67\x69\x6f\xd1\xab\xb3\xb4\x97\x3f\x9d\xa5\xbd\xc5\xd3\x59\xda\x9d\xa5\xbd\x6a\xe2\xce\xd2\xee\x2c\xed\xf5\x93\xef\x66\x69\xef\x5a\x27\xd4\xb6\x7b\x43\x72\xce\x5f\x64\x26\x9c\x4c\x9b\x1a\xa2\xd8\xca\xff\xf5\x6e\xed\xed\xb6\x2d\xbd\xd8\xda\x6e\x5b\xe4\x73\xbe\x45\xb2\xc6\xb4\xae\x8d\xef\xb9\x9e\xab\xad\xee\x8f\xab\x16\x6a\x07\xda\x68\x25\x14\x76\x24\x8e\xcb\x98\x0a\x0f\x17\xff\x0d\xb0\xc9\x93\x67\x70\x10\x33\x2e\x87\x04\x7c\xa5\xdd\xf4\x47\xe5\x64\xbf\x69\x51\xe7\x60\x38\xbd\x38\x75\xde\x66\x2a\x2d\x51\x67\xdd\xeb\x4c\x71\x83\x4f\x12\x21\x68\xa6\xd6\x20\x6d\xb8\xde\x90\xab\x25\x4c\xa5\x14\x8d\xaa\x55\x4c\x1f\x7b\x99\xe3\xef\xe3\x0b\x94\xe7\x8d\x25\x5e\x0f\x5b\x4c\x0d\x94\x5a\xf9\x4e\xe1\xfc\x15\x88\xa1\x94\x5f\xab\x90\x11\xa5\x37\x31\xeb\x1b\x89\x92\x77\x24\xeb\xd9\x13\x78\xc2\x74\xd8\x1e\x58\x5a\x86\x8f\xc8\x73\x7d\xbb\x8d\x48\xfa\xab\x8e\x45\xdd\x6e\x7d\x2c\x6a\x26\x7f\xd7\x9d\x8a\xfa\x2f\x39\x15\xc5\x1f\x3d\x0b\xbd\xf3\xe3\x51\xf0\xef\x70\x01\xa1\x41\x06\x55\x51\xe5\x4e\x96\x4d\xad\x94\xf5\x53\xe5\xde\xca\x1c\x86\xca\x93\x69\xba\xa4\xd9\x44\x3a\x9e\xa5\x4f\x1e\x8f\x6b\xab\x2c\x33\x6d\xa8\xee\x10\x79\x1e\xce\x14\x45\x93\xd4\x97\xb0\xc8\x0f\x5d\x99\xf0\x38\xdc\xd9\x5a\x7b\x33\x2c\x64\x0e\x48\x16\xe6\x84\x50\x92\x6a\x2b\x84\xa8\x77\x8a\x6e\x30\xaa\xde\x91\xbc\x41\xd5\x48\xd2\x03\x7b\x78\x18\x75\xf8\x3b\x95\xf0\xef\x45\x42\x7f\xd3\x92\xa4\xdf\x6d\x22\xa3\x79\x43\xb5\x94\x6e\xc0\xd7\xc8\xe8\x0f\x59\x82\xb1\x4d\x9e\x7f\xbb\x18\xc3\x0e\xf9\xfd\xbf\x30\xb7\xff\xe9\x9c\x2c\xfb\xc0\x11\xc6\x0f\x51\x5b\xff\xd1\x47\x15\xbb\xe2\xfa\xe6\xb9\x6f\x71\xfd\x7b\x8f\x1c\x7e\xd8\x1a\xfb\x4f\x20\x5a\xf8\x21\x6b\xec\xbb\x08\xe1\x4a\xa4\x7c\x6c\xa5\xef\xd3\xcf\x4e\x11\xc1\x2e\x1a\xb8\xb3\x16\xde\x52\xe1\xdc\x37\x0a\xb8\x25\x45\xec\x98\x67\xef\x72\xec\x7f\x4d\x8e\xbd\xb3\x78\x37\x7c\x3a\x8b\x77\x29\x50\x3a\x8b\x17\x3a\x8b\x77\xdd\xf6\x3a\x8b\x77\x25\x78\x3a\x8b\x77\x25\x52\x3a\x8b\xb7\xb3\x78\xe1\x53\xb3\x78\x77\xb9\xa5\xab\xcb\x75\xdf\x2b\xd7\xbd\xad\xb4\xd8\x4a\x46\x6c\x49\x07\x5b\xe7\xb6\xbb\xbc\xf6\xc7\x92\xd7\xde\xf8\xc0\xbf\x72\xf2\xbe\x87\xfe\xdb\xb8\x5a\x76\xf2\x5f\xdc\x68\x99\x41\x59\xb9\x70\x9e\xba\x3b\xfd\xff\x2e\x4e\xff\x4f\x41\xbe\xbb\x02\x60\xa3\x2b\x00\x96\xc1\xac\xbb\x07\xa0\xbb\x07\xe0\x1d\x27\xa1\xbb\x7b\x00\xba\x7b\x00\xba\x7b\x00\xe2\xd3\x9d\x4e\x82\xee\x74\xd2\x46\x4f\x77\x3a\x69\xf9\xd3\x9d\x4e\xfa\x68\xa3\xaf\xd0\x9d\x4e\xfa\xb8\x23\xb1\xd0\x9d\x4e\xea\xa2\xb3\x1b\x22\xea\x13\x3c\x9d\xd4\xdd\x03\xf0\xb1\xd6\x28\x40\x67\x69\x77\x96\x76\x67\x69\x77\x96\xf6\xea\xa7\xb3\xb4\xb7\x78\x3a\x4b\xbb\xb3\xb4\x57\x4d\xdc\x59\xda\x9d\xa5\xbd\x7e\xf2\xee\x1e\x80\x4f\xa8\x36\x02\xba\x7b\x00\xba\x7a\x89\xee\x1e\x80\xff\xde\x7b\x00\xa6\x72\xf7\x1f\xee\x32\x80\xed\x97\xd1\xdd\x08\xd0\xdd\x08\xd0\xdd\x08\xd0\xdd\x08\x10\x9f\xee\x46\x00\xff\x7c\x4c\xb1\xc6\xee\x7c\xd4\x52\xa0\x74\xe7\xa3\xa0\x3b\x1f\xb5\x6e\x7b\x9f\x40\xdc\xb0\x3b\x1f\xf5\x11\xc6\x0a\xbb\xf3\x51\x5d\x5c\x70\x16\x39\x9f\xc8\xf9\xa8\xee\x46\x80\x8f\x31\xdb\xde\x59\xbc\x1b\x3e\x9d\xc5\xbb\x14\x28\x9d\xc5\x0b\x9d\xc5\xbb\x6e\x7b\x9d\xc5\xbb\x12\x3c\x9d\xc5\xbb\x12\x29\x9d\xc5\xdb\x59\xbc\xf0\xa9\x59\xbc\xdd\x8d\x00\xdd\x8d\x00\xdd\x8d\x00\x9f\x62\x86\x7b\x2d\xa6\x0b\x2c\xb4\x99\x5c\x0a\x33\xc2\xa5\x59\xed\x29\x74\xee\xbd\x68\xf5\x20\x09\x39\x94\xa3\xca\x04\x03\xfc\x6f\xcf\x5e\xbd\x78\xf2\xe2\xf9\xd9\x8b\xb3\xcb\x00\xaf\xa1\xf6\x2e\xee\xe8\xf5\xf9\x29\xa4\xc2\x89\x5c\x8f\xe0\x5c\x67\x41\xe9\x7a\xeb\x5f\x0f\x5d\x58\x08\xe4\xb2\x90\xae\xee\x65\xd1\xdc\xa0\xe9\x05\xb8\x71\xf2\xbb\x52\x4e\x16\xe8\x53\xb7\xc2\x39\x62\x4d\x92\x03\x05\xa2\xe3\x73\xee\x85\xb8\x46\x02\x14\x8c\x2a\x61\x84\x72\x18\x51\x21\x9d\xef\x94\x69\xb0\x3a\x98\x0f\x32\xf8\x18\xb4\x0e\x8b\xc1\x52\x38\x8f\x99\xe1\xb1\xb8\xf1\x07\xaa\x87\x9a\x60\x4e\x44\x51\xe8\x4c\x0e\x65\xea\x8d\x3c\x28\x44\x56\x67\xfd\x82\xae\x40\x53\x13\x50\xb3\x81\x63\xe8\xcf\x81\x07\xd5\x8d\x34\x5a\xb1\x06\xbb\x11\x46\x8a\x41\x1e\x76\x35\xf0\x01\x01\x1e\xb7\x59\xa0\x82\xc1\x84\xfc\x1c\x3f\x52\x80\x56\x38\xf9\xbe\xa2\xdf\x54\x73\x0f\xdc\x99\xc6\x5f\x3c\x7c\xf8\x3f\xeb\xe3\xec\xbe\xd3\x95\xf2\xd8\xf1\x12\xb3\xe1\x5b\xea\x21\x87\x20\xdd\x3e\x71\x8c\x25\xcf\x87\x46\x30\x98\x55\x69\x84\x94\x76\xa5\x91\x5e\x2b\x8b\x1a\xe1\x1e\x0c\xc4\x5d\x45\x45\x0c\x40\x02\xc1\x5a\x39\xc8\xb1\x47\x6c\x2f\xdb\x6d\x07\x48\xc0\xe3\x1e\xcc\x9a\x37\x48\x2b\x27\x72\xf3\x12\x17\x91\x78\x5f\xf3\x59\x77\xe1\xf9\x3c\xc3\xa1\xa8\x72\xcf\x1a\x1e\x37\x8c\xdf\x89\xae\x48\x14\x64\x78\x07\xb2\x10\x23\x7f\xf6\x5e\xc0\x50\xe6\xd8\x8f\x39\xf4\x54\xa4\x63\xec\x41\x86\xa4\x5b\xa4\x42\x10\x30\xd2\x3a\x23\x15\x63\xf4\x9d\x2c\x78\xb4\x40\x8f\x35\x7c\x06\x13\xc8\x74\x35\xc8\x6b\x2c\xcb\xdf\x6a\xc9\x50\x8a\xf4\x9a\xe6\xe2\x81\x41\x38\x38\x72\x45\x79\xc4\xbf\xc2\x7f\x43\x0b\x9b\xfc\x62\xb5\x8a\xa2\xaa\xb5\xcc\x64\x06\xfe\xd2\xc2\x00\xad\xeb\xe3\x70\xa8\x8d\xfb\x27\x41\xab\x52\x4c\xad\x4a\xd7\x5b\x8f\x48\xad\x2c\x7a\x1d\xa7\x34\x13\xf2\x14\xe6\xb5\x59\xc0\xa1\x2d\x72\x48\xf6\x96\x48\x80\x92\x38\xcd\xa8\x63\xf8\xbf\x07\x57\x9f\xff\xd1\x3f\xfc\xfe\xe0\xe0\xcd\xc3\xfe\xd7\x6f\x3f\x3f\xb8\x4a\xf8\x8f\xcf\x0e\xbf\x3f\xfc\x23\xfe\xf8\xfc\xf0\xf0\xe0\xe0\xcd\x0f\x2f\x9e\x5d\x9e\x3f\x79\x2b\x0f\xff\x78\xa3\xaa\xe2\xda\xff\xfa\xe3\xe0\x0d\x3e\x79\xbb\xe1\x20\x87\x87\xdf\xff\x6d\xc9\x82\x84\x9a\xbc\x1a\x2e\x57\x46\xfd\x0d\x6b\x5e\xfa\x9b\xa8\xc2\xbb\xfe\x75\x35\x40\xa3\xd0\xa1\xed\x4b\xe5\xfa\xda\xf4\x7d\x87\x63\x70\xa6\xc2\x85\xdd\x48\xe2\xaf\x0b\x14\x4e\xc9\xd5\x97\xad\x0e\x33\x41\x91\x70\x53\x44\xf0\x59\x68\xca\x5a\x40\x92\x5e\xe5\xeb\x10\x5c\xa3\xaf\x12\xb8\x58\xd0\x93\xd5\x52\x68\xb1\x6f\xbd\x02\xb3\xb3\xe3\xcc\xd4\xc1\x78\xc1\xc9\x63\x2e\xd9\xc2\x06\x66\xec\x76\x46\xeb\x5a\x7c\x94\x46\x6a\x23\xdd\xe4\x34\x17\xd6\xbe\x14\x05\x6e\x04\xdd\xb3\x61\x63\x0c\xf4\x88\xd9\x48\x86\x07\xa5\xe5\x0d\xb4\x38\x2e\x4b\x0e\xd2\xb3\xad\xf6\x11\x42\xb1\x4d\xcd\x33\x91\xfb\xb4\x81\xdf\xd0\xe8\x70\xd1\x87\x41\xaf\xab\xe3\xe7\xd5\xc0\x5b\xb1\x57\x8b\x69\xc5\x7b\xd5\xca\xe1\x9d\x3b\x65\x65\xbb\x99\x96\xbe\x58\xd4\x15\x52\xa1\x68\xd9\x7c\xd1\xcb\x10\x7e\xce\x71\x24\xd2\xc9\xcf\xb4\xfc\x9f\x0d\xd2\x42\xc8\x16\xf9\xd9\x1b\xdb\xa7\x5e\x1e\x5f\x70\x25\xc2\x7e\xb8\xb9\xc7\x02\x4a\xbe\x98\x47\xaa\x5f\xbc\xe1\x52\xdb\x64\x86\xeb\xdb\x4a\x9d\x25\x04\xb9\x64\x66\xed\x2c\x93\xea\x8f\xb5\xb2\x7c\xf3\xd9\xdb\xb9\x96\xc1\x05\x23\x27\x8f\xd4\x6e\x9b\x3e\x4d\xc5\x02\x93\x04\x5b\xdc\x20\x9c\x64\x85\x64\xaf\x0f\x0e\xce\x2f\x4e\x0e\xa7\x76\x42\xfa\xda\xab\x98\x4c\xa3\x55\xfb\xce\x2b\xbd\x31\xda\xc6\xd3\x63\xb5\xc1\x85\x16\x9e\x5b\xb8\xd2\x22\xce\x49\x00\x63\xe7\x6f\x80\xf5\xe4\x17\x27\xf0\xf3\x40\x58\xcc\xa5\x42\x0f\xbb\xd2\xc8\x1b\x99\xe3\x88\x66\x6c\xc5\xad\xe1\xb4\x32\x06\x95\xcb\x27\xf1\x06\x98\xc5\x58\x91\x96\x04\xfa\x34\xb9\x45\xca\xaa\xad\xce\x1a\x59\xd4\xda\x62\x96\xc0\x05\xf7\x98\xf8\x10\x45\x68\xc7\xb8\x61\xbd\xb8\x0c\xb9\x60\xd0\xd2\xc0\x52\xf9\x5e\x32\xf3\x2a\x0e\x8d\x21\x97\x87\xab\xc2\x2a\xcb\x06\x70\x9e\xa1\xa9\xd5\x32\xab\x26\x1b\x4d\xb1\x94\x4d\x82\x50\x3a\x17\x00\xb3\x00\xf0\xcb\xf7\x3c\x6d\x54\x38\x5d\xaf\x97\xb5\xdf\x19\x2d\x6e\x58\xb9\xca\x20\xe9\x7f\xc6\x2e\xf3\x5c\x1b\x34\x33\x76\x4c\x7b\xfa\x5e\xbd\xec\x42\xc8\x40\x6a\x36\xce\x69\x70\x50\xc9\x9c\xbd\x40\x59\xef\xcf\x7a\x42\x16\xf5\x74\x7a\x08\xba\x2c\xc2\xf5\x4b\x55\x59\x6a\xe3\x1a\xdf\x20\x6d\xf3\x46\xb0\xdd\x17\x00\x80\x96\x55\x1a\x2c\x85\xa9\x25\xb6\x45\x48\xc7\x42\x91\xfa\xa7\x8d\xbe\xd0\x5c\x2a\xe7\xeb\x2d\x69\x5a\x31\xd0\x95\x63\x1a\x0b\xbc\x3a\xd4\x95\xca\x80\x84\xca\x31\x8c\x9d\x2b\xed\xf1\xd1\x51\xa3\x8f\x12\xa9\x8f\x32\x9d\xda\xa3\x54\xab\x14\x4b\x67\x8f\x22\x37\x1d\x95\x3a\xeb\xc7\x1f\x7d\x11\x99\xe4\x68\x7f\x99\x8e\xdf\x40\x13\x06\xc8\x1f\x83\xc7\xd5\x92\x56\xa8\xaa\x15\x97\xcd\xf4\x57\x77\xa6\x06\x0d\x18\x17\x36\x72\x3a\xe7\xab\x99\x56\x64\x60\xa6\x1d\xd0\xa6\x7d\x7d\x45\x52\x6d\x98\xb6\xa4\xdb\xbe\x6d\x0f\xbd\x5a\x68\xaf\x72\xcc\xd7\xb8\xe2\x73\xd7\x23\xb1\x6c\x23\x73\xaf\x59\x28\x1b\x00\xce\x09\xbe\x20\x89\x0c\x7a\xff\x85\xc4\x95\x9a\x00\xd1\xb3\x0b\xb7\x65\xb5\xae\x8f\x72\x86\xeb\x37\xbf\xa9\xa3\x69\x3d\x1c\x0e\x31\x75\xdf\x05\x7e\xae\xe3\x6a\xcc\xdc\x31\x02\xf6\x4d\xfc\xeb\xbb\xe5\x1e\xe5\x46\xc1\xaa\xcd\xd2\x0d\x7e\x49\xab\xc3\x08\x53\x10\x7a\xc2\x1d\x66\x54\xb6\x87\x80\x1f\x8b\xbd\x3f\x0e\xc8\x06\x9f\xd9\x07\x5f\x82\xbd\x43\x32\xa3\xd5\xd8\x06\x09\xd7\x92\xb6\xc1\x9f\x6e\x22\x7f\x08\x2f\x75\x28\x64\xc6\x1e\x9c\xf3\xdd\x52\xcd\x1b\x56\x64\x2f\xb5\x2f\x69\x5e\x6a\x17\xb5\xe1\xb6\x36\xce\xb2\x36\xe1\x32\x05\x90\x1f\x9a\xf4\x8a\xdf\xd9\x54\x7a\xa5\xa1\xe0\xa9\xe8\xd9\x2a\xc8\x5c\xe3\xa4\x09\xc9\x87\xe4\x0d\x47\xbc\x7a\x0d\x95\x44\xe3\xd3\x47\xd8\xff\x19\x6a\x12\x75\x31\x90\xca\x4f\xe6\x87\x8e\xa8\xe0\xd1\x23\x40\x55\xc6\x3f\x79\x9a\x77\x01\xae\xcd\xb2\x38\x53\x30\x7b\xb5\x45\xce\xa6\x8e\x02\x2f\xce\xd6\xb4\x52\x34\x4f\x7e\xad\x44\x9e\xc0\x63\x2f\x15\x79\xf7\xe1\x55\x68\x34\x17\xb5\xbe\x95\x79\x96\x0a\x93\xb1\x36\xf0\x3c\x0a\x56\x7b\xec\x89\xda\xe0\x88\xdc\xde\xe0\xc8\xdf\x9d\x06\xa5\x30\x4e\xa6\x55\x2e\x58\x6d\xe1\x48\x9b\xc9\x3b\x81\x68\x43\x34\x17\x98\x6a\x95\xad\x09\x24\x2e\x91\xae\xa1\x6f\x1b\xc6\x6c\x46\xa1\x91\xa1\x44\x58\x16\x38\x4b\xa4\x07\xd3\xce\x8d\x1e\x46\xae\xae\x59\xac\xe7\xad\x9a\x5b\xc9\x66\x59\xdb\x2b\x96\xfe\x8c\xc1\x61\x4b\x3c\xd6\x5c\x91\xc0\xbf\x26\x51\x5f\xf5\x40\xba\x18\x3d\x63\xbf\x39\xcc\x19\x48\x36\x00\xbb\x61\xa8\xa1\x36\x78\x83\x06\x0e\x32\xcd\x7d\xb8\x8c\xfe\x30\x81\xff\x90\x89\xef\x63\x10\x23\x5f\xf1\x1d\x48\x3c\x5a\x22\x8e\x2f\x3b\xe4\x28\xe2\x43\x38\xf0\xd5\xf7\xb2\x28\x30\x93\xc2\x61\x3e\x39\xf4\x05\x18\xb1\x7e\x7f\x13\xd4\x6d\x72\x68\xa3\x75\x58\xe3\xab\xbf\xaf\x68\xc9\x8b\xdd\x02\xb3\x3f\xc5\xc8\x58\x03\x19\x6f\x65\xce\xa0\xb0\xd6\x41\x7a\x45\x52\xae\x95\x84\x6b\xd9\x7e\x51\xcc\xd4\x08\xfe\x85\xe8\x40\x80\xc1\x11\x53\xb9\xa7\xdc\x7b\xd0\xb8\x4c\x17\x1f\x3a\x59\xa3\xd1\x56\xe7\xf5\xfb\x40\xe6\xff\x57\x7f\xcf\x84\x13\x4b\x1a\x78\x9c\x4f\xca\x45\xc1\x81\x75\x8a\xb2\x19\x7c\x19\xb2\x36\x88\xea\x86\xe9\x77\x1a\x81\x4d\xfd\x45\x3d\xa7\x5d\x6a\x0e\xa9\xf9\x3c\x6f\xc4\x77\xdf\xe0\x48\x5a\x67\x26\xad\x70\xa8\x0f\xbd\x39\x0d\x52\x59\x27\x94\x93\x2c\xd9\x20\xb6\xec\x87\xd8\x20\x99\xdf\x09\xbc\x22\x5f\x8b\x63\x58\xb7\xa4\xa6\xbd\x81\x7d\x39\x29\x11\xbe\x6d\xfd\x78\x66\xca\x94\x69\x2d\x08\x1a\x4f\x5c\x22\xcb\x0c\xda\x79\xf9\xb0\x88\x7c\x56\xee\x3f\xba\xf9\x6b\x41\xb0\x7f\x1e\x03\x02\x21\xb7\x64\xad\x1c\x91\x95\x19\x4f\x7b\xc5\xd8\xf0\x94\xb5\xe9\xbd\x02\xee\x28\x7f\x63\x6e\x2a\x6a\x25\x20\x5d\xb4\xfb\x53\xad\x6c\x55\xc4\xa2\x2d\xf2\x7a\x4a\x54\x19\xaa\x74\xc2\xc7\x03\xf2\x1b\x34\x09\xfc\x68\x09\x53\xf0\xbf\xe5\x88\xfc\xbe\x30\x69\xdb\x54\x8a\xa7\x4e\x66\x56\x20\x6d\xeb\xce\x4c\x2e\x43\x23\x1b\x28\x8e\x80\xd9\x4c\x7b\x1b\x53\xe1\xb3\x8b\xa8\x7c\xac\xf5\xb2\x3e\x95\x16\x83\xa0\x11\x2e\x9e\xe1\x69\x4b\x23\xed\x0f\x20\x95\xda\xca\x78\x5a\xa6\x96\xa3\x53\x27\xdb\xf4\xd0\x9f\x3b\xf3\xe3\x4e\x3b\xc2\x5c\x53\x31\xb3\x19\x76\xdc\x2a\xe5\x81\x8f\xed\x28\x4d\x14\x33\x0f\xfd\x50\x8b\xfa\xb9\x78\x11\xf1\xf4\x92\x1b\x99\x6e\x84\xba\xc6\x0c\x72\xbc\x93\xa9\x1e\x19\x51\x8e\x65\xca\x87\xab\x88\x4d\x39\x48\xc6\x47\xaa\x44\x81\xc9\xfe\x52\x42\x5b\x26\xc6\xcb\x6a\x90\x4b\x3b\xc6\x85\xb6\xcc\x4a\x1a\xb5\x98\x1a\x74\x0b\x25\xc8\x14\x89\x5e\xf8\x76\x8d\x52\x8e\x15\x29\x61\x80\x50\x71\xe5\x69\x8e\x19\x8f\x40\x9c\xa6\xc4\x48\x31\xad\xd1\x5c\x78\x5b\xc3\x30\x81\x33\x17\x03\xd3\xd4\xe3\x1a\xb1\xf4\x94\xc6\xa9\x51\x5b\x70\x4c\xc5\x4a\x95\xa2\x3f\x22\xe6\x8f\xda\x21\xc6\x30\xa3\x33\x12\xbd\x19\x84\x1c\xe0\x8f\xb8\x41\xe5\x16\x1b\x35\xab\xfd\xae\x15\x3e\xd7\x6a\x30\xd6\x32\x65\x3d\x24\x1b\x59\x14\x75\x22\xfd\x4d\xa0\xe4\x2f\xdb\x62\xd0\x9f\xe8\xbb\xf0\xa5\x25\xeb\x65\xcd\x8f\x53\xcd\x43\xc2\xd2\xc2\x58\xdf\x86\x91\x66\x99\x36\x44\x6c\x22\x6e\x33\x69\x53\xe2\x74\xcc\xe0\x54\x2b\x1b\x8f\xf5\x09\xe5\x4f\xea\xdd\x88\xdc\x93\x42\x1c\xb8\xd4\x39\xe7\x37\xb2\x2a\xba\x13\xbe\xfa\x0e\x8b\x01\xf2\x75\xbc\x36\x2e\x65\x89\x9a\x5b\xa3\x62\xd7\x69\xc1\xa8\x1f\xce\x75\x9e\xaf\xd6\x62\x2b\xfd\xd2\x4d\xbc\xd2\x08\x80\x8d\xaf\x42\x3f\x8b\x10\x0b\xb1\x38\xa2\xe9\x26\x83\xc4\xa4\x41\xa6\x6e\x0d\xd8\x01\xba\x5b\x44\x05\xe9\x18\xd3\x6b\xdb\xe4\x90\xf9\x62\xec\x19\xac\x85\xf8\xd3\xb4\xc4\xaa\xed\x29\xc2\x0a\x3b\x1a\x16\xd1\xa7\xcd\x14\xde\xb6\x63\x56\x0b\xd4\x0d\xa9\xe8\x1b\x21\x73\x31\xc8\xfd\x71\xd6\xfa\x57\xaf\xbd\x0e\x19\xf5\x79\x59\xe5\x79\x48\x22\x71\xd6\xd6\x19\x31\x1c\xca\x94\xd3\xe4\xd2\xf8\xa8\x6f\x50\x6c\x0b\xb7\xb0\xfe\xb2\xf6\x05\x1c\x61\x9d\x70\xd5\x1c\x8e\x56\x20\x78\x15\x62\xc9\x0f\x91\x4b\x03\x44\x33\x57\x1c\x4f\x39\x2b\xb4\x0c\xf4\xce\xd6\x54\xfc\x3b\x81\x97\xda\x85\x1b\xca\x5f\xa0\x25\xb5\xcb\x00\x7a\x8d\xc2\x6a\xd5\x92\xae\x6c\xfd\x1a\x39\x92\x4a\xe4\x61\x53\xed\xf8\x5e\xed\x7b\x08\x0e\x29\x17\x72\x64\x84\xab\x85\x62\xb3\xee\xa0\x5d\x82\x5e\xf4\x91\xd0\x04\x4e\xd4\x84\xf1\x3d\x44\xe1\x38\xe7\x2e\x95\x33\x3a\xab\x52\x0c\x19\xeb\xca\xb6\x07\x79\xa7\x62\x74\x3a\xbd\x70\x1a\x27\x69\x6a\xa4\x32\x74\x42\x86\x94\x92\x56\x08\xc2\x96\xe4\xc7\x45\x9a\xf4\xa1\xf0\x06\xc0\xac\x2c\x4e\xce\xcf\xe0\x75\x38\xec\x98\x40\xbf\xdf\xf7\x79\x4f\xeb\x4c\x95\xb2\x7e\x21\x16\x52\x59\xd0\x14\x9e\xfa\x78\x93\xa2\x55\x5e\x18\x22\x1f\xde\x04\x2b\x85\x1b\x43\xe2\x01\x9f\xb4\x40\x01\xf0\x94\x74\xcd\x9d\x28\x4a\xa2\xfb\x2b\xe5\xa5\xf7\x53\xad\x2f\x3c\x92\xfc\x9c\xbf\xc3\xd1\xd1\x2c\x4d\xe8\x01\x99\xa8\x21\x80\xc8\xa4\x31\xd4\x7a\xdf\x4e\x6f\x29\xa1\x8e\x3f\x28\x7d\xab\x16\xcd\xce\x73\x09\x83\xc7\x70\xb5\x77\x12\xb9\xef\x6a\xaf\x07\x57\x7b\xe7\x46\x8f\xb8\x6c\x4d\x8d\xae\x42\x1d\xda\xd5\xde\x63\x1c\x19\x91\x61\x76\xb5\x47\xc3\x7e\xce\xf5\x86\x2f\xd0\x8c\xf0\x07\x9c\x7c\xcb\x83\xd5\xaf\xa3\x46\xf8\xd6\x97\x26\xd2\x7b\x52\xc1\xa4\xa7\xbe\x2d\x44\x59\xbf\x78\x21\xca\xba\xf3\x69\x43\x67\x6f\xde\x16\xe8\xc4\xcd\xa3\xa4\xc1\xe8\xcf\xbf\x58\xad\x8e\xaf\xf6\x9a\xf5\xf7\x74\x21\xb9\xd2\x62\x72\xb5\x07\x53\xb3\x1e\x5f\xed\xf1\xbc\xf1\x7d\x5c\xe4\xf1\xd5\x1e\xcd\x44\xaf\x8d\x76\x7a\x50\x0d\x8f\xaf\xf6\xb8\x80\xa1\xf7\xa8\x67\xb0\xec\x91\xc1\xf4\x6d\x33\xc3\xd5\xde\xcf\x84\x93\xa3\xa3\x90\xc2\x08\x97\xbf\xff\xb9\x38\x58\xbd\x56\xee\xaf\xab\xcb\xee\x43\x2e\xac\xbb\x34\x42\x59\x9e\xff\x52\x16\x8b\xd3\xb8\xde\x97\x63\x7e\x5f\xfa\xdd\xb0\x0c\x58\xfa\xd9\x53\xc3\xd2\xcf\x4b\xb4\xe7\x26\x9a\x6b\x7e\x0f\x1b\x46\x9d\xe7\x3b\x36\x05\xdb\x64\xcf\xc5\x38\x4d\x8d\x1f\xd2\x01\xa1\x35\x86\x8b\x04\x88\xc5\x83\x7c\xe3\x72\x4c\xc6\x5b\xa8\xea\x69\x1c\xfc\xdb\x70\xc9\x00\x54\x2a\x43\x93\x73\xb2\xaa\x19\xd5\x67\x42\xb2\x04\x7c\xdc\x40\xd4\x51\x9a\x6b\x62\x24\xd6\x4e\xaa\x15\xbc\xf6\x85\x3f\x71\x44\x92\x1d\xe1\x9e\x05\x3f\x0c\x2b\xba\x34\xc5\xd2\xb1\xa6\xdb\x3d\xc5\x0c\xad\xa0\x0a\x59\x56\x7d\xb7\x9c\x3c\x02\x71\x6c\x08\xf8\xd0\xda\xe7\xf7\xc7\x55\x21\x48\x75\x88\x8c\x6b\x7f\xea\x6f\xde\x7d\xf3\xee\x96\x17\xa9\x3e\x29\xe4\x63\xfc\x11\x0f\x01\xd4\x41\x91\x88\xfa\x40\xcd\x9a\x88\xc9\x46\x9b\x2f\xc4\xdd\x73\x54\x23\x37\x3e\x86\x2f\xbf\xf8\x5f\x5f\xfd\x63\x49\x43\x2f\x18\x31\x7b\x86\x2a\xc4\x82\x36\x04\xc3\x7c\xc7\xd9\xa0\x61\x42\x52\x29\x13\x4e\x24\xa3\xa6\x4d\x1d\xe4\x6e\x28\xe8\x56\x70\xe1\x56\x50\x97\x55\x49\x70\x79\xca\x05\x80\xd6\x09\x95\x62\x8f\x8c\xa4\x85\x83\xc9\x5a\x80\xe7\x13\x78\xf4\x85\xff\x47\x52\x78\xea\x39\xf1\xfd\xe6\xee\x6d\xb2\x60\xc9\xd2\xc2\xd7\xbd\x99\xf5\x48\x0b\x84\x2a\x3d\x64\xc2\xf1\x2e\xa6\x41\xaf\x09\x63\x30\x60\x5e\x13\x62\xbd\xde\x75\x88\x5b\x17\x0f\xdc\x2c\x16\x58\x48\x25\x8b\xaa\x38\x86\x87\x4b\x9a\x78\x91\xb6\x21\x36\x7d\xe3\xc6\x10\x10\x24\xba\x46\x46\x14\x05\x97\xfa\xca\x0c\x95\x93\x43\xc9\x45\x03\x35\x69\xb3\xbb\xef\x3b\xc6\x1a\x94\x1a\x8a\x5c\x9e\x42\x72\xa8\x45\xec\xe7\xde\xce\x31\xac\x81\x43\xf6\x26\x6d\x0b\xa8\x49\x89\x9e\x1b\xbc\x03\x03\x78\x57\x7a\x53\xb5\x95\x86\x28\x50\x28\xa9\x46\xb6\xa9\xe7\x0a\xff\x40\x0e\x7d\xbc\x1d\x63\xc8\x9e\x63\x3b\x17\x94\x92\xb3\x94\xb1\xdf\x24\x9a\x9a\xc2\x8c\xc4\x8f\xb7\xd1\x67\x63\x9a\x64\x39\x16\x98\x9f\x0a\x8b\x91\x1b\xdb\xd5\x5c\xf1\xb6\x96\xfa\xf4\xc1\x3b\x63\xd5\x47\x0f\xbf\x58\x89\xf2\xba\xdd\xf2\x14\x5e\x5d\xe6\xf5\xe6\xa4\xff\x1f\xd1\xff\xed\xed\x41\xf8\xe3\x61\xff\xeb\xff\xd7\x3b\x7e\xfb\x59\xeb\xe7\xdb\xe5\xd5\x59\x8b\x8d\xf9\x25\xe4\x13\x94\x48\xb4\x13\x23\x46\x7b\xb1\x4a\xe5\xd2\x54\xd8\x83\xa7\x22\xb7\xd8\x83\x1f\x15\xab\x86\x7b\x02\x6d\x75\x86\x9a\xb4\xf2\x1e\xcd\xba\x2c\x53\x1e\x9a\xf0\x92\x56\xb7\x09\xcb\x5d\xe5\xbe\x6e\x06\xa4\x18\x6a\x68\x49\x1a\xd5\xa2\x33\x5f\xf2\x3c\xd4\x3a\x09\x16\x6e\x92\xea\xe2\xa8\xfe\xee\x4d\xeb\x17\x42\x4d\xa0\x11\x6b\xde\x28\x9d\xa5\x74\xeb\x48\x36\x89\xd4\x68\x6b\x9b\x7b\x48\x20\x97\xd7\x08\x27\x8d\xdf\x48\xc2\x72\x80\xa9\x60\x5b\xdc\x0c\xa4\x33\xc2\x07\x7d\xa3\x5d\xd9\x44\x94\x86\x55\x0e\x07\xe4\xae\x26\x5c\x48\x36\x27\x5d\xc3\x9d\x46\x62\x20\x73\xfe\xa7\x65\xc8\x95\x4e\xb5\x1a\xe6\x32\xb8\x00\x45\xa9\x8d\x13\xca\xc5\x83\x17\x23\xbc\xf3\xff\x9a\x95\x4f\x3b\x48\x0b\x07\x99\xb2\x8f\x1e\x7d\xf1\xe5\x45\x35\xc8\x74\x21\xa4\x7a\x5a\xb8\xa3\xc3\xef\x0f\x7e\xad\x44\xce\x59\xde\x97\xa2\xc0\xa7\x85\x5b\xfe\xef\x02\x6d\xad\x16\x1f\x7d\xb5\x01\x17\x1d\xbc\xf1\xbc\xf2\xf6\xe0\x4d\x3f\xfc\xf5\x59\x7c\x75\xf8\xfd\xc1\x55\xb2\xf2\xfb\xe1\x67\x47\x5c\x23\x59\xb3\xdc\xdb\x37\xfd\x86\xfd\x92\xb7\x9f\x1d\x7e\xdf\xfa\x76\xb8\x88\x19\xa7\x4a\x17\xc9\x0b\xe8\x17\xa2\xec\x5f\xe3\x64\x09\x73\x2e\x35\x47\xe7\x07\xf2\x10\x2b\x44\xb9\xc8\xfb\x1e\xca\xd1\x0b\x51\xbe\xc6\x21\x1a\x54\xe9\x42\x22\xbf\x67\x06\x86\xfc\x87\x15\x9f\xb8\x02\x6b\x87\xa8\x13\xe9\x1d\x1f\x69\x5b\x65\x4e\x6f\x40\x2d\x9b\xd9\x8f\x6a\x45\xfd\xe2\xda\x49\xea\x7d\xee\x3c\x42\xe4\xef\x9f\x7c\xfc\x68\xe7\x71\x2a\xb9\xd4\xd3\x9a\x8e\x61\x9e\x3d\xf6\xa6\x2f\x8b\x1e\x36\xe7\xc6\x9a\xfc\xbc\x4a\xc9\x5f\x2b\x84\xb3\xc7\xf5\x91\x5f\xa9\xd2\xbc\xe2\x4b\xc6\x7e\xfc\xf1\xec\x31\xf9\xef\xff\x0a\xe2\xe6\x16\x21\xd3\x6a\xdf\xc1\xab\x97\xcf\xff\x0f\x07\x03\xb8\x45\xcf\x2b\xf4\x70\xee\x30\x97\xc2\x87\xc9\x82\x02\x86\x7f\xa1\xaf\x93\xe3\x99\x53\x51\xd6\xf1\x13\x16\x77\x5c\x61\x95\x97\x96\x4f\x0f\x80\xad\x4c\x58\x1d\x0d\xec\x33\xbe\x7c\x3a\x29\xe4\x83\xe3\xc1\x87\x5c\xb8\xe5\xe7\x30\x56\x02\x2d\xd5\x4a\x61\xca\x49\x73\xb2\x02\xdf\x03\x7f\x10\x21\xbf\x0a\x36\x2b\xcf\xb1\x03\x33\x84\x84\xda\xce\x64\x41\x6b\x38\xf5\x3b\x7d\xef\x9c\x34\xb7\xdf\x9d\x66\xf4\xf1\x4c\xce\x6c\xbe\x5e\x13\x7f\x9e\x2b\xe3\x9a\x76\x9d\xa7\xa2\x87\x21\xb6\x5a\x27\x47\xc7\xc2\xc2\x00\x51\x71\x38\xd7\x47\xff\x50\x05\xaa\xc3\x26\x10\x5b\x95\x7d\xa7\xfb\xd9\x62\xe4\xad\x81\xdc\x7a\xa8\xad\xf0\x5c\x67\x4e\xef\x6f\xeb\xa8\xde\x8e\x27\x8b\x60\x60\x9b\xcb\xcc\x6a\x1b\x64\xdb\x8d\x2d\x77\x4c\x66\xa2\xba\xec\x59\x84\xa0\x46\xf0\x33\xe6\x97\x44\xde\xe3\x54\x64\xc3\x69\xce\xe6\x4d\x47\xf6\xb6\x5f\xa3\x47\xf3\x05\x9a\x1b\xb9\x93\xf2\x5b\xc7\x98\xa9\xaf\x33\x39\x79\xff\x6c\x45\xa6\xd7\xce\x93\x70\xe8\x2f\xd5\x6b\xd2\x37\x2b\xeb\xdf\x19\x82\xab\xaa\xfc\xb7\x19\x63\x5b\x65\xe9\xa5\xc9\xd4\x21\x0f\xeb\xb4\xe1\x94\x7b\xfb\x5d\x35\xa8\x0d\xe5\x66\xf4\xe0\x03\xc1\xef\x7f\x3e\xf8\xff\x01\x00\x00\xff\xff\x3e\xcb\x2d\xc0\x3f\xed\x00\x00") +var _operatorsCoreosCom_catalogsourcesYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x7d\x79\x73\x1c\x37\x92\xef\xff\xfa\x14\x19\x7c\x1b\x41\xd2\xd3\x5d\x94\x3c\x1b\xf3\x76\x38\x3e\x82\x43\xc9\x7e\x0c\xeb\x60\x88\xb2\x37\xde\x8a\x7a\x4f\xe8\xaa\xec\x6e\x98\x55\x40\x19\x40\x91\x6c\xcf\xcc\x77\xdf\xc8\x04\x50\x47\xdf\xdd\x94\x2c\x29\xb6\xea\x0f\x9b\x5d\x85\x33\x91\xc8\xfc\xe5\x01\x48\x94\xf2\x17\x34\x56\x6a\x75\x0a\xa2\x94\x78\xef\x50\xd1\x2f\x9b\xdc\xfc\x87\x4d\xa4\x3e\xb9\x7d\xf2\xe8\x46\xaa\xec\x14\xce\x2b\xeb\x74\xf1\x1a\xad\xae\x4c\x8a\x4f\x71\x2c\x95\x74\x52\xab\x47\x05\x3a\x91\x09\x27\x4e\x1f\x01\x08\xa5\xb4\x13\xf4\xda\xd2\x4f\x80\x54\x2b\x67\x74\x9e\xa3\x19\x4e\x50\x25\x37\xd5\x08\x47\x95\xcc\x33\x34\xdc\x78\xec\xfa\xf6\x71\xf2\xd7\xe4\xf1\x23\x80\xd4\x20\x57\x7f\x23\x0b\xb4\x4e\x14\xe5\x29\xa8\x2a\xcf\x1f\x01\x28\x51\xe0\x29\xa4\xc2\x89\x5c\x4f\xfc\x20\x6c\xa2\x4b\x34\xc2\x69\x63\x93\x54\x1b\xd4\xf4\xbf\xe2\x91\x2d\x31\xa5\xde\x27\x46\x57\xe5\x29\x2c\x2d\xe3\xdb\x8b\x83\x14\x0e\x27\xda\xc8\xf8\x1b\x60\x08\x3a\x2f\xf8\xef\x30\x79\xdf\xed\x15\x77\xcb\xef\x73\x69\xdd\x4f\x8b\xdf\x9e\x4b\xeb\xf8\x7b\x99\x57\x46\xe4\xf3\x03\xe6\x4f\x76\xaa\x8d\x7b\xd9\x74\x4f\xdd\xa5\xc2\x59\x93\xfa\xcf\x52\x4d\xaa\x5c\x98\xb9\xba\x8f\x00\x6c\xaa\x4b\x3c\x05\xae\x5a\x8a\x14\xb3\x47\x00\x81\x84\xa1\xa9\x21\x88\x2c\xe3\x65\x11\xf9\xa5\x91\xca\xa1\x39\xd7\x79\x55\xa8\xba\x2b\x2a\x93\xa1\x4d\x8d\x2c\x1d\x93\xfe\xcd\x14\xa1\x34\xe8\xdc\x8c\x49\x02\x7a\x0c\x6e\x8a\xb1\xef\xba\x16\xc0\xaf\x56\xab\x4b\xe1\xa6\xa7\x90\x10\x85\x93\x4c\xda\x32\x17\x33\x1a\x4d\xab\x94\x5f\xa6\xa7\xfe\x5b\xeb\xbd\x9b\xd1\xd0\xad\x33\x52\x4d\xd6\x0d\x85\xca\x6d\x3f\x06\x4f\x9a\x37\xb3\x72\x71\x08\x73\x2f\xb7\xed\xbf\xac\x46\xb9\xb4\x53\x34\xdb\x0f\xa2\xae\xb2\x30\x86\xcb\x25\x5f\x56\x0c\xa4\xd5\x68\xdc\x50\xc9\xc2\x66\x58\xe8\xe0\x6c\xb2\x38\xc7\x4c\xb8\xf8\xd2\x17\xba\x7d\x22\xf2\x72\x2a\x9e\x84\x97\x36\x9d\x62\x21\x1a\x7e\xd0\x25\xaa\xb3\xcb\x8b\x5f\xfe\x7c\x35\xf7\x01\xba\xd4\xe9\xf0\x39\x48\x0b\x02\x0c\x96\xda\x4a\xa7\xcd\x8c\xa8\x75\x7e\xf5\x8b\x1d\xc0\xf9\xeb\xa7\x76\x00\x42\x65\xf5\xc6\x83\x52\xa4\x37\x62\x82\x36\x59\x18\xab\x1e\xfd\x8a\xa9\x6b\xbd\x36\xf8\x5b\x25\x0d\x66\xed\x51\x10\x79\x22\x4d\xe6\x5e\x13\xfd\x5b\xaf\x4a\x43\x7d\xba\xd6\x46\xf6\x4f\x4b\xca\x75\xde\xcf\xcd\xf0\x90\xc8\xe0\xcb\x41\x46\x02\x0e\x2d\xb3\x40\xd8\x63\x98\x05\xda\x79\xd6\x90\x96\xe6\x6f\xd0\xa2\xf2\x22\x8f\x5e\x0b\x15\xe6\x94\xc0\x15\x1a\xaa\x48\xdb\xbd\xca\x33\x92\x84\xb7\x68\x1c\x18\x4c\xf5\x44\xc9\xdf\xeb\xd6\x2c\x38\xcd\xdd\xe4\xc2\xa1\x75\xc0\xbb\x56\x89\x1c\x6e\x45\x5e\xa1\x27\x65\x21\x66\x60\x90\xda\x85\x4a\xb5\x5a\xe0\x22\x36\x81\x17\xda\x20\x48\x35\xd6\xa7\x30\x75\xae\xb4\xa7\x27\x27\x13\xe9\xa2\x0c\x4f\x75\x51\x54\x4a\xba\xd9\x09\x8b\x63\x39\xaa\x48\x1c\x9e\x64\x78\x8b\xf9\x89\x95\x93\xa1\x30\xe9\x54\x3a\x4c\x5d\x65\xf0\x44\x94\x72\xc8\x83\x55\x2c\xc7\x93\x22\xfb\x5f\x26\x48\x7d\x7b\x38\x47\xbe\xa5\xcc\x0c\x51\x6c\xae\xa5\x35\x09\x4f\xcf\x45\xbe\xba\x9f\x4b\x43\x52\x7a\x45\x54\x79\xfd\xec\xea\x0d\xc4\x01\x78\xb2\x7b\x0a\x37\x45\x6d\x43\x6c\x22\x94\x54\x63\x34\xbe\xe4\xd8\xe8\x82\x5b\x41\x95\x95\x5a\x2a\xe7\xb7\x74\x2e\x51\x39\xb0\xd5\xa8\x90\xce\x32\xcf\xa1\x75\xb4\x0e\x09\x9c\xb3\x0a\x83\x11\x42\x55\xd2\x4e\xca\x12\xb8\x50\x70\x2e\x0a\xcc\xcf\x85\xc5\x8f\x4e\x6a\xa2\xa8\x1d\x12\xf9\xb6\x27\x76\x5b\x03\x2f\x56\x58\xd8\x63\x00\x51\x43\x6e\x55\x78\xd5\xa6\x04\xbf\x03\x97\x49\x60\x58\xb3\x17\xe9\x11\x59\x66\xd0\x2e\xf9\xb0\xb0\x21\x7d\x41\xcf\x27\x53\x6d\x69\xfd\x84\x83\x57\xcf\x5f\x40\x2a\x14\x54\x16\x69\xf3\xa4\x5a\x29\x62\x08\xa7\x41\x90\x2e\x1b\xe2\xbd\xb4\xcc\x40\x06\x27\xd2\x3a\x33\x4b\xe0\x07\x6d\x0a\xe1\x4e\xe1\x9b\xf8\x6a\xc8\xcd\x69\x03\xb2\xfc\xee\xf4\x9b\x52\x1b\xf7\x1d\xbc\x52\xf9\x8c\x1a\xcd\xe0\x6e\x8a\x0a\xae\xea\xb9\xc1\xb7\xad\x1f\x3f\x9a\x32\x4d\xe0\x62\xa2\xb4\x89\x25\x89\xab\x2e\x0a\x31\x41\x18\x4b\xcc\x99\xaf\x2d\xba\x64\x7e\x05\xd7\xae\x22\x78\xb8\x34\x96\x93\x17\xa2\xdc\x48\x9a\xf3\x58\x92\xfa\xa2\xee\xdb\xca\xbb\xf9\xe8\x34\xb3\x32\x4d\x89\xfe\x14\xe9\x0d\x88\xd0\x4b\x21\xca\xa1\xe5\x6d\xd3\x22\xd3\x76\x14\x38\x8f\x0d\x10\xfd\x9a\xd7\x17\x41\x72\x25\xbb\x4e\xbb\x3d\xb3\x9d\xeb\x36\x30\x64\x23\xd1\x5e\x2c\xd3\x22\x5b\xf4\x31\x31\x65\x7a\xa9\x33\x3f\xed\x8d\xbd\xfc\xd8\x2e\x0d\x78\x5f\x6a\x8b\x16\x32\x39\x1e\xa3\x21\xb9\xa3\x6f\xd1\x18\x99\xa1\x85\xb1\x36\xbc\x5e\xa5\xce\x78\x4f\xd6\xeb\xd7\x51\xb5\x97\x3a\xdb\x76\x61\xa8\x6b\x56\x18\x9e\x19\x03\x1b\xae\x9c\xee\xd2\xdd\x0e\x1b\x36\x2f\x3d\x62\xcc\xf0\x7f\xb6\xfc\xeb\x1c\x3d\xce\x42\xe1\xc8\xa9\x01\x51\x05\xd1\x71\x68\x69\xfa\x87\xb6\x6e\x73\xd9\x70\xb7\x18\xf2\x36\xc3\xa6\x47\xe9\x0c\xcf\x36\x0c\x7f\x61\x0a\x4f\xf9\xc7\x08\x2d\x57\xaf\x87\xca\x1a\x3c\xab\x72\x16\x35\x55\xde\x5d\xd1\x55\xf3\xd8\x72\x2e\xdb\xce\xc7\x97\xc3\x31\x1a\x83\xd9\xd3\x8a\xf8\xf7\xaa\x1e\x55\x10\x52\xfe\xf5\xb3\x7b\x4c\xab\x55\x7b\x6c\xe5\xd4\x09\x14\x87\x69\xa2\x81\x3b\x99\xe7\xa1\x3b\x12\x28\xf1\x03\xcd\x97\x71\x0c\x91\xc7\x7a\x21\x6d\x85\x93\x76\x3c\x63\x72\xd4\x04\xc3\x7b\xd2\xd9\x6c\xb1\x30\xc7\xcb\xb1\xc4\x0c\x46\xb3\xa0\xae\x49\x78\x0e\x60\x54\x39\x90\x8e\x75\x79\x3a\xd5\xda\x22\x08\x4f\x77\x6e\xf7\x56\x6a\x46\x4a\xa0\x15\x92\xfc\x29\x48\x21\x87\x8d\xd3\x6a\x3e\xe1\x91\x37\xd5\xa4\x85\x82\x24\x7e\x4d\xab\xc8\x8e\xd4\xcc\x9d\x74\x53\xfe\x31\x21\xc8\x4d\x28\xcc\x56\x05\x35\x7a\x87\x72\x32\x75\x76\x00\x32\xc1\x84\x57\x17\x45\x3a\x6d\x35\x5b\x20\x3a\x0b\x22\xcf\xe3\x10\xda\x2c\xe1\xf5\x66\x41\x10\x05\x8e\x6a\x0c\x13\xf0\xc6\xa0\xd6\xab\xf3\xab\xb6\x94\x5c\x03\x40\x97\x26\xc7\x03\x48\x75\x51\x56\x8e\x68\x42\x63\x1c\xcd\x40\x3a\xc2\xd9\x1e\x2f\x19\x5d\x4d\xfc\x4c\x30\x0f\x1d\x47\xb0\xea\x35\x13\x09\x07\xb2\x11\xd5\x04\x0e\xfc\xe4\x0e\x22\xfe\xa4\xe6\xa4\x9f\x04\xcf\xaf\x10\x2e\x9d\x06\x08\x9c\x6a\x63\xd0\x96\x5a\x71\x4d\xfe\xf2\xac\x19\xdb\xdf\xea\x4a\x47\xf6\xb8\x21\xe6\x54\x4e\xa6\x91\x96\xc2\x20\xbf\xeb\xae\xc1\xba\x3d\xd2\xec\x13\x61\x4c\xc7\x96\x5c\xf6\x48\x87\xc5\x86\x5d\xb2\xc0\xda\x67\x0a\xb0\x28\xdd\xac\xc5\x13\xad\xd5\x73\x68\x8a\x9a\x06\xbc\xc0\xbc\x5d\xad\x9f\x9f\x2c\xca\x5c\xa6\xd2\x05\x0e\x81\xc7\x70\xc4\x2c\x22\x1d\x89\x32\x50\x7a\xa8\xcb\xe3\x04\xce\xd8\x7d\xb1\x45\x07\x4a\xd7\xed\x87\x86\xa8\x53\xab\x9b\xb6\x36\xce\x6d\x4b\xa1\xe2\x9f\xd5\x98\x6e\xf1\x19\x86\xf1\xa3\x4a\xe7\x51\xde\xf2\xe2\x9e\x26\x1b\x8b\x6e\x2b\xde\x62\xe9\x38\x86\x6d\x4a\xcf\x2f\xb5\x67\x69\x8b\x39\xa6\x64\x92\x12\xed\x07\x20\xac\xd5\xa9\x24\x94\xdf\x30\x6d\x97\xd3\xfd\x4c\x36\xd3\x1e\x76\xa5\x3f\xec\x3c\x7f\x7a\xe6\x37\xde\xb6\xf5\x16\xa8\x91\x4b\x02\xbf\xe3\x39\xaa\x74\x04\xd6\x68\xc6\x5f\x0f\x2d\xe4\x62\x84\xb9\xdd\x8e\x08\xb0\xd3\xae\x6d\x9e\x2d\xf7\xef\xca\x09\xad\x9c\x48\xb0\x31\xeb\x85\x27\xa1\x4d\xb6\x99\x90\xca\x06\xfb\x79\x00\x02\x6e\x70\xe6\x4d\x6d\xb2\xe0\xa3\xe3\x82\x0b\x1b\xf4\xea\x86\x98\xe3\x06\x67\x5c\x28\xd8\xdd\x3b\x0c\x77\x67\xe6\xf0\xcf\x2e\xdb\xb4\x79\x86\x34\xd0\x1d\x6b\xc4\x49\xef\x50\x6d\x77\xfe\xf5\xcf\x0d\xae\x45\x5e\xcb\x9e\x05\x48\xc2\x3c\xc9\xeb\xc1\x8b\xc4\xfa\x2b\xae\xb1\x28\xcb\x5c\x22\xdb\xf3\x3b\x76\xb3\xd6\x0a\x58\xf7\x44\xea\x3d\x68\x5e\xaf\x6b\x87\x86\x67\xc8\x43\xeb\x99\x8f\x76\xfa\x54\x96\xde\xbe\xb5\xc8\x1b\x37\x7a\x7e\x7e\x11\xb9\x6c\x5c\x6d\x96\xf5\xec\x85\x1a\xc0\x4b\xed\xe8\x7f\xcf\xc8\x12\xb6\x03\x78\xaa\xd1\xbe\xd4\x8e\x7f\x26\xf0\xa3\xf3\xbc\xfe\x7c\x4b\xc9\xf6\x01\x08\xe4\xc7\xfb\x20\xf2\x9c\x29\x2f\x53\x68\xfa\x6d\x9f\x91\x4d\xe0\xc2\xc3\x96\x7a\xe3\x4a\x0b\x17\x8a\xc0\x61\x20\x03\x7b\xf1\xb8\x6c\x68\xa2\xa8\x2c\x3b\x79\x94\x56\x43\xc6\x00\x4b\xdb\xf0\xd4\xa3\x76\xda\xf4\x5b\xd3\xdc\xea\xa6\x7e\x64\x5f\xc3\xf3\x95\x95\xa7\xe2\x96\x21\x9d\x54\x93\xbc\x06\x6f\x03\xb8\x9b\xca\x74\xea\x51\xf7\x08\xbd\x6b\xb0\x34\x48\x0a\x4b\x58\x12\x55\xf4\x66\x82\x86\xc0\xae\x8c\xed\x79\xc7\x64\x2e\x52\xcc\x20\x63\x68\xe9\x9d\x6c\xc2\xe1\x44\xa6\x50\xa0\x99\x20\x94\xa4\x49\xf6\x5b\xfd\xdd\x04\xbb\x7f\x76\x16\xef\xed\x0e\x77\x62\x37\x56\x91\x3f\x10\xd6\xfd\x83\xb4\x23\xe3\xea\x5e\x3b\xf6\xda\x71\xee\xe9\xb5\x63\xfd\xf4\xda\x71\xc3\xd3\x6b\xc7\x5e\x3b\x7e\x74\xed\xe8\x6d\xd9\x3d\x8c\xe7\xff\xf4\x2e\x8e\x79\x6b\x99\x35\x6d\x0c\xd3\x75\xcd\x66\xd2\x37\x57\x41\xe0\xbc\x61\x53\x5b\xfa\x20\x89\x11\x6a\x82\xf0\x64\xf8\xe4\xf1\xe3\x5d\x8c\xea\xb0\x90\x5b\xd5\x18\x87\x48\x8f\x54\xee\xcf\x5f\xaf\xad\xb1\xca\xff\xf6\x01\xbc\xa6\x81\xc7\x6b\x47\x5e\x07\x3b\xac\x70\x7c\xb2\x74\x52\xda\x41\x81\x0e\x84\xeb\xb8\x8a\x64\x81\x83\x3a\x54\xc0\x0c\x1f\xa2\x94\xd1\x03\x9b\x81\x56\xc1\x8f\x47\xc4\x4f\xf6\x1b\x41\x8a\xc2\x87\xd4\x46\x58\x8f\x42\x17\xd4\xab\x54\x2e\x6e\x17\x1a\x02\x46\xaa\xc0\x11\x26\x93\x04\xb2\x8a\xab\x09\x15\xc2\xa6\xc7\x7e\xb4\x76\x66\x1d\x16\xec\xc9\xd5\x86\xff\x47\xc3\x76\x66\x46\x85\xf1\x16\x95\xab\x44\x9e\xcf\x00\x6f\x65\xea\xea\xf9\x71\xd4\x56\x3a\xef\x6c\xdf\xce\x45\xb8\x15\x74\xd8\x1e\x2e\x0c\x17\x38\xd8\x6e\xa8\xb3\x8b\xb6\x5f\x68\x7b\x9b\x3d\x39\xa7\x0b\xfd\x4c\x92\x95\x60\xd5\x51\xbb\xde\x07\xce\x7f\x32\x73\xbd\x7a\xbd\xd9\xe5\x0a\x3b\x4b\xb2\x1d\xa4\xd7\x3c\x2c\xad\xf2\x9c\x18\xc3\x7b\x61\x17\x27\xb0\xc4\x3b\xea\xa7\xd4\x61\x66\xef\x78\xf7\x2e\xe6\xb3\x97\x4f\x89\x2a\x54\xe6\x8d\x2e\x75\xae\x27\xb3\x36\xa5\x7d\x7a\x91\x2c\xca\xe8\x1c\x17\x60\xab\x51\x00\x0d\xc4\x7e\x2f\xe7\x96\xa6\xf7\xfc\xf5\x9e\xbf\xde\xb6\x59\x78\x7a\xdb\xa6\x7e\x7a\xdb\x66\xc3\xd3\xdb\x36\xbd\x6d\xd3\x7b\xfe\xa0\xd7\x8e\x6b\x68\xd2\x6b\x47\xe8\xb5\xe3\xca\x79\xf5\xda\x71\x2d\x79\x7a\xed\xd8\x6b\xc7\x65\x4f\xa9\xb3\x07\x24\x3a\x96\x3a\x5b\x93\xe7\xe8\xbd\x3e\xa9\x1e\xe6\x3a\x15\x2e\xe4\xe5\x53\x95\xe0\xe7\xb3\xa2\xf0\x8e\xa8\x01\xfc\xae\x15\xfa\xe4\x35\x5a\x1b\x76\x27\x69\x37\x45\x43\xc5\x8f\xec\xf1\xda\xc4\xa6\x3e\x4f\xb2\xcf\x93\xfc\xec\xf3\x24\xa7\xc2\xfa\x75\xf5\x42\x69\x75\xda\x64\x6b\x43\xbe\x41\x53\x7c\xa1\x59\x93\xc4\x2e\x61\xb9\xf9\xc4\x53\xb3\xa4\x7e\xe6\x59\x88\x17\x60\x76\xd9\x9d\x6f\xc0\xcb\x3c\x29\x91\x65\x98\x41\x89\x66\xe8\x59\x44\xc3\x58\xaa\x6c\xc9\x5c\x23\x7d\x3e\x69\xf6\x63\x77\x1e\x9f\x30\x05\xb2\x3b\x90\x3d\x7c\xae\x6d\xc7\x71\x47\xc2\x7f\x16\x09\x91\xbb\xa2\xfa\x21\xb8\xe0\xe4\xfd\x69\x4b\x5c\xbf\x3b\x34\x67\x40\x1d\x5d\xc2\xfb\xdb\x95\x0c\xcb\x7f\xab\xd0\xcc\xf8\xfc\x47\x03\x58\xeb\xb3\x75\x21\x46\x26\x2d\xa4\xc2\x7a\x4d\xb1\xab\x69\xb9\xa3\x19\xb5\x9f\x9d\xb2\xbf\x27\x1a\xe6\xe9\x32\xdf\x94\xb7\x49\xa3\x0d\xee\x69\xb6\xd4\x08\x5f\x12\x05\x68\xbc\xff\x3b\x8d\x67\x5f\xe8\xb6\x17\x70\x5b\xca\x14\x9f\xb1\x71\x0e\xfb\x1b\xe8\xb0\xb7\x91\x0e\x7b\x19\xea\xb0\xaf\xb1\x0e\x0f\x30\xd8\x61\x3f\xa3\x1d\xe6\x59\x81\x56\x28\xa0\xac\x8f\x63\xbf\xc3\x43\x4c\x54\x78\x80\x1d\x0f\xf3\x53\xad\xd9\xd4\x7c\x2c\xa3\x9e\x79\xbd\x63\xd7\xff\xd1\xc4\xda\xcf\xa6\x87\x79\x52\x05\x63\x58\xb2\x41\xfb\x85\x58\xf8\x7f\x88\xb9\x0d\x0f\x32\xb9\x61\x7f\xb3\x1b\xf6\xe7\x0c\x56\x75\xcf\x39\x9c\xfa\x50\x85\xe9\x5b\xf1\x2a\x82\xcf\xe0\x8e\xe1\x1f\xa4\x09\x78\x5d\xfe\x05\xa5\x90\xc6\x12\xbe\x0b\x3e\x93\xf6\xb7\x60\x9d\xb7\x9b\x29\xfc\x11\x62\x12\xd5\xb7\x22\x27\xdd\xe3\xf3\x38\x82\x5d\x44\xad\xcf\xab\xe9\x01\xdc\x4d\xc9\xda\x24\x29\x55\x9f\x77\x3e\xb8\xc1\xd9\xc1\x60\x81\x91\x0e\x2e\xd4\x81\xd7\x51\x0b\xac\x53\x2b\x34\xad\xf2\x19\x1c\xf0\xb7\x83\x0f\xad\xd9\xf7\x50\x5c\xed\x2b\x54\xf6\xd5\x0b\x7b\x70\x89\x8a\xd7\xba\x7c\x78\xb0\xe9\xb5\x88\x0f\x6c\xc4\x5e\x6c\xa3\x60\x38\xd5\xa2\xa5\x5c\xea\xac\x11\xe6\x31\x7e\x9f\x45\xe3\xb7\x52\xe1\xa6\x8b\x78\xe6\x3c\x34\xe6\x95\xd4\x62\x4a\x53\x58\x78\xad\xd0\x32\xb0\xc3\xda\x45\xd4\xaa\xcc\x65\x13\x9f\x0e\xd2\x68\x3b\x95\xcd\x27\x88\x34\x35\x18\x23\x16\x28\x94\x85\x83\xe8\x7b\x3a\xb4\x4d\x89\x83\xa4\x39\xdd\x57\xb7\x78\xf4\x8f\x7f\x1d\x77\x4e\xf4\x35\x0d\xf6\x48\xbb\x47\xda\x3d\xd2\xde\xa1\x56\x8f\xb4\x57\x3f\x3d\xd2\xde\xe1\xe9\x91\x76\x8f\xb4\xd7\x75\xdc\x23\xed\x1e\x69\x6f\xee\x7c\x3f\xa4\xbd\x6f\x9e\x50\x1b\xf7\x86\xe0\x9c\xbf\xc8\x4c\x38\x99\x36\x39\x44\xb1\x94\xff\xeb\xc3\xe2\xed\x36\x96\x5e\x8e\xb6\xdb\x88\x7c\xc1\xb6\x48\x36\x40\xeb\x1a\x7c\x2f\xd4\x5c\x8f\xba\x3f\xaf\x5c\xa8\x3d\x78\xa3\x15\x50\xd8\x93\x39\xde\xc4\x50\x78\xb8\xf8\x6f\x84\x4d\x9c\x3c\x83\xa3\x18\x71\x39\x26\xe2\x2b\xed\xba\x1f\x95\x93\xc3\xa6\x44\x1d\x83\xe1\xf0\x62\xe7\xbc\x4d\x27\x2c\x51\x47\xdd\xeb\x48\x71\xb3\x9e\x24\x42\xd0\x74\xc6\x20\x6d\xb8\xde\x90\xb3\x25\x4c\xa5\x14\xb5\xaa\x55\x0c\x1f\x7b\x99\xe3\xef\xe3\x0b\x9c\xe7\xc1\x12\x8f\x87\x11\x53\x43\xa5\x56\xbc\x53\x38\x7f\x05\x62\x48\xe5\xd7\x2a\x44\x44\xe9\x4d\x8c\xfa\x46\xa6\xe4\x19\xc9\xba\xf7\x04\x9e\x31\x1f\xb6\x1b\x96\x96\xe9\x23\xf2\x5c\xdf\xed\x22\x92\xfe\xa8\x63\x51\x77\x3b\x1f\x8b\x9a\x8b\xdf\xf5\xa7\xa2\xfe\x87\x9c\x8a\xe2\x8f\x7e\x0b\x7d\xf0\xe3\x51\xf0\x9f\xe1\x02\x42\x83\x4c\xaa\xa2\xca\x9d\x2c\x9b\x5c\x29\xeb\xbb\xca\x3d\xca\x1c\x87\xcc\x93\x2e\x5f\x52\x6f\x22\x9d\xce\xf3\x27\xb7\xc7\xb9\x55\x96\x37\x6d\xc8\xee\x10\x79\x1e\xce\x14\x45\x48\xea\x53\x58\xe4\xa7\xce\x4c\x78\x1a\xee\x6c\xad\xad\x19\x16\x32\x47\x24\x0b\x73\x5a\x50\x92\x6a\x6b\x84\xa8\x37\x8a\x6e\x31\xaa\xde\x89\xbc\x45\xd5\x48\xd2\x23\x7b\x7c\x1c\x75\xf8\x07\x95\xf0\x1f\x45\x42\x7f\xd3\x92\xa4\xdf\x6d\x23\xa3\x79\x42\xb5\x94\x6e\xc8\xd7\xc8\xe8\x4f\x99\x82\xb1\x4b\x9c\x7f\x37\x1f\xc3\x1e\xf1\xfd\x3f\x30\xb6\xff\xe5\x9c\x2c\xfb\xc4\x1e\xc6\x4f\x91\x5b\xff\xd9\x7b\x15\xfb\xe4\xfa\xe6\x79\x68\x72\xfd\x47\xf7\x1c\x7e\xda\x1c\xfb\x2f\xc0\x5b\xf8\x29\x73\xec\x7b\x0f\xe1\xda\x45\xf9\xdc\x52\xdf\xbb\xcf\x5e\x1e\xc1\xde\x1b\xb8\xb7\x16\xde\x51\xe1\x3c\xd4\x0b\xb8\x23\x47\xec\x19\x67\xef\x63\xec\x7f\x4c\x8c\xbd\x47\xbc\x5b\x3e\x3d\xe2\x5d\x49\x94\x1e\xf1\x42\x8f\x78\x37\x4d\xaf\x47\xbc\x6b\xc9\xd3\x23\xde\xb5\x8b\xd2\x23\xde\x1e\xf1\xc2\x97\x86\x78\xf7\xb9\xa5\xab\x8f\x75\x3f\x28\xd6\xbd\xab\xb4\xd8\x49\x46\xec\xc8\x07\x3b\xc7\xb6\xfb\xb8\xf6\xe7\x12\xd7\xde\xfa\xc0\xbf\x72\xf2\xa1\x87\xfe\xdb\x6b\xb5\xea\xe4\xbf\xb8\xd5\x32\x83\xb2\x72\xe1\x3c\x75\x7f\xfa\xff\x43\x9c\xfe\xef\x50\xbe\xbf\x02\x60\xab\x2b\x00\x56\xd1\xac\xbf\x07\xa0\xbf\x07\xe0\x03\x07\xa1\xfb\x7b\x00\xfa\x7b\x00\xfa\x7b\x00\xe2\xd3\x9f\x4e\x82\xfe\x74\xd2\x56\x4f\x7f\x3a\x69\xf5\xd3\x9f\x4e\xfa\x6c\xbd\xaf\xd0\x9f\x4e\xfa\xbc\x3d\xb1\xd0\x9f\x4e\xea\xbd\xb3\x5b\x2e\xd4\x17\x78\x3a\xa9\xbf\x07\xe0\x73\xcd\x51\x80\x1e\x69\xf7\x48\xbb\x47\xda\x3d\xd2\x5e\xff\xf4\x48\x7b\x87\xa7\x47\xda\x3d\xd2\x5e\xd7\x71\x8f\xb4\x7b\xa4\xbd\xb9\xf3\xfe\x1e\x80\x2f\x28\x37\x02\xfa\x7b\x00\xfa\x7c\x89\xfe\x1e\x80\xff\xb9\xf7\x00\x74\x62\xf7\x9f\xee\x32\x80\xdd\x87\xd1\xdf\x08\xd0\xdf\x08\xd0\xdf\x08\xd0\xdf\x08\x10\x9f\xfe\x46\x00\xff\x7c\x4e\xbe\xc6\xfe\x7c\xd4\x4a\xa2\xf4\xe7\xa3\xa0\x3f\x1f\xb5\x69\x7a\x5f\x80\xdf\xb0\x3f\x1f\xf5\x19\xfa\x0a\xfb\xf3\x51\xbd\x5f\x70\x7e\x71\xbe\x90\xf3\x51\xfd\x8d\x00\x9f\x63\xb4\xbd\x47\xbc\x5b\x3e\x3d\xe2\x5d\x49\x94\x1e\xf1\x42\x8f\x78\x37\x4d\xaf\x47\xbc\x6b\xc9\xd3\x23\xde\xb5\x8b\xd2\x23\xde\x1e\xf1\xc2\x97\x86\x78\xfb\x1b\x01\xfa\x1b\x01\xfa\x1b\x01\xbe\xc4\x08\xf7\xc6\x95\xc6\x7b\x67\x44\xea\xce\xb5\x72\xa8\x56\xc6\xb5\x3b\x0b\xfa\xac\x53\x85\x84\xe4\x58\x4e\x2a\x13\x30\xf8\xe4\xf5\xe5\x39\xa4\xc2\x89\x5c\x4f\xe0\x52\xf3\x26\x0d\x9d\xd4\xaf\x0b\x74\x22\x13\x4e\xf8\x90\x24\x2f\xa8\xd1\xb7\x32\xe3\xcd\x9a\xe1\x3d\xc8\x42\x4c\x90\x37\x58\xc5\x87\xd5\xef\x30\xcf\x87\x37\x4a\xdf\x29\xb8\x45\x63\x5b\xdb\xfd\xbd\x2e\x8b\xf7\x60\xd1\xdc\xfa\x53\xf4\x78\x5f\xd2\x62\x49\xe7\x25\x46\xec\xb1\xdd\x6c\x13\x8b\x3b\xf7\x5f\xaf\xfc\x31\x72\x69\x9b\xb9\xf0\xb0\xa9\xef\xaf\x08\x2a\x7c\x45\x4c\x5b\xd9\xc8\x6b\x63\x99\xe3\x70\x24\x2c\x66\xb1\x7d\x4b\x1c\xa7\x4d\xe6\xc7\x50\x39\x99\xcb\xdf\x31\x48\x1d\x14\xae\x32\xb8\x6a\xb9\xb6\xd0\x03\x9b\x8d\x8c\x21\xa4\x22\x9d\xe2\x53\xb9\xda\x3c\x18\xc6\xa1\xae\x2e\xb4\x8d\xbd\x10\xfb\xd9\xfa\xd6\x88\xf3\x50\x21\x5a\x04\x99\x34\xbc\x45\x67\x60\x9d\x36\x91\xa2\xa5\xc1\x61\x2a\xf2\xb4\xca\x79\x43\x9e\x5d\x5e\xf8\x9e\x36\xdf\xfb\xb0\x41\x88\x35\x93\xde\x61\xc4\xb1\xca\xfa\x31\x2f\x72\x01\xe3\x05\x36\xd4\x1f\x32\xec\x02\x0b\x6d\x66\x6f\x84\x99\xe0\x76\xfb\xf1\xe0\x45\xab\xc6\xfc\x76\xfc\xb7\x1f\x5f\xbd\x78\xf6\xe2\xf9\xc5\x8b\x8b\x37\x41\x82\x8d\xb5\x59\xba\x51\x03\x0c\xf6\xf6\xb8\x1e\xbb\x30\x10\xc8\x65\x21\x5d\x5d\xcb\xef\xb4\x41\x90\x64\x9c\x8e\x52\x29\x27\x0b\xf4\xc9\x14\xc2\x39\x52\x96\xb4\x0b\x0a\x44\xc7\x37\x4f\x14\xe2\x06\x49\x74\xc1\xa4\x12\x46\x28\x87\x51\x38\x4a\xe7\x2b\x65\x1a\xac\x0e\x80\x5e\x06\xab\x9f\xc6\x61\x31\x60\xf7\xcb\x98\xab\x31\x15\xb7\xfe\x8a\x83\xb1\x26\x29\x48\x4b\x51\xe8\x4c\x8e\x65\xea\xcd\x2e\x28\x44\x56\xc7\xe1\x03\x7a\x43\x53\x8b\xf4\x66\x02\xa7\x30\x5c\x20\x0f\xaa\x5b\x69\xb4\x62\x4c\x79\x2b\x8c\x14\xa3\x3c\xcc\x6a\xe4\x5d\x74\xdc\x6e\x33\x40\x05\xa3\x99\x43\x1b\x5a\x0a\xd4\x0a\x77\x51\xac\xa9\x77\xad\x3c\xa1\x3d\x1c\x69\x94\x22\x95\x94\x63\x90\xee\x90\xd4\x91\x95\x41\x08\x19\xcc\xaa\x34\x4e\x5a\xbb\xd2\x48\x0f\x79\x45\xbd\x76\x41\xf8\x09\x0b\x45\x45\xda\x85\xb4\xad\xb5\x72\x94\xe3\x80\x74\xaa\x6c\x97\x1d\x21\xd1\x81\x6b\xb0\xde\xbb\x45\x5a\x61\xe2\x1c\x0f\x67\x10\x49\xb1\x6a\xbe\x48\x42\x78\x25\x9a\xe1\x58\x54\xb9\xd7\x3b\x9e\xcc\xbc\x54\x33\x5d\x99\x8e\x58\x9d\x0a\xe2\x1c\xde\x15\x31\x41\x85\xf7\xf0\x00\x32\x24\xe0\x26\x15\x49\xf2\x89\xd6\x19\xe1\x37\xa3\xef\x65\xc1\xad\x05\xd6\xaa\xe9\x33\x9a\x41\xa6\xab\x51\x5e\x2f\x18\x89\xd2\x20\xed\x4b\x91\xde\x50\x5f\xdc\x30\x08\x07\x27\xae\x28\x4f\xf8\x57\xf8\x6f\x28\x61\x93\x5f\xad\x56\x11\x07\xb4\x86\x99\xcc\xd1\x5f\x5a\x18\xa1\x75\x43\x1c\x8f\xb5\x71\x7f\x23\x6a\x55\x8a\x19\x4f\xe9\x7a\xea\x71\x31\x2b\xda\xec\x4c\x27\xcd\x3c\xd9\xd9\x21\xda\x2c\xd9\x6c\x2d\x36\x48\x0e\x56\xc9\x5d\xda\x34\x46\x9d\xc2\xff\x3b\xba\xfe\xd3\x3f\x87\xc7\xdf\x1f\x1d\xbd\x7d\x3c\xfc\xeb\xbb\x3f\x1d\x5d\x27\xfc\xc7\x57\xc7\xdf\x1f\xff\x33\xfe\xf8\xd3\xf1\xf1\xd1\xd1\xdb\x9f\x5e\xfc\xf8\xe6\xf2\xd9\x3b\x79\xfc\xcf\xb7\xaa\x2a\x6e\xfc\xaf\x7f\x1e\xbd\xc5\x67\xef\xb6\x6c\xe4\xf8\xf8\xfb\x7f\x5b\x31\x20\xa1\x66\xaf\xc6\xeb\xb4\xcd\x76\x09\x65\xc3\x6d\x44\xf4\xfd\xf0\xa6\x1a\xa1\x51\xe8\xd0\x0e\xa5\x72\x43\x6d\x86\xbe\xc2\x29\x38\x53\xe1\xd2\x6a\x04\xa7\x36\x79\xe1\x3b\x22\xf2\x65\xab\xc2\x9c\xc7\x31\x5c\xc3\x12\x1c\x02\xd4\x65\x2d\xeb\x4a\x8f\x5e\xc6\xb4\xb8\x11\x0c\x26\x70\xb5\xa4\x26\x63\xbe\x50\xe2\xd0\x7a\x74\x68\xe7\xdb\x99\x4b\x32\xf3\x32\x90\xdb\xdc\x1f\x1b\xec\x66\x11\x6e\x5c\x8f\xd2\x48\x6d\xa4\x9b\x9d\xe7\xc2\xda\x97\xa2\xc0\xad\xa8\x7b\x31\x6e\x90\xf6\x80\x36\x1b\x89\xe3\xa0\x7f\xbc\xf5\x13\xdb\x65\xc9\x41\x20\xb6\x55\x3e\x52\x28\x96\xa9\xf7\x4c\xdc\x7d\xda\xc0\xef\x68\x74\xb8\x45\xc7\xa0\x07\xc2\xf1\xf3\x7a\xe2\xad\x99\xab\xc5\xb4\xe2\xb9\x92\xd2\xbe\x27\x38\x3b\x96\x93\xed\x14\xee\xd5\xb2\xaa\x90\x0a\x45\xc3\xe6\x5b\x94\xc6\xf0\x3e\xc7\x89\x48\x67\xef\x69\xf8\xef\x0d\xd2\x40\x08\xe8\xbf\xf7\xb8\xb4\x83\x3c\x0f\xc3\xb5\x58\x16\x50\xf2\xad\x57\x52\xfd\xea\xad\x82\xda\xe0\x31\x9c\x3c\x5a\xea\x2c\x21\xca\x25\x73\x63\x67\x99\x54\x7f\xac\xf5\xde\xdb\xaf\xde\x2d\x94\x0c\xfe\x0d\xa7\xbd\x1d\xd1\xe6\x4f\x53\xb1\xc0\x24\xc1\x16\x27\x08\x67\x59\x21\xd9\xa5\x02\x47\x97\x57\x67\xc7\x9d\x99\x90\xea\xf5\x2a\x26\xd3\x68\xd5\xa1\xf3\xca\x6e\x8a\xb6\x71\xa3\xb0\xda\xe0\x2c\x26\xbf\x5b\x38\x8d\x29\xf6\x49\x04\x63\xcf\xca\x08\xeb\xce\xaf\xce\xe0\x3d\x81\xaa\x5c\x2a\xf4\xb4\x2b\x8d\xbc\x95\x39\x4e\xa8\xc7\x56\x50\x08\xce\x2b\x63\x50\xb9\x7c\x16\xaf\x57\x5a\xbe\x2a\xd2\x92\x40\xef\xb2\x5b\xe4\xac\xda\xa4\xab\x17\x8b\x4a\x5b\xcc\x12\xb8\xe2\x1a\x33\xef\xff\x0b\xe5\x78\x6d\x58\x2f\xae\x5a\x5c\x30\x68\xa9\x61\xa9\x7c\x2d\x99\x79\x15\x87\xc6\x68\x13\x52\x2e\xbd\x1d\xa1\x73\x32\x16\x6a\xf3\x84\x54\x93\x8d\xa8\x2a\x65\x48\x10\xf2\x52\x03\x61\x96\x10\x7e\xf5\x9c\xbb\xa0\xc2\xe9\x7a\xbc\xac\xfd\x2e\x68\x70\xe3\x8a\xac\x92\xda\x9a\xe2\x3d\xd7\x26\xcd\x1c\x7e\x69\x77\x3f\x68\xec\x38\x21\x03\xab\xd9\xd8\xa7\xc1\x51\x25\x73\x76\xb1\x48\xd3\x98\x47\xcc\xc8\xa2\x6d\xbc\xe9\xb2\x08\x77\x9b\x55\x65\xa9\x8d\x6b\x0c\xef\xb4\x63\x95\x79\xc3\x78\x09\x01\x68\x58\xa5\xc1\x52\x98\x5a\x62\x5b\x84\x74\x2a\x14\xa9\x7f\x9a\xe8\x0b\xcd\x79\xa8\x3e\x99\x99\xba\x15\x23\x5d\x39\xe6\xb1\xb0\x57\xc7\xba\x52\x19\x90\x50\x39\x85\xa9\x73\xa5\x3d\x3d\x39\x69\xf4\x51\x22\xf5\x49\xa6\x53\x7b\x92\x6a\x95\x62\xe9\xec\x49\xdc\x4d\x27\xa5\xce\x86\xf1\xc7\x50\xc4\x4d\x72\x72\xb8\x4a\xc7\x6f\xa1\x09\x03\xe5\x4f\xc1\xaf\xd5\x8a\x52\xa8\xaa\x35\x37\x39\x0d\xd7\x57\xa6\x02\x0d\x19\x97\x16\x72\x3a\xe7\x7b\xcf\xd6\x84\x37\xbb\xde\x9d\xa6\x7c\x7d\xff\x58\x0d\x4c\x5b\xd2\xed\xd0\xb6\x9b\x5e\x2f\xb4\xd7\x79\xbd\x36\xf8\xb9\x16\xee\x1e\x63\xd9\x46\x70\xaf\x19\x28\x03\x00\xe7\x04\xdf\x3e\x46\xd8\xdc\x7f\x21\x71\xa5\x66\x40\xfc\xec\xc2\x55\x74\xad\xbb\xd9\x9c\xe1\xe4\xe8\x6f\x6a\x57\xf5\x00\xc7\x63\x4c\xdd\x77\x2d\xbf\x40\xed\x90\xaa\xdd\xcb\xdf\xc4\xbf\xbe\x5b\x6d\x12\x6e\xe5\x09\xde\x2e\x96\xe7\x87\xb4\xde\x47\xd7\x75\xe5\x70\x85\x39\x95\xed\x29\xe0\xdb\x62\x43\x8e\xa3\x1d\xc1\x21\xe5\x3d\x9b\x01\xef\x90\xcc\x68\x15\xb6\x41\xc2\xb5\xa4\x6d\x70\x56\x35\x6e\x75\x84\x97\x3a\x9c\x12\xc0\x01\x5c\xf2\xc5\x6d\xcd\x1b\x56\x64\x2f\xb5\x3f\x2f\xb0\xd6\xfa\xdf\xda\x89\xb9\x31\x9a\xd9\x21\xc8\x4f\x4d\xec\xd2\xcf\xac\x13\xbb\x6c\x38\xb8\xe3\x9a\x5e\x47\x99\x1b\x9c\x35\xf1\xae\x10\x19\x65\x77\xf2\xa0\xe1\x92\x08\x3e\x7d\xf8\xea\x6f\x21\xe1\x57\x17\x23\xa9\x7c\x67\xbe\xe9\xb8\x14\xdc\x7a\x24\xa8\xca\xf8\x27\x77\xf3\x21\xc8\xb5\x5d\x88\xb4\x43\xb3\x57\x3b\x04\x44\xeb\x10\xcb\xf2\x50\x68\x2b\xfe\xf9\xec\xb7\x4a\xe4\x09\x3c\xf5\x52\x91\x67\x1f\x5e\x85\x42\x0b\x21\xa1\x3b\x99\x67\xa9\x30\x19\x6b\x03\xbf\x47\xc1\x6a\xbf\x7a\xa2\x06\x1c\x71\xb7\x37\x6b\xe4\x2f\x26\x84\x52\x18\x27\xd3\x2a\x17\xac\xb6\x70\xa2\xcd\xec\x83\x50\xb4\x61\x9a\x2b\x4c\xb5\xca\x36\x78\xe9\x57\x48\xd7\x50\xb7\x4d\x63\x86\x51\x68\x64\xc8\xbf\x97\x05\xce\x33\xe9\x51\xd7\xb8\xd1\xe3\xb8\xab\xeb\x2d\x36\xf0\xa8\xe6\x4e\x5a\x6c\x07\x49\xa4\x05\xe9\x0f\xf0\x1c\xb7\xc4\x63\xbd\x2b\x12\xf8\xfb\x2c\xea\xab\x01\x48\x17\x5d\xd3\x6c\x37\x87\x3e\x03\xcb\x06\x62\x37\x1b\x6a\xac\x0d\xde\xa2\x81\xa3\x4c\x73\x1d\x3e\xa3\x72\x9c\xc0\x7f\x11\xc4\xf7\x3e\x88\x89\x3f\x4e\x11\x58\x3c\x22\x11\xc7\x37\x89\xb2\x8b\xfe\x31\x1c\xf9\xa3\x2d\xb2\x28\x30\x93\xc2\x61\x3e\x3b\xf6\xd9\x4d\xf1\x70\xcc\x36\x4b\xb7\xcd\x89\xa8\xd6\x49\xa8\xbf\xfc\xfb\x9a\x92\x3c\xd8\x1d\x56\xf6\x97\xe8\xe4\x6a\x28\xe3\x51\xe6\xdc\x12\xd6\x3a\x48\xaf\x89\x78\xb7\x22\xdc\x2d\xec\x17\xc5\x4c\xbd\xc0\xbf\x12\x1f\x08\x30\x38\x61\x2e\xf7\x9c\xfb\x00\x1e\x97\xe9\xf2\x13\x5d\x1b\x34\xda\x7a\x7f\xf6\x10\x08\xfe\xff\xe5\xdf\x33\xe1\xc4\x8a\x02\x7e\xcd\x67\xe5\x32\xe7\xc0\x26\x45\xd9\x34\xbe\x6a\xb1\xb6\x70\xd0\x86\xee\xf7\x6a\x81\xa1\xfe\xb2\x9a\x5d\x93\x9a\x5d\x6a\x3e\x89\x22\xae\xf7\xd0\xe0\x44\x5a\x67\x66\x2d\xcf\x66\x88\x68\x68\x90\xca\x3a\xa1\x9c\x64\xc9\x06\xb1\xe4\x30\xf8\x06\x09\x7e\x27\xf0\x8a\x6c\x2d\xf6\x61\xdd\x91\x9a\xf6\x00\xfb\xcd\xac\x44\xf8\xb6\xf5\xe3\x47\x53\xa6\xcc\x6b\x41\xd0\x78\xe6\x12\x59\x66\xd0\x2e\xca\x87\x65\xec\xb3\x76\xfe\xd1\xcc\xdf\x48\x82\xc3\xcb\xe8\x10\x08\x81\x5b\x6b\xe5\x84\x50\x66\x3c\x4a\x19\xdd\xbc\x1d\xb4\xe9\xad\x02\xae\xe8\x43\x30\x58\xd4\x4a\x40\xba\x88\xfb\x53\xad\x6c\x55\xc4\x8c\x48\xb2\x7a\x4a\x54\x19\xaa\x74\xc6\x67\x6f\xf2\x5b\x34\x09\xfc\x6c\x69\xa5\xe0\xff\xc8\x09\xd9\x7d\xa1\xd3\x36\x54\x8a\x61\xa4\xb9\x11\x48\xdb\xba\x90\x96\x73\x3c\x09\x03\xc5\x16\x5a\xe1\x82\x70\xc8\x27\xe6\x99\xcc\x0f\xa2\xf2\xbe\xd6\x37\xf5\x91\xcf\xe8\x04\x8d\x74\xf1\x1b\x9e\xa6\x34\xd1\x3e\x94\x56\x6a\x2b\xe3\x51\xb4\x5a\x8e\x76\x8e\x8d\xea\xb1\x3f\xd4\xe9\xdb\xed\x1a\xc2\x9c\xb0\x34\x37\x19\x36\xdc\x2a\xe5\x89\x8f\x6d\x2f\x4d\x14\x33\x8f\xbb\x91\xb6\x76\x3d\x17\x6f\xf9\xee\x0e\xb9\x91\xe9\x46\xa8\x1b\xcc\x20\xc7\x7b\x99\xea\x89\x11\xe5\x54\xa6\x7c\x72\xd1\xc7\x55\x08\xab\x3b\x1f\x3b\x4f\x0e\x57\x32\xda\x2a\x31\x5e\x56\xa3\x5c\xda\x29\x2e\xc5\x32\x6b\x79\xd4\x62\x6a\xd0\x2d\x95\x20\x1d\x16\xbd\xf2\xe5\x1a\xa5\x1c\xd3\xbd\x42\x03\x21\x9d\xd1\xf3\x1c\x6f\x3c\x22\x71\x9a\xd2\x46\x8a\x11\x8a\xe6\x36\xe9\x9a\x86\x09\x5c\xb8\xe8\x98\xa6\x1a\x37\x88\xa5\xe7\x34\xce\x3b\xb0\x05\xfb\x54\xac\x54\x29\xfa\xf3\x97\xfe\x1c\x2b\x62\x74\x33\x3a\x23\xd1\xc3\x20\x64\x07\x7f\x5c\x1b\x54\x6e\x39\xa8\x59\x6f\x77\xad\xb1\xb9\xd6\x93\xb1\x96\x29\x9b\x29\xd9\xc8\xa2\xa8\x13\xe9\x6f\x22\x25\x7f\xd9\x75\x05\xfd\x71\xd9\x2b\x9f\xb7\xb5\x59\xd6\xfc\xdc\x29\x1e\xb2\x01\x2c\x4c\xf5\x5d\x68\x69\x7e\xd3\x06\x8f\x4d\x5c\xdb\x4c\xda\x94\x76\x3a\x66\x70\xae\x95\x8d\x67\x66\x85\xf2\xc7\x60\x6f\x45\xee\x59\x21\x36\x5c\xea\x9c\xe3\x1b\x59\x15\xcd\x09\x9f\xda\x8a\xc5\x08\xf9\xae\x6b\x1b\x87\xb2\x42\xcd\x6d\x50\xb1\x9b\xb4\x60\xd4\x0f\x97\x3a\xcf\xd7\x6b\xb1\xb5\x76\xe9\x36\x56\x69\x24\xc0\xd6\xf1\xd7\x8b\x48\xb1\xe0\x8b\x23\x9e\x6e\x22\x48\xcc\x1a\x04\x75\x6b\xc2\x8e\xd0\xdd\x21\x2a\x48\xa7\x98\xde\xd8\x26\x41\x83\x6f\x9d\x9f\x5b\xb5\xe0\x7f\xea\x4a\xac\x1a\x4f\xd1\xaa\xb0\xa1\x61\x11\x7d\xd8\x4c\xe1\xdd\x7c\xc2\xc1\xa2\xb0\x17\xb7\x42\xe6\x62\x94\xfb\xb3\xe2\xf5\xaf\x41\x7b\x1c\x32\xea\xf3\xb2\xca\xf3\x10\x44\xe2\x00\xac\x33\x62\x3c\x96\x29\xe7\xa0\x70\x98\xb9\x49\x6b\x5a\x3a\x85\xbd\x42\xcb\xd6\x09\x57\x2d\xac\xd1\x9a\x05\x5e\xb7\xb0\x64\x87\xc8\x95\x0e\xa2\xb9\xfb\xc3\x3b\xc6\x0a\x0d\x03\xbd\xb1\xd5\xf1\x7f\x27\xf0\x52\xbb\x90\x97\xf1\x02\xad\x8d\xb9\x1f\xaf\x51\x58\xad\x5a\xd2\x95\xd1\xaf\x91\x13\xa9\x44\x1e\x26\xd5\xf6\xef\xd5\xb6\x87\x60\x97\x72\x21\x27\x46\xb8\x5a\x28\x36\xe3\x0e\xda\x25\xe8\x45\xef\x09\x4d\xe0\x4c\xcd\x78\xbd\x43\xc2\x06\xb5\xec\x8c\xce\xaa\x14\x43\xf0\xb9\xb2\xed\x46\x3e\xa8\x18\xed\x86\x17\xce\x63\x27\x4d\x02\x62\x86\x4e\xc8\x10\x52\xd2\x0a\x41\xd8\x92\xec\xb8\xc8\x93\xde\x15\xde\x10\x98\x95\xc5\xd9\xe5\x05\xbc\x0e\x27\x89\x13\x18\x0e\x87\x3e\xee\x69\x9d\xa9\x52\xd6\x2f\xb4\x85\x54\x16\x34\x85\xe7\x3e\x9f\x6f\xd3\xca\xdd\x0d\x9e\x0f\x0f\xc1\x4a\xe1\xa6\x90\x78\xc2\x27\x2d\x52\x00\xfc\x40\xba\xe6\x5e\x14\x25\xf1\xfd\xb5\xf2\xd2\xfb\x07\xad\xaf\xfc\x22\xf9\x3e\xff\x01\x27\x27\xf3\x3c\xa1\x47\x04\x51\x83\x03\x91\x59\x63\xac\xf5\xa1\xed\x4e\x29\xa1\x8a\x3f\x71\xfa\xcf\x92\xde\xb9\x2f\x61\xf0\x14\xae\x0f\xce\xe2\xee\xbb\x3e\x18\xc0\xf5\xc1\xa5\xd1\x13\xce\x09\x55\x93\xeb\x90\xe4\x79\x7d\xf0\x14\x27\x46\x64\x98\x5d\x1f\x50\xb3\x7f\xe2\x64\xde\x17\x68\x26\xf8\x13\xce\xbe\xe5\xc6\xea\xd7\x51\x23\x7c\xeb\xf3\x7e\xe9\x3d\xa9\x60\xd2\x53\xdf\x16\xa2\xac\x5f\xbc\x10\x65\x5d\xf9\xbc\xe1\xb3\xb7\xef\x0a\x74\xe2\xf6\x49\xd2\xac\xe8\xfb\x5f\xad\x56\xa7\xd7\x07\xcd\xf8\x07\xba\x90\x9c\x34\x31\xbb\x3e\x80\x4e\xaf\xa7\xd7\x07\xdc\x6f\x7c\x1f\x07\x79\x7a\x7d\x40\x3d\xd1\x6b\xa3\x9d\x1e\x55\xe3\xd3\xeb\x03\xce\x45\x18\x3c\x19\x18\x2c\x07\x04\x98\xbe\x6d\x7a\xb8\x3e\x78\x4f\x6b\x72\x72\x12\x42\x18\xe1\x5f\x56\xf8\xd7\x72\x67\xf5\x46\xb9\xbf\x29\x1f\x69\x08\xb9\xb0\xee\x8d\x11\xca\x72\xff\x6f\x64\xb1\x3c\x8c\xeb\x6d\x39\xde\xef\x2b\xbf\x1b\x96\x01\x2b\x3f\x7b\x6e\x58\xf9\x79\x85\xf6\xdc\x46\x73\x2d\xce\x61\x4b\xaf\xf3\x62\xc5\xe6\x34\x04\xe1\xb9\xe8\xa7\xa9\xd7\x87\x74\x40\x28\x8d\xe1\x96\x0e\xda\xe2\x41\xbe\x71\xae\x33\xaf\x5b\x48\xd0\x69\x0c\xfc\xbb\x70\x83\x07\x54\x2a\x43\x93\x73\xb0\xaa\x69\xd5\x47\x42\xb2\x04\xbc\xdf\x40\xd4\x5e\x1a\xce\xa3\x63\xed\xa4\x5a\xce\x6b\x9f\xc3\x13\x5b\x24\xd9\x11\x2e\x31\xf1\xcd\xb0\xa2\x4b\x53\x2c\x1d\x6b\xba\xfd\x43\xcc\xd0\x72\xaa\x10\xb2\x1a\xba\xd5\xec\x11\x98\x63\x4b\xc2\x87\xd2\x3e\xbe\x3f\xad\x0a\x41\xaa\x43\x64\x9c\xc6\x53\x7f\xf3\xe6\x9b\x37\xb7\xbc\x48\xf5\x41\x21\xef\xe3\x8f\xeb\x10\x48\x1d\x14\x89\xa8\x4f\xab\x6d\xf0\x98\x6c\x35\xf9\x42\xdc\x3f\x47\x35\x71\xd3\x53\xf8\xf3\xd7\xff\xfb\x2f\xff\xb1\xa2\xa0\x17\x8c\x98\xfd\x88\x2a\xf8\x82\xb6\x24\xc3\x62\xc5\x79\xa7\x61\x12\xf3\x2f\x93\x49\x53\xa6\x76\x72\x37\x1c\x74\x27\x38\x07\x2b\xa8\xcb\xaa\x24\xba\xfc\xc0\xd9\xb5\xd6\x09\x95\xe2\x80\x40\xd2\xd2\xc6\x64\x2d\xc0\xf3\x19\x3c\xf9\xda\xff\x0b\x44\xdc\xf5\x82\xf8\x7e\x7b\xff\x2e\x59\x32\x64\x69\xe1\xaf\x83\xb9\xf1\x48\x0b\xb4\x54\x7a\xcc\x8c\xe3\x4d\x4c\x83\x5e\x13\x46\x67\xc0\xa2\x26\xc4\x7a\xbc\x9b\x16\x6e\x93\x3f\x70\x3b\x5f\x60\x21\x95\x2c\xaa\xe2\x14\x1e\xaf\xcc\xe7\x24\x91\xb6\xe5\x6a\xfa\xc2\x0d\x10\x10\x24\xba\x26\x46\x14\x05\xe7\xd1\xcb\x0c\x95\x93\x63\xc9\x49\x03\x35\x6b\xb3\xb9\xef\x2b\xc6\x1c\x94\x9a\x8a\x9c\x9e\x42\x72\xa8\xc5\xec\x97\x1e\xe7\x18\xd6\xc0\x21\x7a\x93\xb6\x05\xd4\xac\x44\xbf\x1b\xbc\x01\x03\x78\x5f\x7a\xa8\xda\x0a\x43\x14\x28\x94\x54\x13\xdb\xe4\x73\x85\x7f\x7d\x8a\x3e\xde\x4d\x31\x44\xcf\xb1\x1d\x0b\x4a\xc9\x58\xca\xd8\x6e\x12\x4d\x7a\x20\x27\x80\x7a\x8c\x3e\xef\xd3\x24\xe4\x58\x60\x7e\x2e\x2c\xc6\xdd\xd8\xce\xe6\x8a\x57\x21\xd5\x47\x7b\x3e\xd8\x56\x7d\xf2\xf8\xeb\xb5\x4b\x5e\x97\x5b\x1d\xc2\xab\xd3\xbc\xde\x9e\x0d\xff\x4b\x0c\x7f\x7f\x77\x14\xfe\x78\x3c\xfc\xeb\xff\x1f\x9c\xbe\xfb\xaa\xf5\xf3\xdd\xea\xec\xac\xe5\x60\x7e\x05\xfb\x04\x25\x12\x71\x62\x5c\xd1\x41\xcc\x52\x79\x63\x2a\x1c\xc0\x0f\x22\xb7\x38\x80\x9f\x15\xab\x86\x07\x12\x6d\x7d\x84\x9a\xb4\xf2\x01\xf5\xba\x2a\x52\x1e\x8a\xf0\x90\xd6\x97\x09\xc3\x5d\x67\xbe\x6e\x47\xa4\xe8\x6a\x68\x49\x1a\xd5\xe2\x33\x7f\x9e\x60\xac\x75\x12\x10\x6e\x92\xea\xe2\xa4\xfe\xee\xa1\xf5\x0b\xa1\x66\xd0\x88\x35\x0f\x4a\xe7\x39\xdd\x72\xc2\xbc\x48\x8d\xb6\xb6\xb9\xe4\x07\x72\x79\x83\x70\xd6\xd8\x8d\x24\x2c\x47\x98\x0a\xc6\xe2\x66\x24\x9d\x11\xde\xe9\x1b\x71\x65\xe3\x51\x1a\x57\x39\x1c\x91\xb9\x9a\x70\x22\xd9\x82\x74\x0d\x17\x86\x89\x91\xcc\xf9\xdf\x6d\x22\x53\x3a\xd5\x6a\x9c\xcb\x60\x02\x14\xa5\x36\x4e\x28\x17\x4f\x35\x4d\xf0\xde\xff\x53\x71\x3e\xec\x20\x2d\x1c\x65\xca\x3e\x79\xf2\xf5\x9f\xaf\xaa\x51\xa6\x0b\x21\xd5\x0f\x85\x3b\x39\xfe\xfe\xe8\xb7\x4a\xe4\x1c\xe5\x7d\x29\x0a\xfc\xa1\x70\xab\xff\xd1\xad\x9d\xd5\xe2\x93\xbf\x6c\xb1\x8b\x8e\xde\xfa\xbd\xf2\xee\xe8\xed\x30\xfc\xf5\x55\x7c\x75\xfc\xfd\xd1\x75\xb2\xf6\xfb\xf1\x57\x27\x9c\x23\x59\x6f\xb9\x77\x6f\x87\xcd\xf6\x4b\xde\x7d\x75\xfc\x7d\xeb\xdb\xf1\xb2\xcd\xd8\x49\x5d\x24\x2b\x60\x58\x88\x72\x78\x83\xb3\x15\x9b\x73\x25\x1c\x5d\x6c\xc8\x53\xac\x10\xe5\x32\xeb\x7b\x2c\x27\x2f\x44\xf9\x1a\xc7\x68\x50\xa5\x4b\x99\xfc\x81\x11\x18\xb2\x1f\xd6\x7c\xe2\x0c\xac\x3d\xbc\x4e\xa4\x77\xbc\xa7\x6d\x1d\x9c\xde\x82\x5b\xb6\xc3\x8f\x6a\x4d\xfe\xe2\xc6\x4e\xea\x79\xee\xdd\x42\xdc\xdf\xbf\x78\xff\xd1\xde\xed\x54\x72\xa5\xa5\xd5\xf5\x61\x5e\x3c\xf5\xd0\x97\x45\x0f\xc3\xb9\xa9\x26\x3b\xaf\x52\xf2\xb7\x0a\xe1\xe2\x69\x7d\x9e\x5e\xaa\x34\xaf\xf8\x06\xbf\x9f\x7f\xbe\x78\x4a\xf6\xfb\xdf\x83\xb8\xb9\x43\xc8\xb4\x3a\x74\xf0\xea\xe5\xf3\xff\xcb\xce\x00\x2e\x31\xf0\x0a\x3d\x1c\xea\xcd\xa5\xf0\x6e\xb2\xa0\x80\xe1\xef\xe8\xf3\xe4\xb8\xe7\x54\x94\xb5\xff\x84\xc5\x1d\x67\x58\xe5\xa5\xe5\x83\x00\x60\x2b\x13\x46\x47\x0d\xfb\x88\x2f\x1f\xfd\x0b\xf1\xe0\x78\x86\x81\x4f\x82\xec\x95\xdc\x99\x6a\xa5\x30\xe5\xa0\x39\xa1\xc0\x8f\xb0\x3f\x88\x91\x5f\x05\xcc\xca\x7d\xec\xb1\x19\x42\x40\x6d\x6f\xb6\xa0\x31\x9c\xfb\x99\x7e\xf4\x9d\xb4\x30\xdf\xbd\x7a\xf4\xfe\x4c\x8e\x6c\xbe\xde\xe0\x7f\x5e\x48\xe3\xea\x9a\xce\x73\xe7\xb6\xd8\xb7\x5a\x07\x47\xa7\xc2\xc2\x08\x51\xb1\x3b\xd7\x7b\xff\x50\x05\xae\xc3\xc6\x11\x5b\x95\x43\xa7\x87\xd9\xf2\xc5\xdb\x40\xb9\xcd\x54\x5b\x63\xb9\xce\x5d\x8d\xb1\xab\xa1\x7a\x37\x9d\x2d\xa3\x81\x6d\x6e\x0a\xac\x31\xc8\xae\x13\x5b\x6d\x98\xcc\x79\x75\xd9\xb2\x08\x4e\x8d\x60\x67\x2c\x0e\x89\xac\xc7\x8e\x67\xc3\x69\x8e\xe6\x75\x3d\x7b\xbb\x8f\xd1\x2f\xf3\x15\x9a\x5b\xb9\x97\xf2\xdb\xb4\x31\x53\x9f\x67\x72\xf6\xf1\xb7\x15\x41\xaf\xbd\x3b\x61\xd7\x5f\xaa\x37\x84\x6f\xd6\xe6\xbf\x33\x05\xd7\x65\xf9\xef\xd2\xc6\xae\xca\xd2\x4b\x93\xce\x21\x0f\xeb\xb4\xe1\x90\x7b\xfb\x5d\x35\xaa\x81\x72\xd3\x7a\xb0\x81\xe0\x1f\xff\x7a\xf4\xdf\x01\x00\x00\xff\xff\xf5\x4e\x26\xd1\x9c\xf0\x00\x00") func operatorsCoreosCom_catalogsourcesYamlBytes() ([]byte, error) { return bindataRead( diff --git a/staging/api/go.mod b/staging/api/go.mod index 4120ad8147..c4306090a3 100644 --- a/staging/api/go.mod +++ b/staging/api/go.mod @@ -25,7 +25,7 @@ require ( github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/emicklei/go-restful/v3 v3.10.2 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect diff --git a/staging/api/go.sum b/staging/api/go.sum index a15d6312c8..f2515e68fb 100644 --- a/staging/api/go.sum +++ b/staging/api/go.sum @@ -67,8 +67,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= -github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= +github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= diff --git a/staging/api/pkg/operators/v1alpha1/catalogsource_types.go b/staging/api/pkg/operators/v1alpha1/catalogsource_types.go index 53bd40ca40..b94f045d88 100644 --- a/staging/api/pkg/operators/v1alpha1/catalogsource_types.go +++ b/staging/api/pkg/operators/v1alpha1/catalogsource_types.go @@ -152,7 +152,6 @@ type GrpcPodConfig struct { // will have the following modifications made to the container running the server: // - the $GOMEMLIMIT environment variable will be set to this value in bytes // - the memory request will be set to this value - // - the memory limit will be set to 200% of this value // // This field should be set if it's desired to reduce the footprint of a catalog server as much as possible, or if // a catalog being served is very large and needs more than the default allocation. If your index image has a file- @@ -160,7 +159,22 @@ type GrpcPodConfig struct { // /tmp/cache/cache/packages.json in the index image. // // This field is best-effort; if unset, no default will be used and no Pod memory limit or $GOMEMLIMIT value will be set. + // +optional MemoryTarget *resource.Quantity `json:"memoryTarget,omitempty"` + + // ExtractContent configures the gRPC catalog Pod to extract catalog metadata from the provided index image and + // use a well-known version of the `opm` server to expose it. The catalog index image that this CatalogSource is + // configured to use *must* be using the file-based catalogs in order to utilize this feature. + // +optional + ExtractContent *ExtractContentConfig `json:"extractContent,omitempty"` +} + +// ExtractContentConfig configures context extraction from a file-based catalog index image. +type ExtractContentConfig struct { + // CacheDir is the directory storing the pre-calculated API cache. + CacheDir string `json:"cacheDir"` + // CatalogDir is the directory storing the file-based catalog contents. + CatalogDir string `json:"catalogDir"` } // UpdateStrategy holds all the different types of catalog source update strategies diff --git a/staging/api/pkg/operators/v1alpha1/zz_generated.deepcopy.go b/staging/api/pkg/operators/v1alpha1/zz_generated.deepcopy.go index b4459a00a4..de6ec2b826 100644 --- a/staging/api/pkg/operators/v1alpha1/zz_generated.deepcopy.go +++ b/staging/api/pkg/operators/v1alpha1/zz_generated.deepcopy.go @@ -690,6 +690,21 @@ func (in *DependentStatus) DeepCopy() *DependentStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtractContentConfig) DeepCopyInto(out *ExtractContentConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtractContentConfig. +func (in *ExtractContentConfig) DeepCopy() *ExtractContentConfig { + if in == nil { + return nil + } + out := new(ExtractContentConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GRPCConnectionState) DeepCopyInto(out *GRPCConnectionState) { *out = *in @@ -738,6 +753,11 @@ func (in *GrpcPodConfig) DeepCopyInto(out *GrpcPodConfig) { x := (*in).DeepCopy() *out = &x } + if in.ExtractContent != nil { + in, out := &in.ExtractContent, &out.ExtractContent + *out = new(ExtractContentConfig) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GrpcPodConfig. diff --git a/staging/operator-lifecycle-manager/.github/workflows/build.yml b/staging/operator-lifecycle-manager/.github/workflows/build.yml index b48d9e8939..1a18c958aa 100644 --- a/staging/operator-lifecycle-manager/.github/workflows/build.yml +++ b/staging/operator-lifecycle-manager/.github/workflows/build.yml @@ -1,5 +1,6 @@ name: build on: + merge_group: pull_request: workflow_dispatch: jobs: diff --git a/staging/operator-lifecycle-manager/.github/workflows/e2e-tests.yml b/staging/operator-lifecycle-manager/.github/workflows/e2e-tests.yml index 4d2c44370e..a93fc4a243 100644 --- a/staging/operator-lifecycle-manager/.github/workflows/e2e-tests.yml +++ b/staging/operator-lifecycle-manager/.github/workflows/e2e-tests.yml @@ -7,6 +7,7 @@ on: - master pull_request: workflow_dispatch: + merge_group: jobs: e2e: strategy: diff --git a/staging/operator-lifecycle-manager/.github/workflows/sanity.yaml b/staging/operator-lifecycle-manager/.github/workflows/sanity.yaml index e9eb2c372c..f9f7ab4c24 100644 --- a/staging/operator-lifecycle-manager/.github/workflows/sanity.yaml +++ b/staging/operator-lifecycle-manager/.github/workflows/sanity.yaml @@ -5,6 +5,7 @@ on: - '**' pull_request: workflow_dispatch: + merge_group: jobs: vendor: runs-on: ubuntu-latest diff --git a/staging/operator-lifecycle-manager/.github/workflows/unit.yml b/staging/operator-lifecycle-manager/.github/workflows/unit.yml index 90ac078a90..342aa87cd3 100644 --- a/staging/operator-lifecycle-manager/.github/workflows/unit.yml +++ b/staging/operator-lifecycle-manager/.github/workflows/unit.yml @@ -7,6 +7,7 @@ on: - master pull_request: workflow_dispatch: + merge_group: jobs: unit: runs-on: ubuntu-latest diff --git a/staging/operator-lifecycle-manager/.github/workflows/verify.yml b/staging/operator-lifecycle-manager/.github/workflows/verify.yml index 734ba2f4c7..9dad6ffe06 100644 --- a/staging/operator-lifecycle-manager/.github/workflows/verify.yml +++ b/staging/operator-lifecycle-manager/.github/workflows/verify.yml @@ -5,6 +5,7 @@ on: - master pull_request: workflow_dispatch: + merge_group: jobs: verify: runs-on: ubuntu-latest diff --git a/staging/operator-lifecycle-manager/Dockerfile b/staging/operator-lifecycle-manager/Dockerfile index 2a92bcc63d..1ed3c19c3d 100644 --- a/staging/operator-lifecycle-manager/Dockerfile +++ b/staging/operator-lifecycle-manager/Dockerfile @@ -33,6 +33,7 @@ COPY --from=builder /build/bin/olm /bin/olm COPY --from=builder /build/bin/catalog /bin/catalog COPY --from=builder /build/bin/package-server /bin/package-server COPY --from=builder /build/bin/cpb /bin/cpb +COPY --from=builder /build/bin/copy-content /bin/copy-content USER 1001 EXPOSE 8080 EXPOSE 5443 diff --git a/staging/operator-lifecycle-manager/Makefile b/staging/operator-lifecycle-manager/Makefile index b96a246917..06df094021 100644 --- a/staging/operator-lifecycle-manager/Makefile +++ b/staging/operator-lifecycle-manager/Makefile @@ -64,7 +64,7 @@ ifeq (, $(wildcard $(KUBEBUILDER_ASSETS)/kube-apiserver)) endif cover.out: - go test $(MOD_FLAGS) -tags "json1" -v -race -coverprofile=cover.out -covermode=atomic \ + go test $(MOD_FLAGS) -tags "json1" -race -coverprofile=cover.out -covermode=atomic \ -coverpkg ./pkg/controller/... ./pkg/... coverage: cover.out @@ -97,11 +97,14 @@ bin/wait: FORCE build-util-linux: arch_flags=GOOS=linux GOARCH=$(ARCH) build-util-linux: build-util -build-util: bin/cpb +build-util: bin/cpb bin/copy-content bin/cpb: FORCE CGO_ENABLED=0 $(arch_flags) go build -buildvcs=false $(MOD_FLAGS) -ldflags '-extldflags "-static"' -o $@ ./util/cpb +bin/copy-content: FORCE + CGO_ENABLED=0 $(arch_flags) go build -buildvcs=false $(MOD_FLAGS) -ldflags '-extldflags "-static"' -o $@ ./cmd/copy-content + $(CMDS): version_flags=-ldflags "-X $(PKG)/pkg/version.GitCommit=$(GIT_COMMIT) -X $(PKG)/pkg/version.OLMVersion=`cat OLM_VERSION`" $(CMDS): $(arch_flags) go $(build_cmd) $(MOD_FLAGS) $(version_flags) -tags $(BUILD_TAGS) -o bin/$(shell basename $@) $@ diff --git a/staging/operator-lifecycle-manager/OWNERS b/staging/operator-lifecycle-manager/OWNERS index 8a849d2c6c..aa902778c3 100644 --- a/staging/operator-lifecycle-manager/OWNERS +++ b/staging/operator-lifecycle-manager/OWNERS @@ -10,6 +10,7 @@ approvers: - perdasilva - grokspawn - joelanford + - tmshort # review == this code is good /lgtm reviewers: - ecordell @@ -29,3 +30,4 @@ reviewers: - grokspawn - dtfranz - asmacdo + - tmshort diff --git a/staging/operator-lifecycle-manager/cmd/copy-content/main.go b/staging/operator-lifecycle-manager/cmd/copy-content/main.go new file mode 100644 index 0000000000..94c4046ef0 --- /dev/null +++ b/staging/operator-lifecycle-manager/cmd/copy-content/main.go @@ -0,0 +1,39 @@ +package main + +import ( + "flag" + "fmt" + "os" + + "github.com/otiai10/copy" +) + +func main() { + catalogSource := flag.String("catalog.from", "", "Path to catalog contents to copy.") + catalogDestination := flag.String("catalog.to", "", "Path to where catalog contents should be copied.") + cacheSource := flag.String("cache.from", "", "Path to cache contents to copy.") + cacheDestination := flag.String("cache.to", "", "Path to where cache contents should be copied.") + flag.Parse() + + for flagName, value := range map[string]*string{ + "catalog.from": catalogSource, + "catalog.to": catalogDestination, + "cache.from": cacheSource, + "cache.to": cacheDestination, + } { + if value == nil || *value == "" { + fmt.Printf("--%s is required", flagName) + os.Exit(1) + } + } + + for from, to := range map[string]string{ + *catalogSource: *catalogDestination, + *cacheSource: *cacheDestination, + } { + if err := copy.Copy(from, to); err != nil { + fmt.Printf("failed to copy %s to %s: %s\n", from, to, err) + os.Exit(1) + } + } +} diff --git a/staging/operator-lifecycle-manager/cmd/olm/main.go b/staging/operator-lifecycle-manager/cmd/olm/main.go index c0b6868f2b..4473496787 100644 --- a/staging/operator-lifecycle-manager/cmd/olm/main.go +++ b/staging/operator-lifecycle-manager/cmd/olm/main.go @@ -11,6 +11,7 @@ import ( configclientset "github.com/openshift/client-go/config/clientset/versioned" configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/validatingroundtripper" "github.com/sirupsen/logrus" "github.com/spf13/pflag" corev1 "k8s.io/api/core/v1" @@ -139,6 +140,9 @@ func main() { } config := mgr.GetConfig() + // create a config that validates we're creating objects with labels + validatingConfig := validatingroundtripper.Wrap(config) + versionedConfigClient, err := configclientset.NewForConfig(config) if err != nil { logger.WithError(err).Fatal("error configuring openshift proxy client") @@ -147,7 +151,7 @@ func main() { if err != nil { logger.WithError(err).Fatal("error configuring config client") } - opClient, err := operatorclient.NewClientFromRestConfig(config) + opClient, err := operatorclient.NewClientFromRestConfig(validatingConfig) if err != nil { logger.WithError(err).Fatal("error configuring operator client") } diff --git a/staging/operator-lifecycle-manager/deploy/chart/crds/0000_50_olm_00-catalogsources.crd.yaml b/staging/operator-lifecycle-manager/deploy/chart/crds/0000_50_olm_00-catalogsources.crd.yaml index f678b426c3..2d892c1ed7 100644 --- a/staging/operator-lifecycle-manager/deploy/chart/crds/0000_50_olm_00-catalogsources.crd.yaml +++ b/staging/operator-lifecycle-manager/deploy/chart/crds/0000_50_olm_00-catalogsources.crd.yaml @@ -532,8 +532,21 @@ spec: topologyKey: description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. type: string + extractContent: + description: ExtractContent configures the gRPC catalog Pod to extract catalog metadata from the provided index image and use a well-known version of the `opm` server to expose it. The catalog index image that this CatalogSource is configured to use *must* be using the file-based catalogs in order to utilize this feature. + type: object + required: + - cacheDir + - catalogDir + properties: + cacheDir: + description: CacheDir is the directory storing the pre-calculated API cache. + type: string + catalogDir: + description: CatalogDir is the directory storing the file-based catalog contents. + type: string memoryTarget: - description: "MemoryTarget configures the $GOMEMLIMIT value for the gRPC catalog Pod. This is a soft memory limit for the server, which the runtime will attempt to meet but makes no guarantees that it will do so. If this value is set, the Pod will have the following modifications made to the container running the server: - the $GOMEMLIMIT environment variable will be set to this value in bytes - the memory request will be set to this value - the memory limit will be set to 200% of this value \n This field should be set if it's desired to reduce the footprint of a catalog server as much as possible, or if a catalog being served is very large and needs more than the default allocation. If your index image has a file- system cache, determine a good approximation for this value by doubling the size of the package cache at /tmp/cache/cache/packages.json in the index image. \n This field is best-effort; if unset, no default will be used and no Pod memory limit or $GOMEMLIMIT value will be set." + description: "MemoryTarget configures the $GOMEMLIMIT value for the gRPC catalog Pod. This is a soft memory limit for the server, which the runtime will attempt to meet but makes no guarantees that it will do so. If this value is set, the Pod will have the following modifications made to the container running the server: - the $GOMEMLIMIT environment variable will be set to this value in bytes - the memory request will be set to this value \n This field should be set if it's desired to reduce the footprint of a catalog server as much as possible, or if a catalog being served is very large and needs more than the default allocation. If your index image has a file- system cache, determine a good approximation for this value by doubling the size of the package cache at /tmp/cache/cache/packages.json in the index image. \n This field is best-effort; if unset, no default will be used and no Pod memory limit or $GOMEMLIMIT value will be set." pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ anyOf: - type: integer diff --git a/staging/operator-lifecycle-manager/deploy/chart/templates/0000_90_olm_01-prometheus-rule.yaml b/staging/operator-lifecycle-manager/deploy/chart/templates/0000_90_olm_01-prometheus-rule.yaml index c9039ae552..e5417bb75e 100644 --- a/staging/operator-lifecycle-manager/deploy/chart/templates/0000_90_olm_01-prometheus-rule.yaml +++ b/staging/operator-lifecycle-manager/deploy/chart/templates/0000_90_olm_01-prometheus-rule.yaml @@ -34,7 +34,7 @@ spec: - name: olm.installplan.rules rules: - alert: InstallPlanStepAppliedWithWarnings - expr: sum(increase(installplan_warnings_total[5m])) > 0 + expr: sum by(namespace) (increase(installplan_warnings_total[5m])) > 0 labels: severity: warning annotations: diff --git a/staging/operator-lifecycle-manager/e2e.Dockerfile b/staging/operator-lifecycle-manager/e2e.Dockerfile index 4f450f2d9a..2cce485ab3 100644 --- a/staging/operator-lifecycle-manager/e2e.Dockerfile +++ b/staging/operator-lifecycle-manager/e2e.Dockerfile @@ -1,6 +1,6 @@ # ./pkg/controller/bundle/bundle_unpacker.go requires "/bin/cp" FROM busybox -COPY olm catalog package-server wait cpb /bin/ +COPY olm catalog package-server wait cpb copy-content /bin/ EXPOSE 8080 EXPOSE 5443 USER 1001 diff --git a/staging/operator-lifecycle-manager/go.mod b/staging/operator-lifecycle-manager/go.mod index 7aba22bb54..e58dba09d7 100644 --- a/staging/operator-lifecycle-manager/go.mod +++ b/staging/operator-lifecycle-manager/go.mod @@ -7,6 +7,7 @@ require ( github.com/coreos/go-semver v0.3.0 github.com/davecgh/go-spew v1.1.1 github.com/distribution/distribution v2.7.1+incompatible + github.com/evanphx/json-patch v5.6.0+incompatible github.com/fsnotify/fsnotify v1.6.0 github.com/ghodss/yaml v1.0.0 github.com/go-air/gini v1.0.4 @@ -24,9 +25,9 @@ require ( github.com/onsi/gomega v1.27.7 github.com/openshift/api v3.9.0+incompatible github.com/openshift/client-go v0.0.0-20220525160904-9e1acff93e4a - github.com/operator-framework/api v0.17.8-0.20230803152844-704ae942c4a9 - github.com/operator-framework/operator-registry v1.27.1 - github.com/otiai10/copy v1.2.0 + github.com/operator-framework/api v0.17.8-0.20230908201838-28c6773d2b74 + github.com/operator-framework/operator-registry v1.29.0 + github.com/otiai10/copy v1.12.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.15.1 github.com/prometheus/client_model v0.4.0 @@ -36,6 +37,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.3 golang.org/x/net v0.10.0 + golang.org/x/sync v0.2.0 golang.org/x/time v0.3.0 google.golang.org/grpc v1.54.0 gopkg.in/yaml.v2 v2.4.0 @@ -61,7 +63,7 @@ replace google.golang.org/grpc => google.golang.org/grpc v1.40.0 require ( github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 // indirect - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/BurntSushi/toml v1.2.1 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect @@ -69,7 +71,7 @@ require ( github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/Masterminds/squirrel v1.5.4 // indirect github.com/Masterminds/vcs v1.13.3 // indirect - github.com/Microsoft/go-winio v0.6.0 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Microsoft/hcsshim v0.10.0-rc.7 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/adrg/xdg v0.4.0 // indirect @@ -87,7 +89,7 @@ require ( github.com/containerd/typeurl/v2 v2.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/cyphar/filepath-securejoin v0.2.3 // indirect + github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/docker/cli v23.0.1+incompatible // indirect github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/docker v23.0.3+incompatible // indirect @@ -95,8 +97,7 @@ require ( github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/emicklei/go-restful/v3 v3.10.1 // indirect - github.com/evanphx/json-patch v5.6.0+incompatible // indirect + github.com/emicklei/go-restful/v3 v3.10.2 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect github.com/fatih/color v1.13.0 // indirect @@ -115,7 +116,7 @@ require ( github.com/goccy/go-yaml v1.8.1 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-migrate/migrate/v4 v4.6.2 // indirect + github.com/golang-migrate/migrate/v4 v4.16.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/btree v1.0.1 // indirect @@ -154,7 +155,7 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect - github.com/mattn/go-sqlite3 v1.14.15 // indirect + github.com/mattn/go-sqlite3 v1.14.16 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-wordwrap v1.0.0 // indirect @@ -163,7 +164,7 @@ require ( github.com/moby/spdystream v0.2.0 // indirect github.com/moby/sys/mountinfo v0.6.2 // indirect github.com/moby/sys/sequential v0.5.0 // indirect - github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect + github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect @@ -205,11 +206,10 @@ require ( go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/crypto v0.7.0 // indirect - golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect + golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 // indirect golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/oauth2 v0.5.0 // indirect - golang.org/x/sync v0.2.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/term v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect diff --git a/staging/operator-lifecycle-manager/go.sum b/staging/operator-lifecycle-manager/go.sum index 116c4919f6..cf844ef4a1 100644 --- a/staging/operator-lifecycle-manager/go.sum +++ b/staging/operator-lifecycle-manager/go.sum @@ -1,5 +1,4 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= @@ -42,9 +41,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 h1:EKPd1INOIyr5hWOWhvpmQpY6tKjeG0hT1s3AMC/9fic= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= @@ -66,18 +64,14 @@ github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8 github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/Masterminds/vcs v1.13.3 h1:IIA2aBdXvfbIM+yl/eTnL4hb1XwdpvuQLglAix1gweE= github.com/Masterminds/vcs v1.13.3/go.mod h1:TiE7xuEjl1N4j016moRd6vezp6e6Lz23gypeXfzXeW8= -github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= -github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= -github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/hcsshim v0.10.0-rc.7 h1:HBytQPxcv8Oy4244zbQbe6hnOnx544eL5QPUqhJldz8= github.com/Microsoft/hcsshim v0.10.0-rc.7/go.mod h1:ILuwjA+kNW+MrN/w5un7n3mTqkwsFu4Bp05/okFUZlE= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/a8m/expect v1.0.0/go.mod h1:4IwSCMumY49ScypDnjNbYEjgVeqy1/U2cEs3Lat96eA= github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= @@ -88,7 +82,6 @@ github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPp github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -97,7 +90,6 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= -github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -105,11 +97,9 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70= github.com/bugsnag/bugsnag-go v1.5.3 h1:yeRUT3mUE13jL1tGwvoQsKdVbAsQx9AJ+fqahKveP04= github.com/bugsnag/panicwrap v1.2.0 h1:OzrKrRvXis8qEvOkfcxNcYbOd2O7xXS2nnKMEMABFQA= @@ -126,11 +116,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= -github.com/containerd/containerd v1.2.7/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.7.0 h1:G/ZQr3gMZs6ZT0qPUZ15znx5QSdQdASW11nXTLTM2Pg= github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= @@ -155,36 +142,21 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHH github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= -github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= -github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8= -github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg= -github.com/cznic/golex v0.0.0-20170803123110-4ab7c5e190e4/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc= -github.com/cznic/internal v0.0.0-20180608152220-f44710a21d00/go.mod h1:olo7eAdKwJdXxb55TKGLiJ6xt1H0/tiiRCWKVLmtjY4= -github.com/cznic/lldb v1.1.0/go.mod h1:FIZVUmYUVhPwRiPzL8nD/mpFcJ/G7SSXjjXYG4uRI3A= -github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= -github.com/cznic/ql v1.2.0/go.mod h1:FbpzhyZrqr0PVlK6ury+PoW3T0ODUV22OeWIxcaOrSE= -github.com/cznic/sortutil v0.0.0-20150617083342-4c7342852e65/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ= -github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc= -github.com/cznic/zappy v0.0.0-20160723133515-2533cb5b45cc/go.mod h1:Y1SNZ4dRUOKXshKUbwUapqNncRrho4mkjQebgEHZLj8= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dhui/dktest v0.3.0/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc= github.com/distribution/distribution v2.7.1+incompatible h1:aGFx4EvJWKEh//lHPLwFhFgwFHKH06TzNVPamrMn04M= github.com/distribution/distribution v2.7.1+incompatible/go.mod h1:EgLm2NgWtdKgzF9NpMzUKgzmR7AMmb0VQi2B+ZzDRjc= github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc= github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM= github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v0.7.3-0.20190103212154-2b7e084dc98b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v0.7.3-0.20190817195342-4760db040282/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v23.0.3+incompatible h1:9GhVsShNWz1hO//9BNg/dpMnZW25KydO4wtVxWAIbho= github.com/docker/docker v23.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= @@ -194,18 +166,13 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= -github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ= -github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= +github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= @@ -229,7 +196,6 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk= github.com/fvbommel/sortorder v1.0.1 h1:dSnXLt4mJYH25uDDGa3biZNQsozaUWDSWeKJ0qqFfzE= github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc= @@ -271,7 +237,6 @@ github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/ github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -289,20 +254,18 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-yaml v1.8.1 h1:JuZRFlqLM5cWF6A+waL8AKVuCcqvKOuhJtUQI+L3ez0= github.com/goccy/go-yaml v1.8.1/go.mod h1:wS4gNoLalDSJxo/SpngzPQ2BN4uuZVLCmbM4S3vd4+Y= -github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godror/godror v0.24.2/go.mod h1:wZv/9vPiUib6tkoDl+AZ/QLf5YZgMravZ7jxH2eQWAE= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= -github.com/golang-migrate/migrate/v4 v4.6.2 h1:LDDOHo/q1W5UDj6PbkxdCv7lv9yunyZHXvxuwDkGo3k= -github.com/golang-migrate/migrate/v4 v4.6.2/go.mod h1:JYi6reN3+Z734VZ0akNuyOJNcrg45ZL7LDBMW3WGJL0= +github.com/golang-migrate/migrate/v4 v4.16.1 h1:O+0C55RbMN66pWm5MjO6mw0px6usGpY0+bkSGW9zCo0= +github.com/golang-migrate/migrate/v4 v4.16.1/go.mod h1:qXiwa/3Zeqaltm1MxOCZDYysW/F6folYiBgBG03l9hc= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= @@ -341,9 +304,6 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -368,8 +328,6 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= @@ -404,10 +362,7 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -430,7 +385,6 @@ github.com/h2non/filetype v1.1.1 h1:xvOwnXKAckvtLWsN398qS9QhlxlnVXBjXBydK2/UFB4= github.com/h2non/filetype v1.1.1/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c h1:fEE5/5VNnYUoBOj2I9TP8Jc+a7lge3QWn9DKE7NCwfc= github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c/go.mod h1:ObS/W+h8RYb1Y7fYivughjxojTmIu5iAIjSrSLCLeqE= -github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -476,13 +430,10 @@ github.com/itchyny/astgen-go v0.0.0-20200519013840-cf3ea398f645/go.mod h1:296z3W github.com/itchyny/go-flags v1.5.0/go.mod h1:lenkYuCobuxLBAd/HGFE4LRoW8D3B6iXRQfWYJ+MNbA= github.com/itchyny/gojq v0.11.0 h1:z7HnaKZ6erVzxPo3BkhJBG7jHmzKdAW8Hcse5N6YAic= github.com/itchyny/gojq v0.11.0/go.mod h1:my6D2qN2Sm6qa+/5GsPDUZlCWGR+U8Qsa9he76sudv0= -github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= -github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/joefitzgerald/rainbow-reporter v0.1.0 h1:AuMG652zjdzI0YCCnXAqATtRBpGXMcAnrajcaTrSeuo= @@ -502,7 +453,6 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= -github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= @@ -513,7 +463,6 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kortschak/utter v1.0.1/go.mod h1:vSmSjbyrlKjjsL71193LmzBOKgwePk9DH6uFaWHIInc= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -527,7 +476,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= @@ -539,7 +487,6 @@ github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2t github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= github.com/lestrrat-go/strftime v1.0.1 h1:o7qz5pmLzPDLyGW4lG6JvTKPUfTFXwe+vOamIYWtnVU= github.com/lestrrat-go/strftime v1.0.1/go.mod h1:E1nN3pCbtMSu1yjSVeyuRFVm/U0xoR76fd03sz+Qz4g= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= @@ -576,10 +523,10 @@ github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mN github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= -github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= @@ -618,8 +565,8 @@ github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vyg github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -629,13 +576,11 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= -github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA= github.com/nelsam/hel/v2 v2.3.2/go.mod h1:1ZTGfU2PFTOd5mx22i5O0Lc2GY933lQ2wb/ggy+rL3w= github.com/nelsam/hel/v2 v2.3.3/go.mod h1:1ZTGfU2PFTOd5mx22i5O0Lc2GY933lQ2wb/ggy+rL3w= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= @@ -643,19 +588,15 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b h1:YWuSjZCQAPM8UUBLkYUk1e+rZcvWHJmFb6i6rM44Xs8= github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= github.com/opencontainers/runtime-spec v1.1.0-rc.1 h1:wHa9jroFfKGQqFHj0I1fMRKLl0pfj+ynAqBxo3v6u9w= @@ -663,18 +604,13 @@ github.com/openshift/api v0.0.0-20221021112143-4226c2167e40 h1:PxjGCA72RtsdHWToZ github.com/openshift/api v0.0.0-20221021112143-4226c2167e40/go.mod h1:aQ6LDasvHMvHZXqLHnX2GRmnfTWCF/iIwz8EMTTIE9A= github.com/openshift/client-go v0.0.0-20221019143426-16aed247da5c h1:CV76yFOTXmq9VciBR3Bve5ZWzSxdft7gaMVB3kS0rwg= github.com/openshift/client-go v0.0.0-20221019143426-16aed247da5c/go.mod h1:lFMO8mLHXWFzSdYvGNo8ivF9SfF6zInA8ZGw4phRnUE= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/operator-framework/api v0.17.8-0.20230803152844-704ae942c4a9 h1:0rOIH8rbWsjhiZb14DD7V8Ohl0CjPkTYIbm/0G/nv1s= -github.com/operator-framework/api v0.17.8-0.20230803152844-704ae942c4a9/go.mod h1:lnurXgadLnoZ7pufKMHkErr2BVOIZSpHtvEkHBcKvdk= -github.com/operator-framework/operator-registry v1.27.1 h1:yU4atKR69XKH/GHlhgTdKTOAv4qRZUIFVHgrJE4FyiE= -github.com/operator-framework/operator-registry v1.27.1/go.mod h1:zVsP+QdutDReiSpASIYqbrixjoNEHZKAyBOgLz1jaXk= -github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k= -github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= -github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= -github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= -github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= -github.com/otiai10/mint v1.3.1 h1:BCmzIS3n71sGfHB5NMNDB3lHYPz8fWSkCAErHed//qc= -github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= +github.com/operator-framework/api v0.17.8-0.20230908201838-28c6773d2b74 h1:BNzxQqrfGRaEuw5SliqTFvloLE76L1MAo/uzbszzrPw= +github.com/operator-framework/api v0.17.8-0.20230908201838-28c6773d2b74/go.mod h1:Wbg136l1Po6zqG2QcTN1QZ8dbT4BQvNlQDM9tmQYvz0= +github.com/operator-framework/operator-registry v1.29.0 h1:HMmVTiuOAGoHLzYqR9Lr2QSOqbVzA50++ojNl2mu9f4= +github.com/operator-framework/operator-registry v1.29.0/go.mod h1:4rVQu/cOuCtVt3JzKsAmwyq2lsiu9uPaH9nYNfnqj9o= +github.com/otiai10/copy v1.12.0 h1:cLMgSQnXBs1eehF0Wy/FAGsgDTDmAqFR7rQylBb1nDY= +github.com/otiai10/copy v1.12.0/go.mod h1:rSaLseMUsZFFbsFGc7wCJnnkTAvdc5L6VWxPE4308Ww= +github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pbnjay/strptime v0.0.0-20140226051138-5c05b0d668c9 h1:4lfz0keanz7/gAlvJ7lAe9zmE08HXxifBZJC0AdeGKo= github.com/pbnjay/strptime v0.0.0-20140226051138-5c05b0d668c9/go.mod h1:6Hr+C/olSdkdL3z68MlyXWzwhvwmwN7KuUFXGb3PoOk= @@ -686,7 +622,6 @@ github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -701,27 +636,23 @@ github.com/poy/onpar v0.0.0-20200406201722-06f95a1c68e8/go.mod h1:nSbFQvMj97ZyhF github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= @@ -729,7 +660,6 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -743,18 +673,15 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sclevine/spec v1.2.0 h1:1Jwdf9jSfDl9NVmt8ndHqbTZ7XCCPbh1jI3hkDBHVYA= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -804,13 +731,9 @@ github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tebeka/strftime v0.1.3 h1:5HQXOqWKYRFfNyBMNVc9z5+QzuBtIXy03psIhtdJYto= github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ= -github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= -github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= -github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -833,7 +756,6 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t github.com/yvasiyarov/go-metrics v0.0.0-20150112132944-c25f46c4b940 h1:p7OofyZ509h8DmPLh8Hn+EIIZm/xYhdZHJ9GnXHdr6U= github.com/yvasiyarov/gorelic v0.0.7 h1:4DTF1WOM2ZZS/xMOkTFBOcb6XiHu/PKn3rVo6dbewQE= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20160601141957-9c099fbc30e9 h1:AsFN8kXcCVkUFHyuzp1FtYbzp1nCO/H6+1uPSGEyPzM= -gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= @@ -850,8 +772,6 @@ go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/ go.etcd.io/etcd/pkg/v3 v3.5.7 h1:obOzeVwerFwZ9trMWapU/VjDcYUJb5OfgC1zqEGWO/0= go.etcd.io/etcd/raft/v3 v3.5.7 h1:aN79qxLmV3SvIq84aNTliYGmjwsW6NqJSnqmI1HLJKc= go.etcd.io/etcd/server/v3 v3.5.7 h1:BTBD8IJUV7YFgsczZMHhMTS67XuA4KpRquL0MFOJGRk= -go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -896,12 +816,10 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -924,8 +842,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 h1:pVgRXcIictcr+lBQIFeiwuwtDIs4eL21OuM9nyAADmo= +golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -957,16 +875,13 @@ golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -1003,9 +918,7 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1039,13 +952,10 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1140,7 +1050,6 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190425222832-ad9eeb80039a/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -1201,8 +1110,6 @@ golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3j golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc= gomodules.xyz/jsonpatch/v2 v2.3.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= -google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1225,7 +1132,6 @@ google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjR google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= -google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= @@ -1235,7 +1141,6 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6 google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1333,8 +1238,6 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= helm.sh/helm/v3 v3.12.2 h1:kFyDBr/mgJUlyGzVTCieG4wW0zmo7fcNRWK0+FKkxqU= helm.sh/helm/v3 v3.12.2/go.mod h1:v1PMayudIfZAvec3Wp4wAErensvK/rv5fu/xCiE6t3I= diff --git a/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go b/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go index 37686e8627..79f67ab177 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go +++ b/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go @@ -86,11 +86,19 @@ func newBundleUnpackResult(lookup *operatorsv1alpha1.BundleLookup) *BundleUnpack func (c *ConfigMapUnpacker) job(cmRef *corev1.ObjectReference, bundlePath string, secrets []corev1.LocalObjectReference, annotationUnpackTimeout time.Duration) *batchv1.Job { job := &batchv1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + }, + }, Spec: batchv1.JobSpec{ //ttlSecondsAfterFinished: 0 // can use in the future to not have to clean up job Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Name: cmRef.Name, + Labels: map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + }, }, Spec: corev1.PodSpec{ // With restartPolicy = "OnFailure" when the spec.backoffLimit is reached, the job controller will delete all @@ -687,6 +695,7 @@ func (c *ConfigMapUnpacker) ensureRole(cmRef *corev1.ObjectReference) (role *rba fresh.SetNamespace(cmRef.Namespace) fresh.SetName(cmRef.Name) fresh.SetOwnerReferences([]metav1.OwnerReference{ownerRef(cmRef)}) + fresh.SetLabels(map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}) role, err = c.roleLister.Roles(fresh.GetNamespace()).Get(fresh.GetName()) if err != nil { @@ -730,6 +739,7 @@ func (c *ConfigMapUnpacker) ensureRoleBinding(cmRef *corev1.ObjectReference) (ro fresh.SetNamespace(cmRef.Namespace) fresh.SetName(cmRef.Name) fresh.SetOwnerReferences([]metav1.OwnerReference{ownerRef(cmRef)}) + fresh.SetLabels(map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}) roleBinding, err = c.rbLister.RoleBindings(fresh.GetNamespace()).Get(fresh.GetName()) if err != nil { diff --git a/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker_test.go b/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker_test.go index ffb006d45c..2bb0d47025 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker_test.go @@ -208,6 +208,7 @@ func TestConfigMapUnpacker(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: pathHash, Namespace: "ns-a", + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ { APIVersion: "v1", @@ -224,7 +225,8 @@ func TestConfigMapUnpacker(t *testing.T) { BackoffLimit: &backoffLimit, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Name: pathHash, + Name: pathHash, + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, }, Spec: corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyNever, @@ -369,6 +371,7 @@ func TestConfigMapUnpacker(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: pathHash, Namespace: "ns-a", + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ { APIVersion: "v1", @@ -402,6 +405,7 @@ func TestConfigMapUnpacker(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: pathHash, Namespace: "ns-a", + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ { APIVersion: "v1", @@ -437,6 +441,7 @@ func TestConfigMapUnpacker(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: digestHash, Namespace: "ns-a", + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ { APIVersion: "v1", @@ -452,7 +457,8 @@ func TestConfigMapUnpacker(t *testing.T) { BackoffLimit: &backoffLimit, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Name: digestHash, + Name: digestHash, + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, }, Spec: corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyNever, @@ -607,6 +613,7 @@ func TestConfigMapUnpacker(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: digestHash, Namespace: "ns-a", + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ { APIVersion: "operators.coreos.com/v1alpha1", @@ -705,6 +712,7 @@ func TestConfigMapUnpacker(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: digestHash, Namespace: "ns-a", + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ { APIVersion: "v1", @@ -720,7 +728,8 @@ func TestConfigMapUnpacker(t *testing.T) { BackoffLimit: &backoffLimit, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Name: digestHash, + Name: digestHash, + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, }, Spec: corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyNever, @@ -877,6 +886,7 @@ func TestConfigMapUnpacker(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: digestHash, Namespace: "ns-a", + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ { APIVersion: "v1", @@ -910,6 +920,7 @@ func TestConfigMapUnpacker(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: digestHash, Namespace: "ns-a", + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ { APIVersion: "v1", @@ -967,6 +978,7 @@ func TestConfigMapUnpacker(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: pathHash, Namespace: "ns-a", + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ { APIVersion: "v1", @@ -982,7 +994,8 @@ func TestConfigMapUnpacker(t *testing.T) { BackoffLimit: &backoffLimit, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Name: pathHash, + Name: pathHash, + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, }, Spec: corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyNever, @@ -1124,6 +1137,7 @@ func TestConfigMapUnpacker(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: pathHash, Namespace: "ns-a", + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ { APIVersion: "operators.coreos.com/v1alpha1", @@ -1199,6 +1213,7 @@ func TestConfigMapUnpacker(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: pathHash, Namespace: "ns-a", + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ { APIVersion: "v1", @@ -1214,7 +1229,8 @@ func TestConfigMapUnpacker(t *testing.T) { BackoffLimit: &backoffLimit, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Name: pathHash, + Name: pathHash, + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, }, Spec: corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyNever, @@ -1368,6 +1384,7 @@ func TestConfigMapUnpacker(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: pathHash, Namespace: "ns-a", + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ { APIVersion: "operators.coreos.com/v1alpha1", @@ -1442,6 +1459,7 @@ func TestConfigMapUnpacker(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: pathHash, Namespace: "ns-a", + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ { APIVersion: "v1", @@ -1457,7 +1475,8 @@ func TestConfigMapUnpacker(t *testing.T) { BackoffLimit: &backoffLimit, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Name: pathHash, + Name: pathHash, + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, }, Spec: corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyNever, diff --git a/staging/operator-lifecycle-manager/pkg/controller/install/certresources.go b/staging/operator-lifecycle-manager/pkg/controller/install/certresources.go index f48e62b771..1a2dcbca7d 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/install/certresources.go +++ b/staging/operator-lifecycle-manager/pkg/controller/install/certresources.go @@ -251,6 +251,7 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo service.SetName(ServiceName(deploymentName)) service.SetNamespace(i.owner.GetNamespace()) ownerutil.AddNonBlockingOwner(service, i.owner) + service.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}) existingService, err := i.strategyClient.GetOpLister().CoreV1().ServiceLister().Services(i.owner.GetNamespace()).Get(service.GetName()) if err == nil { @@ -366,6 +367,7 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo } secretRole.SetName(secret.GetName()) secretRole.SetNamespace(i.owner.GetNamespace()) + secretRole.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}) existingSecretRole, err := i.strategyClient.GetOpLister().RbacV1().RoleLister().Roles(i.owner.GetNamespace()).Get(secretRole.GetName()) if err == nil { @@ -412,6 +414,7 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo } secretRoleBinding.SetName(secret.GetName()) secretRoleBinding.SetNamespace(i.owner.GetNamespace()) + secretRoleBinding.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}) existingSecretRoleBinding, err := i.strategyClient.GetOpLister().RbacV1().RoleBindingLister().RoleBindings(i.owner.GetNamespace()).Get(secretRoleBinding.GetName()) if err == nil { @@ -454,6 +457,7 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo }, } authDelegatorClusterRoleBinding.SetName(service.GetName() + "-system:auth-delegator") + authDelegatorClusterRoleBinding.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}) existingAuthDelegatorClusterRoleBinding, err := i.strategyClient.GetOpLister().RbacV1().ClusterRoleBindingLister().Get(authDelegatorClusterRoleBinding.GetName()) if err == nil { @@ -502,6 +506,7 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo } authReaderRoleBinding.SetName(service.GetName() + "-auth-reader") authReaderRoleBinding.SetNamespace(KubeSystem) + authReaderRoleBinding.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}) existingAuthReaderRoleBinding, err := i.strategyClient.GetOpLister().RbacV1().RoleBindingLister().RoleBindings(KubeSystem).Get(authReaderRoleBinding.GetName()) if err == nil { diff --git a/staging/operator-lifecycle-manager/pkg/controller/install/certresources_test.go b/staging/operator-lifecycle-manager/pkg/controller/install/certresources_test.go index 3823f29f37..ad8e1041b4 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/install/certresources_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/install/certresources_test.go @@ -7,6 +7,7 @@ import ( "time" "github.com/golang/mock/gomock" + "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" @@ -155,7 +156,8 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { mockOpClient.EXPECT().DeleteService(namespace, "test-service", &metav1.DeleteOptions{}).Return(nil) service := corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-service", + Name: "test-service", + Labels: map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ ownerutil.NonBlockingOwner(&v1alpha1.ClusterServiceVersion{}), }, @@ -198,6 +200,7 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: secret.GetName(), Namespace: namespace, + Labels: map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}, }, Rules: []rbacv1.PolicyRule{ { @@ -214,6 +217,7 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: secret.GetName(), Namespace: namespace, + Labels: map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}, }, Subjects: []rbacv1.Subject{ { @@ -233,7 +237,8 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { authDelegatorClusterRoleBinding := &rbacv1.ClusterRoleBinding{ ObjectMeta: metav1.ObjectMeta{ - Name: service.GetName() + "-system:auth-delegator", + Name: service.GetName() + "-system:auth-delegator", + Labels: map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}, }, Subjects: []rbacv1.Subject{ { @@ -269,6 +274,7 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { } authReaderRoleBinding.SetName(service.GetName() + "-auth-reader") authReaderRoleBinding.SetNamespace(KubeSystem) + authReaderRoleBinding.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}) mockOpClient.EXPECT().UpdateRoleBinding(authReaderRoleBinding).Return(authReaderRoleBinding, nil) }, @@ -380,6 +386,7 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "test-service", Namespace: owner.GetNamespace(), + Labels: map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ ownerutil.NonBlockingOwner(owner), }, @@ -422,6 +429,7 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: secret.GetName(), Namespace: namespace, + Labels: map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}, }, Rules: []rbacv1.PolicyRule{ { @@ -438,6 +446,7 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: secret.GetName(), Namespace: namespace, + Labels: map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}, }, Subjects: []rbacv1.Subject{ { @@ -457,7 +466,8 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { authDelegatorClusterRoleBinding := &rbacv1.ClusterRoleBinding{ ObjectMeta: metav1.ObjectMeta{ - Name: service.GetName() + "-system:auth-delegator", + Name: service.GetName() + "-system:auth-delegator", + Labels: map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}, }, Subjects: []rbacv1.Subject{ { @@ -493,6 +503,7 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { } authReaderRoleBinding.SetName(service.GetName() + "-auth-reader") authReaderRoleBinding.SetNamespace(KubeSystem) + authReaderRoleBinding.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}) mockOpClient.EXPECT().UpdateRoleBinding(authReaderRoleBinding).Return(authReaderRoleBinding, nil) }, @@ -596,7 +607,8 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { mockOpClient.EXPECT().DeleteService(namespace, "test-service", &metav1.DeleteOptions{}).Return(nil) service := corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-service", + Name: "test-service", + Labels: map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ ownerutil.NonBlockingOwner(&v1alpha1.ClusterServiceVersion{}), }, @@ -649,6 +661,7 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: secret.GetName(), Namespace: namespace, + Labels: map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}, }, Rules: []rbacv1.PolicyRule{ { @@ -665,6 +678,7 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: secret.GetName(), Namespace: namespace, + Labels: map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}, }, Subjects: []rbacv1.Subject{ { @@ -684,7 +698,8 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { authDelegatorClusterRoleBinding := &rbacv1.ClusterRoleBinding{ ObjectMeta: metav1.ObjectMeta{ - Name: service.GetName() + "-system:auth-delegator", + Name: service.GetName() + "-system:auth-delegator", + Labels: map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}, }, Subjects: []rbacv1.Subject{ { @@ -720,6 +735,7 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { } authReaderRoleBinding.SetName(service.GetName() + "-auth-reader") authReaderRoleBinding.SetNamespace(KubeSystem) + authReaderRoleBinding.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}) mockOpClient.EXPECT().UpdateRoleBinding(authReaderRoleBinding).Return(authReaderRoleBinding, nil) }, @@ -853,7 +869,7 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { return } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("installCertRequirementsForDeployment() \n got = %v \n want = %v", got, tt.want) + t.Errorf("installCertRequirementsForDeployment() \n got = %v \n want = %v\n diff=%s\n", got, tt.want, cmp.Diff(got, tt.want)) } }) } diff --git a/staging/operator-lifecycle-manager/pkg/controller/install/deployment.go b/staging/operator-lifecycle-manager/pkg/controller/install/deployment.go index 43aab8e1ce..12e8044b25 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/install/deployment.go +++ b/staging/operator-lifecycle-manager/pkg/controller/install/deployment.go @@ -152,6 +152,10 @@ func (i *StrategyDeploymentInstaller) deploymentForSpec(name string, spec appsv1 dep.Spec.Template.SetAnnotations(annotations) // Set custom labels before CSV owner labels + if dep.Labels == nil { + dep.Labels = map[string]string{} + } + dep.Labels[OLMManagedLabelKey] = OLMManagedLabelValue dep.SetLabels(specLabels) ownerutil.AddNonBlockingOwner(dep, i.owner) diff --git a/staging/operator-lifecycle-manager/pkg/controller/install/webhook.go b/staging/operator-lifecycle-manager/pkg/controller/install/webhook.go index 74c1987516..a152434ced 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/install/webhook.go +++ b/staging/operator-lifecycle-manager/pkg/controller/install/webhook.go @@ -67,11 +67,11 @@ func (i *StrategyDeploymentInstaller) createOrUpdateWebhook(caPEM []byte, desc v switch desc.Type { case v1alpha1.ValidatingAdmissionWebhook: - i.createOrUpdateValidatingWebhook(ogNamespacelabelSelector, caPEM, desc) + return i.createOrUpdateValidatingWebhook(ogNamespacelabelSelector, caPEM, desc) case v1alpha1.MutatingAdmissionWebhook: - i.createOrUpdateMutatingWebhook(ogNamespacelabelSelector, caPEM, desc) + return i.createOrUpdateMutatingWebhook(ogNamespacelabelSelector, caPEM, desc) case v1alpha1.ConversionWebhook: - i.createOrUpdateConversionWebhook(caPEM, desc) + return i.createOrUpdateConversionWebhook(caPEM, desc) } return nil } @@ -287,6 +287,7 @@ func addWebhookLabels(object metav1.Object, webhookDesc v1alpha1.WebhookDescript } labels[WebhookDescKey] = webhookDesc.GenerateName labels[WebhookHashKey] = HashWebhookDesc(webhookDesc) + labels[OLMManagedLabelKey] = OLMManagedLabelValue object.SetLabels(labels) return nil diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go index aa7eb9668b..615f2267e3 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go @@ -11,16 +11,18 @@ import ( "sync" "time" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/labeller" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/validatingroundtripper" errorwrap "github.com/pkg/errors" "github.com/sirupsen/logrus" "google.golang.org/grpc/connectivity" + batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" "k8s.io/apiextensions-apiserver/pkg/apiserver/validation" - extinf "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -32,8 +34,14 @@ import ( utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apimachinery/pkg/util/yaml" + batchv1applyconfigurations "k8s.io/client-go/applyconfigurations/batch/v1" + corev1applyconfigurations "k8s.io/client-go/applyconfigurations/core/v1" + rbacv1applyconfigurations "k8s.io/client-go/applyconfigurations/rbac/v1" "k8s.io/client-go/dynamic" "k8s.io/client-go/informers" + "k8s.io/client-go/metadata" + "k8s.io/client-go/metadata/metadatainformer" + "k8s.io/client-go/metadata/metadatalister" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/record" @@ -138,14 +146,22 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo return nil, err } + // create a config that validates we're creating objects with labels + validatingConfig := validatingroundtripper.Wrap(config) + // Create a new client for dynamic types (CRs) - dynamicClient, err := dynamic.NewForConfig(config) + dynamicClient, err := dynamic.NewForConfig(validatingConfig) + if err != nil { + return nil, err + } + + metadataClient, err := metadata.NewForConfig(config) if err != nil { return nil, err } // Create a new queueinformer-based operator. - opClient, err := operatorclient.NewClientFromRestConfig(config) + opClient, err := operatorclient.NewClientFromRestConfig(validatingConfig) if err != nil { return nil, err } @@ -169,6 +185,11 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo return nil, err } + canFilter, err := labeller.Validate(ctx, logger, metadataClient) + if err != nil { + return nil, err + } + // Allocate the new instance of an Operator. op := &Operator{ Operator: queueOperator, @@ -194,7 +215,7 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo op.sources = grpc.NewSourceStore(logger, 10*time.Second, 10*time.Minute, op.syncSourceState) op.sourceInvalidator = resolver.SourceProviderFromRegistryClientProvider(op.sources, logger) resolverSourceProvider := NewOperatorGroupToggleSourceProvider(op.sourceInvalidator, logger, op.lister.OperatorsV1().OperatorGroupLister()) - op.reconciler = reconciler.NewRegistryReconcilerFactory(lister, opClient, configmapRegistryImage, op.now, ssaClient, workloadUserID) + op.reconciler = reconciler.NewRegistryReconcilerFactory(lister, opClient, configmapRegistryImage, op.now, ssaClient, workloadUserID, opmImage, utilImage) res := resolver.NewOperatorStepResolver(lister, crClient, operatorNamespace, resolverSourceProvider, logger) op.resolver = resolver.NewInstrumentedResolver(res, metrics.RegisterDependencyResolutionSuccess, metrics.RegisterDependencyResolutionFailure) @@ -344,7 +365,14 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo } // Wire k8s sharedIndexInformers - k8sInformerFactory := informers.NewSharedInformerFactoryWithOptions(op.opClient.KubernetesInterface(), resyncPeriod()) + k8sInformerFactory := informers.NewSharedInformerFactoryWithOptions(op.opClient.KubernetesInterface(), resyncPeriod(), func() []informers.SharedInformerOption { + if !canFilter { + return nil + } + return []informers.SharedInformerOption{informers.WithTweakListOptions(func(options *metav1.ListOptions) { + options.LabelSelector = labels.SelectorFromSet(labels.Set{install.OLMManagedLabelKey: install.OLMManagedLabelValue}).String() + })} + }()...) sharedIndexInformers := []cache.SharedIndexInformer{} // Wire Roles @@ -352,21 +380,114 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo op.lister.RbacV1().RegisterRoleLister(metav1.NamespaceAll, roleInformer.Lister()) sharedIndexInformers = append(sharedIndexInformers, roleInformer.Informer()) + labelObjects := func(gvr schema.GroupVersionResource, informer cache.SharedIndexInformer, sync queueinformer.LegacySyncHandler) error { + if canFilter { + return nil + } + queue := workqueue.NewRateLimitingQueueWithConfig(workqueue.DefaultControllerRateLimiter(), workqueue.RateLimitingQueueConfig{ + Name: gvr.String(), + }) + queueInformer, err := queueinformer.NewQueueInformer( + ctx, + queueinformer.WithQueue(queue), + queueinformer.WithLogger(op.logger), + queueinformer.WithInformer(informer), + queueinformer.WithSyncer(sync.ToSyncer()), + ) + if err != nil { + return err + } + + if err := op.RegisterQueueInformer(queueInformer); err != nil { + return err + } + + return nil + } + + rolesgvk := rbacv1.SchemeGroupVersion.WithResource("roles") + if err := labelObjects(rolesgvk, roleInformer.Informer(), labeller.ObjectLabeler[*rbacv1.Role, *rbacv1applyconfigurations.RoleApplyConfiguration]( + ctx, op.logger, labeller.Filter(rolesgvk), + rbacv1applyconfigurations.Role, + func(namespace string, ctx context.Context, cfg *rbacv1applyconfigurations.RoleApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.Role, error) { + return op.opClient.KubernetesInterface().RbacV1().Roles(namespace).Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + if err := labelObjects(rolesgvk, roleInformer.Informer(), labeller.ContentHashLabeler[*rbacv1.Role, *rbacv1applyconfigurations.RoleApplyConfiguration]( + ctx, op.logger, labeller.ContentHashFilter, + func(role *rbacv1.Role) (string, error) { + return resolver.PolicyRuleHashLabelValue(role.Rules) + }, + rbacv1applyconfigurations.Role, + func(namespace string, ctx context.Context, cfg *rbacv1applyconfigurations.RoleApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.Role, error) { + return op.opClient.KubernetesInterface().RbacV1().Roles(namespace).Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + // Wire RoleBindings roleBindingInformer := k8sInformerFactory.Rbac().V1().RoleBindings() op.lister.RbacV1().RegisterRoleBindingLister(metav1.NamespaceAll, roleBindingInformer.Lister()) sharedIndexInformers = append(sharedIndexInformers, roleBindingInformer.Informer()) + rolebindingsgvk := rbacv1.SchemeGroupVersion.WithResource("rolebindings") + if err := labelObjects(rolebindingsgvk, roleBindingInformer.Informer(), labeller.ObjectLabeler[*rbacv1.RoleBinding, *rbacv1applyconfigurations.RoleBindingApplyConfiguration]( + ctx, op.logger, labeller.Filter(rolebindingsgvk), + rbacv1applyconfigurations.RoleBinding, + func(namespace string, ctx context.Context, cfg *rbacv1applyconfigurations.RoleBindingApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.RoleBinding, error) { + return op.opClient.KubernetesInterface().RbacV1().RoleBindings(namespace).Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + if err := labelObjects(rolebindingsgvk, roleBindingInformer.Informer(), labeller.ContentHashLabeler[*rbacv1.RoleBinding, *rbacv1applyconfigurations.RoleBindingApplyConfiguration]( + ctx, op.logger, labeller.ContentHashFilter, + func(roleBinding *rbacv1.RoleBinding) (string, error) { + return resolver.RoleReferenceAndSubjectHashLabelValue(roleBinding.RoleRef, roleBinding.Subjects) + }, + rbacv1applyconfigurations.RoleBinding, + func(namespace string, ctx context.Context, cfg *rbacv1applyconfigurations.RoleBindingApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.RoleBinding, error) { + return op.opClient.KubernetesInterface().RbacV1().RoleBindings(namespace).Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + // Wire ServiceAccounts serviceAccountInformer := k8sInformerFactory.Core().V1().ServiceAccounts() op.lister.CoreV1().RegisterServiceAccountLister(metav1.NamespaceAll, serviceAccountInformer.Lister()) sharedIndexInformers = append(sharedIndexInformers, serviceAccountInformer.Informer()) + serviceaccountsgvk := corev1.SchemeGroupVersion.WithResource("serviceaccounts") + if err := labelObjects(serviceaccountsgvk, serviceAccountInformer.Informer(), labeller.ObjectLabeler[*corev1.ServiceAccount, *corev1applyconfigurations.ServiceAccountApplyConfiguration]( + ctx, op.logger, labeller.Filter(serviceaccountsgvk), + corev1applyconfigurations.ServiceAccount, + func(namespace string, ctx context.Context, cfg *corev1applyconfigurations.ServiceAccountApplyConfiguration, opts metav1.ApplyOptions) (*corev1.ServiceAccount, error) { + return op.opClient.KubernetesInterface().CoreV1().ServiceAccounts(namespace).Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + // Wire Services serviceInformer := k8sInformerFactory.Core().V1().Services() op.lister.CoreV1().RegisterServiceLister(metav1.NamespaceAll, serviceInformer.Lister()) sharedIndexInformers = append(sharedIndexInformers, serviceInformer.Informer()) + servicesgvk := corev1.SchemeGroupVersion.WithResource("services") + if err := labelObjects(servicesgvk, serviceInformer.Informer(), labeller.ObjectLabeler[*corev1.Service, *corev1applyconfigurations.ServiceApplyConfiguration]( + ctx, op.logger, labeller.Filter(servicesgvk), + corev1applyconfigurations.Service, + func(namespace string, ctx context.Context, cfg *corev1applyconfigurations.ServiceApplyConfiguration, opts metav1.ApplyOptions) (*corev1.Service, error) { + return op.opClient.KubernetesInterface().CoreV1().Services(namespace).Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + // Wire Pods for CatalogSource catsrcReq, err := labels.NewRequirement(reconciler.CatalogSourceLabelKey, selection.Exists, nil) if err != nil { @@ -381,6 +502,17 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo op.lister.CoreV1().RegisterPodLister(metav1.NamespaceAll, csPodInformer.Lister()) sharedIndexInformers = append(sharedIndexInformers, csPodInformer.Informer()) + podsgvk := corev1.SchemeGroupVersion.WithResource("pods") + if err := labelObjects(podsgvk, csPodInformer.Informer(), labeller.ObjectLabeler[*corev1.Pod, *corev1applyconfigurations.PodApplyConfiguration]( + ctx, op.logger, labeller.Filter(podsgvk), + corev1applyconfigurations.Pod, + func(namespace string, ctx context.Context, cfg *corev1applyconfigurations.PodApplyConfiguration, opts metav1.ApplyOptions) (*corev1.Pod, error) { + return op.opClient.KubernetesInterface().CoreV1().Pods(namespace).Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + // Wire Pods for BundleUnpack job buReq, err := labels.NewRequirement(bundle.BundleUnpackPodLabel, selection.Exists, nil) if err != nil { @@ -405,6 +537,19 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo jobInformer := k8sInformerFactory.Batch().V1().Jobs() sharedIndexInformers = append(sharedIndexInformers, jobInformer.Informer()) + jobsgvk := batchv1.SchemeGroupVersion.WithResource("jobs") + if err := labelObjects(jobsgvk, jobInformer.Informer(), labeller.ObjectLabeler[*batchv1.Job, *batchv1applyconfigurations.JobApplyConfiguration]( + ctx, op.logger, labeller.JobFilter(func(namespace, name string) (metav1.Object, error) { + return configMapInformer.Lister().ConfigMaps(namespace).Get(name) + }), + batchv1applyconfigurations.Job, + func(namespace string, ctx context.Context, cfg *batchv1applyconfigurations.JobApplyConfiguration, opts metav1.ApplyOptions) (*batchv1.Job, error) { + return op.opClient.KubernetesInterface().BatchV1().Jobs(namespace).Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + // Generate and register QueueInformers for k8s resources k8sSyncer := queueinformer.LegacySyncHandler(op.syncObject).ToSyncerWithDelete(op.handleDeletion) for _, informer := range sharedIndexInformers { @@ -443,13 +588,23 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo return nil, err } - // Register CustomResourceDefinition QueueInformer - crdInformer := extinf.NewSharedInformerFactory(op.opClient.ApiextensionsInterface(), resyncPeriod()).Apiextensions().V1().CustomResourceDefinitions() - op.lister.APIExtensionsV1().RegisterCustomResourceDefinitionLister(crdInformer.Lister()) + // Register CustomResourceDefinition QueueInformer. Object metadata requests are used + // by this informer in order to reduce cached size. + gvr := apiextensionsv1.SchemeGroupVersion.WithResource("customresourcedefinitions") + crdInformer := metadatainformer.NewFilteredMetadataInformer( + metadataClient, + gvr, + metav1.NamespaceAll, + resyncPeriod(), + cache.Indexers{}, + nil, + ).Informer() + crdLister := metadatalister.New(crdInformer.GetIndexer(), gvr) + op.lister.APIExtensionsV1().RegisterCustomResourceDefinitionLister(crdLister) crdQueueInformer, err := queueinformer.NewQueueInformer( ctx, queueinformer.WithLogger(op.logger), - queueinformer.WithInformer(crdInformer.Informer()), + queueinformer.WithInformer(crdInformer), queueinformer.WithSyncer(queueinformer.LegacySyncHandler(op.syncObject).ToSyncerWithDelete(op.handleDeletion)), ) if err != nil { @@ -459,6 +614,14 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo return nil, err } + customresourcedefinitionsgvk := apiextensionsv1.SchemeGroupVersion.WithResource("customresourcedefinitions") + if err := labelObjects(customresourcedefinitionsgvk, crdInformer, labeller.ObjectPatchLabeler( + ctx, op.logger, labeller.Filter(customresourcedefinitionsgvk), + op.opClient.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Patch, + )); err != nil { + return nil, err + } + // Namespace sync for resolving subscriptions namespaceInformer := informers.NewSharedInformerFactory(op.opClient.KubernetesInterface(), resyncPeriod()).Core().V1().Namespaces() op.lister.CoreV1().RegisterNamespaceLister(namespaceInformer.Lister()) @@ -2096,6 +2259,10 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { // Attempt to create the CSV. csv.SetNamespace(namespace) + if csv.Labels == nil { + csv.Labels = map[string]string{} + } + csv.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue status, err := ensurer.EnsureClusterServiceVersion(&csv) if err != nil { @@ -2121,6 +2288,10 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { // Attempt to create the Subscription sub.SetNamespace(namespace) + if sub.Labels == nil { + sub.Labels = map[string]string{} + } + sub.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue status, err := ensurer.EnsureSubscription(&sub) if err != nil { @@ -2151,6 +2322,10 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { } s.SetOwnerReferences(updated) s.SetNamespace(namespace) + if s.Labels == nil { + s.Labels = map[string]string{} + } + s.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue status, err := ensurer.EnsureBundleSecret(plan.Namespace, &s) if err != nil { @@ -2175,6 +2350,11 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { return errorwrap.Wrapf(err, "error parsing step manifest: %s", step.Resource.Name) } + if cr.Labels == nil { + cr.Labels = map[string]string{} + } + cr.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue + status, err := ensurer.EnsureClusterRole(&cr, step) if err != nil { return err @@ -2189,6 +2369,10 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { if err != nil { return errorwrap.Wrapf(err, "error parsing step manifest: %s", step.Resource.Name) } + if rb.Labels == nil { + rb.Labels = map[string]string{} + } + rb.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue status, err := ensurer.EnsureClusterRoleBinding(&rb, step) if err != nil { @@ -2212,6 +2396,10 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { } r.SetOwnerReferences(updated) r.SetNamespace(namespace) + if r.Labels == nil { + r.Labels = map[string]string{} + } + r.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue status, err := ensurer.EnsureRole(plan.Namespace, &r) if err != nil { @@ -2235,6 +2423,10 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { } rb.SetOwnerReferences(updated) rb.SetNamespace(namespace) + if rb.Labels == nil { + rb.Labels = map[string]string{} + } + rb.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue status, err := ensurer.EnsureRoleBinding(plan.Namespace, &rb) if err != nil { @@ -2258,6 +2450,10 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { } sa.SetOwnerReferences(updated) sa.SetNamespace(namespace) + if sa.Labels == nil { + sa.Labels = map[string]string{} + } + sa.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue status, err := ensurer.EnsureServiceAccount(namespace, &sa) if err != nil { @@ -2289,6 +2485,10 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { } s.SetOwnerReferences(updated) s.SetNamespace(namespace) + if s.Labels == nil { + s.Labels = map[string]string{} + } + s.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue status, err := ensurer.EnsureService(namespace, &s) if err != nil { @@ -2319,6 +2519,10 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { } cfg.SetOwnerReferences(updated) cfg.SetNamespace(namespace) + if cfg.Labels == nil { + cfg.Labels = map[string]string{} + } + cfg.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue status, err := ensurer.EnsureConfigMap(plan.Namespace, &cfg) if err != nil { @@ -2378,6 +2582,12 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { } } } + l := unstructuredObject.GetLabels() + if l == nil { + l = map[string]string{} + } + l[install.OLMManagedLabelKey] = install.OLMManagedLabelValue + unstructuredObject.SetLabels(l) // Set up the dynamic client ResourceInterface and set ownerrefs var resourceInterface dynamic.ResourceInterface diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator_test.go b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator_test.go index cdf31e4d5a..79f70d2fb8 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator_test.go @@ -13,6 +13,7 @@ import ( "testing/quick" "time" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" "github.com/sirupsen/logrus" @@ -568,6 +569,14 @@ func TestExecutePlan(t *testing.T) { modify(t, decodeFile(t, "./testdata/prometheusrule.cr.yaml", &unstructured.Unstructured{}), withNamespace(namespace), withOwner(csv("csv", namespace, nil, nil)), + modifyMeta(func(m metav1.Object) { + labels := m.GetLabels() + if labels == nil { + labels = map[string]string{} + } + labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue + m.SetLabels(labels) + }), ), }, err: nil, @@ -599,7 +608,7 @@ func TestExecutePlan(t *testing.T) { }), want: []runtime.Object{ &apiextensionsv1.CustomResourceDefinition{ - ObjectMeta: metav1.ObjectMeta{Name: "test"}, + ObjectMeta: metav1.ObjectMeta{Name: "test", Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}}, TypeMeta: metav1.TypeMeta{ Kind: "CustomResourceDefinition", APIVersion: "apiextensions.k8s.io/v1", // v1 CRD version of API @@ -1764,7 +1773,7 @@ func NewFakeOperator(ctx context.Context, namespace string, namespaces []string, } applier := controllerclient.NewFakeApplier(s, "testowner") - op.reconciler = reconciler.NewRegistryReconcilerFactory(lister, op.opClient, "test:pod", op.now, applier, 1001) + op.reconciler = reconciler.NewRegistryReconcilerFactory(lister, op.opClient, "test:pod", op.now, applier, 1001, "", "") } op.RunInformers(ctx) @@ -1826,6 +1835,7 @@ func csv(name, namespace string, owned, required []string) *v1alpha1.ClusterServ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, }, Spec: v1alpha1.ClusterServiceVersionSpec{ CustomResourceDefinitions: v1alpha1.CustomResourceDefinitions{ @@ -1839,7 +1849,8 @@ func csv(name, namespace string, owned, required []string) *v1alpha1.ClusterServ func crd(name string) apiextensionsv1beta1.CustomResourceDefinition { return apiextensionsv1beta1.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{ - Name: name, + Name: name, + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, }, Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{ Group: name + "group", @@ -1860,6 +1871,7 @@ func service(name, namespace string) *corev1.Service { ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, }, } } @@ -1869,6 +1881,7 @@ func secret(name, namespace string) *corev1.Secret { ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, }, } } @@ -1877,12 +1890,12 @@ func serviceAccount(name, namespace, generateName string, secretRef *corev1.Obje if secretRef == nil { return &corev1.ServiceAccount{ TypeMeta: metav1.TypeMeta{Kind: serviceAccountKind, APIVersion: ""}, - ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace, GenerateName: generateName}, + ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace, GenerateName: generateName, Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}}, } } return &corev1.ServiceAccount{ TypeMeta: metav1.TypeMeta{Kind: serviceAccountKind, APIVersion: ""}, - ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace, GenerateName: generateName}, + ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace, GenerateName: generateName, Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}}, Secrets: []corev1.ObjectReference{*secretRef}, } } @@ -1890,7 +1903,7 @@ func serviceAccount(name, namespace, generateName string, secretRef *corev1.Obje func configMap(name, namespace string) *corev1.ConfigMap { return &corev1.ConfigMap{ TypeMeta: metav1.TypeMeta{Kind: configMapKind}, - ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace}, + ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace, Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}}, } } @@ -1916,7 +1929,7 @@ func toManifest(t *testing.T, obj runtime.Object) string { } func pod(s v1alpha1.CatalogSource) *corev1.Pod { - pod := reconciler.Pod(&s, "registry-server", s.Spec.Image, s.GetName(), s.GetLabels(), s.GetAnnotations(), 5, 10, 1001) + pod := reconciler.Pod(&s, "registry-server", "central-opm", "central-util", s.Spec.Image, s.GetName(), s.GetLabels(), s.GetAnnotations(), 5, 10, 1001) ownerutil.AddOwner(pod, &s, false, true) return pod } diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/step.go b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/step.go index 54abd56bf9..d3f54f1827 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/step.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/step.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" "github.com/pkg/errors" "github.com/sirupsen/logrus" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -128,6 +129,10 @@ func (b *builder) NewCRDV1Step(client apiextensionsv1client.ApiextensionsV1Inter } setInstalledAlongsideAnnotation(b.annotator, crd, b.plan.GetNamespace(), step.Resolving, b.csvLister, crd) + if crd.Labels == nil { + crd.Labels = map[string]string{} + } + crd.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue _, createError := client.CustomResourceDefinitions().Create(context.TODO(), crd, metav1.CreateOptions{}) if apierrors.IsAlreadyExists(createError) { @@ -211,6 +216,10 @@ func (b *builder) NewCRDV1Beta1Step(client apiextensionsv1beta1client.Apiextensi } setInstalledAlongsideAnnotation(b.annotator, crd, b.plan.GetNamespace(), step.Resolving, b.csvLister, crd) + if crd.Labels == nil { + crd.Labels = map[string]string{} + } + crd.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue _, createError := client.CustomResourceDefinitions().Create(context.TODO(), crd, metav1.CreateOptions{}) if apierrors.IsAlreadyExists(createError) { diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/step_ensurer.go b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/step_ensurer.go index 91c309f97a..3369aa6561 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/step_ensurer.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/step_ensurer.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" errorwrap "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -91,6 +92,9 @@ func (o *StepEnsurer) EnsureSecret(operatorNamespace, planNamespace, name string ObjectMeta: metav1.ObjectMeta{ Name: secret.Name, Namespace: planNamespace, + Labels: map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + }, }, Data: secret.Data, Type: secret.Type, diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/internal/alongside/alongside.go b/staging/operator-lifecycle-manager/pkg/controller/operators/internal/alongside/alongside.go index 5004650b27..7517cf2777 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/internal/alongside/alongside.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/internal/alongside/alongside.go @@ -10,7 +10,7 @@ import ( ) const ( - prefix = "operatorframework.io/installed-alongside-" + AnnotationPrefix = "operatorframework.io/installed-alongside-" ) // NamespacedName is a reference to an object by namespace and name. @@ -33,7 +33,7 @@ type Annotator struct{} func (a Annotator) FromObject(o Annotatable) []NamespacedName { var result []NamespacedName for k, v := range o.GetAnnotations() { - if !strings.HasPrefix(k, prefix) { + if !strings.HasPrefix(k, AnnotationPrefix) { continue } tokens := strings.Split(v, "/") @@ -55,7 +55,7 @@ func (a Annotator) ToObject(o Annotatable, nns []NamespacedName) { annotations := o.GetAnnotations() for key := range annotations { - if strings.HasPrefix(key, prefix) { + if strings.HasPrefix(key, AnnotationPrefix) { delete(annotations, key) } } @@ -82,5 +82,5 @@ func key(n NamespacedName) string { hasher.Write([]byte(n.Namespace)) hasher.Write([]byte{'/'}) hasher.Write([]byte(n.Name)) - return fmt.Sprintf("%s%x", prefix, hasher.Sum64()) + return fmt.Sprintf("%s%x", AnnotationPrefix, hasher.Sum64()) } diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/internal/alongside/alongside_test.go b/staging/operator-lifecycle-manager/pkg/controller/operators/internal/alongside/alongside_test.go index dee4b943fe..902d3ab536 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/internal/alongside/alongside_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/internal/alongside/alongside_test.go @@ -23,7 +23,7 @@ func TestAnnotatorFromObject(t *testing.T) { NamespacedNames []NamespacedName }{ { - Name: "annotation without prefix ignored", + Name: "annotation without AnnotationPrefix ignored", Object: TestAnnotatable{ "foo": "namespace/name", }, @@ -66,7 +66,7 @@ func TestAnnotatorToObject(t *testing.T) { }, }, { - Name: "annotation without prefix ignored", + Name: "annotation without AnnotationPrefix ignored", Object: TestAnnotatable{ "operatorframework.io/something-else": "", }, diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/labeller/filters.go b/staging/operator-lifecycle-manager/pkg/controller/operators/labeller/filters.go new file mode 100644 index 0000000000..4bdbfece31 --- /dev/null +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/labeller/filters.go @@ -0,0 +1,128 @@ +package labeller + +import ( + "context" + "fmt" + "strings" + "sync" + + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler" + "github.com/sirupsen/logrus" + "golang.org/x/sync/errgroup" + appsv1 "k8s.io/api/apps/v1" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/metadata" + + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/internal/alongside" +) + +func ContentHashFilter(object metav1.Object) bool { + return HasOLMOwnerRef(object) && !hasHashLabel(object) +} + +func Filter(gvr schema.GroupVersionResource) func(metav1.Object) bool { + if f, ok := filters[gvr]; ok { + return f + } + return func(object metav1.Object) bool { + return false + } +} + +func JobFilter(getConfigMap func(namespace, name string) (metav1.Object, error)) func(object metav1.Object) bool { + return func(object metav1.Object) bool { + for _, ownerRef := range object.GetOwnerReferences() { + if ownerRef.APIVersion == corev1.SchemeGroupVersion.String() && ownerRef.Kind == "ConfigMap" { + cm, err := getConfigMap(object.GetNamespace(), ownerRef.Name) + if err != nil { + return false + } + return HasOLMOwnerRef(cm) + } + } + return false + } +} + +var filters = map[schema.GroupVersionResource]func(metav1.Object) bool{ + corev1.SchemeGroupVersion.WithResource("services"): HasOLMOwnerRef, + corev1.SchemeGroupVersion.WithResource("pods"): func(object metav1.Object) bool { + _, ok := object.GetLabels()[reconciler.CatalogSourceLabelKey] + return ok + }, + corev1.SchemeGroupVersion.WithResource("serviceaccounts"): func(object metav1.Object) bool { + return HasOLMOwnerRef(object) || HasOLMLabel(object) + }, + appsv1.SchemeGroupVersion.WithResource("deployments"): HasOLMOwnerRef, + rbacv1.SchemeGroupVersion.WithResource("roles"): HasOLMOwnerRef, + rbacv1.SchemeGroupVersion.WithResource("rolebindings"): HasOLMOwnerRef, + rbacv1.SchemeGroupVersion.WithResource("clusterroles"): HasOLMOwnerRef, + rbacv1.SchemeGroupVersion.WithResource("clusterrolebindings"): HasOLMOwnerRef, + apiextensionsv1.SchemeGroupVersion.WithResource("customresourcedefinitions"): func(object metav1.Object) bool { + for key := range object.GetAnnotations() { + if strings.HasPrefix(key, alongside.AnnotationPrefix) { + return true + } + } + return false + }, +} + +func Validate(ctx context.Context, logger *logrus.Logger, metadataClient metadata.Interface) (bool, error) { + okLock := sync.Mutex{} + var ok bool + g, ctx := errgroup.WithContext(ctx) + allFilters := map[schema.GroupVersionResource]func(metav1.Object) bool{} + for gvr, filter := range filters { + allFilters[gvr] = filter + } + allFilters[batchv1.SchemeGroupVersion.WithResource("jobs")] = JobFilter(func(namespace, name string) (metav1.Object, error) { + return metadataClient.Resource(corev1.SchemeGroupVersion.WithResource("configmaps")).Namespace(namespace).Get(ctx, name, metav1.GetOptions{}) + }) + + for _, gvr := range []schema.GroupVersionResource{ + rbacv1.SchemeGroupVersion.WithResource("roles"), + rbacv1.SchemeGroupVersion.WithResource("rolebindings"), + rbacv1.SchemeGroupVersion.WithResource("clusterroles"), + rbacv1.SchemeGroupVersion.WithResource("clusterrolebindings"), + } { + previous := allFilters[gvr] + allFilters[gvr] = func(object metav1.Object) bool { + return previous != nil && previous(object) && ContentHashFilter(object) + } + } + for gvr, filter := range allFilters { + gvr, filter := gvr, filter + g.Go(func() error { + list, err := metadataClient.Resource(gvr).List(ctx, metav1.ListOptions{}) + if err != nil { + return fmt.Errorf("failed to list %s: %w", gvr.String(), err) + } + var count int + for _, item := range list.Items { + if filter(&item) && !hasLabel(&item) { + count++ + } + } + if count > 0 { + logger.WithFields(logrus.Fields{ + "gvr": gvr.String(), + "nonconforming": count, + }).Info("found nonconforming items") + } + okLock.Lock() + ok = ok && count == 0 + okLock.Unlock() + return nil + }) + } + if err := g.Wait(); err != nil { + return false, err + } + return ok, nil +} diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/labeller/labels.go b/staging/operator-lifecycle-manager/pkg/controller/operators/labeller/labels.go new file mode 100644 index 0000000000..8c2af67c9d --- /dev/null +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/labeller/labels.go @@ -0,0 +1,159 @@ +package labeller + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + jsonpatch "github.com/evanphx/json-patch" + "github.com/sirupsen/logrus" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + + operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" + operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + operatorsv1alpha2 "github.com/operator-framework/api/pkg/operators/v1alpha2" + + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/decorators" + "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil" + "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer" +) + +type ApplyConfig[T any] interface { + WithLabels(map[string]string) T +} + +type Client[A ApplyConfig[A], T metav1.Object] interface { + Apply(ctx context.Context, cfg ApplyConfig[A], opts metav1.ApplyOptions) (result T, err error) +} + +func hasLabel(obj metav1.Object) bool { + value, ok := obj.GetLabels()[install.OLMManagedLabelKey] + return ok && value == install.OLMManagedLabelValue +} + +func ObjectLabeler[T metav1.Object, A ApplyConfig[A]]( + ctx context.Context, + logger *logrus.Logger, + check func(metav1.Object) bool, + applyConfigFor func(name, namespace string) A, + apply func(namespace string, ctx context.Context, cfg A, opts metav1.ApplyOptions) (T, error), +) queueinformer.LegacySyncHandler { + return func(obj interface{}) error { + cast, ok := obj.(T) + if !ok { + err := fmt.Errorf("wrong type %T, expected %T: %#v", obj, new(T), obj) + logger.WithError(err).Error("casting failed") + return fmt.Errorf("casting failed: %w", err) + } + + if !check(cast) || hasLabel(cast) { + return nil + } + + cfg := applyConfigFor(cast.GetName(), cast.GetNamespace()) + cfg.WithLabels(map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + }) + + _, err := apply(cast.GetNamespace(), ctx, cfg, metav1.ApplyOptions{}) + return err + } +} + +// CRDs did not have applyconfigurations generated for them on accident, we can remove this when +// https://github.com/kubernetes/kubernetes/pull/120177 lands +func ObjectPatchLabeler( + ctx context.Context, + logger *logrus.Logger, + check func(metav1.Object) bool, + patch func(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *apiextensionsv1.CustomResourceDefinition, err error), +) func( + obj interface{}, +) error { + return func(obj interface{}) error { + cast, ok := obj.(*apiextensionsv1.CustomResourceDefinition) + if !ok { + err := fmt.Errorf("wrong type %T, expected %T: %#v", obj, new(*apiextensionsv1.CustomResourceDefinition), obj) + logger.WithError(err).Error("casting failed") + return fmt.Errorf("casting failed: %w", err) + } + + if !check(cast) || hasLabel(cast) { + return nil + } + + uid := cast.GetUID() + rv := cast.GetResourceVersion() + + // to ensure they appear in the patch as preconditions + previous := cast.DeepCopy() + previous.SetUID("") + previous.SetResourceVersion("") + + oldData, err := json.Marshal(previous) + if err != nil { + return fmt.Errorf("failed to Marshal old data for %s/%s: %w", previous.GetNamespace(), previous.GetName(), err) + } + + // to ensure they appear in the patch as preconditions + updated := cast.DeepCopy() + updated.SetUID(uid) + updated.SetResourceVersion(rv) + labels := updated.GetLabels() + if labels == nil { + labels = map[string]string{} + } + labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue + updated.SetLabels(labels) + + newData, err := json.Marshal(updated) + if err != nil { + return fmt.Errorf("failed to Marshal old data for %s/%s: %w", updated.GetNamespace(), updated.GetName(), err) + } + + patchBytes, err := jsonpatch.CreateMergePatch(oldData, newData) + if err != nil { + return fmt.Errorf("failed to create patch for %s/%s: %w", cast.GetNamespace(), cast.GetName(), err) + } + + _, err = patch(ctx, cast.GetName(), types.MergePatchType, patchBytes, metav1.PatchOptions{}) + return err + } +} + +// HasOLMOwnerRef determines if an object is owned by another object in the OLM Groups. +// This checks both classical OwnerRefs and the "OLM OwnerRef" in labels to handle +// cluster-scoped resources. +func HasOLMOwnerRef(object metav1.Object) bool { + for _, ref := range object.GetOwnerReferences() { + for _, gv := range []schema.GroupVersion{ + operatorsv1.GroupVersion, + operatorsv1alpha1.SchemeGroupVersion, + operatorsv1alpha2.GroupVersion, + } { + if ref.APIVersion == gv.String() { + return true + } + } + } + hasOLMOwnerLabels := true + for _, label := range []string{ownerutil.OwnerKey, ownerutil.OwnerNamespaceKey, ownerutil.OwnerKind} { + _, exists := object.GetLabels()[label] + hasOLMOwnerLabels = hasOLMOwnerLabels && exists + } + return hasOLMOwnerLabels +} + +func HasOLMLabel(object metav1.Object) bool { + for key := range object.GetLabels() { + if strings.HasPrefix(key, decorators.ComponentLabelKeyPrefix) { + return true + } + } + return false +} diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/labeller/rbac.go b/staging/operator-lifecycle-manager/pkg/controller/operators/labeller/rbac.go new file mode 100644 index 0000000000..6e64791ca7 --- /dev/null +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/labeller/rbac.go @@ -0,0 +1,56 @@ +package labeller + +import ( + "context" + "fmt" + + "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver" + "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil" + "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer" + "github.com/sirupsen/logrus" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func hasHashLabel(obj metav1.Object) bool { + _, ok := obj.GetLabels()[resolver.ContentHashLabelKey] + return ok +} + +func ContentHashLabeler[T metav1.Object, A ApplyConfig[A]]( + ctx context.Context, + logger *logrus.Logger, + check func(metav1.Object) bool, + hasher func(object T) (string, error), + applyConfigFor func(name, namespace string) A, + apply func(namespace string, ctx context.Context, cfg A, opts metav1.ApplyOptions) (T, error), +) queueinformer.LegacySyncHandler { + return func(obj interface{}) error { + cast, ok := obj.(T) + if !ok { + err := fmt.Errorf("wrong type %T, expected %T: %#v", obj, new(T), obj) + logger.WithError(err).Error("casting failed") + return fmt.Errorf("casting failed: %w", err) + } + + if _, _, ok := ownerutil.GetOwnerByKindLabel(cast, v1alpha1.ClusterServiceVersionKind); !ok { + return nil + } + + if !check(cast) || hasHashLabel(cast) { + return nil + } + + hash, err := hasher(cast) + if err != nil { + return fmt.Errorf("failed to calculate hash: %w", err) + } + + cfg := applyConfigFor(cast.GetName(), cast.GetNamespace()) + cfg.WithLabels(map[string]string{ + resolver.ContentHashLabelKey: hash, + }) + _, err = apply(cast.GetNamespace(), ctx, cfg, metav1.ApplyOptions{}) + return err + } +} diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/apiservices.go b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/apiservices.go index c71b5594f3..cb052f510f 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/apiservices.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/apiservices.go @@ -228,6 +228,7 @@ func (a *Operator) areAPIServicesAvailable(csv *v1alpha1.ClusterServiceVersion) for _, desc := range csv.Spec.APIServiceDefinitions.Owned { apiService, err := a.lister.APIRegistrationV1().APIServiceLister().Get(desc.GetName()) if apierrors.IsNotFound(err) { + a.logger.Debugf("APIRegistration APIService %s not found", desc.GetName()) return false, nil } @@ -236,10 +237,12 @@ func (a *Operator) areAPIServicesAvailable(csv *v1alpha1.ClusterServiceVersion) } if !install.IsAPIServiceAvailable(apiService) { + a.logger.Debugf("APIService not available for %s", desc.GetName()) return false, nil } if ok, err := a.isGVKRegistered(desc.Group, desc.Version, desc.Kind); !ok || err != nil { + a.logger.Debugf("%s.%s/%s not registered for %s", desc.Group, desc.Version, desc.Kind, desc.GetName()) return false, err } } diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator.go b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator.go index c8aa9ea09a..824f5940ee 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator.go @@ -7,21 +7,25 @@ import ( "strings" "time" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/labeller" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/plugins" "github.com/sirupsen/logrus" admissionregistrationv1 "k8s.io/api/admissionregistration/v1" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - extinf "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/selection" utilerrors "k8s.io/apimachinery/pkg/util/errors" utilruntime "k8s.io/apimachinery/pkg/util/runtime" + appsv1applyconfigurations "k8s.io/client-go/applyconfigurations/apps/v1" + rbacv1applyconfigurations "k8s.io/client-go/applyconfigurations/rbac/v1" "k8s.io/client-go/informers" k8sscheme "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/metadata/metadatainformer" @@ -136,6 +140,11 @@ func newOperatorWithConfig(ctx context.Context, config *operatorConfig) (*Operat return nil, err } + canFilter, err := labeller.Validate(ctx, config.logger, config.metadataClient) + if err != nil { + return nil, err + } + op := &Operator{ Operator: queueOperator, clock: config.clock, @@ -309,7 +318,17 @@ func newOperatorWithConfig(ctx context.Context, config *operatorConfig) (*Operat } // Wire Deployments - k8sInformerFactory := informers.NewSharedInformerFactoryWithOptions(op.opClient.KubernetesInterface(), config.resyncPeriod(), informers.WithNamespace(namespace)) + k8sInformerFactory := informers.NewSharedInformerFactoryWithOptions(op.opClient.KubernetesInterface(), config.resyncPeriod(), func() []informers.SharedInformerOption { + opts := []informers.SharedInformerOption{ + informers.WithNamespace(namespace), + } + if canFilter { + opts = append(opts, informers.WithTweakListOptions(func(options *metav1.ListOptions) { + options.LabelSelector = labels.SelectorFromSet(labels.Set{install.OLMManagedLabelKey: install.OLMManagedLabelValue}).String() + })) + } + return opts + }()...) depInformer := k8sInformerFactory.Apps().V1().Deployments() informersByNamespace[namespace].DeploymentInformer = depInformer op.lister.AppsV1().RegisterDeploymentLister(namespace, depInformer.Lister()) @@ -428,6 +447,42 @@ func newOperatorWithConfig(ctx context.Context, config *operatorConfig) (*Operat } } + labelObjects := func(gvr schema.GroupVersionResource, informer cache.SharedIndexInformer, sync queueinformer.LegacySyncHandler) error { + if canFilter { + return nil + } + queue := workqueue.NewRateLimitingQueueWithConfig(workqueue.DefaultControllerRateLimiter(), workqueue.RateLimitingQueueConfig{ + Name: gvr.String(), + }) + queueInformer, err := queueinformer.NewQueueInformer( + ctx, + queueinformer.WithQueue(queue), + queueinformer.WithLogger(op.logger), + queueinformer.WithInformer(informer), + queueinformer.WithSyncer(sync.ToSyncer()), + ) + if err != nil { + return err + } + + if err := op.RegisterQueueInformer(queueInformer); err != nil { + return err + } + + return nil + } + + deploymentsgvk := appsv1.SchemeGroupVersion.WithResource("deployments") + if err := labelObjects(deploymentsgvk, informersByNamespace[metav1.NamespaceAll].DeploymentInformer.Informer(), labeller.ObjectLabeler[*appsv1.Deployment, *appsv1applyconfigurations.DeploymentApplyConfiguration]( + ctx, op.logger, labeller.Filter(deploymentsgvk), + appsv1applyconfigurations.Deployment, + func(namespace string, ctx context.Context, cfg *appsv1applyconfigurations.DeploymentApplyConfiguration, opts metav1.ApplyOptions) (*appsv1.Deployment, error) { + return op.opClient.KubernetesInterface().AppsV1().Deployments(namespace).Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + // add queue for all namespaces as well objGCQueue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), fmt.Sprintf("%s/obj-gc", "")) op.objGCQueueSet.Set("", objGCQueue) @@ -465,7 +520,14 @@ func newOperatorWithConfig(ctx context.Context, config *operatorConfig) (*Operat return nil, err } - k8sInformerFactory := informers.NewSharedInformerFactory(op.opClient.KubernetesInterface(), config.resyncPeriod()) + k8sInformerFactory := informers.NewSharedInformerFactoryWithOptions(op.opClient.KubernetesInterface(), config.resyncPeriod(), func() []informers.SharedInformerOption { + if !canFilter { + return nil + } + return []informers.SharedInformerOption{informers.WithTweakListOptions(func(options *metav1.ListOptions) { + options.LabelSelector = labels.SelectorFromSet(labels.Set{install.OLMManagedLabelKey: install.OLMManagedLabelValue}).String() + })} + }()...) clusterRoleInformer := k8sInformerFactory.Rbac().V1().ClusterRoles() informersByNamespace[metav1.NamespaceAll].ClusterRoleInformer = clusterRoleInformer op.lister.RbacV1().RegisterClusterRoleLister(clusterRoleInformer.Lister()) @@ -482,6 +544,33 @@ func newOperatorWithConfig(ctx context.Context, config *operatorConfig) (*Operat return nil, err } + clusterrolesgvk := rbacv1.SchemeGroupVersion.WithResource("clusterroles") + if err := labelObjects(clusterrolesgvk, clusterRoleInformer.Informer(), labeller.ObjectLabeler[*rbacv1.ClusterRole, *rbacv1applyconfigurations.ClusterRoleApplyConfiguration]( + ctx, op.logger, labeller.Filter(clusterrolesgvk), + func(name, _ string) *rbacv1applyconfigurations.ClusterRoleApplyConfiguration { + return rbacv1applyconfigurations.ClusterRole(name) + }, + func(_ string, ctx context.Context, cfg *rbacv1applyconfigurations.ClusterRoleApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.ClusterRole, error) { + return op.opClient.KubernetesInterface().RbacV1().ClusterRoles().Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + if err := labelObjects(clusterrolesgvk, clusterRoleInformer.Informer(), labeller.ContentHashLabeler[*rbacv1.ClusterRole, *rbacv1applyconfigurations.ClusterRoleApplyConfiguration]( + ctx, op.logger, labeller.ContentHashFilter, + func(clusterRole *rbacv1.ClusterRole) (string, error) { + return resolver.PolicyRuleHashLabelValue(clusterRole.Rules) + }, + func(name, _ string) *rbacv1applyconfigurations.ClusterRoleApplyConfiguration { + return rbacv1applyconfigurations.ClusterRole(name) + }, + func(_ string, ctx context.Context, cfg *rbacv1applyconfigurations.ClusterRoleApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.ClusterRole, error) { + return op.opClient.KubernetesInterface().RbacV1().ClusterRoles().Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + clusterRoleBindingInformer := k8sInformerFactory.Rbac().V1().ClusterRoleBindings() informersByNamespace[metav1.NamespaceAll].ClusterRoleBindingInformer = clusterRoleBindingInformer op.lister.RbacV1().RegisterClusterRoleBindingLister(clusterRoleBindingInformer.Lister()) @@ -498,6 +587,33 @@ func newOperatorWithConfig(ctx context.Context, config *operatorConfig) (*Operat return nil, err } + clusterrolebindingssgvk := rbacv1.SchemeGroupVersion.WithResource("clusterrolebindings") + if err := labelObjects(clusterrolebindingssgvk, clusterRoleBindingInformer.Informer(), labeller.ObjectLabeler[*rbacv1.ClusterRoleBinding, *rbacv1applyconfigurations.ClusterRoleBindingApplyConfiguration]( + ctx, op.logger, labeller.Filter(clusterrolebindingssgvk), + func(name, _ string) *rbacv1applyconfigurations.ClusterRoleBindingApplyConfiguration { + return rbacv1applyconfigurations.ClusterRoleBinding(name) + }, + func(_ string, ctx context.Context, cfg *rbacv1applyconfigurations.ClusterRoleBindingApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.ClusterRoleBinding, error) { + return op.opClient.KubernetesInterface().RbacV1().ClusterRoleBindings().Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + if err := labelObjects(clusterrolebindingssgvk, clusterRoleBindingInformer.Informer(), labeller.ContentHashLabeler[*rbacv1.ClusterRoleBinding, *rbacv1applyconfigurations.ClusterRoleBindingApplyConfiguration]( + ctx, op.logger, labeller.ContentHashFilter, + func(clusterRoleBinding *rbacv1.ClusterRoleBinding) (string, error) { + return resolver.RoleReferenceAndSubjectHashLabelValue(clusterRoleBinding.RoleRef, clusterRoleBinding.Subjects) + }, + func(name, _ string) *rbacv1applyconfigurations.ClusterRoleBindingApplyConfiguration { + return rbacv1applyconfigurations.ClusterRoleBinding(name) + }, + func(_ string, ctx context.Context, cfg *rbacv1applyconfigurations.ClusterRoleBindingApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.ClusterRoleBinding, error) { + return op.opClient.KubernetesInterface().RbacV1().ClusterRoleBindings().Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + // register namespace queueinformer namespaceInformer := k8sInformerFactory.Core().V1().Namespaces() informersByNamespace[metav1.NamespaceAll].NamespaceInformer = namespaceInformer @@ -541,14 +657,25 @@ func newOperatorWithConfig(ctx context.Context, config *operatorConfig) (*Operat return nil, err } - // Register CustomResourceDefinition QueueInformer - crdInformer := extinf.NewSharedInformerFactory(op.opClient.ApiextensionsInterface(), config.resyncPeriod()).Apiextensions().V1().CustomResourceDefinitions() + // Register CustomResourceDefinition QueueInformer. Object metadata requests are used + // by this informer in order to reduce cached size. + gvr := apiextensionsv1.SchemeGroupVersion.WithResource("customresourcedefinitions") + crdInformer := metadatainformer.NewFilteredMetadataInformer( + config.metadataClient, + gvr, + metav1.NamespaceAll, + config.resyncPeriod(), + cache.Indexers{}, + nil, + ).Informer() + crdLister := metadatalister.New(crdInformer.GetIndexer(), gvr) informersByNamespace[metav1.NamespaceAll].CRDInformer = crdInformer - op.lister.APIExtensionsV1().RegisterCustomResourceDefinitionLister(crdInformer.Lister()) + informersByNamespace[metav1.NamespaceAll].CRDLister = crdLister + op.lister.APIExtensionsV1().RegisterCustomResourceDefinitionLister(crdLister) crdQueueInformer, err := queueinformer.NewQueueInformer( ctx, queueinformer.WithLogger(op.logger), - queueinformer.WithInformer(crdInformer.Informer()), + queueinformer.WithInformer(crdInformer), queueinformer.WithSyncer(k8sSyncer), ) if err != nil { @@ -1183,7 +1310,7 @@ func (a *Operator) handleClusterServiceVersionDeletion(obj interface{}) { } for i, crdName := range desc.ConversionCRDs { - crd, err := a.lister.APIExtensionsV1().CustomResourceDefinitionLister().Get(crdName) + crd, err := a.opClient.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), crdName, metav1.GetOptions{}) if err != nil { logger.Errorf("error getting CRD %v which was defined in CSVs spec.WebhookDefinition[%d]: %v\n", crdName, i, err) continue diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator_test.go b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator_test.go index 86e331c2aa..99dca3fd98 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator_test.go @@ -8,6 +8,7 @@ import ( "crypto/x509" "crypto/x509/pkix" "encoding/pem" + "errors" "fmt" "math" "math/big" @@ -51,6 +52,9 @@ import ( operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" "github.com/operator-framework/api/pkg/operators/v1alpha1" + opregistry "github.com/operator-framework/operator-registry/pkg/registry" + clienttesting "k8s.io/client-go/testing" + "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned/fake" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/certs" @@ -65,8 +69,6 @@ import ( "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/scoped" - opregistry "github.com/operator-framework/operator-registry/pkg/registry" - clienttesting "k8s.io/client-go/testing" ) type TestStrategy struct{} @@ -298,13 +300,14 @@ func NewFakeOperator(ctx context.Context, options ...fakeOperatorOption) (*Opera *config.actionLog = append(*config.actionLog, action) return false, nil, nil })) - config.operatorClient = operatorclient.NewClient(k8sClientFake, apiextensionsfake.NewSimpleClientset(config.extObjs...), apiregistrationfake.NewSimpleClientset(config.regObjs...)) + apiextensionsFake := apiextensionsfake.NewSimpleClientset(config.extObjs...) + config.operatorClient = operatorclient.NewClient(k8sClientFake, apiextensionsFake, apiregistrationfake.NewSimpleClientset(config.regObjs...)) config.configClient = configfake.NewSimpleClientset() metadataFake := metadatafake.NewSimpleMetadataClient(scheme, config.partialMetadata...) config.metadataClient = metadataFake // It's a travesty that we need to do this, but the fakes leave us no other option. In the API server, of course // changes to objects are transparently exposed in the metadata client. In fake-land, we need to enforce that ourselves. - externalFake.PrependReactor("*", "*", func(action clienttesting.Action) (bool, runtime.Object, error) { + propagate := func(action clienttesting.Action) (bool, runtime.Object, error) { var err error switch action.GetVerb() { case "create": @@ -320,7 +323,9 @@ func NewFakeOperator(ctx context.Context, options ...fakeOperatorOption) (*Opera err = metadataFake.Resource(action.GetResource()).Delete(context.TODO(), a.GetName(), metav1.DeleteOptions{}) } return false, nil, err - }) + } + externalFake.PrependReactor("*", "*", propagate) + apiextensionsFake.PrependReactor("*", "*", propagate) for _, ns := range config.namespaces { _, err := config.operatorClient.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}}, metav1.CreateOptions{}) @@ -4397,7 +4402,7 @@ func TestSyncOperatorGroups(t *testing.T) { operatorGroup *operatorsv1.OperatorGroup csvs []*v1alpha1.ClusterServiceVersion clientObjs []runtime.Object - crds []runtime.Object + crds []*apiextensionsv1.CustomResourceDefinition k8sObjs []runtime.Object apis []runtime.Object } @@ -4474,7 +4479,7 @@ func TestSyncOperatorGroups(t *testing.T) { role, roleBinding, }, - crds: []runtime.Object{crd}, + crds: []*apiextensionsv1.CustomResourceDefinition{crd}, }, expectedStatus: operatorsv1.OperatorGroupStatus{}, final: final{objects: map[string][]runtime.Object{ @@ -4518,6 +4523,407 @@ func TestSyncOperatorGroups(t *testing.T) { LastUpdated: &now, }, }, + { + name: "MatchingNamespace/NoCSVs/CreatesClusterRoles", + expectedEqual: true, + initial: initial{ + operatorGroup: &operatorsv1.OperatorGroup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "operator-group-1", + Namespace: operatorNamespace, Labels: map[string]string{"app": "app-a"}, + }, + Spec: operatorsv1.OperatorGroupSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "app-a"}, + }, + }, + }, + k8sObjs: []runtime.Object{ + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: operatorNamespace, + }, + }, + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: targetNamespace, + Labels: map[string]string{"app": "app-a"}, + }, + }, + }, + }, + expectedStatus: operatorsv1.OperatorGroupStatus{ + Namespaces: []string{targetNamespace}, + LastUpdated: &now, + }, + final: final{objects: map[string][]runtime.Object{ + "": { + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm.og.operator-group-1.admin-8rdAjL0E35JMMAkOqYmoorzjpIIihfnj3DcgDU", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm.og.operator-group-1.edit-9lBEUxqAYE7CX7wZfFEPYutTfQTo43WarB08od", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm.og.operator-group-1.view-1l6ymczPK5SceF4d0DCtAnWZuvmKn6s8oBUxHr", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + }, + }}, + }, + { + // check that even if cluster roles exist without the naming convention, we create the new ones and leave the old ones unchanged + name: "MatchingNamespace/NoCSVs/KeepOldClusterRoles", + expectedEqual: true, + initial: initial{ + operatorGroup: &operatorsv1.OperatorGroup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "operator-group-1", + Namespace: operatorNamespace, + }, + Spec: operatorsv1.OperatorGroupSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "app-a"}, + }, + }, + }, + k8sObjs: []runtime.Object{ + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: operatorNamespace, + }, + }, + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: targetNamespace, + Labels: map[string]string{"app": "app-a"}, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "operator-group-1-admin", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "operator-group-1-view", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "operator-group-1-edit", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + }, + }, + expectedStatus: operatorsv1.OperatorGroupStatus{ + Namespaces: []string{targetNamespace}, + LastUpdated: &now, + }, + final: final{objects: map[string][]runtime.Object{ + "": { + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm.og.operator-group-1.admin-8rdAjL0E35JMMAkOqYmoorzjpIIihfnj3DcgDU", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm.og.operator-group-1.edit-9lBEUxqAYE7CX7wZfFEPYutTfQTo43WarB08od", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm.og.operator-group-1.view-1l6ymczPK5SceF4d0DCtAnWZuvmKn6s8oBUxHr", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "operator-group-1-admin", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "operator-group-1-view", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "operator-group-1-edit", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + }, + }}, + }, + { + // ensure that ownership labels are fixed but user labels are preserved + name: "MatchingNamespace/NoCSVs/ClusterRoleOwnershipLabels", + expectedEqual: true, + initial: initial{ + operatorGroup: &operatorsv1.OperatorGroup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "operator-group-1", + Namespace: operatorNamespace, + }, + Spec: operatorsv1.OperatorGroupSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "app-a"}, + }, + }, + }, + k8sObjs: []runtime.Object{ + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: operatorNamespace, + }, + }, + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: targetNamespace, + Labels: map[string]string{"app": "app-a"}, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm.og.operator-group-1.admin-8rdAjL0E35JMMAkOqYmoorzjpIIihfnj3DcgDU", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns-bob", + "olm.owner.kind": "OperatorGroup", + "not.an.olm.label": "true", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm.og.operator-group-1.view-1l6ymczPK5SceF4d0DCtAnWZuvmKn6s8oBUxHr", + Labels: map[string]string{ + "olm.owner": "operator-group-5", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + "not.an.olm.label": "false", + "another.olm.label": "or maybe not", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm.og.operator-group-1.edit-9lBEUxqAYE7CX7wZfFEPYutTfQTo43WarB08od", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroupKind", + }, + }, + }, + }, + }, + expectedStatus: operatorsv1.OperatorGroupStatus{ + Namespaces: []string{targetNamespace}, + LastUpdated: &now, + }, + final: final{objects: map[string][]runtime.Object{ + "": { + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm.og.operator-group-1.admin-8rdAjL0E35JMMAkOqYmoorzjpIIihfnj3DcgDU", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + "not.an.olm.label": "true", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm.og.operator-group-1.edit-9lBEUxqAYE7CX7wZfFEPYutTfQTo43WarB08od", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm.og.operator-group-1.view-1l6ymczPK5SceF4d0DCtAnWZuvmKn6s8oBUxHr", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + "not.an.olm.label": "false", + "another.olm.label": "or maybe not", + }, + }, + }, + }, + }}, + }, + { + // if a cluster role exists with the correct name, use that + name: "MatchingNamespace/NoCSVs/DoesNotUpdateClusterRoles", + expectedEqual: true, + initial: initial{ + operatorGroup: &operatorsv1.OperatorGroup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "operator-group-1", + Namespace: operatorNamespace, + }, + Spec: operatorsv1.OperatorGroupSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "app-a"}, + }, + }, + }, + k8sObjs: []runtime.Object{ + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: operatorNamespace, + }, + }, + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: targetNamespace, + Labels: map[string]string{"app": "app-a"}, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm.og.operator-group-1.admin-8rdAjL0E35JMMAkOqYmoorzjpIIihfnj3DcgDU", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm.og.operator-group-1.edit-9lBEUxqAYE7CX7wZfFEPYutTfQTo43WarB08od", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm.og.operator-group-1.view-1l6ymczPK5SceF4d0DCtAnWZuvmKn6s8oBUxHr", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }}, + }, + expectedStatus: operatorsv1.OperatorGroupStatus{ + Namespaces: []string{targetNamespace}, + LastUpdated: &now, + }, + final: final{objects: map[string][]runtime.Object{ + "": { + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm.og.operator-group-1.admin-8rdAjL0E35JMMAkOqYmoorzjpIIihfnj3DcgDU", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm.og.operator-group-1.edit-9lBEUxqAYE7CX7wZfFEPYutTfQTo43WarB08od", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm.og.operator-group-1.view-1l6ymczPK5SceF4d0DCtAnWZuvmKn6s8oBUxHr", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + }, + }, + }, + }, { name: "MatchingNamespace/CSVPresent/Found", expectedEqual: true, @@ -4553,7 +4959,7 @@ func TestSyncOperatorGroups(t *testing.T) { role, roleBinding, }, - crds: []runtime.Object{crd}, + crds: []*apiextensionsv1.CustomResourceDefinition{crd}, }, expectedStatus: operatorsv1.OperatorGroupStatus{ Namespaces: []string{operatorNamespace, targetNamespace}, @@ -4656,7 +5062,7 @@ func TestSyncOperatorGroups(t *testing.T) { role, roleBinding, }, - crds: []runtime.Object{crd}, + crds: []*apiextensionsv1.CustomResourceDefinition{crd}, }, expectedStatus: operatorsv1.OperatorGroupStatus{ Namespaces: []string{operatorNamespace, targetNamespace}, @@ -4762,7 +5168,7 @@ func TestSyncOperatorGroups(t *testing.T) { role, roleBinding, }, - crds: []runtime.Object{crd}, + crds: []*apiextensionsv1.CustomResourceDefinition{crd}, }, expectedStatus: operatorsv1.OperatorGroupStatus{ Namespaces: []string{corev1.NamespaceAll}, @@ -4925,7 +5331,7 @@ func TestSyncOperatorGroups(t *testing.T) { role, roleBinding, }, - crds: []runtime.Object{crd}, + crds: []*apiextensionsv1.CustomResourceDefinition{crd}, }, expectedStatus: operatorsv1.OperatorGroupStatus{ Namespaces: []string{corev1.NamespaceAll}, @@ -4982,7 +5388,7 @@ func TestSyncOperatorGroups(t *testing.T) { operatorGroup = tt.initial.operatorGroup.DeepCopy() clientObjs = copyObjs(append(tt.initial.clientObjs, operatorGroup)) k8sObjs = copyObjs(tt.initial.k8sObjs) - extObjs = copyObjs(tt.initial.crds) + extObjs []runtime.Object regObjs = copyObjs(tt.initial.apis) ) @@ -4992,11 +5398,25 @@ func TestSyncOperatorGroups(t *testing.T) { var partials []runtime.Object for _, csv := range tt.initial.csvs { - clientObjs = append(clientObjs, csv) + clientObjs = append(clientObjs, csv.DeepCopy()) partials = append(partials, &metav1.PartialObjectMetadata{ + TypeMeta: metav1.TypeMeta{ + Kind: "ClusterServiceVersion", + APIVersion: v1alpha1.SchemeGroupVersion.String(), + }, ObjectMeta: csv.ObjectMeta, }) } + for _, crd := range tt.initial.crds { + extObjs = append(extObjs, crd.DeepCopy()) + partials = append(partials, &metav1.PartialObjectMetadata{ + TypeMeta: metav1.TypeMeta{ + Kind: "CustomResourceDefinition", + APIVersion: apiextensionsv1.SchemeGroupVersion.String(), + }, + ObjectMeta: crd.ObjectMeta, + }) + } l := logrus.New() l.SetLevel(logrus.DebugLevel) l = l.WithField("test", tt.name).Logger @@ -5094,12 +5514,12 @@ func TestSyncOperatorGroups(t *testing.T) { t.Log("op.syncClusterServiceVersion") if err := op.syncClusterServiceVersion(&csv); err != nil { - return false, err + return false, fmt.Errorf("failed to syncClusterServiceVersion: %w", err) } t.Log("op.syncCopyCSV") if err := op.syncCopyCSV(&csv); err != nil && !tt.ignoreCopyError { - return false, err + return false, fmt.Errorf("failed to syncCopyCSV: %w", err) } } @@ -5349,7 +5769,10 @@ func RequireObjectsInCache(t *testing.T, lister operatorlister.OperatorLister, n require.Failf(t, "couldn't find expected object", "%#v", object) } if err != nil { - return fmt.Errorf("namespace: %v, error: %v", namespace, err) + if apierrors.IsNotFound(err) { + return err + } + return errors.Join(err, fmt.Errorf("namespace: %v, error: %v", namespace, err)) } if doCompare { if !reflect.DeepEqual(object, fetched) { diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go index 745048cbb0..92c70c649f 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go @@ -2,35 +2,49 @@ package olm import ( "context" + "crypto/sha256" "fmt" "hash/fnv" + "math/big" "reflect" "strings" - utillabels "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/labels" + "k8s.io/apimachinery/pkg/api/equality" + "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/errors" + utillabels "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/labels" + operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" "github.com/operator-framework/api/pkg/operators/v1alpha1" + opregistry "github.com/operator-framework/operator-registry/pkg/registry" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/decorators" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/cache" hashutil "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/hash" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil" - opregistry "github.com/operator-framework/operator-registry/pkg/registry" ) const ( AdminSuffix = "admin" EditSuffix = "edit" ViewSuffix = "view" + + // kubeResourceNameLimit is the maximum length of a Kubernetes resource name + kubeResourceNameLimit = 253 + + // operatorGroupClusterRoleNameFmt template for ClusterRole names owned by OperatorGroups\ + // e.g. olm.og.my-group.admin- + operatorGroupClusterRoleNameFmt = "olm.og.%s.%s-%s" ) var ( @@ -65,6 +79,8 @@ func (a *Operator) syncOperatorGroups(obj interface{}) error { "namespace": op.GetNamespace(), }) + logger.Infof("syncing OperatorGroup %s/%s", op.GetNamespace(), op.GetName()) + // Query OG in this namespace groups, err := a.lister.OperatorsV1().OperatorGroupLister().OperatorGroups(op.GetNamespace()).List(labels.Everything()) if err != nil { @@ -382,7 +398,8 @@ func (a *Operator) ensureProvidedAPIClusterRole(namePrefix, suffix string, verbs // Matches aggregation rules on the bootstrap ClusterRoles. // https://github.com/kubernetes/kubernetes/blob/61847eab61788fb0543b4cf147773c9da646ed2f/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go#L232 fmt.Sprintf("rbac.authorization.k8s.io/aggregate-to-%s", suffix): "true", - aggregationLabel: "true", + aggregationLabel: "true", + install.OLMManagedLabelKey: install.OLMManagedLabelValue, }, OwnerReferences: []metav1.OwnerReference{ownerutil.NonBlockingOwner(api)}, }, @@ -422,6 +439,7 @@ func (a *Operator) ensureClusterRolesForCSV(csv *v1alpha1.ClusterServiceVersion) if err != nil { return fmt.Errorf("crd %q not found: %s", owned.Name, err.Error()) } + crd.SetGroupVersionKind(apiextensionsv1.SchemeGroupVersion.WithKind("customresourcedefinition")) nameGroupPair := strings.SplitN(owned.Name, ".", 2) // -> etcdclusters etcd.database.coreos.com if len(nameGroupPair) != 2 { return fmt.Errorf("invalid parsing of name '%v', got %v", owned.Name, nameGroupPair) @@ -978,58 +996,88 @@ func (a *Operator) updateNamespaceList(op *operatorsv1.OperatorGroup) ([]string, return namespaceList, nil } -func (a *Operator) ensureOpGroupClusterRole(op *operatorsv1.OperatorGroup, suffix string, apis cache.APISet) error { - clusterRole := &rbacv1.ClusterRole{ - ObjectMeta: metav1.ObjectMeta{ - Name: strings.Join([]string{op.GetName(), suffix}, "-"), - }, - } - var selectors []metav1.LabelSelector - for api := range apis { - aggregationLabel, err := aggregationLabelFromAPIKey(api, suffix) - if err != nil { - return err - } - selectors = append(selectors, metav1.LabelSelector{ - MatchLabels: map[string]string{ - aggregationLabel: "true", - }, - }) +func (a *Operator) getClusterRoleName(op *operatorsv1.OperatorGroup, roleType string) (string, error) { + roleSuffix := hash(fmt.Sprintf("%s/%s/%s", op.GetNamespace(), op.GetName(), roleType)) + // calculate how many characters are left for the operator group name + nameLimit := kubeResourceNameLimit - len(strings.Replace(operatorGroupClusterRoleNameFmt, "%s", "", -1)) - len(roleType) - len(roleSuffix) + if len(op.GetName()) < nameLimit { + return fmt.Sprintf(operatorGroupClusterRoleNameFmt, op.GetName(), roleType, roleSuffix), nil } - if len(selectors) > 0 { - clusterRole.AggregationRule = &rbacv1.AggregationRule{ - ClusterRoleSelectors: selectors, - } + return fmt.Sprintf(operatorGroupClusterRoleNameFmt, op.GetName()[:nameLimit], roleType, roleSuffix), nil +} + +func (a *Operator) ensureOpGroupClusterRole(op *operatorsv1.OperatorGroup, suffix string, apis cache.APISet) error { + // create target cluster role spec + var clusterRole *rbacv1.ClusterRole + clusterRoleName, err := a.getClusterRoleName(op, suffix) + if err != nil { + return err } - err := ownerutil.AddOwnerLabels(clusterRole, op) + aggregationRule, err := a.getClusterRoleAggregationRule(apis, suffix) if err != nil { return err } - existingRole, err := a.lister.RbacV1().ClusterRoleLister().Get(clusterRole.Name) + // get existing cluster role for this level (suffix: admin, edit, view)) + existingRole, err := a.lister.RbacV1().ClusterRoleLister().Get(clusterRoleName) if err != nil && !apierrors.IsNotFound(err) { return err } - if apierrors.IsNotFound(err) { - existingRole, err = a.opClient.KubernetesInterface().RbacV1().ClusterRoles().Create(context.TODO(), clusterRole, metav1.CreateOptions{}) - if err == nil { + + if existingRole != nil { + // if the existing role conforms to the naming convention, check for skew + cp := existingRole.DeepCopy() + if err := ownerutil.AddOwnerLabels(cp, op); err != nil { + return err + } + + // ensure that the labels and aggregation rules are correct + if labels.Equals(existingRole.Labels, cp.Labels) && equality.Semantic.DeepEqual(existingRole.AggregationRule, aggregationRule) { return nil } - if !apierrors.IsAlreadyExists(err) { - a.logger.WithError(err).Errorf("Create cluster role failed: %v", clusterRole) - return err + + cp.AggregationRule = aggregationRule + if _, err := a.opClient.UpdateClusterRole(cp); err != nil { + a.logger.WithError(err).Errorf("update existing cluster role failed: %v", clusterRole) } + return err } - if existingRole != nil && labels.Equals(existingRole.Labels, clusterRole.Labels) && reflect.DeepEqual(existingRole.AggregationRule, clusterRole.AggregationRule) { - return nil + clusterRole = &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: clusterRoleName, + }, + AggregationRule: aggregationRule, } - if _, err := a.opClient.UpdateClusterRole(clusterRole); err != nil { - a.logger.WithError(err).Errorf("Update existing cluster role failed: %v", clusterRole) + if err := ownerutil.AddOwnerLabels(clusterRole, op); err != nil { return err } - return nil + + a.logger.Infof("creating cluster role: %s owned by operator group: %s/%s", clusterRole.GetName(), op.GetNamespace(), op.GetName()) + _, err = a.opClient.KubernetesInterface().RbacV1().ClusterRoles().Create(context.TODO(), clusterRole, metav1.CreateOptions{}) + return err +} + +func (a *Operator) getClusterRoleAggregationRule(apis cache.APISet, suffix string) (*rbacv1.AggregationRule, error) { + var selectors []metav1.LabelSelector + for api := range apis { + aggregationLabel, err := aggregationLabelFromAPIKey(api, suffix) + if err != nil { + return nil, err + } + selectors = append(selectors, metav1.LabelSelector{ + MatchLabels: map[string]string{ + aggregationLabel: "true", + }, + }) + } + if len(selectors) > 0 { + return &rbacv1.AggregationRule{ + ClusterRoleSelectors: selectors, + }, nil + } + return nil, nil } func (a *Operator) ensureOpGroupClusterRoles(op *operatorsv1.OperatorGroup, apis cache.APISet) error { @@ -1126,3 +1174,13 @@ func csvCopyPrototype(src, dst *v1alpha1.ClusterServiceVersion) { dst.Status.Reason = v1alpha1.CSVReasonCopied dst.Status.Message = fmt.Sprintf("The operator is running in %s but is managing this namespace", src.GetNamespace()) } + +func hash(s string) string { + return toBase62(sha256.Sum224([]byte(s))) +} + +func toBase62(hash [28]byte) string { + var i big.Int + i.SetBytes(hash[:]) + return i.Text(62) +} diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/plugins/operator_plugin.go b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/plugins/operator_plugin.go index 8ab49e4d91..0f38f0543b 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/plugins/operator_plugin.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/plugins/operator_plugin.go @@ -11,7 +11,6 @@ import ( "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer" "github.com/sirupsen/logrus" - extensionsv1informers "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1" appsv1informers "k8s.io/client-go/informers/apps/v1" corev1informers "k8s.io/client-go/informers/core/v1" rbacv1informers "k8s.io/client-go/informers/rbac/v1" @@ -49,7 +48,8 @@ type Informers struct { ClusterRoleBindingInformer rbacv1informers.ClusterRoleBindingInformer NamespaceInformer corev1informers.NamespaceInformer APIServiceInformer apiregistrationv1informers.APIServiceInformer - CRDInformer extensionsv1informers.CustomResourceDefinitionInformer + CRDInformer cache.SharedIndexInformer + CRDLister metadatalister.Lister } // OperatorConfig gives access to required configuration from the host operator diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/requirements.go b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/requirements.go index f4d408121c..0c288b8e36 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/requirements.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/requirements.go @@ -1,6 +1,7 @@ package olm import ( + "context" "encoding/json" "fmt" "strings" @@ -94,7 +95,7 @@ func (a *Operator) requirementStatus(strategyDetailsDeployment *v1alpha1.Strateg } // check if CRD exists - this verifies group, version, and kind, so no need for GVK check via discovery - crd, err := a.lister.APIExtensionsV1().CustomResourceDefinitionLister().Get(r.Name) + crd, err := a.opClient.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), r.Name, metav1.GetOptions{}) if err != nil { status.Status = v1alpha1.RequirementStatusReasonNotPresent status.Message = "CRD is not present" diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go b/staging/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go index 45e85e44cb..c805977c01 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go @@ -5,11 +5,12 @@ import ( "reflect" "github.com/go-logr/logr" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" - meta "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -128,6 +129,9 @@ func (r *OperatorConditionReconciler) ensureOperatorConditionRole(operatorCondit ObjectMeta: metav1.ObjectMeta{ Name: operatorCondition.GetName(), Namespace: operatorCondition.GetNamespace(), + Labels: map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + }, }, Rules: []rbacv1.PolicyRule{ { @@ -176,6 +180,9 @@ func (r *OperatorConditionReconciler) ensureOperatorConditionRoleBinding(operato ObjectMeta: metav1.ObjectMeta{ Name: operatorCondition.GetName(), Namespace: operatorCondition.GetNamespace(), + Labels: map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + }, }, Subjects: subjects, RoleRef: rbacv1.RoleRef{ diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/validatingroundtripper/validating_round_tripper.go b/staging/operator-lifecycle-manager/pkg/controller/operators/validatingroundtripper/validating_round_tripper.go new file mode 100644 index 0000000000..c9c1cbd395 --- /dev/null +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/validatingroundtripper/validating_round_tripper.go @@ -0,0 +1,53 @@ +package validatingroundtripper + +import ( + "fmt" + "net/http" + "os" + + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/util/yaml" + "k8s.io/client-go/rest" +) + +type validatingRoundTripper struct { + delegate http.RoundTripper +} + +func (rt *validatingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + if req.Method == "POST" { + b, err := req.GetBody() + if err != nil { + panic(err) + } + dec := yaml.NewYAMLOrJSONDecoder(b, 10) + unstructuredObject := &unstructured.Unstructured{} + if err := dec.Decode(unstructuredObject); err != nil { + panic(fmt.Errorf("error decoding object to an unstructured object: %w", err)) + } + gvk := unstructuredObject.GroupVersionKind() + if gvk.Kind != "Event" { + if labels := unstructuredObject.GetLabels(); labels[install.OLMManagedLabelKey] != install.OLMManagedLabelValue { + panic(fmt.Errorf("%s.%s/%v %s/%s does not have labels[%s]=%s", gvk.Kind, gvk.Group, gvk.Version, unstructuredObject.GetNamespace(), unstructuredObject.GetName(), install.OLMManagedLabelKey, install.OLMManagedLabelValue)) + } + } + } + return rt.delegate.RoundTrip(req) +} + +var _ http.RoundTripper = (*validatingRoundTripper)(nil) + +// Wrap is meant to be used in developer environments and CI to make it easy to find places +// where we accidentally create Kubernetes objects without our management label. +func Wrap(cfg *rest.Config) *rest.Config { + if _, set := os.LookupEnv("CI"); !set { + return cfg + } + + cfgCopy := *cfg + cfgCopy.Wrap(func(rt http.RoundTripper) http.RoundTripper { + return &validatingRoundTripper{delegate: rt} + }) + return &cfgCopy +} diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/configmap.go b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/configmap.go index 11a87a8746..1b6a97b075 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/configmap.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/configmap.go @@ -5,6 +5,7 @@ import ( "context" "fmt" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" "github.com/pkg/errors" "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" @@ -52,7 +53,8 @@ const ( func (s *configMapCatalogSourceDecorator) Labels() map[string]string { labels := map[string]string{ - CatalogSourceLabelKey: s.GetName(), + CatalogSourceLabelKey: s.GetName(), + install.OLMManagedLabelKey: install.OLMManagedLabelValue, } if s.Spec.SourceType == v1alpha1.SourceTypeInternal || s.Spec.SourceType == v1alpha1.SourceTypeConfigmap { labels[ConfigMapRVLabelKey] = s.Status.ConfigMapResource.ResourceVersion @@ -93,7 +95,9 @@ func (s *configMapCatalogSourceDecorator) Service() *corev1.Service { }, } - labels := map[string]string{} + labels := map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + } hash := HashServiceSpec(svc.Spec) labels[ServiceHashLabelKey] = hash svc.SetLabels(labels) @@ -102,7 +106,7 @@ func (s *configMapCatalogSourceDecorator) Service() *corev1.Service { } func (s *configMapCatalogSourceDecorator) Pod(image string) *corev1.Pod { - pod := Pod(s.CatalogSource, "configmap-registry-server", image, "", s.Labels(), s.Annotations(), 5, 5, s.runAsUser) + pod := Pod(s.CatalogSource, "configmap-registry-server", "", "", image, "", s.Labels(), s.Annotations(), 5, 5, s.runAsUser) pod.Spec.ServiceAccountName = s.GetName() + ConfigMapServerPostfix pod.Spec.Containers[0].Command = []string{"configmap-server", "-c", s.Spec.ConfigMap, "-n", s.GetNamespace()} ownerutil.AddOwner(pod, s.CatalogSource, false, true) @@ -114,6 +118,9 @@ func (s *configMapCatalogSourceDecorator) ServiceAccount() *corev1.ServiceAccoun ObjectMeta: metav1.ObjectMeta{ Name: s.serviceAccountName(), Namespace: s.GetNamespace(), + Labels: map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + }, }, } ownerutil.AddOwner(sa, s.CatalogSource, false, false) @@ -125,6 +132,9 @@ func (s *configMapCatalogSourceDecorator) Role() *rbacv1.Role { ObjectMeta: metav1.ObjectMeta{ Name: s.roleName(), Namespace: s.GetNamespace(), + Labels: map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + }, }, Rules: []rbacv1.PolicyRule{ { @@ -144,6 +154,9 @@ func (s *configMapCatalogSourceDecorator) RoleBinding() *rbacv1.RoleBinding { ObjectMeta: metav1.ObjectMeta{ Name: s.GetName() + "-server-configmap-reader", Namespace: s.GetNamespace(), + Labels: map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + }, }, Subjects: []rbacv1.Subject{ { diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/configmap_test.go b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/configmap_test.go index 281217a1bf..e9d987bf9c 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/configmap_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/configmap_test.go @@ -198,7 +198,7 @@ func objectsForCatalogSource(catsrc *v1alpha1.CatalogSource) []runtime.Object { ) case v1alpha1.SourceTypeGrpc: if catsrc.Spec.Image != "" { - decorated := grpcCatalogSourceDecorator{catsrc, runAsUser} + decorated := grpcCatalogSourceDecorator{CatalogSource: catsrc, createPodAsUser: runAsUser, opmImage: ""} objs = clientfake.AddSimpleGeneratedNames( decorated.Pod(catsrc.GetName()), decorated.Service(), diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc.go b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc.go index 117c081b23..b92658f5ab 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc.go @@ -4,8 +4,10 @@ import ( "context" "fmt" "hash/fnv" + "strings" "time" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" "github.com/pkg/errors" "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" @@ -33,6 +35,8 @@ const ( type grpcCatalogSourceDecorator struct { *v1alpha1.CatalogSource createPodAsUser int64 + opmImage string + utilImage string } type UpdateNotReadyErr struct { @@ -58,7 +62,8 @@ func (s *grpcCatalogSourceDecorator) SelectorForUpdate() labels.Selector { func (s *grpcCatalogSourceDecorator) Labels() map[string]string { return map[string]string{ - CatalogSourceLabelKey: s.GetName(), + CatalogSourceLabelKey: s.GetName(), + install.OLMManagedLabelKey: install.OLMManagedLabelValue, } } @@ -70,7 +75,7 @@ func (s *grpcCatalogSourceDecorator) Annotations() map[string]string { func (s *grpcCatalogSourceDecorator) Service() *corev1.Service { svc := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: s.GetName(), + Name: strings.ReplaceAll(s.GetName(), ".", "-"), Namespace: s.GetNamespace(), }, Spec: corev1.ServiceSpec{ @@ -88,6 +93,7 @@ func (s *grpcCatalogSourceDecorator) Service() *corev1.Service { labels := map[string]string{} hash := HashServiceSpec(svc.Spec) labels[ServiceHashLabelKey] = hash + labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue svc.SetLabels(labels) ownerutil.AddOwner(svc, s.CatalogSource, false, false) return svc @@ -107,6 +113,7 @@ func (s *grpcCatalogSourceDecorator) ServiceAccount() *corev1.ServiceAccount { ObjectMeta: metav1.ObjectMeta{ Name: s.GetName(), Namespace: s.GetNamespace(), + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ { Name: s.GetName(), @@ -123,7 +130,7 @@ func (s *grpcCatalogSourceDecorator) ServiceAccount() *corev1.ServiceAccount { } func (s *grpcCatalogSourceDecorator) Pod(saName string) *corev1.Pod { - pod := Pod(s.CatalogSource, "registry-server", s.Spec.Image, saName, s.Labels(), s.Annotations(), 5, 10, s.createPodAsUser) + pod := Pod(s.CatalogSource, "registry-server", s.opmImage, s.utilImage, s.Spec.Image, saName, s.Labels(), s.Annotations(), 5, 10, s.createPodAsUser) ownerutil.AddOwner(pod, s.CatalogSource, false, true) return pod } @@ -134,6 +141,8 @@ type GrpcRegistryReconciler struct { OpClient operatorclient.ClientInterface SSAClient *controllerclient.ServerSideApplier createPodAsUser int64 + opmImage string + utilImage string } var _ RegistryReconciler = &GrpcRegistryReconciler{} @@ -191,16 +200,25 @@ func (c *GrpcRegistryReconciler) currentPodsWithCorrectImageAndSpec(source grpcC found := []*corev1.Pod{} newPod := source.Pod(saName) for _, p := range pods { - if p.Spec.Containers[0].Image == source.Spec.Image && podHashMatch(p, newPod) { + if correctImages(source, p) && podHashMatch(p, newPod) { found = append(found, p) } } return found } +func correctImages(source grpcCatalogSourceDecorator, pod *corev1.Pod) bool { + if source.CatalogSource.Spec.GrpcPodConfig != nil && source.CatalogSource.Spec.GrpcPodConfig.ExtractContent != nil { + return pod.Spec.InitContainers[0].Image == source.utilImage && + pod.Spec.InitContainers[1].Image == source.CatalogSource.Spec.Image && + pod.Spec.Containers[0].Image == source.opmImage + } + return pod.Spec.Containers[0].Image == source.CatalogSource.Spec.Image +} + // EnsureRegistryServer ensures that all components of registry server are up to date. func (c *GrpcRegistryReconciler) EnsureRegistryServer(catalogSource *v1alpha1.CatalogSource) error { - source := grpcCatalogSourceDecorator{catalogSource, c.createPodAsUser} + source := grpcCatalogSourceDecorator{CatalogSource: catalogSource, createPodAsUser: c.createPodAsUser, opmImage: c.opmImage, utilImage: c.utilImage} // if service status is nil, we force create every object to ensure they're created the first time overwrite := source.Status.RegistryServiceStatus == nil || !isRegistryServiceStatusValid(&source) @@ -449,7 +467,7 @@ func (c *GrpcRegistryReconciler) removePods(pods []*corev1.Pod, namespace string // CheckRegistryServer returns true if the given CatalogSource is considered healthy; false otherwise. func (c *GrpcRegistryReconciler) CheckRegistryServer(catalogSource *v1alpha1.CatalogSource) (healthy bool, err error) { - source := grpcCatalogSourceDecorator{catalogSource, c.createPodAsUser} + source := grpcCatalogSourceDecorator{CatalogSource: catalogSource, createPodAsUser: c.createPodAsUser, opmImage: c.opmImage, utilImage: c.utilImage} // Check on registry resources // TODO: add gRPC health check if len(c.currentPodsWithCorrectImageAndSpec(source, source.ServiceAccount().GetName())) < 1 || diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc_test.go b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc_test.go index c219329b3d..696c292547 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc_test.go @@ -2,9 +2,12 @@ package reconciler import ( "context" + "fmt" "testing" "time" + "github.com/google/go-cmp/cmp" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -61,6 +64,13 @@ func grpcCatalogSourceWithAnnotations(annotations map[string]string) *v1alpha1.C return catsrc } +func grpcCatalogSourceWithName(name string) *v1alpha1.CatalogSource { + catsrc := validGrpcCatalogSource("image", "") + catsrc.SetName(name) + catsrc.ObjectMeta.Labels["olm.catalogSource"] = name + return catsrc +} + func TestGrpcRegistryReconciler(t *testing.T) { now := func() metav1.Time { return metav1.Date(2018, time.January, 26, 20, 40, 0, 0, time.UTC) } blockOwnerDeletion := true @@ -102,6 +112,21 @@ func TestGrpcRegistryReconciler(t *testing.T) { }, }, }, + { + testName: "Grpc/NoExistingRegistry/CreateSuccessful/CatalogSourceWithPeriodInNameCreatesValidServiceName", + in: in{ + catsrc: grpcCatalogSourceWithName("img.catalog"), + }, + out: out{ + status: &v1alpha1.RegistryServiceStatus{ + CreatedAt: now(), + Protocol: "grpc", + ServiceName: "img-catalog", + ServiceNamespace: testNamespace, + Port: "50051", + }, + }, + }, { testName: "Grpc/ExistingRegistry/CreateSuccessful", in: in{ @@ -250,6 +275,7 @@ func TestGrpcRegistryReconciler(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "private-catalog", Namespace: testNamespace, + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ { Name: "private-catalog", @@ -331,7 +357,7 @@ func TestGrpcRegistryReconciler(t *testing.T) { } // Check for resource existence - decorated := grpcCatalogSourceDecorator{tt.in.catsrc, runAsUser} + decorated := grpcCatalogSourceDecorator{CatalogSource: tt.in.catsrc, createPodAsUser: runAsUser} pod := decorated.Pod(tt.in.catsrc.GetName()) service := decorated.Service() sa := decorated.ServiceAccount() @@ -343,6 +369,9 @@ func TestGrpcRegistryReconciler(t *testing.T) { case *GrpcRegistryReconciler: // Should be created by a GrpcRegistryReconciler require.NoError(t, podErr) + if diff := cmp.Diff(outPods.Items, []corev1.Pod{*pod}); diff != "" { + fmt.Printf("incorrect pods: %s\n", diff) + } require.Len(t, outPods.Items, 1) outPod := outPods.Items[0] require.Equal(t, pod.GetGenerateName(), outPod.GetGenerateName()) @@ -421,7 +450,7 @@ func TestRegistryPodPriorityClass(t *testing.T) { require.NoError(t, err) // Check for resource existence - decorated := grpcCatalogSourceDecorator{tt.in.catsrc, runAsUser} + decorated := grpcCatalogSourceDecorator{CatalogSource: tt.in.catsrc, createPodAsUser: runAsUser} pod := decorated.Pod(tt.in.catsrc.GetName()) listOptions := metav1.ListOptions{LabelSelector: labels.SelectorFromSet(labels.Set{CatalogSourceLabelKey: tt.in.catsrc.GetName()}).String()} outPods, podErr := client.KubernetesInterface().CoreV1().Pods(pod.GetNamespace()).List(context.TODO(), listOptions) diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/reconciler.go b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/reconciler.go index 88a421a713..d2f120de20 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/reconciler.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/reconciler.go @@ -4,7 +4,9 @@ package reconciler import ( "fmt" "hash/fnv" + "path/filepath" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -63,6 +65,8 @@ type registryReconcilerFactory struct { ConfigMapServerImage string SSAClient *controllerclient.ServerSideApplier createPodAsUser int64 + opmImage string + utilImage string } // ReconcilerForSource returns a RegistryReconciler based on the configuration of the given CatalogSource. @@ -85,6 +89,8 @@ func (r *registryReconcilerFactory) ReconcilerForSource(source *operatorsv1alpha OpClient: r.OpClient, SSAClient: r.SSAClient, createPodAsUser: r.createPodAsUser, + opmImage: r.opmImage, + utilImage: r.utilImage, } } else if source.Spec.Address != "" { return &GrpcAddressRegistryReconciler{ @@ -96,7 +102,7 @@ func (r *registryReconcilerFactory) ReconcilerForSource(source *operatorsv1alpha } // NewRegistryReconcilerFactory returns an initialized RegistryReconcilerFactory. -func NewRegistryReconcilerFactory(lister operatorlister.OperatorLister, opClient operatorclient.ClientInterface, configMapServerImage string, now nowFunc, ssaClient *controllerclient.ServerSideApplier, createPodAsUser int64) RegistryReconcilerFactory { +func NewRegistryReconcilerFactory(lister operatorlister.OperatorLister, opClient operatorclient.ClientInterface, configMapServerImage string, now nowFunc, ssaClient *controllerclient.ServerSideApplier, createPodAsUser int64, opmImage, utilImage string) RegistryReconcilerFactory { return ®istryReconcilerFactory{ now: now, Lister: lister, @@ -104,10 +110,12 @@ func NewRegistryReconcilerFactory(lister operatorlister.OperatorLister, opClient ConfigMapServerImage: configMapServerImage, SSAClient: ssaClient, createPodAsUser: createPodAsUser, + opmImage: opmImage, + utilImage: utilImage, } } -func Pod(source *operatorsv1alpha1.CatalogSource, name string, img string, saName string, labels map[string]string, annotations map[string]string, readinessDelay int32, livenessDelay int32, runAsUser int64) *corev1.Pod { +func Pod(source *operatorsv1alpha1.CatalogSource, name, opmImg, utilImage, img, saName string, labels, annotations map[string]string, readinessDelay, livenessDelay int32, runAsUser int64) *corev1.Pod { // make a copy of the labels and annotations to avoid mutating the input parameters podLabels := make(map[string]string) podAnnotations := make(map[string]string) @@ -115,6 +123,7 @@ func Pod(source *operatorsv1alpha1.CatalogSource, name string, img string, saNam for key, value := range labels { podLabels[key] = value } + podLabels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue for key, value := range annotations { podAnnotations[key] = value @@ -227,9 +236,6 @@ func Pod(source *operatorsv1alpha1.CatalogSource, name string, img string, saNam if pod.Spec.Containers[0].Resources.Limits == nil { pod.Spec.Containers[0].Resources.Limits = map[corev1.ResourceName]resource.Quantity{} } - double := *grpcPodConfig.MemoryTarget - double.Add(double.DeepCopy()) - pod.Spec.Containers[0].Resources.Limits[corev1.ResourceMemory] = double grpcPodConfig.MemoryTarget.Format = resource.BinarySI pod.Spec.Containers[0].Env = append(pod.Spec.Containers[0].Env, corev1.EnvVar{ @@ -237,6 +243,58 @@ func Pod(source *operatorsv1alpha1.CatalogSource, name string, img string, saNam Value: grpcPodConfig.MemoryTarget.String() + "B", // k8s resources use Mi, GOMEMLIMIT wants MiB }) } + + // Reconfigure pod to extract content + if grpcPodConfig.ExtractContent != nil { + pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{ + Name: "utilities", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, corev1.Volume{ + Name: "catalog-content", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }) + const utilitiesPath = "/utilities" + utilitiesVolumeMount := corev1.VolumeMount{ + Name: "utilities", + MountPath: utilitiesPath, + } + const catalogPath = "/extracted-catalog" + contentVolumeMount := corev1.VolumeMount{ + Name: "catalog-content", + MountPath: catalogPath, + } + pod.Spec.InitContainers = append(pod.Spec.InitContainers, corev1.Container{ + Name: "extract-utilities", + Image: utilImage, + Command: []string{"cp"}, + Args: []string{"/bin/copy-content", fmt.Sprintf("%s/copy-content", utilitiesPath)}, + VolumeMounts: []corev1.VolumeMount{utilitiesVolumeMount}, + }, corev1.Container{ + Name: "extract-content", + Image: img, + Command: []string{utilitiesPath + "/copy-content"}, + Args: []string{ + "--catalog.from=" + grpcPodConfig.ExtractContent.CatalogDir, + "--catalog.to=" + fmt.Sprintf("%s/catalog", catalogPath), + "--cache.from=" + grpcPodConfig.ExtractContent.CacheDir, + "--cache.to=" + fmt.Sprintf("%s/cache", catalogPath), + }, + VolumeMounts: []corev1.VolumeMount{utilitiesVolumeMount, contentVolumeMount}, + }) + + pod.Spec.Containers[0].Image = opmImg + pod.Spec.Containers[0].Command = []string{"/bin/opm"} + pod.Spec.Containers[0].Args = []string{ + "serve", + filepath.Join(catalogPath, "catalog"), + "--cache-dir=" + filepath.Join(catalogPath, "cache"), + } + pod.Spec.Containers[0].VolumeMounts = append(pod.Spec.Containers[0].VolumeMounts, contentVolumeMount) + } } // Set priorityclass if its annotation exists diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/reconciler_test.go b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/reconciler_test.go index 7535107a60..4055b6312f 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/reconciler_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/reconciler_test.go @@ -35,7 +35,7 @@ func TestPodMemoryTarget(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ GenerateName: "test-", Namespace: "testns", - Labels: map[string]string{"olm.pod-spec-hash": "68d7885bb7"}, + Labels: map[string]string{"olm.pod-spec-hash": "68d7885bb7", "olm.managed": "true"}, Annotations: map[string]string{"cluster-autoscaler.kubernetes.io/safe-to-evict": "true"}, }, Spec: corev1.PodSpec{ @@ -107,7 +107,7 @@ func TestPodMemoryTarget(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ GenerateName: "test-", Namespace: "testns", - Labels: map[string]string{"olm.pod-spec-hash": "855b6c6cf6"}, + Labels: map[string]string{"olm.pod-spec-hash": "5c6bb6945f", "olm.managed": "true"}, Annotations: map[string]string{"cluster-autoscaler.kubernetes.io/safe-to-evict": "true"}, }, Spec: corev1.PodSpec{ @@ -150,8 +150,200 @@ func TestPodMemoryTarget(t *testing.T) { corev1.ResourceCPU: resource.MustParse("10m"), corev1.ResourceMemory: resource.MustParse("5Mi"), }, - Limits: corev1.ResourceList{ - corev1.ResourceMemory: resource.MustParse("10Mi"), + Limits: corev1.ResourceList{}, + }, + SecurityContext: &corev1.SecurityContext{ + ReadOnlyRootFilesystem: pointer.Bool(false), + }, + ImagePullPolicy: image.InferImagePullPolicy("image"), + TerminationMessagePolicy: "FallbackToLogsOnError", + }, + }, + NodeSelector: map[string]string{"kubernetes.io/os": "linux"}, + ServiceAccountName: "service-account", + }, + }, + }, + } + + for _, testCase := range testCases { + pod := Pod(testCase.input, "name", "opmImage", "utilImage", "image", "service-account", map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID)) + if diff := cmp.Diff(pod, testCase.expected); diff != "" { + t.Errorf("got incorrect pod: %v", diff) + } + } +} + +func TestPodExtractContent(t *testing.T) { + var testCases = []struct { + name string + input *v1alpha1.CatalogSource + expected *corev1.Pod + }{ + { + name: "content extraction not requested", + input: &v1alpha1.CatalogSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "testns", + }, + }, + expected: &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "test-", + Namespace: "testns", + Labels: map[string]string{"olm.pod-spec-hash": "68d7885bb7", "olm.managed": "true"}, + Annotations: map[string]string{"cluster-autoscaler.kubernetes.io/safe-to-evict": "true"}, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "name", + Image: "image", + Ports: []corev1.ContainerPort{{Name: "grpc", ContainerPort: 50051}}, + ReadinessProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + Exec: &corev1.ExecAction{ + Command: []string{"grpc_health_probe", "-addr=:50051"}, + }, + }, + InitialDelaySeconds: 0, + TimeoutSeconds: 5, + }, + LivenessProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + Exec: &corev1.ExecAction{ + Command: []string{"grpc_health_probe", "-addr=:50051"}, + }, + }, + InitialDelaySeconds: 0, + TimeoutSeconds: 5, + }, + StartupProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + Exec: &corev1.ExecAction{ + Command: []string{"grpc_health_probe", "-addr=:50051"}, + }, + }, + FailureThreshold: 10, + PeriodSeconds: 10, + TimeoutSeconds: 5, + }, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("10m"), + corev1.ResourceMemory: resource.MustParse("50Mi"), + }, + }, + SecurityContext: &corev1.SecurityContext{ + ReadOnlyRootFilesystem: pointer.Bool(false), + }, + ImagePullPolicy: image.InferImagePullPolicy("image"), + TerminationMessagePolicy: "FallbackToLogsOnError", + }, + }, + NodeSelector: map[string]string{"kubernetes.io/os": "linux"}, + ServiceAccountName: "service-account", + }, + }, + }, + { + name: "content extraction expected", + input: &v1alpha1.CatalogSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "testns", + }, + Spec: v1alpha1.CatalogSourceSpec{ + GrpcPodConfig: &v1alpha1.GrpcPodConfig{ + ExtractContent: &v1alpha1.ExtractContentConfig{ + CacheDir: "/tmp/cache", + CatalogDir: "/catalog", + }, + }, + }, + }, + expected: &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "test-", + Namespace: "testns", + Labels: map[string]string{"olm.pod-spec-hash": "667f4b9769", "olm.managed": "true"}, + Annotations: map[string]string{"cluster-autoscaler.kubernetes.io/safe-to-evict": "true"}, + }, + Spec: corev1.PodSpec{ + Volumes: []corev1.Volume{ + { + Name: "utilities", + VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}, + }, + { + Name: "catalog-content", + VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}, + }, + }, + InitContainers: []corev1.Container{ + { + Name: "extract-utilities", + Image: "utilImage", + Command: []string{"cp"}, + Args: []string{"/bin/copy-content", "/utilities/copy-content"}, + VolumeMounts: []corev1.VolumeMount{{Name: "utilities", MountPath: "/utilities"}}, + }, + { + Name: "extract-content", + Image: "image", + Command: []string{"/utilities/copy-content"}, + Args: []string{ + "--catalog.from=/catalog", + "--catalog.to=/extracted-catalog/catalog", + "--cache.from=/tmp/cache", + "--cache.to=/extracted-catalog/cache", + }, + VolumeMounts: []corev1.VolumeMount{ + {Name: "utilities", MountPath: "/utilities"}, + {Name: "catalog-content", MountPath: "/extracted-catalog"}, + }, + }, + }, + Containers: []corev1.Container{ + { + Name: "name", + Image: "opmImage", + Command: []string{"/bin/opm"}, + Args: []string{"serve", "/extracted-catalog/catalog", "--cache-dir=/extracted-catalog/cache"}, + Ports: []corev1.ContainerPort{{Name: "grpc", ContainerPort: 50051}}, + ReadinessProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + Exec: &corev1.ExecAction{ + Command: []string{"grpc_health_probe", "-addr=:50051"}, + }, + }, + InitialDelaySeconds: 0, + TimeoutSeconds: 5, + }, + LivenessProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + Exec: &corev1.ExecAction{ + Command: []string{"grpc_health_probe", "-addr=:50051"}, + }, + }, + InitialDelaySeconds: 0, + TimeoutSeconds: 5, + }, + StartupProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + Exec: &corev1.ExecAction{ + Command: []string{"grpc_health_probe", "-addr=:50051"}, + }, + }, + FailureThreshold: 10, + PeriodSeconds: 10, + TimeoutSeconds: 5, + }, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("10m"), + corev1.ResourceMemory: resource.MustParse("50Mi"), }, }, SecurityContext: &corev1.SecurityContext{ @@ -159,6 +351,7 @@ func TestPodMemoryTarget(t *testing.T) { }, ImagePullPolicy: image.InferImagePullPolicy("image"), TerminationMessagePolicy: "FallbackToLogsOnError", + VolumeMounts: []corev1.VolumeMount{{Name: "catalog-content", MountPath: "/extracted-catalog"}}, }, }, NodeSelector: map[string]string{"kubernetes.io/os": "linux"}, @@ -169,7 +362,7 @@ func TestPodMemoryTarget(t *testing.T) { } for _, testCase := range testCases { - pod := Pod(testCase.input, "name", "image", "service-account", map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID)) + pod := Pod(testCase.input, "name", "opmImage", "utilImage", "image", "service-account", map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID)) if diff := cmp.Diff(pod, testCase.expected); diff != "" { t.Errorf("got incorrect pod: %v", diff) } @@ -187,7 +380,7 @@ func TestPodNodeSelector(t *testing.T) { key := "kubernetes.io/os" value := "linux" - gotCatSrcPod := Pod(catsrc, "hello", "busybox", "", map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID)) + gotCatSrcPod := Pod(catsrc, "hello", "utilImage", "opmImage", "busybox", "", map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID)) gotCatSrcPodSelector := gotCatSrcPod.Spec.NodeSelector if gotCatSrcPodSelector[key] != value { @@ -235,7 +428,7 @@ func TestPullPolicy(t *testing.T) { } for _, tt := range table { - p := Pod(source, "catalog", tt.image, "", nil, nil, int32(0), int32(0), int64(workloadUserID)) + p := Pod(source, "catalog", "opmImage", "utilImage", tt.image, "", nil, nil, int32(0), int32(0), int64(workloadUserID)) policy := p.Spec.Containers[0].ImagePullPolicy if policy != tt.policy { t.Fatalf("expected pull policy %s for image %s", tt.policy, tt.image) @@ -347,7 +540,7 @@ func TestPodContainerSecurityContext(t *testing.T) { }, } for _, testcase := range testcases { - outputPod := Pod(testcase.inputCatsrc, "hello", "busybox", "", map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID)) + outputPod := Pod(testcase.inputCatsrc, "hello", "utilImage", "opmImage", "busybox", "", map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID)) if testcase.expectedSecurityContext != nil { require.Equal(t, testcase.expectedSecurityContext, outputPod.Spec.SecurityContext) } @@ -377,7 +570,7 @@ func TestPodAvoidsConcurrentWrite(t *testing.T) { "annotation": "somethingelse", } - gotPod := Pod(catsrc, "hello", "busybox", "", labels, annotations, int32(0), int32(0), int64(workloadUserID)) + gotPod := Pod(catsrc, "hello", "opmImage", "utilImage", "busybox", "", labels, annotations, int32(0), int32(0), int64(workloadUserID)) // check labels and annotations point to different addresses between parameters and what's in the pod require.NotEqual(t, &labels, &gotPod.Labels) @@ -606,7 +799,7 @@ func TestPodSchedulingOverrides(t *testing.T) { } for _, testCase := range testCases { - pod := Pod(testCase.catalogSource, "hello", "busybox", "", map[string]string{}, testCase.annotations, int32(0), int32(0), int64(workloadUserID)) + pod := Pod(testCase.catalogSource, "hello", "opmImage", "utilImage", "busybox", "", map[string]string{}, testCase.annotations, int32(0), int32(0), int64(workloadUserID)) require.Equal(t, testCase.expectedNodeSelectors, pod.Spec.NodeSelector) require.Equal(t, testCase.expectedPriorityClassName, pod.Spec.PriorityClassName) require.Equal(t, testCase.expectedTolerations, pod.Spec.Tolerations) diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/rbac.go b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/rbac.go index 45012df0e4..f0079e5016 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/rbac.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/rbac.go @@ -1,8 +1,11 @@ package resolver import ( + "crypto/sha256" + "encoding/json" "fmt" "hash/fnv" + "math/big" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -62,6 +65,37 @@ func (o *OperatorPermissions) AddClusterRoleBinding(clusterRoleBinding *rbacv1.C o.ClusterRoleBindings = append(o.ClusterRoleBindings, clusterRoleBinding) } +const ContentHashLabelKey = "olm.permissions.hash" + +func PolicyRuleHashLabelValue(rules []rbacv1.PolicyRule) (string, error) { + raw, err := json.Marshal(rules) + if err != nil { + return "", err + } + return toBase62(sha256.Sum224(raw)), nil +} + +func RoleReferenceAndSubjectHashLabelValue(roleRef rbacv1.RoleRef, subjects []rbacv1.Subject) (string, error) { + var container = struct { + RoleRef rbacv1.RoleRef + Subjects []rbacv1.Subject + }{ + RoleRef: roleRef, + Subjects: subjects, + } + raw, err := json.Marshal(&container) + if err != nil { + return "", err + } + return toBase62(sha256.Sum224(raw)), nil +} + +func toBase62(hash [28]byte) string { + var i big.Int + i.SetBytes(hash[:]) + return i.Text(62) +} + func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[string]*OperatorPermissions, error) { permissions := map[string]*OperatorPermissions{} @@ -100,6 +134,11 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri }, Rules: permission.Rules, } + hash, err := PolicyRuleHashLabelValue(permission.Rules) + if err != nil { + return nil, fmt.Errorf("failed to hash permission rules: %w", err) + } + role.Labels[ContentHashLabelKey] = hash permissions[permission.ServiceAccountName].AddRole(role) // Create RoleBinding @@ -120,6 +159,11 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri Namespace: csv.GetNamespace(), }}, } + hash, err = RoleReferenceAndSubjectHashLabelValue(roleBinding.RoleRef, roleBinding.Subjects) + if err != nil { + return nil, fmt.Errorf("failed to hash binding content: %w", err) + } + roleBinding.Labels[ContentHashLabelKey] = hash permissions[permission.ServiceAccountName].AddRoleBinding(roleBinding) } @@ -142,6 +186,11 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri }, Rules: permission.Rules, } + hash, err := PolicyRuleHashLabelValue(permission.Rules) + if err != nil { + return nil, fmt.Errorf("failed to hash permission rules: %w", err) + } + role.Labels[ContentHashLabelKey] = hash permissions[permission.ServiceAccountName].AddClusterRole(role) // Create ClusterRoleBinding @@ -162,6 +211,11 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri Namespace: csv.GetNamespace(), }}, } + hash, err = RoleReferenceAndSubjectHashLabelValue(roleBinding.RoleRef, roleBinding.Subjects) + if err != nil { + return nil, fmt.Errorf("failed to hash binding content: %w", err) + } + roleBinding.Labels[ContentHashLabelKey] = hash permissions[permission.ServiceAccountName].AddClusterRoleBinding(roleBinding) } return permissions, nil diff --git a/staging/operator-lifecycle-manager/pkg/lib/operatorlister/customresourcedefinition.go b/staging/operator-lifecycle-manager/pkg/lib/operatorlister/customresourcedefinition.go index 07c60a9126..69cac64e34 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/operatorlister/customresourcedefinition.go +++ b/staging/operator-lifecycle-manager/pkg/lib/operatorlister/customresourcedefinition.go @@ -4,20 +4,30 @@ import ( "fmt" "sync" - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - aextv1 "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/metadata/metadatalister" ) // UnionCustomResourceDefinitionLister is a custom implementation of an CustomResourceDefinition lister that allows a new -// Lister to be registered on the fly. This Lister lists both v1 and v1beta1 APIVersion (at the newer version) CRDs. +// Lister to be registered on the fly. type UnionCustomResourceDefinitionLister struct { - CustomResourceDefinitionLister aextv1.CustomResourceDefinitionLister + CustomResourceDefinitionLister metadatalister.Lister CustomResourceDefinitionLock sync.RWMutex } +func (ucl *UnionCustomResourceDefinitionLister) Namespace(namespace string) metadatalister.NamespaceLister { + ucl.CustomResourceDefinitionLock.RLock() + defer ucl.CustomResourceDefinitionLock.RUnlock() + + if ucl.CustomResourceDefinitionLister == nil { + panic(fmt.Errorf("no CustomResourceDefinition lister registered")) + } + return ucl.CustomResourceDefinitionLister.Namespace(namespace) +} + // List lists all CustomResourceDefinitions in the indexer. -func (ucl *UnionCustomResourceDefinitionLister) List(selector labels.Selector) (ret []*apiextensionsv1.CustomResourceDefinition, err error) { +func (ucl *UnionCustomResourceDefinitionLister) List(selector labels.Selector) (ret []*metav1.PartialObjectMetadata, err error) { ucl.CustomResourceDefinitionLock.RLock() defer ucl.CustomResourceDefinitionLock.RUnlock() @@ -28,7 +38,7 @@ func (ucl *UnionCustomResourceDefinitionLister) List(selector labels.Selector) ( } // Get retrieves the CustomResourceDefinition with the given name -func (ucl *UnionCustomResourceDefinitionLister) Get(name string) (*apiextensionsv1.CustomResourceDefinition, error) { +func (ucl *UnionCustomResourceDefinitionLister) Get(name string) (*metav1.PartialObjectMetadata, error) { ucl.CustomResourceDefinitionLock.RLock() defer ucl.CustomResourceDefinitionLock.RUnlock() @@ -39,17 +49,17 @@ func (ucl *UnionCustomResourceDefinitionLister) Get(name string) (*apiextensions } // RegisterCustomResourceDefinitionLister registers a new CustomResourceDefinitionLister -func (ucl *UnionCustomResourceDefinitionLister) RegisterCustomResourceDefinitionLister(lister aextv1.CustomResourceDefinitionLister) { +func (ucl *UnionCustomResourceDefinitionLister) RegisterCustomResourceDefinitionLister(lister metadatalister.Lister) { ucl.CustomResourceDefinitionLock.Lock() defer ucl.CustomResourceDefinitionLock.Unlock() ucl.CustomResourceDefinitionLister = lister } -func (l *apiExtensionsV1Lister) RegisterCustomResourceDefinitionLister(lister aextv1.CustomResourceDefinitionLister) { +func (l *apiExtensionsV1Lister) RegisterCustomResourceDefinitionLister(lister metadatalister.Lister) { l.customResourceDefinitionLister.RegisterCustomResourceDefinitionLister(lister) } -func (l *apiExtensionsV1Lister) CustomResourceDefinitionLister() aextv1.CustomResourceDefinitionLister { +func (l *apiExtensionsV1Lister) CustomResourceDefinitionLister() metadatalister.Lister { return l.customResourceDefinitionLister } diff --git a/staging/operator-lifecycle-manager/pkg/lib/operatorlister/lister.go b/staging/operator-lifecycle-manager/pkg/lib/operatorlister/lister.go index 0bf77a89e4..388f38ddaf 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/operatorlister/lister.go +++ b/staging/operator-lifecycle-manager/pkg/lib/operatorlister/lister.go @@ -1,10 +1,10 @@ package operatorlister import ( - aextv1 "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1" appsv1 "k8s.io/client-go/listers/apps/v1" corev1 "k8s.io/client-go/listers/core/v1" rbacv1 "k8s.io/client-go/listers/rbac/v1" + "k8s.io/client-go/metadata/metadatalister" aregv1 "k8s.io/kube-aggregator/pkg/client/listers/apiregistration/v1" v1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/listers/operators/v1" @@ -88,8 +88,8 @@ type APIRegistrationV1Lister interface { //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . APIExtensionsV1Lister type APIExtensionsV1Lister interface { - RegisterCustomResourceDefinitionLister(lister aextv1.CustomResourceDefinitionLister) - CustomResourceDefinitionLister() aextv1.CustomResourceDefinitionLister + RegisterCustomResourceDefinitionLister(lister metadatalister.Lister) + CustomResourceDefinitionLister() metadatalister.Lister } //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . OperatorsV1alpha1Lister diff --git a/staging/operator-lifecycle-manager/pkg/lib/operatorlister/operatorlisterfakes/fake_apiextensions_v1lister.go b/staging/operator-lifecycle-manager/pkg/lib/operatorlister/operatorlisterfakes/fake_apiextensions_v1lister.go index ac6d23e817..31bdfcab3c 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/operatorlister/operatorlisterfakes/fake_apiextensions_v1lister.go +++ b/staging/operator-lifecycle-manager/pkg/lib/operatorlister/operatorlisterfakes/fake_apiextensions_v1lister.go @@ -5,30 +5,30 @@ import ( "sync" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorlister" - v1 "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1" + "k8s.io/client-go/metadata/metadatalister" ) type FakeAPIExtensionsV1Lister struct { - CustomResourceDefinitionListerStub func() v1.CustomResourceDefinitionLister + CustomResourceDefinitionListerStub func() metadatalister.Lister customResourceDefinitionListerMutex sync.RWMutex customResourceDefinitionListerArgsForCall []struct { } customResourceDefinitionListerReturns struct { - result1 v1.CustomResourceDefinitionLister + result1 metadatalister.Lister } customResourceDefinitionListerReturnsOnCall map[int]struct { - result1 v1.CustomResourceDefinitionLister + result1 metadatalister.Lister } - RegisterCustomResourceDefinitionListerStub func(v1.CustomResourceDefinitionLister) + RegisterCustomResourceDefinitionListerStub func(metadatalister.Lister) registerCustomResourceDefinitionListerMutex sync.RWMutex registerCustomResourceDefinitionListerArgsForCall []struct { - arg1 v1.CustomResourceDefinitionLister + arg1 metadatalister.Lister } invocations map[string][][]interface{} invocationsMutex sync.RWMutex } -func (fake *FakeAPIExtensionsV1Lister) CustomResourceDefinitionLister() v1.CustomResourceDefinitionLister { +func (fake *FakeAPIExtensionsV1Lister) CustomResourceDefinitionLister() metadatalister.Lister { fake.customResourceDefinitionListerMutex.Lock() ret, specificReturn := fake.customResourceDefinitionListerReturnsOnCall[len(fake.customResourceDefinitionListerArgsForCall)] fake.customResourceDefinitionListerArgsForCall = append(fake.customResourceDefinitionListerArgsForCall, struct { @@ -51,39 +51,39 @@ func (fake *FakeAPIExtensionsV1Lister) CustomResourceDefinitionListerCallCount() return len(fake.customResourceDefinitionListerArgsForCall) } -func (fake *FakeAPIExtensionsV1Lister) CustomResourceDefinitionListerCalls(stub func() v1.CustomResourceDefinitionLister) { +func (fake *FakeAPIExtensionsV1Lister) CustomResourceDefinitionListerCalls(stub func() metadatalister.Lister) { fake.customResourceDefinitionListerMutex.Lock() defer fake.customResourceDefinitionListerMutex.Unlock() fake.CustomResourceDefinitionListerStub = stub } -func (fake *FakeAPIExtensionsV1Lister) CustomResourceDefinitionListerReturns(result1 v1.CustomResourceDefinitionLister) { +func (fake *FakeAPIExtensionsV1Lister) CustomResourceDefinitionListerReturns(result1 metadatalister.Lister) { fake.customResourceDefinitionListerMutex.Lock() defer fake.customResourceDefinitionListerMutex.Unlock() fake.CustomResourceDefinitionListerStub = nil fake.customResourceDefinitionListerReturns = struct { - result1 v1.CustomResourceDefinitionLister + result1 metadatalister.Lister }{result1} } -func (fake *FakeAPIExtensionsV1Lister) CustomResourceDefinitionListerReturnsOnCall(i int, result1 v1.CustomResourceDefinitionLister) { +func (fake *FakeAPIExtensionsV1Lister) CustomResourceDefinitionListerReturnsOnCall(i int, result1 metadatalister.Lister) { fake.customResourceDefinitionListerMutex.Lock() defer fake.customResourceDefinitionListerMutex.Unlock() fake.CustomResourceDefinitionListerStub = nil if fake.customResourceDefinitionListerReturnsOnCall == nil { fake.customResourceDefinitionListerReturnsOnCall = make(map[int]struct { - result1 v1.CustomResourceDefinitionLister + result1 metadatalister.Lister }) } fake.customResourceDefinitionListerReturnsOnCall[i] = struct { - result1 v1.CustomResourceDefinitionLister + result1 metadatalister.Lister }{result1} } -func (fake *FakeAPIExtensionsV1Lister) RegisterCustomResourceDefinitionLister(arg1 v1.CustomResourceDefinitionLister) { +func (fake *FakeAPIExtensionsV1Lister) RegisterCustomResourceDefinitionLister(arg1 metadatalister.Lister) { fake.registerCustomResourceDefinitionListerMutex.Lock() fake.registerCustomResourceDefinitionListerArgsForCall = append(fake.registerCustomResourceDefinitionListerArgsForCall, struct { - arg1 v1.CustomResourceDefinitionLister + arg1 metadatalister.Lister }{arg1}) fake.recordInvocation("RegisterCustomResourceDefinitionLister", []interface{}{arg1}) fake.registerCustomResourceDefinitionListerMutex.Unlock() @@ -98,13 +98,13 @@ func (fake *FakeAPIExtensionsV1Lister) RegisterCustomResourceDefinitionListerCal return len(fake.registerCustomResourceDefinitionListerArgsForCall) } -func (fake *FakeAPIExtensionsV1Lister) RegisterCustomResourceDefinitionListerCalls(stub func(v1.CustomResourceDefinitionLister)) { +func (fake *FakeAPIExtensionsV1Lister) RegisterCustomResourceDefinitionListerCalls(stub func(metadatalister.Lister)) { fake.registerCustomResourceDefinitionListerMutex.Lock() defer fake.registerCustomResourceDefinitionListerMutex.Unlock() fake.RegisterCustomResourceDefinitionListerStub = stub } -func (fake *FakeAPIExtensionsV1Lister) RegisterCustomResourceDefinitionListerArgsForCall(i int) v1.CustomResourceDefinitionLister { +func (fake *FakeAPIExtensionsV1Lister) RegisterCustomResourceDefinitionListerArgsForCall(i int) metadatalister.Lister { fake.registerCustomResourceDefinitionListerMutex.RLock() defer fake.registerCustomResourceDefinitionListerMutex.RUnlock() argsForCall := fake.registerCustomResourceDefinitionListerArgsForCall[i] diff --git a/staging/operator-lifecycle-manager/pkg/lib/operatorstatus/status.go b/staging/operator-lifecycle-manager/pkg/lib/operatorstatus/status.go index 4067392c6e..bb0b092d85 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/operatorstatus/status.go +++ b/staging/operator-lifecycle-manager/pkg/lib/operatorstatus/status.go @@ -228,7 +228,7 @@ func MonitorClusterStatus(name string, syncCh <-chan error, stopCh <-chan struct // if we've reported success, we can sleep longer, otherwise we want to keep watching for // successful if successfulSyncs > 0 { - time.Sleep(5 * time.Minute) + time.Sleep(25 * time.Second) } }, 5*time.Second, stopCh) diff --git a/staging/operator-lifecycle-manager/pkg/lib/ownerutil/util.go b/staging/operator-lifecycle-manager/pkg/lib/ownerutil/util.go index 24ff1afe2e..352b2a8025 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/ownerutil/util.go +++ b/staging/operator-lifecycle-manager/pkg/lib/ownerutil/util.go @@ -20,10 +20,9 @@ import ( ) const ( - OwnerKey = "olm.owner" - OwnerNamespaceKey = "olm.owner.namespace" - OwnerKind = "olm.owner.kind" - OwnerPackageServer = "packageserver" + OwnerKey = "olm.owner" + OwnerNamespaceKey = "olm.owner.namespace" + OwnerKind = "olm.owner.kind" ) var ( @@ -272,6 +271,11 @@ func CSVOwnerSelector(owner *operatorsv1alpha1.ClusterServiceVersion) labels.Sel return labels.SelectorFromSet(OwnerLabel(owner, operatorsv1alpha1.ClusterServiceVersionKind)) } +// OperatorGroupOwnerSelector returns a label selector to find generated objects owned by owner +func OperatorGroupOwnerSelector(owner *operatorsv1.OperatorGroup) labels.Selector { + return labels.SelectorFromSet(OwnerLabel(owner, operatorsv1.OperatorGroupKind)) +} + // AddOwner adds an owner to the ownerref list. func AddOwner(object metav1.Object, owner Owner, blockOwnerDeletion, isController bool) { // Most of the time we won't have TypeMeta on the object, so we infer it for types we know about diff --git a/staging/operator-lifecycle-manager/pkg/package-server/provider/registry_test.go b/staging/operator-lifecycle-manager/pkg/package-server/provider/registry_test.go index 2f0b5277f1..beeb82a747 100644 --- a/staging/operator-lifecycle-manager/pkg/package-server/provider/registry_test.go +++ b/staging/operator-lifecycle-manager/pkg/package-server/provider/registry_test.go @@ -787,7 +787,7 @@ func TestRegistryProviderList(t *testing.T) { globalNS: "ns", requestNamespace: "wisconsin", expectedErr: "", - expected: &operators.PackageManifestList{Items: []operators.PackageManifest{}}, + expected: &operators.PackageManifestList{}, }, { name: "PackagesFound", @@ -1230,7 +1230,6 @@ func TestRegistryProviderList(t *testing.T) { } else { require.Nil(t, err) } - require.Equal(t, len(test.expected.Items), len(packageManifestList.Items)) require.ElementsMatch(t, test.expected.Items, packageManifestList.Items) }) diff --git a/staging/operator-lifecycle-manager/scripts/build_local.sh b/staging/operator-lifecycle-manager/scripts/build_local.sh index e30ea18a0e..19c342e2c4 100755 --- a/staging/operator-lifecycle-manager/scripts/build_local.sh +++ b/staging/operator-lifecycle-manager/scripts/build_local.sh @@ -4,11 +4,12 @@ # This is used to start and build services for running e2e tests set -e +set -o xtrace [ -x "$(command -v kind)" ] && [[ "$(kubectl config current-context)" =~ ^kind-? ]] && KIND=1 NO_MINIKUBE=1 if [ -z "$NO_MINIKUBE" ]; then - pgrep -f "[m]inikube" >/dev/null || minikube start --extra-config=apiserver.v=4 || { echo 'Cannot start minikube.'; exit 1; } + pgrep -f "[m]inikube" >/dev/null || minikube start "${MINIKUBE_ARGS}" --extra-config=apiserver.v=4 || { echo 'Cannot start minikube.'; exit 1; } eval "$(minikube docker-env)" || { echo 'Cannot switch to minikube docker'; exit 1; } kubectl config use-context minikube fi diff --git a/staging/operator-lifecycle-manager/scripts/lib/olm_util.sh b/staging/operator-lifecycle-manager/scripts/lib/olm_util.sh index 4a56b25ac1..5b58cea50a 100755 --- a/staging/operator-lifecycle-manager/scripts/lib/olm_util.sh +++ b/staging/operator-lifecycle-manager/scripts/lib/olm_util.sh @@ -13,6 +13,7 @@ olm::util::await_csv_success() { echo "awaiting ${namespace}/${csv} csv installation success" until [[ "${retries}" -le "0" || "${phase:=$(kubectl get csv -n "${namespace}" "${csv}" -o jsonpath='{.status.phase}' 2>/dev/null || echo "missing")}" == "Succeeded" ]]; do retries=$((retries - 1)) + kubectl get csv -n "${namespace}" "${csv}" -o yaml echo "current phase: ${phase}, remaining attempts: ${retries}" unset phase sleep 1 @@ -29,7 +30,7 @@ olm::util::await_csv_success() { olm::util::await_olm_ready() { local namespace="$1" - kubectl rollout status -w deployment/olm-operator --namespace="${namespace}" || return - kubectl rollout status -w deployment/catalog-operator --namespace="${namespace}" || return + kubectl rollout status -w deployment/olm-operator --namespace="${namespace}" || kubectl get deployment olm-operator --namespace="${namespace}" -o yaml && return + kubectl rollout status -w deployment/catalog-operator --namespace="${namespace}" || kubectl get deployment catalog-operator --namespace="${namespace}" -o yaml && return olm::util::await_csv_success "${namespace}" "packageserver" 32 || return } \ No newline at end of file diff --git a/staging/operator-lifecycle-manager/test/e2e/bundle_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/bundle_e2e_test.go index 8690ad1956..4d1aae0940 100644 --- a/staging/operator-lifecycle-manager/test/e2e/bundle_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/bundle_e2e_test.go @@ -114,14 +114,14 @@ var _ = Describe("Installing bundles with new object types", func() { }).Should(Succeed()) // Wait for the CatalogSource to be ready - _, err = fetchCatalogSourceOnStatus(operatorClient, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(operatorClient, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred(), "catalog source did not become ready") // Create a Subscription for package _ = createSubscriptionForCatalog(operatorClient, source.GetNamespace(), subName, source.GetName(), packageName, channelName, "", v1alpha1.ApprovalAutomatic) // Wait for the Subscription to succeed - sub, err := fetchSubscription(operatorClient, generatedNamespace.GetName(), subName, subscriptionStateAtLatestChecker) + sub, err := fetchSubscription(operatorClient, generatedNamespace.GetName(), subName, subscriptionStateAtLatestChecker()) Expect(err).ToNot(HaveOccurred(), "could not get subscription at latest status") installPlanRef := sub.Status.InstallPlanRef diff --git a/staging/operator-lifecycle-manager/test/e2e/catalog_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/catalog_e2e_test.go index 41c6cca141..b7aa95a1d8 100644 --- a/staging/operator-lifecycle-manager/test/e2e/catalog_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/catalog_e2e_test.go @@ -5,6 +5,7 @@ package e2e import ( "context" + "errors" "fmt" "net" "path/filepath" @@ -14,6 +15,7 @@ import ( operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + packageserverclientset "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/client/clientset/versioned" k8serror "k8s.io/apimachinery/pkg/api/errors" "sigs.k8s.io/controller-runtime/pkg/client" @@ -47,13 +49,14 @@ const ( var _ = Describe("Starting CatalogSource e2e tests", func() { var ( - ns corev1.Namespace - c operatorclient.ClientInterface - crc versioned.Interface + ns corev1.Namespace + c operatorclient.ClientInterface + crc versioned.Interface + packageserverClient *packageserverclientset.Clientset ) BeforeEach(func() { - // In OPC, PSA labels for any namespace created that is not prefixed with "openshift-" is overriden to enforce + // In OCP, PSA labels for any namespace created that is not prefixed with "openshift-" is overridden to enforce // PSA restricted. This test namespace needs to prefixed with openshift- so that baseline/privileged enforcement // for the PSA specific tests are not overridden, // Change it only after https://github.com/operator-framework/operator-lifecycle-manager/issues/2859 is closed. @@ -67,6 +70,7 @@ var _ = Describe("Starting CatalogSource e2e tests", func() { ns = SetupGeneratedTestNamespaceWithOperatorGroup(namespaceName, og) c = ctx.Ctx().KubeClient() crc = ctx.Ctx().OperatorClient() + packageserverClient = packageserverclientset.NewForConfigOrDie(ctx.Ctx().RESTConfig()) }) AfterEach(func() { @@ -105,7 +109,7 @@ var _ = Describe("Starting CatalogSource e2e tests", func() { defer cleanupSource() // ensure the mock catalog exists and has been synced by the catalog operator - catalogSource, err := fetchCatalogSourceOnStatus(crc, catalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced) + catalogSource, err := fetchCatalogSourceOnStatus(crc, catalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ShouldNot(HaveOccurred()) // get catalog operator deployment @@ -176,7 +180,7 @@ var _ = Describe("Starting CatalogSource e2e tests", func() { defer cleanup() // Attempt to get the catalog source before creating install plan - _, err := fetchCatalogSourceOnStatus(crc, cs.GetName(), cs.GetNamespace(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, cs.GetName(), cs.GetNamespace(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) subscriptionSpec := &v1alpha1.SubscriptionSpec{ @@ -192,7 +196,7 @@ var _ = Describe("Starting CatalogSource e2e tests", func() { subscriptionName := genName("sub-") createSubscriptionForCatalogWithSpec(GinkgoT(), crc, ns.GetName(), subscriptionName, subscriptionSpec) - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) Expect(err).ShouldNot(HaveOccurred()) Expect(subscription).ToNot(BeNil()) @@ -228,10 +232,10 @@ var _ = Describe("Starting CatalogSource e2e tests", func() { updateInternalCatalog(GinkgoT(), c, crc, cs.GetName(), cs.GetNamespace(), []apiextensions.CustomResourceDefinition{mainCRD}, []v1alpha1.ClusterServiceVersion{mainCSV, replacementCSV}, mainManifests) // Get updated catalogsource - fetchedUpdatedCatalog, err := fetchCatalogSourceOnStatus(crc, cs.GetName(), cs.GetNamespace(), catalogSourceRegistryPodSynced) + fetchedUpdatedCatalog, err := fetchCatalogSourceOnStatus(crc, cs.GetName(), cs.GetNamespace(), catalogSourceRegistryPodSynced()) Expect(err).ShouldNot(HaveOccurred()) - subscription, err = fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionStateUpgradePendingChecker) + subscription, err = fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionStateUpgradePendingChecker()) Expect(err).ShouldNot(HaveOccurred()) Expect(subscription).ShouldNot(BeNil()) @@ -294,7 +298,7 @@ var _ = Describe("Starting CatalogSource e2e tests", func() { createInternalCatalogSource(c, crc, mainCatalogName, ns.GetName(), mainManifests, nil, []v1alpha1.ClusterServiceVersion{mainCSV}) // Attempt to get the catalog source before creating install plan - fetchedInitialCatalog, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) + fetchedInitialCatalog, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ShouldNot(HaveOccurred()) // Get initial configmap @@ -357,7 +361,7 @@ var _ = Describe("Starting CatalogSource e2e tests", func() { subscriptionName := genName("sub-") createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, fetchedUpdatedCatalog.GetName(), mainPackageName, stableChannel, "", v1alpha1.ApprovalAutomatic) - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionStateAtLatestChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionStateAtLatestChecker()) Expect(err).ShouldNot(HaveOccurred()) Expect(subscription).ShouldNot(BeNil()) _, err = fetchCSV(crc, subscription.Status.CurrentCSV, ns.GetName(), buildCSVConditionChecker(v1alpha1.CSVPhaseSucceeded)) @@ -427,7 +431,7 @@ var _ = Describe("Starting CatalogSource e2e tests", func() { _, cleanupSource := createInternalCatalogSource(c, crc, mainCatalogName, ns.GetName(), mainManifests, nil, []v1alpha1.ClusterServiceVersion{mainCSV}) // Attempt to get the catalog source before creating install plan - fetchedInitialCatalog, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) + fetchedInitialCatalog, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ShouldNot(HaveOccurred()) // Get initial configmap configMap, err := c.KubernetesInterface().CoreV1().ConfigMaps(ns.GetName()).Get(context.Background(), fetchedInitialCatalog.Spec.ConfigMap, metav1.GetOptions{}) @@ -448,7 +452,7 @@ var _ = Describe("Starting CatalogSource e2e tests", func() { subscriptionName := genName("sub-") createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", v1alpha1.ApprovalAutomatic) - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionStateAtLatestChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionStateAtLatestChecker()) Expect(err).ShouldNot(HaveOccurred()) Expect(subscription).ToNot(BeNil()) _, err = fetchCSV(crc, subscription.Status.CurrentCSV, ns.GetName(), buildCSVConditionChecker(v1alpha1.CSVPhaseSucceeded)) @@ -536,9 +540,9 @@ var _ = Describe("Starting CatalogSource e2e tests", func() { createInternalCatalogSource(c, crc, replacementSourceName, ns.GetName(), append(replacementManifests, dependentManifests...), []apiextensions.CustomResourceDefinition{dependentCRD}, []v1alpha1.ClusterServiceVersion{replacementCSV, mainCSV, dependentCSV}) // Wait for ConfigMap CatalogSources to be ready - mainSource, err := fetchCatalogSourceOnStatus(crc, mainSourceName, ns.GetName(), catalogSourceRegistryPodSynced) + mainSource, err := fetchCatalogSourceOnStatus(crc, mainSourceName, ns.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ShouldNot(HaveOccurred()) - replacementSource, err := fetchCatalogSourceOnStatus(crc, replacementSourceName, ns.GetName(), catalogSourceRegistryPodSynced) + replacementSource, err := fetchCatalogSourceOnStatus(crc, replacementSourceName, ns.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ShouldNot(HaveOccurred()) // Replicate catalog pods with no OwnerReferences @@ -576,7 +580,7 @@ var _ = Describe("Starting CatalogSource e2e tests", func() { }() // Wait for the CatalogSource to be ready - _, err = fetchCatalogSourceOnStatus(crc, addressSource.GetName(), addressSource.GetNamespace(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, addressSource.GetName(), addressSource.GetNamespace(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred(), "catalog source did not become ready") // Delete CatalogSources @@ -590,7 +594,7 @@ var _ = Describe("Starting CatalogSource e2e tests", func() { cleanupSubscription := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, addressSourceName, mainPackageName, stableChannel, "", v1alpha1.ApprovalAutomatic) defer cleanupSubscription() - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionStateAtLatestChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionStateAtLatestChecker()) Expect(err).ShouldNot(HaveOccurred()) Expect(subscription).ShouldNot(BeNil()) _, err = fetchCSV(crc, subscription.Status.CurrentCSV, ns.GetName(), csvSucceededChecker) @@ -750,6 +754,54 @@ var _ = Describe("Starting CatalogSource e2e tests", func() { Expect(registryPods.Items).To(HaveLen(1), "unexpected number of replacement registry pods found") }) + It("configure gRPC registry pod to extract content", func() { + + By("Create gRPC CatalogSource using an external registry image (community-operators)") + source := &v1alpha1.CatalogSource{ + TypeMeta: metav1.TypeMeta{ + Kind: v1alpha1.CatalogSourceKind, + APIVersion: v1alpha1.CatalogSourceCRDAPIVersion, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("catalog-"), + Namespace: ns.GetName(), + }, + Spec: v1alpha1.CatalogSourceSpec{ + SourceType: v1alpha1.SourceTypeGrpc, + Image: communityOperatorsImage, + GrpcPodConfig: &v1alpha1.GrpcPodConfig{ + SecurityContextConfig: v1alpha1.Restricted, + ExtractContent: &v1alpha1.ExtractContentConfig{ + CacheDir: "/tmp/cache", + CatalogDir: "/configs", + }, + }, + }, + } + + source, err := crc.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Create(context.Background(), source, metav1.CreateOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + + By("Wait for the CatalogSource to be ready") + source, err = fetchCatalogSourceOnStatus(crc, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced()) + Expect(err).ToNot(HaveOccurred(), "catalog source did not become ready") + + // the gRPC endpoints are not exposed from the pod, and there's no simple way to get at them - + // the index images don't contain `grpcurl`, port-forwarding is a mess, etc. let's use the + // package-server as a proxy for a functional catalog + By("Waiting for packages from the catalog to show up in the Kubernetes API") + Eventually(func() error { + manifests, err := packageserverClient.OperatorsV1().PackageManifests("default").List(context.Background(), metav1.ListOptions{}) + if err != nil { + return err + } + if len(manifests.Items) == 0 { + return errors.New("did not find any PackageManifests") + } + return nil + }).Should(Succeed()) + }) + It("image update", func() { if ok, err := inKind(c); ok && err == nil { Skip("This spec fails when run using KIND cluster. See https://github.com/operator-framework/operator-lifecycle-manager/issues/2420 for more details") @@ -871,7 +923,7 @@ var _ = Describe("Starting CatalogSource e2e tests", func() { defer cleanupSubscription() // Wait for the Subscription to succeed - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionStateAtLatestChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionStateAtLatestChecker()) Expect(err).ShouldNot(HaveOccurred()) Expect(subscription).ShouldNot(BeNil()) @@ -1036,7 +1088,7 @@ var _ = Describe("Starting CatalogSource e2e tests", func() { }() By("waiting for the CatalogSource to be ready") - _, err = fetchCatalogSourceOnStatus(crc, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred(), "catalog source did not become ready") By("creating a Subscription for busybox") @@ -1045,7 +1097,7 @@ var _ = Describe("Starting CatalogSource e2e tests", func() { defer cleanupSubscription() By("waiting for the Subscription to succeed") - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionStateAtLatestChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionStateAtLatestChecker()) Expect(err).ShouldNot(HaveOccurred()) Expect(subscription).ShouldNot(BeNil()) Expect(subscription.Status.InstalledCSV).To(Equal("busybox.v1.0.0")) @@ -1062,7 +1114,7 @@ var _ = Describe("Starting CatalogSource e2e tests", func() { Expect(dependencySubscriptionName).ToNot(BeEmpty()) By("waiting for the Subscription to succeed") - subscription, err = fetchSubscription(crc, ns.GetName(), dependencySubscriptionName, subscriptionStateAtLatestChecker) + subscription, err = fetchSubscription(crc, ns.GetName(), dependencySubscriptionName, subscriptionStateAtLatestChecker()) Expect(err).ShouldNot(HaveOccurred()) Expect(subscription).ShouldNot(BeNil()) Expect(subscription.Status.InstalledCSV).To(Equal("busybox-dependency.v1.0.0")) @@ -1080,7 +1132,7 @@ var _ = Describe("Starting CatalogSource e2e tests", func() { }).Should(Succeed()) By("waiting for the CatalogSource to be ready") - _, err = fetchCatalogSourceOnStatus(crc, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred(), "catalog source did not become ready") By("waiting for the busybox v2 Subscription to succeed") diff --git a/staging/operator-lifecycle-manager/test/e2e/crd_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/crd_e2e_test.go index 123a3622fb..616db36407 100644 --- a/staging/operator-lifecycle-manager/test/e2e/crd_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/crd_e2e_test.go @@ -92,14 +92,14 @@ var _ = Describe("CRD Versions", func() { }() // Attempt to get the catalog source before creating install plan - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) subscriptionName := genName("sub-nginx-update2-") subscriptionCleanup := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) Expect(err).ToNot(HaveOccurred()) Expect(subscription).ToNot(Equal(nil)) Expect(subscription.Status.InstallPlanRef).ToNot(Equal(nil)) @@ -231,14 +231,14 @@ var _ = Describe("CRD Versions", func() { }() // Attempt to get the catalog source before creating install plan - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) subscriptionName := genName("sub-nginx-update2-") subscriptionCleanup := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) Expect(err).ToNot(HaveOccurred()) Expect(subscription).ToNot(BeNil()) Expect(subscription.Status.InstallPlanRef).ToNot(Equal(nil)) @@ -261,8 +261,9 @@ var _ = Describe("CRD Versions", func() { })).Should(Succeed()) ctx.Ctx().Logf("updated subscription to point to alpha channel") + checker := subscriptionStateAtLatestChecker() subscriptionAtLatestWithDifferentInstallPlan := func(v *operatorsv1alpha1.Subscription) bool { - return subscriptionStateAtLatestChecker(v) && v.Status.InstallPlanRef != nil && v.Status.InstallPlanRef.Name != fetchedInstallPlan.Name + return checker(v) && v.Status.InstallPlanRef != nil && v.Status.InstallPlanRef.Name != fetchedInstallPlan.Name } // fetch new subscription @@ -421,13 +422,13 @@ var _ = Describe("CRD Versions", func() { defer cleanupMainCatalogSource() // Attempt to get the catalog source before creating install plan - _, err = fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) subscriptionName := genName("sub-nginx-update2-") _ = createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) Expect(err).ToNot(HaveOccurred()) Expect(subscription).ToNot(BeNil()) Expect(subscription.Status.InstallPlanRef).ToNot(Equal(nil)) @@ -467,7 +468,7 @@ var _ = Describe("CRD Versions", func() { subscriptionNameNew := genName("sub-nginx-update2-new-") _ = createSubscriptionForCatalog(crc, ns.GetName(), subscriptionNameNew, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) - subscription, err = fetchSubscription(crc, ns.GetName(), subscriptionNameNew, subscriptionHasInstallPlanChecker) + subscription, err = fetchSubscription(crc, ns.GetName(), subscriptionNameNew, subscriptionHasInstallPlanChecker()) Expect(err).ToNot(HaveOccurred()) Expect(subscription).ToNot(BeNil()) Expect(subscription.Status.InstallPlanRef).ToNot(Equal(nil)) diff --git a/staging/operator-lifecycle-manager/test/e2e/csv_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/csv_e2e_test.go index 5afda922dc..3f9172d03c 100644 --- a/staging/operator-lifecycle-manager/test/e2e/csv_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/csv_e2e_test.go @@ -3,6 +3,7 @@ package e2e import ( "context" "fmt" + "os" "strconv" "strings" "time" @@ -4205,6 +4206,11 @@ func findLastEvent(events *corev1.EventList) (event corev1.Event) { func buildCSVCleanupFunc(c operatorclient.ClientInterface, crc versioned.Interface, csv operatorsv1alpha1.ClusterServiceVersion, namespace string, deleteCRDs, deleteAPIServices bool) cleanupFunc { return func() { + if env := os.Getenv("SKIP_CLEANUP"); env != "" { + fmt.Printf("Skipping deletion of CSV %s/%s...\n", namespace, csv.Name) + return + } + err := crc.OperatorsV1alpha1().ClusterServiceVersions(namespace).Delete(context.TODO(), csv.GetName(), metav1.DeleteOptions{}) if err != nil && apierrors.IsNotFound(err) { err = nil @@ -4248,6 +4254,11 @@ func createCSV(c operatorclient.ClientInterface, crc versioned.Interface, csv op func buildCRDCleanupFunc(c operatorclient.ClientInterface, crdName string) cleanupFunc { return func() { + if env := os.Getenv("SKIP_CLEANUP"); env != "" { + fmt.Printf("Skipping deletion of CRD %s...\n", crdName) + return + } + err := c.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.TODO(), crdName, *metav1.NewDeleteOptions(immediateDeleteGracePeriod)) if err != nil { fmt.Println(err) @@ -4262,6 +4273,11 @@ func buildCRDCleanupFunc(c operatorclient.ClientInterface, crdName string) clean func buildAPIServiceCleanupFunc(c operatorclient.ClientInterface, apiServiceName string) cleanupFunc { return func() { + if env := os.Getenv("SKIP_CLEANUP"); env != "" { + fmt.Printf("Skipping deletion of APIService %s...\n", apiServiceName) + return + } + err := c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().Delete(context.TODO(), apiServiceName, *metav1.NewDeleteOptions(immediateDeleteGracePeriod)) if err != nil { fmt.Println(err) @@ -4402,21 +4418,43 @@ func newMockExtServerDeployment(labelName string, mGVKs []mockGroupVersionKind) type csvConditionChecker func(csv *operatorsv1alpha1.ClusterServiceVersion) bool func buildCSVConditionChecker(phases ...operatorsv1alpha1.ClusterServiceVersionPhase) csvConditionChecker { + var lastPhase operatorsv1alpha1.ClusterServiceVersionPhase + var lastReason operatorsv1alpha1.ConditionReason + var lastMessage string + lastTime := time.Now() + return func(csv *operatorsv1alpha1.ClusterServiceVersion) bool { conditionMet := false for _, phase := range phases { conditionMet = conditionMet || csv.Status.Phase == phase } + phase, reason, message := csv.Status.Phase, csv.Status.Reason, csv.Status.Message + if phase != lastPhase || reason != lastReason || message != lastMessage { + ctx.Ctx().Logf("waited %s for CSV %s/%s: to be in phases %s, in phase %s (%s): %s", time.Since(lastTime), csv.Namespace, csv.Name, phases, phase, reason, message) + lastPhase, lastReason, lastMessage = phase, reason, message + lastTime = time.Now() + } return conditionMet } } func buildCSVReasonChecker(reasons ...operatorsv1alpha1.ConditionReason) csvConditionChecker { + var lastPhase operatorsv1alpha1.ClusterServiceVersionPhase + var lastReason operatorsv1alpha1.ConditionReason + var lastMessage string + lastTime := time.Now() + return func(csv *operatorsv1alpha1.ClusterServiceVersion) bool { conditionMet := false for _, reason := range reasons { conditionMet = conditionMet || csv.Status.Reason == reason } + phase, reason, message := csv.Status.Phase, csv.Status.Reason, csv.Status.Message + if phase != lastPhase || reason != lastReason || message != lastMessage { + ctx.Ctx().Logf("waited %s for CSV %s/%s: to have reasons %s, in phase %s (%s): %s", time.Since(lastTime), csv.Namespace, csv.Name, reasons, phase, reason, message) + lastPhase, lastReason, lastMessage = phase, reason, message + lastTime = time.Now() + } return conditionMet } } @@ -4432,17 +4470,17 @@ func fetchCSV(c versioned.Interface, name, namespace string, checker csvConditio var fetchedCSV *operatorsv1alpha1.ClusterServiceVersion var err error + ctx.Ctx().Logf("waiting for CSV %s/%s to reach condition", namespace, name) Eventually(func() (bool, error) { fetchedCSV, err = c.OperatorsV1alpha1().ClusterServiceVersions(namespace).Get(context.TODO(), name, metav1.GetOptions{}) if err != nil { return false, err } - ctx.Ctx().Logf("%s (%s): %s", fetchedCSV.Status.Phase, fetchedCSV.Status.Reason, fetchedCSV.Status.Message) return checker(fetchedCSV), nil }).Should(BeTrue()) if err != nil { - ctx.Ctx().Logf("never got correct status: %#v", fetchedCSV.Status) + ctx.Ctx().Logf("CSV %s/%s never got correct status: %#v", namespace, name, fetchedCSV.Status) } return fetchedCSV, err } diff --git a/staging/operator-lifecycle-manager/test/e2e/dynamic_resource_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/dynamic_resource_e2e_test.go index aae13be5d6..387a77c743 100644 --- a/staging/operator-lifecycle-manager/test/e2e/dynamic_resource_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/dynamic_resource_e2e_test.go @@ -78,7 +78,7 @@ var _ = Describe("Subscriptions create required objects from Catalogs", func() { Expect(err).NotTo(HaveOccurred()) // Wait for the CatalogSource to be ready - _, err = fetchCatalogSourceOnStatus(crc, catsrc.GetName(), catsrc.GetNamespace(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, catsrc.GetName(), catsrc.GetNamespace(), catalogSourceRegistryPodSynced()) Expect(err).NotTo(HaveOccurred()) // Generate a Subscription @@ -110,13 +110,13 @@ var _ = Describe("Subscriptions create required objects from Catalogs", func() { It("should install the operator successfully", func() { Skip("this test disabled pending fix of the v1 CRD feature") - _, err := fetchSubscription(crc, catsrc.GetNamespace(), subName, subscriptionHasInstallPlanChecker) + _, err := fetchSubscription(crc, catsrc.GetNamespace(), subName, subscriptionHasInstallPlanChecker()) Expect(err).NotTo(HaveOccurred()) }) It("should have created the expected prometheus objects", func() { Skip("this test disabled pending fix of the v1 CRD feature") - sub, err := fetchSubscription(crc, catsrc.GetNamespace(), subName, subscriptionHasInstallPlanChecker) + sub, err := fetchSubscription(crc, catsrc.GetNamespace(), subName, subscriptionHasInstallPlanChecker()) Expect(err).NotTo(HaveOccurred()) ipName := sub.Status.InstallPlanRef.Name diff --git a/staging/operator-lifecycle-manager/test/e2e/e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/e2e_test.go index d5b06da5fb..1cdcdda9a7 100644 --- a/staging/operator-lifecycle-manager/test/e2e/e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/e2e_test.go @@ -3,6 +3,7 @@ package e2e import ( "context" "flag" + "fmt" "os" "testing" "time" @@ -11,11 +12,17 @@ import ( . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" "github.com/operator-framework/operator-lifecycle-manager/test/e2e/ctx" ) +func init() { + log.SetLogger(zap.New()) +} + var ( kubeConfigPath = flag.String( "kubeconfig", "", "path to the kubeconfig file") @@ -31,7 +38,7 @@ var ( communityOperators = flag.String( "communityOperators", - "quay.io/operator-framework/upstream-community-operators@sha256:098457dc5e0b6ca9599bd0e7a67809f8eca397907ca4d93597380511db478fec", + "quay.io/operatorhubio/catalog:latest", "reference to upstream-community-operators image", ) @@ -121,5 +128,9 @@ var _ = BeforeSuite(func() { }) var _ = AfterSuite(func() { + if env := os.Getenv("SKIP_CLEANUP"); env != "" { + fmt.Println("Skipping deprovisioning...") + return + } deprovision() }) diff --git a/staging/operator-lifecycle-manager/test/e2e/fail_forward_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/fail_forward_e2e_test.go index 3df0768f61..8f06170322 100644 --- a/staging/operator-lifecycle-manager/test/e2e/fail_forward_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/fail_forward_e2e_test.go @@ -93,7 +93,7 @@ var _ = Describe("Fail Forward Upgrades", func() { Expect(c.Create(context.Background(), subscription)).To(BeNil()) By("waiting until the subscription has an IP reference") - subscription, err := fetchSubscription(crclient, subscription.GetNamespace(), subscription.GetName(), subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crclient, subscription.GetNamespace(), subscription.GetName(), subscriptionHasInstallPlanChecker()) Expect(err).Should(BeNil()) originalInstallPlanRef = subscription.Status.InstallPlanRef @@ -214,7 +214,7 @@ var _ = Describe("Fail Forward Upgrades", func() { Consistently(subscriptionCurrentCSVGetter(crclient, subscription.GetNamespace(), subscription.GetName())).Should(Equal("example-operator.v0.2.0")) By("verifying the subscription is referencing the same InstallPlan") - subscription, err = fetchSubscription(crclient, subscription.GetNamespace(), subscription.GetName(), subscriptionHasInstallPlanChecker) + subscription, err = fetchSubscription(crclient, subscription.GetNamespace(), subscription.GetName(), subscriptionHasInstallPlanChecker()) Expect(err).Should(BeNil()) Expect(subscription.Status.InstallPlanRef.Name).To(Equal(failedInstallPlanRef.Name)) }) @@ -251,7 +251,7 @@ var _ = Describe("Fail Forward Upgrades", func() { Expect(c.Create(context.Background(), subscription)).To(BeNil()) By("waiting until the subscription has an IP reference") - subscription, err := fetchSubscription(crclient, subscription.GetNamespace(), subscription.GetName(), subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crclient, subscription.GetNamespace(), subscription.GetName(), subscriptionHasInstallPlanChecker()) Expect(err).Should(BeNil()) By("waiting for the v0.1.0 CSV to report a succeeded phase") diff --git a/staging/operator-lifecycle-manager/test/e2e/gc_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/gc_e2e_test.go index b33c40c518..f9bdd992f8 100644 --- a/staging/operator-lifecycle-manager/test/e2e/gc_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/gc_e2e_test.go @@ -367,14 +367,14 @@ var _ = Describe("Garbage collection for dependent resources", func() { }).Should(Succeed(), "could not create catalog source") // Wait for the CatalogSource to be ready - _, err := fetchCatalogSourceOnStatus(operatorClient, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(operatorClient, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred(), "catalog source did not become ready") // Create a Subscription for package _ = createSubscriptionForCatalog(operatorClient, source.GetNamespace(), subName, source.GetName(), packageName, channelName, "", v1alpha1.ApprovalAutomatic) // Wait for the Subscription to succeed - sub, err := fetchSubscription(operatorClient, ns.GetName(), subName, subscriptionStateAtLatestChecker) + sub, err := fetchSubscription(operatorClient, ns.GetName(), subName, subscriptionStateAtLatestChecker()) Expect(err).ToNot(HaveOccurred(), "could not get subscription at latest status") installPlanRef = sub.Status.InstallPlanRef.Name @@ -486,14 +486,14 @@ var _ = Describe("Garbage collection for dependent resources", func() { }).Should(Succeed(), "could not create catalog source") // Wait for the CatalogSource to be ready - _, err = fetchCatalogSourceOnStatus(operatorClient, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(operatorClient, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred(), "catalog source did not become ready") // Create a Subscription for package _ = createSubscriptionForCatalog(operatorClient, source.GetNamespace(), subName, source.GetName(), packageName, channelName, "", v1alpha1.ApprovalAutomatic) // Wait for the Subscription to succeed - sub, err := fetchSubscription(operatorClient, ns.GetName(), subName, subscriptionStateAtLatestChecker) + sub, err := fetchSubscription(operatorClient, ns.GetName(), subName, subscriptionStateAtLatestChecker()) Expect(err).ToNot(HaveOccurred(), "could not get subscription at latest status") installPlanRef = sub.Status.InstallPlanRef.Name @@ -530,7 +530,7 @@ var _ = Describe("Garbage collection for dependent resources", func() { }).Should(Succeed(), "could not update subscription") // Wait for the Subscription to succeed - sub, err := fetchSubscription(operatorClient, ns.GetName(), subName, subscriptionStateAtLatestChecker) + sub, err := fetchSubscription(operatorClient, ns.GetName(), subName, subscriptionStateAtLatestChecker()) Expect(err).ToNot(HaveOccurred(), "could not get subscription at latest status") installPlanRef = sub.Status.InstallPlanRef.Name @@ -604,14 +604,14 @@ var _ = Describe("Garbage collection for dependent resources", func() { }).Should(Succeed()) // Wait for the CatalogSource to be ready - _, err = fetchCatalogSourceOnStatus(operatorClient, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(operatorClient, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred(), "catalog source did not become ready") // Create a Subscription for package _ = createSubscriptionForCatalog(operatorClient, source.GetNamespace(), subName, source.GetName(), packageName, channelName, "", v1alpha1.ApprovalAutomatic) // Wait for the Subscription to succeed - sub, err := fetchSubscription(operatorClient, ns.GetName(), subName, subscriptionStateAtLatestChecker) + sub, err := fetchSubscription(operatorClient, ns.GetName(), subName, subscriptionStateAtLatestChecker()) Expect(err).ToNot(HaveOccurred(), "could not get subscription at latest status") installPlanRef = sub.Status.InstallPlanRef.Name @@ -649,7 +649,7 @@ var _ = Describe("Garbage collection for dependent resources", func() { }).Should(Succeed(), "could not update subscription") // Wait for the Subscription to succeed - sub, err := fetchSubscription(operatorClient, ns.GetName(), subName, subscriptionStateAtLatestChecker) + sub, err := fetchSubscription(operatorClient, ns.GetName(), subName, subscriptionStateAtLatestChecker()) Expect(err).ToNot(HaveOccurred(), "could not get subscription at latest status") installPlanRef = sub.Status.InstallPlanRef.Name diff --git a/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go index 92d2c4c3e0..2de113cb25 100644 --- a/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go @@ -736,14 +736,14 @@ var _ = Describe("Install Plan", func() { defer cleanupDependentCatalogSource() // Attempt to get the catalog source before creating install plan - _, err := fetchCatalogSourceOnStatus(crc, dependentCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, dependentCatalogName, ns.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) _, cleanupMainCatalogSource := createInternalCatalogSource(c, crc, mainCatalogName, ns.GetName(), mainManifests, nil, []operatorsv1alpha1.ClusterServiceVersion{mainCSV}) defer cleanupMainCatalogSource() // Attempt to get the catalog source before creating install plan - _, err = fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) // Create expected install plan step sources @@ -758,7 +758,7 @@ var _ = Describe("Install Plan", func() { subscriptionCleanup := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -806,7 +806,7 @@ var _ = Describe("Install Plan", func() { log("All expected resources resolved") // Verify that the dependent subscription is in a good state - dependentSubscription, err := fetchSubscription(crc, ns.GetName(), strings.Join([]string{dependentPackageStable, dependentCatalogName, ns.GetName()}, "-"), subscriptionStateAtLatestChecker) + dependentSubscription, err := fetchSubscription(crc, ns.GetName(), strings.Join([]string{dependentPackageStable, dependentCatalogName, ns.GetName()}, "-"), subscriptionStateAtLatestChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), dependentSubscription) require.NotNil(GinkgoT(), dependentSubscription.Status.InstallPlanRef) @@ -909,7 +909,7 @@ var _ = Describe("Install Plan", func() { defer cleanupCatalogSource() // Attempt to get the catalog source before creating install plan(s) - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) expectedSteps := map[registry.ResourceKey]struct{}{ @@ -930,7 +930,7 @@ var _ = Describe("Install Plan", func() { subscriptionCleanup := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogSourceName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -1334,14 +1334,14 @@ var _ = Describe("Install Plan", func() { defer cleanupCatalogSource() // Attempt to get the catalog source before creating install plan(s) - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-alpha-") cleanupSubscription := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogSourceName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer cleanupSubscription() - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -1385,12 +1385,12 @@ var _ = Describe("Install Plan", func() { updateInternalCatalog(GinkgoT(), c, crc, mainCatalogSourceName, ns.GetName(), []apiextensions.CustomResourceDefinition{*tt.newCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainStableCSV, mainBetaCSV}, mainManifests) // Attempt to get the catalog source before creating install plan(s) - _, err = fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) // Update the subscription resource to point to the beta CSV err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { - subscription, err = fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err = fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -1582,7 +1582,7 @@ var _ = Describe("Install Plan", func() { defer cleanupCatalogSource() // Attempt to get the catalog source before creating install plan(s) - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-") @@ -1590,7 +1590,7 @@ var _ = Describe("Install Plan", func() { // this subscription will be cleaned up below without the clean up function createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogSourceName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -1623,7 +1623,7 @@ var _ = Describe("Install Plan", func() { updateInternalCatalog(GinkgoT(), c, crc, mainCatalogSourceName, ns.GetName(), []apiextensions.CustomResourceDefinition{*tt.intermediateCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainStableCSV, mainBetaCSV}, mainManifests) // Attempt to get the catalog source before creating install plan(s) - _, err = fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscription, err = fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanDifferentChecker(installPlanName)) require.NoError(GinkgoT(), err) @@ -1663,7 +1663,7 @@ var _ = Describe("Install Plan", func() { updateInternalCatalog(GinkgoT(), c, crc, mainCatalogSourceName, ns.GetName(), []apiextensions.CustomResourceDefinition{*tt.newCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainStableCSV, mainBetaCSV, mainDeltaCSV}, mainManifests) // Attempt to get the catalog source before creating install plan(s) - _, err = fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscription, err = fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanDifferentChecker(installPlanName)) require.NoError(GinkgoT(), err) @@ -1797,14 +1797,14 @@ var _ = Describe("Install Plan", func() { defer cleanupMainCatalogSource() // Attempt to get the catalog source before creating install plan - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-update-perms1") subscriptionCleanup := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) require.NotNil(GinkgoT(), subscription.Status.InstallPlanRef) @@ -1995,14 +1995,14 @@ var _ = Describe("Install Plan", func() { defer cleanupMainCatalogSource() // Attempt to get the catalog source before creating install plan - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-update-perms1") subscriptionCleanup := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) require.NotNil(GinkgoT(), subscription.Status.InstallPlanRef) @@ -2211,14 +2211,14 @@ var _ = Describe("Install Plan", func() { defer cleanupMainCatalogSource() // Attempt to get the catalog source before creating install plan - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-stompy-") subscriptionCleanup := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) require.NotNil(GinkgoT(), subscription.Status.InstallPlanRef) @@ -2451,13 +2451,13 @@ var _ = Describe("Install Plan", func() { defer cleanupMainCatalogSource() // Attempt to get the catalog source before creating install plan - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-update-") createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) require.NotNil(GinkgoT(), subscription.Status.InstallPlanRef) @@ -2650,14 +2650,14 @@ var _ = Describe("Install Plan", func() { defer cleanupMainCatalogSource() // Attempt to get the catalog source before creating install plan - _, err = fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-update2-") subscriptionCleanup := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) require.NotNil(GinkgoT(), subscription.Status.InstallPlanRef) @@ -2792,14 +2792,14 @@ var _ = Describe("Install Plan", func() { defer cleanupCatalogSource() // Attempt to get CatalogSource - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-") subscriptionCleanup := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogSourceName, packageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -3040,14 +3040,14 @@ var _ = Describe("Install Plan", func() { defer cleanupCatalogSource() // Attempt to get the catalog source before creating install plan - _, err := fetchCatalogSourceOnStatus(crc, catalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, catalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-") cleanupSubscription := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, catalogSourceName, packageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer cleanupSubscription() - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -3145,7 +3145,7 @@ var _ = Describe("Install Plan", func() { defer cleanupDependentCatalogSource() // Attempt to get the catalog source before creating install plan - dependentCatalogSource, err := fetchCatalogSourceOnStatus(crc, dependentCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) + dependentCatalogSource, err := fetchCatalogSourceOnStatus(crc, dependentCatalogName, ns.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) // Create the alt dependent catalog sources @@ -3174,7 +3174,7 @@ var _ = Describe("Install Plan", func() { require.NoError(GinkgoT(), err) // Attempt to get the catalog source before creating install plan - _, err = fetchCatalogSourceOnStatus(crc, addressSource.GetName(), ns.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, addressSource.GetName(), ns.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) wg.Done() }(i) @@ -3186,14 +3186,14 @@ var _ = Describe("Install Plan", func() { defer cleanupMainCatalogSource() // Attempt to get the catalog source before creating install plan - _, err = fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-") subscriptionCleanup := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -3354,7 +3354,7 @@ var _ = Describe("Install Plan", func() { Expect(err).ToNot(HaveOccurred()) // Wait for the CatalogSource to be ready - catsrc, err = fetchCatalogSourceOnStatus(crc, catsrc.GetName(), catsrc.GetNamespace(), catalogSourceRegistryPodSynced) + catsrc, err = fetchCatalogSourceOnStatus(crc, catsrc.GetName(), catsrc.GetNamespace(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) // Generate a Subscription @@ -3362,7 +3362,7 @@ var _ = Describe("Install Plan", func() { cleanUpSubscriptionFn := createSubscriptionForCatalog(crc, catsrc.GetNamespace(), subName, catsrc.GetName(), "kiali", stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer cleanUpSubscriptionFn() - sub, err := fetchSubscription(crc, catsrc.GetNamespace(), subName, subscriptionHasInstallPlanChecker) + sub, err := fetchSubscription(crc, catsrc.GetNamespace(), subName, subscriptionHasInstallPlanChecker()) Expect(err).ToNot(HaveOccurred()) // Wait for the expected InstallPlan's execution to either fail or succeed @@ -3929,8 +3929,14 @@ func validateCRDVersions(t GinkgoTInterface, c operatorclient.ClientInterface, n } func buildInstallPlanPhaseCheckFunc(phases ...operatorsv1alpha1.InstallPlanPhase) checkInstallPlanFunc { + var lastPhase operatorsv1alpha1.InstallPlanPhase + lastTime := time.Now() return func(fip *operatorsv1alpha1.InstallPlan) bool { - ctx.Ctx().Logf("installplan %v is in phase %v", fip.GetName(), fip.Status.Phase) + if fip.Status.Phase != lastPhase { + ctx.Ctx().Logf("waiting %s for installplan %s/%s to be phases %v, in phase %s", time.Since(lastTime), fip.Namespace, fip.Name, phases, fip.Status.Phase) + lastPhase = fip.Status.Phase + lastTime = time.Now() + } satisfiesAny := false for _, phase := range phases { satisfiesAny = satisfiesAny || fip.Status.Phase == phase diff --git a/staging/operator-lifecycle-manager/test/e2e/metrics_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/metrics_e2e_test.go index 0d0d119c10..64c33ed59d 100644 --- a/staging/operator-lifecycle-manager/test/e2e/metrics_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/metrics_e2e_test.go @@ -362,7 +362,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { // operator can generate all the requisite resources (e.g. the ServiceAccount), which can leave the underlying // registry Pod in a terminating state until kubelet times out waiting for the generated ServiceAccount // resource to be present so it can mount it in the registry container. - _, err := fetchCatalogSourceOnStatus(crc, cs.GetName(), cs.GetNamespace(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, cs.GetName(), cs.GetNamespace(), catalogSourceRegistryPodSynced()) Expect(err).ShouldNot(HaveOccurred()) var once sync.Once diff --git a/staging/operator-lifecycle-manager/test/e2e/operator_condition_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/operator_condition_e2e_test.go index c10ba615d4..1a6cbc9712 100644 --- a/staging/operator-lifecycle-manager/test/e2e/operator_condition_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/operator_condition_e2e_test.go @@ -72,7 +72,7 @@ var _ = Describe("Operator Condition", func() { catalog := genName("catalog-") _, cleanupCatalogSource := createInternalCatalogSource(c, crc, catalog, generatedNamespace.GetName(), manifests, []apiextensions.CustomResourceDefinition{crd}, []operatorsv1alpha1.ClusterServiceVersion{csvA}) defer cleanupCatalogSource() - _, err := fetchCatalogSourceOnStatus(crc, catalog, generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, catalog, generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) subName := genName("sub-") cleanupSub := createSubscriptionForCatalog(crc, generatedNamespace.GetName(), subName, catalog, pkgA, stableChannel, pkgAStable, operatorsv1alpha1.ApprovalAutomatic) defer cleanupSub() @@ -117,7 +117,7 @@ var _ = Describe("Operator Condition", func() { updateInternalCatalog(GinkgoT(), c, crc, catalog, generatedNamespace.GetName(), []apiextensions.CustomResourceDefinition{crd}, []operatorsv1alpha1.ClusterServiceVersion{csvA, csvB}, manifests) // Attempt to get the catalog source before creating install plan(s) - _, err = fetchCatalogSourceOnStatus(crc, catalog, generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, catalog, generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) // csvB will be in Pending phase due to csvA reports Upgradeable=False condition @@ -176,7 +176,7 @@ var _ = Describe("Operator Condition", func() { updateInternalCatalog(GinkgoT(), c, crc, catalog, generatedNamespace.GetName(), []apiextensions.CustomResourceDefinition{crd}, []operatorsv1alpha1.ClusterServiceVersion{csvA, csvB, csvD}, manifests) // Attempt to get the catalog source before creating install plan(s) - _, err = fetchCatalogSourceOnStatus(crc, catalog, generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, catalog, generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) // CSVD will be in Pending status due to overrides in csvB's condition diff --git a/staging/operator-lifecycle-manager/test/e2e/operator_groups_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/operator_groups_e2e_test.go index 743f8ff37d..940b06e5e1 100644 --- a/staging/operator-lifecycle-manager/test/e2e/operator_groups_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/operator_groups_e2e_test.go @@ -7,8 +7,10 @@ import ( "time" "github.com/blang/semver/v4" + "github.com/google/go-cmp/cmp" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" authorizationv1 "k8s.io/api/authorization/v1" corev1 "k8s.io/api/core/v1" @@ -340,27 +342,41 @@ var _ = Describe("Operator Group", func() { }) // validate provided API clusterroles for the operatorgroup - adminRole, err := c.KubernetesInterface().RbacV1().ClusterRoles().Get(context.TODO(), operatorGroup.Name+"-admin", metav1.GetOptions{}) + existingClusterRoleList, err := c.KubernetesInterface().RbacV1().ClusterRoles().List(context.TODO(), metav1.ListOptions{ + LabelSelector: labels.SelectorFromSet(ownerutil.OwnerLabel(&operatorGroup, "OperatorGroup")).String(), + }) require.NoError(GinkgoT(), err) - adminPolicyRules := []rbacv1.PolicyRule{ - {Verbs: []string{"*"}, APIGroups: []string{mainCRD.Spec.Group}, Resources: []string{mainCRDPlural}}, - } - require.Equal(GinkgoT(), adminPolicyRules, adminRole.Rules) + require.Len(GinkgoT(), existingClusterRoleList.Items, 3) - editRole, err := c.KubernetesInterface().RbacV1().ClusterRoles().Get(context.TODO(), operatorGroup.Name+"-edit", metav1.GetOptions{}) - require.NoError(GinkgoT(), err) - editPolicyRules := []rbacv1.PolicyRule{ - {Verbs: []string{"create", "update", "patch", "delete"}, APIGroups: []string{mainCRD.Spec.Group}, Resources: []string{mainCRDPlural}}, - } - require.Equal(GinkgoT(), editPolicyRules, editRole.Rules) + for _, role := range existingClusterRoleList.Items { + if strings.HasSuffix(role.Name, "admin") { + adminPolicyRules := []rbacv1.PolicyRule{ + {Verbs: []string{"*"}, APIGroups: []string{mainCRD.Spec.Group}, Resources: []string{mainCRDPlural}}, + } + if assert.Equal(GinkgoT(), adminPolicyRules, role.Rules) == false { + fmt.Println(cmp.Diff(adminPolicyRules, role.Rules)) + GinkgoT().Fail() + } - viewRole, err := c.KubernetesInterface().RbacV1().ClusterRoles().Get(context.TODO(), operatorGroup.Name+"-view", metav1.GetOptions{}) - require.NoError(GinkgoT(), err) - viewPolicyRules := []rbacv1.PolicyRule{ - {Verbs: []string{"get"}, APIGroups: []string{"apiextensions.k8s.io"}, Resources: []string{"customresourcedefinitions"}, ResourceNames: []string{mainCRD.Name}}, - {Verbs: []string{"get", "list", "watch"}, APIGroups: []string{mainCRD.Spec.Group}, Resources: []string{mainCRDPlural}}, + } else if strings.HasSuffix(role.Name, "edit") { + editPolicyRules := []rbacv1.PolicyRule{ + {Verbs: []string{"create", "update", "patch", "delete"}, APIGroups: []string{mainCRD.Spec.Group}, Resources: []string{mainCRDPlural}}, + } + if assert.Equal(GinkgoT(), editPolicyRules, role.Rules) == false { + fmt.Println(cmp.Diff(editPolicyRules, role.Rules)) + GinkgoT().Fail() + } + } else if strings.HasSuffix(role.Name, "view") { + viewPolicyRules := []rbacv1.PolicyRule{ + {Verbs: []string{"get"}, APIGroups: []string{"apiextensions.k8s.io"}, Resources: []string{"customresourcedefinitions"}, ResourceNames: []string{mainCRD.Name}}, + {Verbs: []string{"get", "list", "watch"}, APIGroups: []string{mainCRD.Spec.Group}, Resources: []string{mainCRDPlural}}, + } + if assert.Equal(GinkgoT(), viewPolicyRules, role.Rules) == false { + fmt.Println(cmp.Diff(viewPolicyRules, role.Rules)) + GinkgoT().Fail() + } + } } - require.Equal(GinkgoT(), viewPolicyRules, viewRole.Rules) // Unsupport all InstallModes log("unsupporting all csv installmodes") @@ -426,8 +442,8 @@ var _ = Describe("Operator Group", func() { // Create crd so csv succeeds // Ensure clusterroles created and aggregated for access provided APIs - // Generate namespaceA nsA := genName("a") + GinkgoT().Logf("generating namespaceA: %s", nsA) c := newKubeClient() for _, ns := range []string{nsA} { namespace := &corev1.Namespace{ @@ -442,25 +458,29 @@ var _ = Describe("Operator Group", func() { }(ns) } - // Generate operatorGroupA - OwnNamespace - groupA := newOperatorGroup(nsA, genName("a"), nil, nil, []string{nsA}, false) + groupAName := genName("a") + GinkgoT().Logf("Generate operatorGroupA - OwnNamespace: %s", groupAName) + groupA := newOperatorGroup(nsA, groupAName, nil, nil, []string{nsA}, false) _, err := crc.OperatorsV1().OperatorGroups(nsA).Create(context.TODO(), groupA, metav1.CreateOptions{}) require.NoError(GinkgoT(), err) defer func() { require.NoError(GinkgoT(), crc.OperatorsV1().OperatorGroups(nsA).Delete(context.TODO(), groupA.GetName(), metav1.DeleteOptions{})) }() - // Generate csvA in namespaceA with all installmodes supported - crd := newCRD(genName("a")) - namedStrategy := newNginxInstallStrategy(genName("dep-"), nil, nil) - csvA := newCSV("nginx-a", nsA, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{crd}, nil, &namedStrategy) + crdAName := genName("a") + strategyName := genName("dep-") + csvAName := "nginx-a" + GinkgoT().Logf("Generate csv (%s/%s) with crd %s and with all installmodes supported: %s", nsA, csvAName, crdAName, strategyName) + crd := newCRD(crdAName) + namedStrategy := newNginxInstallStrategy(strategyName, nil, nil) + csvA := newCSV(csvAName, nsA, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{crd}, nil, &namedStrategy) _, err = crc.OperatorsV1alpha1().ClusterServiceVersions(nsA).Create(context.TODO(), &csvA, metav1.CreateOptions{}) require.NoError(GinkgoT(), err) defer func() { require.NoError(GinkgoT(), crc.OperatorsV1alpha1().ClusterServiceVersions(nsA).Delete(context.TODO(), csvA.GetName(), metav1.DeleteOptions{})) }() - // Create crd so csv succeeds + GinkgoT().Logf("Create crd %s so csv %s/%s succeeds", crdAName, nsA, csvAName) cleanupCRD, err := createCRD(c, crd) require.NoError(GinkgoT(), err) defer cleanupCRD() @@ -468,8 +488,8 @@ var _ = Describe("Operator Group", func() { _, err = fetchCSV(crc, csvA.GetName(), nsA, csvSucceededChecker) require.NoError(GinkgoT(), err) - // Create a csv for an apiserver depName := genName("hat-server") + GinkgoT().Logf("Create csv %s/%s for an apiserver", nsA, depName) mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName("")) version := "v1alpha1" mockGroupVersion := strings.Join([]string{mockGroup, version}, "/") @@ -531,19 +551,20 @@ var _ = Describe("Operator Group", func() { } csvB.SetName(depName) - // Create the APIService CSV + GinkgoT().Logf("Create the APIService CSV %s/%s", nsA, depName) cleanupCSV, err := createCSV(c, crc, csvB, nsA, false, true) require.NoError(GinkgoT(), err) defer cleanupCSV() + GinkgoT().Logf("Fetch the APIService CSV %s/%s", nsA, depName) _, err = fetchCSV(crc, csvB.GetName(), nsA, csvSucceededChecker) require.NoError(GinkgoT(), err) - // Ensure clusterroles created and aggregated for access provided APIs + GinkgoT().Logf("Ensure clusterroles created and aggregated for access provided APIs") padmin, cleanupPadmin := createProjectAdmin(GinkgoT(), c, nsA) defer cleanupPadmin() - // Check CRD access aggregated + GinkgoT().Logf("Check CRD access aggregated") err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { res, err := c.KubernetesInterface().AuthorizationV1().SubjectAccessReviews().Create(context.TODO(), &authorizationv1.SubjectAccessReview{ Spec: authorizationv1.SubjectAccessReviewSpec{ @@ -563,12 +584,12 @@ var _ = Describe("Operator Group", func() { if res == nil { return false, nil } - GinkgoT().Log("checking padmin for permission") + GinkgoT().Logf("checking padmin for permission: %#v", res) return res.Status.Allowed, nil }) require.NoError(GinkgoT(), err) - // Check apiserver access aggregated + GinkgoT().Logf("Check apiserver access aggregated") err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { res, err := c.KubernetesInterface().AuthorizationV1().SubjectAccessReviews().Create(context.TODO(), &authorizationv1.SubjectAccessReview{ Spec: authorizationv1.SubjectAccessReviewSpec{ @@ -917,15 +938,15 @@ var _ = Describe("Operator Group", func() { catalog := genName("catalog-") _, cleanupCatalogSource := createInternalCatalogSource(c, crc, catalog, nsA, manifests, []apiextensions.CustomResourceDefinition{crdA, crdD, crdB}, []v1alpha1.ClusterServiceVersion{csvA, csvB, csvD}) defer cleanupCatalogSource() - _, err := fetchCatalogSourceOnStatus(crc, catalog, nsA, catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, catalog, nsA, catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) _, cleanupCatalogSource = createInternalCatalogSource(c, crc, catalog, nsB, manifests, []apiextensions.CustomResourceDefinition{crdA, crdD, crdB}, []v1alpha1.ClusterServiceVersion{csvA, csvB, csvD}) defer cleanupCatalogSource() - _, err = fetchCatalogSourceOnStatus(crc, catalog, nsB, catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, catalog, nsB, catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) _, cleanupCatalogSource = createInternalCatalogSource(c, crc, catalog, nsD, manifests, []apiextensions.CustomResourceDefinition{crdA, crdD, crdB}, []v1alpha1.ClusterServiceVersion{csvA, csvB, csvD}) defer cleanupCatalogSource() - _, err = fetchCatalogSourceOnStatus(crc, catalog, nsD, catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, catalog, nsD, catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) // Create operatorgroups @@ -944,7 +965,7 @@ var _ = Describe("Operator Group", func() { subDName := genName("d-") cleanupSubD := createSubscriptionForCatalog(crc, nsD, subDName, catalog, pkgD, stableChannel, pkgDStable, v1alpha1.ApprovalAutomatic) defer cleanupSubD() - subD, err := fetchSubscription(crc, nsD, subDName, subscriptionHasInstallPlanChecker) + subD, err := fetchSubscription(crc, nsD, subDName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subD) @@ -967,7 +988,7 @@ var _ = Describe("Operator Group", func() { subD2Name := genName("d2-") cleanupSubD2 := createSubscriptionForCatalog(crc, nsA, subD2Name, catalog, pkgD, stableChannel, pkgDStable, v1alpha1.ApprovalAutomatic) defer cleanupSubD2() - subD2, err := fetchSubscription(crc, nsA, subD2Name, subscriptionHasInstallPlanChecker) + subD2, err := fetchSubscription(crc, nsA, subD2Name, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subD2) @@ -991,7 +1012,7 @@ var _ = Describe("Operator Group", func() { subAName := genName("a-") cleanupSubA := createSubscriptionForCatalog(crc, nsA, subAName, catalog, pkgA, stableChannel, pkgAStable, v1alpha1.ApprovalAutomatic) defer cleanupSubA() - subA, err := fetchSubscription(crc, nsA, subAName, subscriptionHasInstallPlanChecker) + subA, err := fetchSubscription(crc, nsA, subAName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subA) @@ -1062,7 +1083,7 @@ var _ = Describe("Operator Group", func() { subBName := genName("b-") cleanupSubB := createSubscriptionForCatalog(crc, nsB, subBName, catalog, pkgB, stableChannel, pkgBStable, v1alpha1.ApprovalAutomatic) defer cleanupSubB() - subB, err := fetchSubscription(crc, nsB, subBName, subscriptionHasInstallPlanChecker) + subB, err := fetchSubscription(crc, nsB, subBName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subB) @@ -1184,11 +1205,11 @@ var _ = Describe("Operator Group", func() { catalog := genName("catalog-") _, cleanupCatalogSource := createInternalCatalogSource(c, crc, catalog, nsB, manifests, []apiextensions.CustomResourceDefinition{crdA, crdB}, []v1alpha1.ClusterServiceVersion{csvA, csvB}) defer cleanupCatalogSource() - _, err := fetchCatalogSourceOnStatus(crc, catalog, nsB, catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, catalog, nsB, catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) _, cleanupCatalogSource = createInternalCatalogSource(c, crc, catalog, nsC, manifests, []apiextensions.CustomResourceDefinition{crdA, crdB}, []v1alpha1.ClusterServiceVersion{csvA, csvB}) defer cleanupCatalogSource() - _, err = fetchCatalogSourceOnStatus(crc, catalog, nsC, catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, catalog, nsC, catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) // Create OperatorGroups @@ -1207,7 +1228,7 @@ var _ = Describe("Operator Group", func() { subAName := genName("a-") cleanupSubA := createSubscriptionForCatalog(crc, nsB, subAName, catalog, pkgA, stableChannel, pkgAStable, v1alpha1.ApprovalAutomatic) defer cleanupSubA() - subA, err := fetchSubscription(crc, nsB, subAName, subscriptionHasInstallPlanChecker) + subA, err := fetchSubscription(crc, nsB, subAName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subA) @@ -1233,7 +1254,7 @@ var _ = Describe("Operator Group", func() { // Create subscription for csvA in namespaceC cleanupSubAC := createSubscriptionForCatalog(crc, nsC, subAName, catalog, pkgA, stableChannel, pkgAStable, v1alpha1.ApprovalAutomatic) defer cleanupSubAC() - subAC, err := fetchSubscription(crc, nsC, subAName, subscriptionHasInstallPlanChecker) + subAC, err := fetchSubscription(crc, nsC, subAName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subAC) @@ -1259,7 +1280,7 @@ var _ = Describe("Operator Group", func() { subBName := genName("b-") cleanupSubB := createSubscriptionForCatalog(crc, nsB, subBName, catalog, pkgB, stableChannel, pkgBStable, v1alpha1.ApprovalAutomatic) defer cleanupSubB() - subB, err := fetchSubscription(crc, nsB, subBName, subscriptionHasInstallPlanChecker) + subB, err := fetchSubscription(crc, nsB, subBName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subB) diff --git a/staging/operator-lifecycle-manager/test/e2e/operator_test.go b/staging/operator-lifecycle-manager/test/e2e/operator_test.go index d9e541c53c..6824adcdd2 100644 --- a/staging/operator-lifecycle-manager/test/e2e/operator_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/operator_test.go @@ -279,7 +279,7 @@ var _ = Describe("Operator API", func() { }).Should(Succeed()) // Wait for the CatalogSource to be ready - _, err := fetchCatalogSourceOnStatus(newCRClient(), cs.GetName(), cs.GetNamespace(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(newCRClient(), cs.GetName(), cs.GetNamespace(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) sub = &operatorsv1alpha1.Subscription{ diff --git a/staging/operator-lifecycle-manager/test/e2e/packagemanifest_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/packagemanifest_e2e_test.go index 10af623b39..5e13fe17d8 100644 --- a/staging/operator-lifecycle-manager/test/e2e/packagemanifest_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/packagemanifest_e2e_test.go @@ -111,7 +111,7 @@ var _ = Describe("Package Manifest API lists available Operators from Catalog So _, cleanupCatalogSource = createInternalCatalogSource(c, crc, catsrcName, testNamespace, manifests, []apiextensions.CustomResourceDefinition{crd}, []v1alpha1.ClusterServiceVersion{csv, csvAlpha}) // Verify catalog source was created - _, err := fetchCatalogSourceOnStatus(crc, catsrcName, testNamespace, catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, catsrcName, testNamespace, catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) }) @@ -238,7 +238,7 @@ var _ = Describe("Package Manifest API lists available Operators from Catalog So Expect(err).NotTo(HaveOccurred()) // Wait for the CatalogSource to be ready - _, err = fetchCatalogSourceOnStatus(crc, catalogSource.GetName(), catalogSource.GetNamespace(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, catalogSource.GetName(), catalogSource.GetNamespace(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred(), "catalog source did not become ready") }) diff --git a/staging/operator-lifecycle-manager/test/e2e/subscription_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/subscription_e2e_test.go index 0c968997fb..a3421b12dd 100644 --- a/staging/operator-lifecycle-manager/test/e2e/subscription_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/subscription_e2e_test.go @@ -20,6 +20,7 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" + "k8s.io/apimachinery/pkg/api/equality" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -110,7 +111,7 @@ var _ = Describe("Subscription", func() { } _, teardown = createInternalCatalogSource(ctx.Ctx().KubeClient(), ctx.Ctx().OperatorClient(), "test-catalog", generatedNamespace.GetName(), packages, crds, csvs) - _, err := fetchCatalogSourceOnStatus(ctx.Ctx().OperatorClient(), "test-catalog", generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(ctx.Ctx().OperatorClient(), "test-catalog", generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) Expect(err).NotTo(HaveOccurred()) createSubscriptionForCatalog(ctx.Ctx().OperatorClient(), generatedNamespace.GetName(), "test-subscription", "test-catalog", "root", "channel-root", "", operatorsv1alpha1.ApprovalAutomatic) @@ -202,7 +203,7 @@ var _ = Describe("Subscription", func() { subscriptionCleanup, _ := createSubscription(GinkgoT(), crc, generatedNamespace.GetName(), testSubscriptionName, testPackageName, alphaChannel, operatorsv1alpha1.ApprovalAutomatic) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), testSubscriptionName, subscriptionStateAtLatestChecker) + subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), testSubscriptionName, subscriptionStateAtLatestChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) _, err = fetchCSV(crc, subscription.Status.CurrentCSV, generatedNamespace.GetName(), buildCSVConditionChecker(operatorsv1alpha1.CSVPhaseSucceeded)) @@ -281,7 +282,7 @@ var _ = Describe("Subscription", func() { _, cleanupMainCatalogSource := createInternalCatalogSource(c, crc, mainCatalogName, generatedNamespace.GetName(), mainManifests, []apiextensions.CustomResourceDefinition{crd}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV}) defer cleanupMainCatalogSource() // Attempt to get the catalog source before creating subscription - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) // Create a subscription @@ -315,7 +316,7 @@ var _ = Describe("Subscription", func() { subscriptionCleanup, _ := createSubscription(GinkgoT(), crc, generatedNamespace.GetName(), "manual-subscription", testPackageName, stableChannel, operatorsv1alpha1.ApprovalManual) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), "manual-subscription", subscriptionStateUpgradePendingChecker) + subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), "manual-subscription", subscriptionStateUpgradePendingChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -358,7 +359,7 @@ var _ = Describe("Subscription", func() { return nil })).Should(Succeed()) - subscription, err = fetchSubscription(crc, generatedNamespace.GetName(), "manual-subscription", subscriptionStateAtLatestChecker) + subscription, err = fetchSubscription(crc, generatedNamespace.GetName(), "manual-subscription", subscriptionStateAtLatestChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -424,14 +425,14 @@ var _ = Describe("Subscription", func() { defer cleanupCatalogSource() // Attempt to get the catalog source before creating install plan - _, err := fetchCatalogSourceOnStatus(crc, catalogSourceName, generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, catalogSourceName, generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-") cleanupSubscription := createSubscriptionForCatalog(crc, generatedNamespace.GetName(), subscriptionName, catalogSourceName, packageName, stableChannel, csvA.GetName(), operatorsv1alpha1.ApprovalManual) defer cleanupSubscription() - subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -545,14 +546,14 @@ var _ = Describe("Subscription", func() { defer cleanupCatalogSource() // Attempt to get the catalog source before creating install plan - _, err := fetchCatalogSourceOnStatus(crc, catalogSourceName, generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, catalogSourceName, generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-") cleanupSubscription := createSubscriptionForCatalog(crc, generatedNamespace.GetName(), subscriptionName, catalogSourceName, packageName, stableChannel, csvA.GetName(), operatorsv1alpha1.ApprovalAutomatic) defer cleanupSubscription() - subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -631,7 +632,7 @@ var _ = Describe("Subscription", func() { defer cleanupCatalogSource() // Attempt to get the catalog source before creating install plan - _, err := fetchCatalogSourceOnStatus(crc, catalogSourceName, generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, catalogSourceName, generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) // Create a subscription to just get an InstallPlan for csvB @@ -642,7 +643,7 @@ var _ = Describe("Subscription", func() { _, err = awaitCSV(crc, generatedNamespace.GetName(), csvB.GetName(), csvSucceededChecker) require.NoError(GinkgoT(), err) - subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) fetchedInstallPlan, err := fetchInstallPlanWithNamespace(GinkgoT(), crc, subscription.Status.InstallPlanRef.Name, generatedNamespace.GetName(), buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) // Delete this subscription @@ -678,7 +679,7 @@ var _ = Describe("Subscription", func() { cleanupSubscription := createSubscriptionForCatalog(crc, generatedNamespace.GetName(), subscriptionName, catalogSourceName, packageName, stableChannel, csvA.GetName(), operatorsv1alpha1.ApprovalManual) defer cleanupSubscription() - subscription, err = fetchSubscription(crc, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err = fetchSubscription(crc, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -699,7 +700,7 @@ var _ = Describe("Subscription", func() { require.NoError(GinkgoT(), err) // Wait for the subscription to begin upgrading to csvB - subscription, err = fetchSubscription(crc, generatedNamespace.GetName(), subscriptionName, subscriptionStateUpgradePendingChecker) + subscription, err = fetchSubscription(crc, generatedNamespace.GetName(), subscriptionName, subscriptionStateUpgradePendingChecker()) require.NoError(GinkgoT(), err) // Fetch existing csvB installPlan @@ -768,7 +769,7 @@ var _ = Describe("Subscription", func() { Expect(err).NotTo(HaveOccurred()) // Wait for success - _, err = fetchSubscription(crc, generatedNamespace.GetName(), testSubscriptionName, subscriptionStateAtLatestChecker) + _, err = fetchSubscription(crc, generatedNamespace.GetName(), testSubscriptionName, subscriptionStateAtLatestChecker()) Expect(err).NotTo(HaveOccurred()) }) }) @@ -1055,7 +1056,7 @@ var _ = Describe("Subscription", func() { catalogName := genName("catalog-") _, cleanupCatalogSource := createInternalCatalogSource(c, crc, catalogName, generatedNamespace.GetName(), manifests, []apiextensions.CustomResourceDefinition{crd}, []operatorsv1alpha1.ClusterServiceVersion{csv}) defer cleanupCatalogSource() - _, err := fetchCatalogSourceOnStatus(crc, catalogName, generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, catalogName, generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) // Create Subscription to a package of cs in ns, sub @@ -1063,6 +1064,7 @@ var _ = Describe("Subscription", func() { defer createSubscriptionForCatalog(crc, generatedNamespace.GetName(), subName, catalogName, pkgName, channelName, pkgName, operatorsv1alpha1.ApprovalAutomatic)() // Wait for the package from sub to install successfully with no remaining InstallPlan status conditions + checker := subscriptionStateAtLatestChecker() sub, err := fetchSubscription(crc, generatedNamespace.GetName(), subName, func(s *operatorsv1alpha1.Subscription) bool { for _, cond := range s.Status.Conditions { switch cond.Type { @@ -1070,7 +1072,7 @@ var _ = Describe("Subscription", func() { return false } } - return subscriptionStateAtLatestChecker(s) + return checker(s) }) Expect(err).ToNot(HaveOccurred()) Expect(sub).ToNot(BeNil()) @@ -1333,7 +1335,7 @@ var _ = Describe("Subscription", func() { defer catsrcCleanup() // Ensure that the catalog source is resolved before we create a subscription. - _, err = fetchCatalogSourceOnStatus(crClient, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crClient, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscriptionName := genName("podconfig-sub-") @@ -1341,7 +1343,7 @@ var _ = Describe("Subscription", func() { cleanupSubscription := createSubscriptionForCatalogWithSpec(GinkgoT(), crClient, generatedNamespace.GetName(), subscriptionName, subSpec) defer cleanupSubscription() - subscription, err := fetchSubscription(crClient, generatedNamespace.GetName(), subscriptionName, subscriptionStateAtLatestChecker) + subscription, err := fetchSubscription(crClient, generatedNamespace.GetName(), subscriptionName, subscriptionStateAtLatestChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -1392,7 +1394,7 @@ var _ = Describe("Subscription", func() { defer catsrcCleanup() // Ensure that the catalog source is resolved before we create a subscription. - _, err = fetchCatalogSourceOnStatus(crClient, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crClient, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscriptionName := genName("podconfig-sub-") @@ -1400,7 +1402,7 @@ var _ = Describe("Subscription", func() { cleanupSubscription := createSubscriptionForCatalogWithSpec(GinkgoT(), crClient, generatedNamespace.GetName(), subscriptionName, subSpec) defer cleanupSubscription() - subscription, err := fetchSubscription(crClient, generatedNamespace.GetName(), subscriptionName, subscriptionStateAtLatestChecker) + subscription, err := fetchSubscription(crClient, generatedNamespace.GetName(), subscriptionName, subscriptionStateAtLatestChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -1424,7 +1426,7 @@ var _ = Describe("Subscription", func() { defer catsrcCleanup() // Ensure that the catalog source is resolved before we create a subscription. - _, err := fetchCatalogSourceOnStatus(crClient, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crClient, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) // Create duplicates of the CatalogSource @@ -1433,7 +1435,7 @@ var _ = Describe("Subscription", func() { defer duplicateCatSrcCleanup() // Ensure that the catalog source is resolved before we create a subscription. - _, err = fetchCatalogSourceOnStatus(crClient, duplicateCatsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crClient, duplicateCatsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) } @@ -1442,7 +1444,7 @@ var _ = Describe("Subscription", func() { cleanupSubscription := createSubscriptionForCatalogWithSpec(GinkgoT(), crClient, generatedNamespace.GetName(), subscriptionName, subSpec) defer cleanupSubscription() - subscription, err := fetchSubscription(crClient, generatedNamespace.GetName(), subscriptionName, subscriptionStateAtLatestChecker) + subscription, err := fetchSubscription(crClient, generatedNamespace.GetName(), subscriptionName, subscriptionStateAtLatestChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -1557,9 +1559,9 @@ var _ = Describe("Subscription", func() { defer cleanup() By("waiting for catalogsources to be ready", func() { - _, err := fetchCatalogSourceOnStatus(crClient, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crClient, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) - _, err = fetchCatalogSourceOnStatus(crClient, catsrc2.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crClient, catsrc2.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) }) @@ -1575,7 +1577,7 @@ var _ = Describe("Subscription", func() { cleanupSubscription := createSubscriptionForCatalogWithSpec(GinkgoT(), crClient, generatedNamespace.GetName(), subscriptionName, subscriptionSpec) defer cleanupSubscription() - subscription, err := fetchSubscription(crClient, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crClient, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -1649,11 +1651,11 @@ var _ = Describe("Subscription", func() { catsrcDepWrong, catsrcCleanup3 = createInternalCatalogSource(kubeClient, crClient, "catsrc2", generatedNamespace.GetName(), []registry.PackageManifest{packageDepWrong}, []apiextensions.CustomResourceDefinition{crd}, csvsWrong) - _, err := fetchCatalogSourceOnStatus(crClient, catsrcMain.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crClient, catsrcMain.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) - _, err = fetchCatalogSourceOnStatus(crClient, catsrcDepRight.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crClient, catsrcDepRight.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) - _, err = fetchCatalogSourceOnStatus(crClient, catsrcDepWrong.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crClient, catsrcDepWrong.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) }) @@ -1685,7 +1687,7 @@ var _ = Describe("Subscription", func() { cleanupSubscription = createSubscriptionForCatalogWithSpec(GinkgoT(), crClient, generatedNamespace.GetName(), subscriptionName, subscriptionSpec) var err error - subscription, err = fetchSubscription(crClient, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err = fetchSubscription(crClient, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) Expect(err).ToNot(HaveOccurred()) Expect(subscription).ToNot(BeNil()) @@ -1741,9 +1743,9 @@ var _ = Describe("Subscription", func() { csvsWrong, 100) // waiting for catalogsources to be ready - _, err := fetchCatalogSourceOnStatus(crClient, catsrcMain.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crClient, catsrcMain.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) - _, err = fetchCatalogSourceOnStatus(crClient, catsrcDepWrong.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crClient, catsrcDepWrong.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) }) @@ -1773,7 +1775,7 @@ var _ = Describe("Subscription", func() { cleanupSubscription = createSubscriptionForCatalogWithSpec(GinkgoT(), crClient, generatedNamespace.GetName(), subscriptionName, subscriptionSpec) var err error - subscription, err = fetchSubscription(crClient, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err = fetchSubscription(crClient, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) Expect(err).ToNot(HaveOccurred()) Expect(subscription).ToNot(BeNil()) @@ -1831,11 +1833,11 @@ var _ = Describe("Subscription", func() { []registry.PackageManifest{packageDepWrong}, []apiextensions.CustomResourceDefinition{crd}, csvsWrong) // waiting for catalogsources to be ready - _, err := fetchCatalogSourceOnStatus(crClient, catsrcMain.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crClient, catsrcMain.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) - _, err = fetchCatalogSourceOnStatus(crClient, catsrcDepRight.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crClient, catsrcDepRight.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) - _, err = fetchCatalogSourceOnStatus(crClient, catsrcDepWrong.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crClient, catsrcDepWrong.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) }) @@ -1867,7 +1869,7 @@ var _ = Describe("Subscription", func() { cleanupSubscription = createSubscriptionForCatalogWithSpec(GinkgoT(), crClient, generatedNamespace.GetName(), subscriptionName, subscriptionSpec) var err error - subscription, err = fetchSubscription(crClient, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err = fetchSubscription(crClient, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) Expect(err).ToNot(HaveOccurred()) Expect(subscription).ToNot(BeNil()) @@ -1925,11 +1927,11 @@ var _ = Describe("Subscription", func() { []registry.PackageManifest{packageDepWrong}, []apiextensions.CustomResourceDefinition{crd}, csvsWrong) // waiting for catalogsources to be ready - _, err := fetchCatalogSourceOnStatus(crClient, catsrcMain.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crClient, catsrcMain.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) - _, err = fetchCatalogSourceOnStatus(crClient, catsrcDepRight.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crClient, catsrcDepRight.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) - _, err = fetchCatalogSourceOnStatus(crClient, catsrcDepWrong.GetName(), operatorNamespace, catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crClient, catsrcDepWrong.GetName(), operatorNamespace, catalogSourceRegistryPodSynced()) Expect(err).ToNot(HaveOccurred()) }) @@ -1961,7 +1963,7 @@ var _ = Describe("Subscription", func() { cleanupSubscription = createSubscriptionForCatalogWithSpec(GinkgoT(), crClient, generatedNamespace.GetName(), subscriptionName, subscriptionSpec) var err error - subscription, err = fetchSubscription(crClient, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err = fetchSubscription(crClient, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) Expect(err).ToNot(HaveOccurred()) Expect(subscription).ToNot(BeNil()) @@ -2054,7 +2056,7 @@ var _ = Describe("Subscription", func() { defer cleanup() // Ensure that the catalog source is resolved before we create a subscription. - _, err := fetchCatalogSourceOnStatus(crClient, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crClient, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscriptionSpec := &operatorsv1alpha1.SubscriptionSpec{ @@ -2071,7 +2073,7 @@ var _ = Describe("Subscription", func() { cleanupSubscription := createSubscriptionForCatalogWithSpec(GinkgoT(), crClient, generatedNamespace.GetName(), subscriptionName, subscriptionSpec) defer cleanupSubscription() - subscription, err := fetchSubscription(crClient, generatedNamespace.GetName(), subscriptionName, subscriptionStateAtLatestChecker) + subscription, err := fetchSubscription(crClient, generatedNamespace.GetName(), subscriptionName, subscriptionStateAtLatestChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -2103,7 +2105,7 @@ var _ = Describe("Subscription", func() { } updateInternalCatalog(GinkgoT(), kubeClient, crClient, catalogSourceName, generatedNamespace.GetName(), []apiextensions.CustomResourceDefinition{crd, crd2}, []operatorsv1alpha1.ClusterServiceVersion{csvNewA, csvA, csvB}, manifests) csvAsub := strings.Join([]string{packageName1, stableChannel, catalogSourceName, generatedNamespace.GetName()}, "-") - _, err = fetchSubscription(crClient, generatedNamespace.GetName(), csvAsub, subscriptionStateAtLatestChecker) + _, err = fetchSubscription(crClient, generatedNamespace.GetName(), csvAsub, subscriptionStateAtLatestChecker()) require.NoError(GinkgoT(), err) // Ensure csvNewA is not installed _, err = crClient.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Get(context.Background(), csvNewA.Name, metav1.GetOptions{}) @@ -2173,7 +2175,7 @@ var _ = Describe("Subscription", func() { _, teardown = createInternalCatalogSource(c, ctx.Ctx().OperatorClient(), catSrcName, generatedNamespace.GetName(), packages, nil, []operatorsv1alpha1.ClusterServiceVersion{csvA}) // Ensure that the catalog source is resolved before we create a subscription. - _, err := fetchCatalogSourceOnStatus(crc, catSrcName, generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, catSrcName, generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) cleanup = createSubscriptionForCatalog(crc, generatedNamespace.GetName(), subName, catSrcName, "packageA", "alpha", "", operatorsv1alpha1.ApprovalAutomatic) @@ -2367,7 +2369,7 @@ var _ = Describe("Subscription", func() { }() By("waiting for the CatalogSource to be ready") - catsrc, err = fetchCatalogSourceOnStatus(crc, catsrc.GetName(), catsrc.GetNamespace(), catalogSourceRegistryPodSynced) + catsrc, err = fetchCatalogSourceOnStatus(crc, catsrc.GetName(), catsrc.GetNamespace(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) By("generating a Subscription") @@ -2376,7 +2378,7 @@ var _ = Describe("Subscription", func() { defer cleanUpSubscriptionFn() By("waiting for the InstallPlan to get created for the subscription") - sub, err := fetchSubscription(crc, catsrc.GetNamespace(), subName, subscriptionHasInstallPlanChecker) + sub, err := fetchSubscription(crc, catsrc.GetNamespace(), subName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) By("waiting for the expected InstallPlan's execution to either fail or succeed") @@ -2431,7 +2433,7 @@ var _ = Describe("Subscription", func() { createSubscriptionForCatalog(crc, generatedNamespace.GetName(), subName, catalogSourceName, "packageA", stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) By("waiting until the subscription has an IP reference") - subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), subName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), subName, subscriptionHasInstallPlanChecker()) Expect(err).Should(BeNil()) By("waiting for the v0.1.0 CSV to report a succeeded phase") @@ -2775,7 +2777,7 @@ func initCatalog(t GinkgoTInterface, namespace string, c operatorclient.ClientIn return err } - fetched, err := fetchCatalogSourceOnStatus(crc, dummyCatalogSource.GetName(), dummyCatalogSource.GetNamespace(), catalogSourceRegistryPodSynced) + fetched, err := fetchCatalogSourceOnStatus(crc, dummyCatalogSource.GetName(), dummyCatalogSource.GetNamespace(), catalogSourceRegistryPodSynced()) require.NoError(t, err) require.NotNil(t, fetched) @@ -2784,40 +2786,72 @@ func initCatalog(t GinkgoTInterface, namespace string, c operatorclient.ClientIn type subscriptionStateChecker func(subscription *operatorsv1alpha1.Subscription) bool -func subscriptionStateUpgradeAvailableChecker(subscription *operatorsv1alpha1.Subscription) bool { - return subscription.Status.State == operatorsv1alpha1.SubscriptionStateUpgradeAvailable +func subscriptionStateUpgradeAvailableChecker() func(subscription *operatorsv1alpha1.Subscription) bool { + var lastState operatorsv1alpha1.SubscriptionState + lastTime := time.Now() + return func(subscription *operatorsv1alpha1.Subscription) bool { + if subscription.Status.State != lastState { + ctx.Ctx().Logf("waiting %s for subscription %s/%s to have state %s: has state %s", time.Since(lastTime), subscription.Namespace, subscription.Name, operatorsv1alpha1.SubscriptionStateUpgradeAvailable, subscription.Status.State) + lastState = subscription.Status.State + lastTime = time.Now() + } + return subscription.Status.State == operatorsv1alpha1.SubscriptionStateUpgradeAvailable + } } -func subscriptionStateUpgradePendingChecker(subscription *operatorsv1alpha1.Subscription) bool { - return subscription.Status.State == operatorsv1alpha1.SubscriptionStateUpgradePending +func subscriptionStateUpgradePendingChecker() func(subscription *operatorsv1alpha1.Subscription) bool { + var lastState operatorsv1alpha1.SubscriptionState + lastTime := time.Now() + return func(subscription *operatorsv1alpha1.Subscription) bool { + if subscription.Status.State != lastState { + ctx.Ctx().Logf("waiting %s for subscription %s/%s to have state %s: has state %s", time.Since(lastTime), subscription.Namespace, subscription.Name, operatorsv1alpha1.SubscriptionStateUpgradePending, subscription.Status.State) + lastState = subscription.Status.State + lastTime = time.Now() + } + return subscription.Status.State == operatorsv1alpha1.SubscriptionStateUpgradePending + } } -func subscriptionStateAtLatestChecker(subscription *operatorsv1alpha1.Subscription) bool { - return subscription.Status.State == operatorsv1alpha1.SubscriptionStateAtLatest +func subscriptionStateAtLatestChecker() func(subscription *operatorsv1alpha1.Subscription) bool { + var lastState operatorsv1alpha1.SubscriptionState + lastTime := time.Now() + return func(subscription *operatorsv1alpha1.Subscription) bool { + if subscription.Status.State != lastState { + ctx.Ctx().Logf("waiting %s for subscription %s/%s to have state %s: has state %s", time.Since(lastTime), subscription.Namespace, subscription.Name, operatorsv1alpha1.SubscriptionStateAtLatest, subscription.Status.State) + lastState = subscription.Status.State + lastTime = time.Now() + } + return subscription.Status.State == operatorsv1alpha1.SubscriptionStateAtLatest + } } -func subscriptionHasInstallPlanChecker(subscription *operatorsv1alpha1.Subscription) bool { - ctx.Ctx().Logf("waiting for %s to have installplan ref", subscription.GetName()) - return subscription.Status.InstallPlanRef != nil +func subscriptionHasInstallPlanChecker() func(subscription *operatorsv1alpha1.Subscription) bool { + var lastState operatorsv1alpha1.SubscriptionState + lastTime := time.Now() + return func(subscription *operatorsv1alpha1.Subscription) bool { + if subscription.Status.State != lastState { + ctx.Ctx().Logf("waiting %s for subscription %s/%s to have installplan ref: has ref %#v", time.Since(lastTime), subscription.Namespace, subscription.Name, subscription.Status.InstallPlanRef) + lastState = subscription.Status.State + lastTime = time.Now() + } + return subscription.Status.InstallPlanRef != nil + } } func subscriptionHasInstallPlanDifferentChecker(currentInstallPlanName string) subscriptionStateChecker { + checker := subscriptionHasInstallPlanChecker() + var lastState operatorsv1alpha1.SubscriptionState + lastTime := time.Now() return func(subscription *operatorsv1alpha1.Subscription) bool { - return subscriptionHasInstallPlanChecker(subscription) && subscription.Status.InstallPlanRef.Name != currentInstallPlanName + if subscription.Status.State != lastState { + ctx.Ctx().Logf("waiting %s for subscription %s/%s to have installplan different from %s: has ref %#v", time.Since(lastTime), subscription.Namespace, subscription.Name, currentInstallPlanName, subscription.Status.InstallPlanRef) + lastState = subscription.Status.State + lastTime = time.Now() + } + return checker(subscription) && subscription.Status.InstallPlanRef.Name != currentInstallPlanName } } -func subscriptionStateNoneChecker(subscription *operatorsv1alpha1.Subscription) bool { - return subscription.Status.State == operatorsv1alpha1.SubscriptionStateNone -} - -func subscriptionStateAny(subscription *operatorsv1alpha1.Subscription) bool { - return subscriptionStateNoneChecker(subscription) || - subscriptionStateAtLatestChecker(subscription) || - subscriptionStateUpgradePendingChecker(subscription) || - subscriptionStateUpgradeAvailableChecker(subscription) -} - func subscriptionHasCurrentCSV(currentCSV string) subscriptionStateChecker { return func(subscription *operatorsv1alpha1.Subscription) bool { return subscription.Status.CurrentCSV == currentCSV @@ -2845,12 +2879,20 @@ func fetchSubscription(crc versioned.Interface, namespace, name string, checker ctx.Ctx().Logf("%s: %s", time.Now().Format("15:04:05.9999"), s) } + var lastState operatorsv1alpha1.SubscriptionState + var lastCSV string + var lastInstallPlanRef *corev1.ObjectReference + err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { fetchedSubscription, err = crc.OperatorsV1alpha1().Subscriptions(namespace).Get(context.Background(), name, metav1.GetOptions{}) if err != nil || fetchedSubscription == nil { return false, err } - log(fmt.Sprintf("%s (%s): %s", fetchedSubscription.Status.State, fetchedSubscription.Status.CurrentCSV, fetchedSubscription.Status.InstallPlanRef)) + thisState, thisCSV, thisInstallPlanRef := fetchedSubscription.Status.State, fetchedSubscription.Status.CurrentCSV, fetchedSubscription.Status.InstallPlanRef + if thisState != lastState || thisCSV != lastCSV || equality.Semantic.DeepEqual(thisInstallPlanRef, lastInstallPlanRef) { + lastState, lastCSV, lastInstallPlanRef = thisState, thisCSV, thisInstallPlanRef + log(fmt.Sprintf("%s (%s): %s", thisState, thisCSV, thisInstallPlanRef)) + } return checker(fetchedSubscription), nil }) if err != nil { @@ -3093,7 +3135,7 @@ func checkDeploymentWithPodConfiguration(client operatorclient.ClientInterface, } func updateInternalCatalog(t GinkgoTInterface, c operatorclient.ClientInterface, crc versioned.Interface, catalogSourceName, namespace string, crds []apiextensions.CustomResourceDefinition, csvs []operatorsv1alpha1.ClusterServiceVersion, packages []registry.PackageManifest) { - fetchedInitialCatalog, err := fetchCatalogSourceOnStatus(crc, catalogSourceName, namespace, catalogSourceRegistryPodSynced) + fetchedInitialCatalog, err := fetchCatalogSourceOnStatus(crc, catalogSourceName, namespace, catalogSourceRegistryPodSynced()) require.NoError(t, err) // Get initial configmap diff --git a/staging/operator-lifecycle-manager/test/e2e/user_defined_sa_test.go b/staging/operator-lifecycle-manager/test/e2e/user_defined_sa_test.go index b4a9806032..1e05304b9a 100644 --- a/staging/operator-lifecycle-manager/test/e2e/user_defined_sa_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/user_defined_sa_test.go @@ -50,15 +50,15 @@ var _ = Describe("User defined service account", func() { It("with no permission", func() { - // Create a service account, but add no permission to it. + By("Create a service account, but add no permission to it.") saName := genName("scoped-sa-") _, cleanupSA := newServiceAccount(c, generatedNamespace.GetName(), saName) defer cleanupSA() - // Create token secret for the serviceaccount + By("Create token secret for the serviceaccount") _, cleanupSE := newTokenSecret(c, generatedNamespace.GetName(), saName) defer cleanupSE() - // Add an OperatorGroup and specify the service account. + By("Add an OperatorGroup and specify the service account.") ogName := genName("scoped-og-") _, cleanupOG := newOperatorGroupWithServiceAccount(crc, generatedNamespace.GetName(), ogName, saName) defer cleanupOG() @@ -67,20 +67,20 @@ var _ = Describe("User defined service account", func() { catsrc, subSpec, catsrcCleanup := newCatalogSource(GinkgoT(), c, crc, "scoped", generatedNamespace.GetName(), permissions) defer catsrcCleanup() - // Ensure that the catalog source is resolved before we create a subscription. - _, err := fetchCatalogSourceOnStatus(crc, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + By("Ensure that the catalog source is resolved before we create a subscription.") + _, err := fetchCatalogSourceOnStatus(crc, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscriptionName := genName("scoped-sub-") cleanupSubscription := createSubscriptionForCatalog(crc, generatedNamespace.GetName(), subscriptionName, catsrc.GetName(), subSpec.Package, subSpec.Channel, subSpec.StartingCSV, subSpec.InstallPlanApproval) defer cleanupSubscription() - // Wait until an install plan is created. - subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + By("Wait until an install plan is created.") + subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) - // We expect the InstallPlan to be in status: Failed. + By("We expect the InstallPlan to be in status: Failed.") ipName := subscription.Status.Install.Name ipPhaseCheckerFunc := buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseFailed) ipGot, err := fetchInstallPlanWithNamespace(GinkgoT(), crc, ipName, generatedNamespace.GetName(), ipPhaseCheckerFunc) @@ -91,29 +91,29 @@ var _ = Describe("User defined service account", func() { assert.Equal(GinkgoT(), v1alpha1.InstallPlanReasonComponentFailed, conditionGot.Reason) assert.Contains(GinkgoT(), conditionGot.Message, fmt.Sprintf("is forbidden: User \"system:serviceaccount:%s:%s\" cannot create resource", generatedNamespace.GetName(), saName)) - // Verify that all step resources are in Unknown state. + By("Verify that all step resources are in Unknown state.") for _, step := range ipGot.Status.Plan { assert.Equal(GinkgoT(), v1alpha1.StepStatusUnknown, step.Status) } }) It("with permission", func() { - // Create the CatalogSource + By("Create the CatalogSource") namespace := genName("scoped-ns-") _, cleanupNS := newNamespace(c, namespace) defer cleanupNS() - // Create a service account, add enough permission to it so that operator install is successful. + By("Create a service account, add enough permission to it so that operator install is successful.") saName := genName("scoped-sa") _, cleanupSA := newServiceAccount(c, generatedNamespace.GetName(), saName) defer cleanupSA() - // Create token secret for the serviceaccount + By("Create token secret for the serviceaccount") _, cleanupSE := newTokenSecret(c, generatedNamespace.GetName(), saName) defer cleanupSE() cleanupPerm := grantPermission(GinkgoT(), c, generatedNamespace.GetName(), saName) defer cleanupPerm() - // Add an OperatorGroup and specify the service account. + By("Add an OperatorGroup and specify the service account.") ogName := genName("scoped-og-") _, cleanupOG := newOperatorGroupWithServiceAccount(crc, generatedNamespace.GetName(), ogName, saName) defer cleanupOG() @@ -122,20 +122,20 @@ var _ = Describe("User defined service account", func() { catsrc, subSpec, catsrcCleanup := newCatalogSource(GinkgoT(), c, crc, "scoped", generatedNamespace.GetName(), permissions) defer catsrcCleanup() - // Ensure that the catalog source is resolved before we create a subscription. - _, err := fetchCatalogSourceOnStatus(crc, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + By("Ensure that the catalog source is resolved before we create a subscription.") + _, err := fetchCatalogSourceOnStatus(crc, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscriptionName := genName("scoped-sub-") cleanupSubscription := createSubscriptionForCatalog(crc, generatedNamespace.GetName(), subscriptionName, catsrc.GetName(), subSpec.Package, subSpec.Channel, subSpec.StartingCSV, subSpec.InstallPlanApproval) defer cleanupSubscription() - // Wait until an install plan is created. - subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + By("Wait until an install plan is created.") + subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) - // We expect the InstallPlan to be in status: Complete. + By("We expect the InstallPlan to be in status: Complete.") ipName := subscription.Status.Install.Name ipPhaseCheckerFunc := buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete) ipGot, err := fetchInstallPlanWithNamespace(GinkgoT(), crc, ipName, generatedNamespace.GetName(), ipPhaseCheckerFunc) @@ -146,7 +146,7 @@ var _ = Describe("User defined service account", func() { assert.Equal(GinkgoT(), corev1.ConditionTrue, conditionGot.Status) assert.Equal(GinkgoT(), "", conditionGot.Message) - // Verify that all step resources are in Created state. + By("Verify that all step resources are in Created state.") for _, step := range ipGot.Status.Plan { // TODO: switch back to commented assertion once InstallPlan status is being patched instead of updated // assert.Equal(GinkgoT(), v1alpha1.StepStatusCreated, step.Status) @@ -155,15 +155,15 @@ var _ = Describe("User defined service account", func() { }) It("with retry", func() { - // Create a service account, but add no permission to it. + By("Create a service account, but add no permission to it.") saName := genName("scoped-sa-") _, cleanupSA := newServiceAccount(c, generatedNamespace.GetName(), saName) defer cleanupSA() - // Create token secret for the serviceaccount + By("Create token secret for the serviceaccount") _, cleanupSE := newTokenSecret(c, generatedNamespace.GetName(), saName) defer cleanupSE() - // Add an OperatorGroup and specify the service account. + By("Add an OperatorGroup and specify the service account.") ogName := genName("scoped-og-") _, cleanupOG := newOperatorGroupWithServiceAccount(crc, generatedNamespace.GetName(), ogName, saName) defer cleanupOG() @@ -172,27 +172,27 @@ var _ = Describe("User defined service account", func() { catsrc, subSpec, catsrcCleanup := newCatalogSource(GinkgoT(), c, crc, "scoped", generatedNamespace.GetName(), permissions) defer catsrcCleanup() - // Ensure that the catalog source is resolved before we create a subscription. - _, err := fetchCatalogSourceOnStatus(crc, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) + By("Ensure that the catalog source is resolved before we create a subscription.") + _, err := fetchCatalogSourceOnStatus(crc, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) subscriptionName := genName("scoped-sub-") cleanupSubscription := createSubscriptionForCatalog(crc, generatedNamespace.GetName(), subscriptionName, catsrc.GetName(), subSpec.Package, subSpec.Channel, subSpec.StartingCSV, subSpec.InstallPlanApproval) defer cleanupSubscription() - // Wait until an install plan is created. - subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) + By("Wait until an install plan is created.") + subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker()) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) - // We expect the InstallPlan to be in status: Failed. + By("We expect the InstallPlan to be in status: Failed.") ipNameOld := subscription.Status.InstallPlanRef.Name ipPhaseCheckerFunc := buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseFailed) ipGotOld, err := fetchInstallPlanWithNamespace(GinkgoT(), crc, ipNameOld, generatedNamespace.GetName(), ipPhaseCheckerFunc) require.NoError(GinkgoT(), err) require.Equal(GinkgoT(), v1alpha1.InstallPlanPhaseFailed, ipGotOld.Status.Phase) - // Grant permission now and this should trigger an retry of InstallPlan. + By("Grant permission now and this should trigger an retry of InstallPlan.") cleanupPerm := grantPermission(GinkgoT(), c, generatedNamespace.GetName(), saName) defer cleanupPerm() diff --git a/staging/operator-lifecycle-manager/test/e2e/util.go b/staging/operator-lifecycle-manager/test/e2e/util.go index 1764292bf6..04878b321b 100644 --- a/staging/operator-lifecycle-manager/test/e2e/util.go +++ b/staging/operator-lifecycle-manager/test/e2e/util.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "os" "regexp" "strings" "time" @@ -314,6 +315,7 @@ var checkPodHealth = false func registryPodHealthy(address string) bool { if !checkPodHealth { + fmt.Println("skipping health check") return true } @@ -335,19 +337,27 @@ func registryPodHealthy(address string) bool { return true } -func catalogSourceRegistryPodSynced(catalog *operatorsv1alpha1.CatalogSource) bool { - registry := catalog.Status.RegistryServiceStatus - connState := catalog.Status.GRPCConnectionState - if registry != nil && connState != nil && !connState.LastConnectTime.IsZero() && connState.LastObservedState == "READY" { - fmt.Printf("catalog %s pod with address %s\n", catalog.GetName(), registry.Address()) - return registryPodHealthy(registry.Address()) - } - state := "NO_CONNECTION" - if connState != nil { - state = connState.LastObservedState +func catalogSourceRegistryPodSynced() func(catalog *operatorsv1alpha1.CatalogSource) bool { + var lastState string + lastTime := time.Now() + return func(catalog *operatorsv1alpha1.CatalogSource) bool { + registry := catalog.Status.RegistryServiceStatus + connState := catalog.Status.GRPCConnectionState + state := "NO_CONNECTION" + if connState != nil { + state = connState.LastObservedState + } + if state != lastState { + fmt.Printf("waiting %s for catalog pod %s/%s to be available (for sync) - %s\n", time.Since(lastTime), catalog.GetNamespace(), catalog.GetName(), state) + lastState = state + lastTime = time.Now() + } + if registry != nil && connState != nil && !connState.LastConnectTime.IsZero() && connState.LastObservedState == "READY" { + fmt.Printf("probing catalog %s pod with address %s\n", catalog.GetName(), registry.Address()) + return registryPodHealthy(registry.Address()) + } + return false } - fmt.Printf("waiting for catalog pod %v to be available (for sync) - %s\n", catalog.GetName(), state) - return false } func catalogSourceInvalidSpec(catalog *operatorsv1alpha1.CatalogSource) bool { @@ -361,7 +371,7 @@ func fetchCatalogSourceOnStatus(crc versioned.Interface, name, namespace string, err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { fetched, err = crc.OperatorsV1alpha1().CatalogSources(namespace).Get(context.Background(), name, metav1.GetOptions{}) if err != nil || fetched == nil { - fmt.Println(err) + fmt.Printf("failed to fetch catalogSource %s/%s: %v\n", namespace, name, err) return false, err } return check(fetched), nil @@ -417,6 +427,10 @@ var ( // TearDown deletes all OLM resources in the corresponding namespace and at the cluster scope. func TearDown(namespace string) { + if env := os.Getenv("SKIP_CLEANUP"); env != "" { + fmt.Printf("Skipping cleanup of namespace %s...\n", namespace) + return + } var ( clientCtx = context.Background() client = ctx.Ctx().Client() @@ -531,6 +545,10 @@ func TearDown(namespace string) { func buildCatalogSourceCleanupFunc(c operatorclient.ClientInterface, crc versioned.Interface, namespace string, catalogSource *operatorsv1alpha1.CatalogSource) cleanupFunc { return func() { + if env := os.Getenv("SKIP_CLEANUP"); env != "" { + fmt.Printf("Skipping cleanup of CatalogSource %s/%s...\n", namespace, catalogSource.GetName()) + return + } ctx.Ctx().Logf("Deleting catalog source %s...", catalogSource.GetName()) err := crc.OperatorsV1alpha1().CatalogSources(namespace).Delete(context.Background(), catalogSource.GetName(), metav1.DeleteOptions{}) Expect(err).ToNot(HaveOccurred()) @@ -555,6 +573,10 @@ func buildCatalogSourceCleanupFunc(c operatorclient.ClientInterface, crc version func buildConfigMapCleanupFunc(c operatorclient.ClientInterface, namespace string, configMap *corev1.ConfigMap) cleanupFunc { return func() { + if env := os.Getenv("SKIP_CLEANUP"); env != "" { + fmt.Printf("Skipping cleanup of ConfigMap %s/%s...\n", namespace, configMap.GetName()) + return + } ctx.Ctx().Logf("Deleting config map %s...", configMap.GetName()) err := c.KubernetesInterface().CoreV1().ConfigMaps(namespace).Delete(context.Background(), configMap.GetName(), metav1.DeleteOptions{}) Expect(err).ToNot(HaveOccurred()) @@ -563,6 +585,10 @@ func buildConfigMapCleanupFunc(c operatorclient.ClientInterface, namespace strin func buildServiceAccountCleanupFunc(t GinkgoTInterface, c operatorclient.ClientInterface, namespace string, serviceAccount *corev1.ServiceAccount) cleanupFunc { return func() { + if env := os.Getenv("SKIP_CLEANUP"); env != "" { + fmt.Printf("Skipping cleanup of ServiceAccount %s/%s...\n", namespace, serviceAccount.GetName()) + return + } t.Logf("Deleting service account %s...", serviceAccount.GetName()) require.NoError(t, c.KubernetesInterface().CoreV1().ServiceAccounts(namespace).Delete(context.Background(), serviceAccount.GetName(), metav1.DeleteOptions{})) } @@ -884,6 +910,10 @@ func createCR(c operatorclient.ClientInterface, item *unstructured.Unstructured, func buildCRCleanupFunc(c operatorclient.ClientInterface, apiGroup, version, namespace, resourceKind, resourceName string) cleanupFunc { return func() { + if env := os.Getenv("SKIP_CLEANUP"); env != "" { + fmt.Printf("Skipping cleanup of custom resource %s.%s/%s %s/%s...\n", apiGroup, resourceKind, version, namespace, resourceName) + return + } err := c.DeleteCustomResource(apiGroup, version, namespace, resourceKind, resourceName) if err != nil { fmt.Println(err) @@ -1048,6 +1078,10 @@ func SetupGeneratedTestNamespace(name string, targetNamespaces ...string) corev1 } func TeardownNamespace(ns string) { + if env := os.Getenv("SKIP_CLEANUP"); env != "" { + fmt.Printf("Skipping cleanup of namespace %s...\n", ns) + return + } log := ctx.Ctx().Logf currentTest := CurrentSpecReport() @@ -1102,6 +1136,10 @@ func newTokenSecret(client operatorclient.ClientInterface, namespace, saName str Expect(se).ToNot(BeNil()) cleanup = func() { + if env := os.Getenv("SKIP_CLEANUP"); env != "" { + fmt.Printf("Skipping cleanup of secret %s/%s...\n", namespace, se.GetName()) + return + } err := client.KubernetesInterface().CoreV1().Secrets(namespace).Delete(context.TODO(), se.GetName(), metav1.DeleteOptions{}) Expect(err).ToNot(HaveOccurred()) } diff --git a/staging/operator-lifecycle-manager/test/e2e/webhook_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/webhook_e2e_test.go index df2793cdea..273b009a51 100644 --- a/staging/operator-lifecycle-manager/test/e2e/webhook_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/webhook_e2e_test.go @@ -682,7 +682,7 @@ var _ = Describe("CSVs with a Webhook", func() { } // Wait for the CatalogSource to be ready - _, err = fetchCatalogSourceOnStatus(crc, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, source.GetName(), source.GetNamespace(), catalogSourceRegistryPodSynced()) require.NoError(GinkgoT(), err) // Create a Subscription for the webhook-operator diff --git a/staging/operator-registry/Makefile b/staging/operator-registry/Makefile index df4ac5072b..8db4b4333e 100644 --- a/staging/operator-registry/Makefile +++ b/staging/operator-registry/Makefile @@ -3,6 +3,7 @@ GO := go CMDS := $(addprefix bin/, $(shell ls ./cmd | grep -v opm)) OPM := $(addprefix bin/, opm) SPECIFIC_UNIT_TEST := $(if $(TEST),-run $(TEST),) +SPECIFIC_SKIP_UNIT_TEST := $(if $(SKIP),-skip $(SKIP),) extra_env := $(GOENV) export PKG := github.com/operator-framework/operator-registry export GIT_COMMIT := $(or $(SOURCE_GIT_COMMIT),$(shell git rev-parse --short HEAD)) @@ -60,7 +61,7 @@ static: build .PHONY: unit unit: - $(GO) test -coverprofile=coverage.out $(SPECIFIC_UNIT_TEST) $(TAGS) $(TEST_RACE) -count=1 ./pkg/... ./alpha/... + $(GO) test -coverprofile=coverage.out $(SPECIFIC_UNIT_TEST) $(SPECIFIC_SKIP_UNIT_TEST) $(TAGS) $(TEST_RACE) -count=1 ./pkg/... ./alpha/... .PHONY: sanity-check sanity-check: diff --git a/staging/operator-registry/alpha/declcfg/declcfg.go b/staging/operator-registry/alpha/declcfg/declcfg.go index 994d47a0b7..f688574b1c 100644 --- a/staging/operator-registry/alpha/declcfg/declcfg.go +++ b/staging/operator-registry/alpha/declcfg/declcfg.go @@ -6,6 +6,8 @@ import ( "errors" "fmt" + prettyunmarshaler "github.com/operator-framework/operator-registry/pkg/prettyunmarshaler" + "golang.org/x/text/cases" utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" @@ -107,7 +109,7 @@ func (m *Meta) UnmarshalJSON(blob []byte) error { // that eat our error type and return a generic error, such that we lose the // ability to errors.As to get this error on the other side. For now, just return // a string error that includes the pretty printed message. - return errors.New(newJSONUnmarshalError(blob, err).Pretty()) + return errors.New(prettyunmarshaler.NewJSONUnmarshalError(blob, err).Pretty()) } // TODO: this function ensures we do not break backwards compatibility with diff --git a/staging/operator-registry/alpha/template/composite/composite.go b/staging/operator-registry/alpha/template/composite/composite.go index ce2cd0f4dd..41a287c08a 100644 --- a/staging/operator-registry/alpha/template/composite/composite.go +++ b/staging/operator-registry/alpha/template/composite/composite.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "io" - "net/http" "net/url" "os" "path/filepath" @@ -14,23 +13,6 @@ import ( "k8s.io/apimachinery/pkg/util/yaml" ) -type BuilderMap map[string]Builder - -type CatalogBuilderMap map[string]BuilderMap - -type builderFunc func(BuilderConfig) Builder - -type Template struct { - catalogFile io.Reader - contributionFile io.Reader - validate bool - outputType string - registry image.Registry - registeredBuilders map[string]builderFunc -} - -type TemplateOption func(t *Template) - func WithCatalogFile(catalogFile io.Reader) TemplateOption { return func(t *Template) { t.catalogFile = catalogFile @@ -79,10 +61,6 @@ func NewTemplate(opts ...TemplateOption) *Template { return temp } -type HttpGetter interface { - Get(url string) (*http.Response, error) -} - // FetchCatalogConfig will fetch the catalog configuration file from the given path. // The path can be a local file path OR a URL that returns the raw contents of the catalog // configuration file. @@ -100,7 +78,7 @@ func FetchCatalogConfig(path string, httpGetter HttpGetter) (io.ReadCloser, erro } } else { // Evalute remote catalog config - // If URi is valid, execute fetch + // If URI is valid, execute fetch tempResp, err := httpGetter.Get(catalogURI.String()) if err != nil { return nil, fmt.Errorf("fetching remote catalog config file %q: %v", path, err) @@ -111,26 +89,37 @@ func FetchCatalogConfig(path string, httpGetter HttpGetter) (io.ReadCloser, erro return tempCatalog, nil } -// TODO(everettraven): do we need the context here? If so, how should it be used? -func (t *Template) Render(ctx context.Context, validate bool) error { +func (t *Template) Parse() (*Specs, error) { + var s Specs - catalogFile, err := t.parseCatalogsSpec() + catalogSpec, err := t.parseCatalogsSpec() if err != nil { - return err + return nil, err + } + s.CatalogSpec = catalogSpec + + contributionSpec, err := t.parseContributionSpec() + if err != nil { + return nil, err } + s.ContributionSpec = contributionSpec + + return &s, nil +} - contributionFile, err := t.parseContributionSpec() +func (t *Template) Render(ctx context.Context, validate bool) error { + specs, err := t.Parse() if err != nil { return err } - catalogBuilderMap, err := t.newCatalogBuilderMap(catalogFile.Catalogs, t.outputType) + catalogBuilderMap, err := t.newCatalogBuilderMap(specs.CatalogSpec.Catalogs, t.outputType) if err != nil { return err } // TODO(everettraven): should we return aggregated errors? - for _, component := range contributionFile.Components { + for _, component := range specs.ContributionSpec.Components { if builderMap, ok := (*catalogBuilderMap)[component.Name]; ok { if builder, ok := builderMap[component.Strategy.Template.Schema]; ok { // run the builder corresponding to the schema diff --git a/staging/operator-registry/alpha/template/composite/types.go b/staging/operator-registry/alpha/template/composite/types.go index 5295a5ddfd..93b53883c5 100644 --- a/staging/operator-registry/alpha/template/composite/types.go +++ b/staging/operator-registry/alpha/template/composite/types.go @@ -1,6 +1,12 @@ package composite -import "encoding/json" +import ( + "encoding/json" + "io" + "net/http" + + "github.com/operator-framework/operator-registry/pkg/image" +) type TemplateDefinition struct { Schema string @@ -27,3 +33,29 @@ type CustomConfig struct { Args []string Output string } + +type BuilderMap map[string]Builder + +type CatalogBuilderMap map[string]BuilderMap + +type builderFunc func(BuilderConfig) Builder + +type Template struct { + catalogFile io.Reader + contributionFile io.Reader + validate bool + outputType string + registry image.Registry + registeredBuilders map[string]builderFunc +} + +type TemplateOption func(t *Template) + +type Specs struct { + CatalogSpec *CatalogConfig + ContributionSpec *CompositeConfig +} + +type HttpGetter interface { + Get(url string) (*http.Response, error) +} diff --git a/staging/operator-registry/go.mod b/staging/operator-registry/go.mod index efca010495..afb8267a1d 100644 --- a/staging/operator-registry/go.mod +++ b/staging/operator-registry/go.mod @@ -1,17 +1,17 @@ module github.com/operator-framework/operator-registry -go 1.19 +go 1.20 require ( github.com/adrg/xdg v0.4.0 github.com/blang/semver/v4 v4.0.0 - github.com/containerd/containerd v1.5.18 + github.com/containerd/containerd v1.6.22 github.com/docker/cli v20.10.12+incompatible github.com/docker/distribution v2.8.2+incompatible github.com/docker/docker v20.10.24+incompatible github.com/ghodss/yaml v1.0.0 github.com/golang-migrate/migrate/v4 v4.16.1 - github.com/golang/mock v1.5.0 + github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.5.9 github.com/grpc-ecosystem/grpc-health-probe v0.4.11 github.com/h2non/filetype v1.1.1 @@ -22,7 +22,7 @@ require ( github.com/onsi/ginkgo/v2 v2.9.5 github.com/onsi/gomega v1.27.7 github.com/opencontainers/go-digest v1.0.0 - github.com/opencontainers/image-spec v1.0.2 + github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b github.com/operator-framework/api v0.17.7 github.com/otiai10/copy v1.2.0 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 @@ -30,7 +30,7 @@ require ( github.com/sirupsen/logrus v1.9.2 github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.3 - go.etcd.io/bbolt v1.3.6 + go.etcd.io/bbolt v1.3.7 golang.org/x/mod v0.10.0 golang.org/x/net v0.10.0 golang.org/x/sync v0.2.0 @@ -55,7 +55,7 @@ require ( github.com/BurntSushi/toml v0.3.1 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/Microsoft/hcsshim v0.8.25 // indirect + github.com/Microsoft/hcsshim v0.9.8 // indirect github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d // indirect github.com/alessio/shellescape v1.4.1 // indirect github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect @@ -66,16 +66,16 @@ require ( github.com/bugsnag/panicwrap v1.2.0 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/containerd/cgroups v1.0.3 // indirect + github.com/containerd/cgroups v1.0.4 // indirect github.com/containerd/continuity v0.3.0 // indirect - github.com/containerd/ttrpc v1.1.0 // indirect + github.com/containerd/ttrpc v1.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/docker-credential-helpers v0.6.3 // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect - github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/emicklei/go-restful/v3 v3.10.2 // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect @@ -95,7 +95,7 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/google/cel-go v0.15.3 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect - github.com/google/gofuzz v1.1.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/google/uuid v1.3.0 // indirect github.com/gorilla/handlers v1.4.2 // indirect @@ -115,13 +115,13 @@ require ( github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/moby/locker v1.0.1 // indirect github.com/moby/spdystream v0.2.0 // indirect - github.com/moby/sys/mountinfo v0.4.1 // indirect + github.com/moby/sys/mountinfo v0.6.2 // indirect github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/pelletier/go-toml v1.9.3 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.15.1 // indirect github.com/prometheus/client_model v0.4.0 // indirect diff --git a/staging/operator-registry/go.sum b/staging/operator-registry/go.sum index 87549f5b3b..5b5672e937 100644 --- a/staging/operator-registry/go.sum +++ b/staging/operator-registry/go.sum @@ -34,24 +34,51 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/Microsoft/hcsshim v0.8.25 h1:fRMwXiwk3qDwc0P05eHnh+y2v07JdtsfQ1fuAc69m9g= -github.com/Microsoft/hcsshim v0.8.25/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= +github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= +github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= +github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= +github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= +github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= +github.com/Microsoft/hcsshim v0.9.8 h1:lf7xxK2+Ikbj9sVf2QZsouGjRjEp2STj1yDHgoVtU5k= +github.com/Microsoft/hcsshim v0.9.8/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= +github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= +github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= @@ -59,9 +86,12 @@ github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= @@ -83,12 +113,16 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bshuster-repo/logrus-logstash-hook v0.4.1 h1:pgAtgj+A31JBVtEHu2uHuEx0n+2ukqUJnS2vVe5pQNA= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/bugsnag-go v1.5.3 h1:yeRUT3mUE13jL1tGwvoQsKdVbAsQx9AJ+fqahKveP04= github.com/bugsnag/bugsnag-go v1.5.3/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= @@ -104,10 +138,16 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= +github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -116,37 +156,127 @@ github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= +github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= +github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E= +github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= +github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= -github.com/containerd/cgroups v1.0.3 h1:ADZftAkglvCiD44c77s5YmMqaP2pzVCFZvBmAlBdAP4= -github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8= +github.com/containerd/cgroups v1.0.4 h1:jN/mbWBEaz+T1pi5OFtnkQ+8qnmEbAr1Oo1FRm5B0dA= +github.com/containerd/cgroups v1.0.4/go.mod h1:nLNQtsF7Sl2HxNebu77i1R0oDlhiTG+kO4JTrUzo6IA= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= -github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.5.18 h1:doHr6cNxfOLTotWmZs6aZF6LrfJFcjmYFcWlRmQgYPM= -github.com/containerd/containerd v1.5.18/go.mod h1:7IN9MtIzTZH4WPEmD1gNH8bbTQXVX68yd3ZXxSHYCis= +github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ= +github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= +github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= +github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s= +github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= +github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c= +github.com/containerd/containerd v1.6.22 h1:rGTIBxPJusM0evF6wKgIzuD+tV70nmx9eEjzHVm1JzI= +github.com/containerd/containerd v1.6.22/go.mod h1:BQAJdahvGz8xboAvxKg9hsDYIovn79Ea318anowQ1/o= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= +github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= +github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU= +github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g= +github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= -github.com/containerd/ttrpc v1.1.0 h1:GbtyLRxb0gOLR0TYQWt3O6B0NvT8tMdorEHqIQo/lWI= +github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0= +github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA= +github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow= +github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms= +github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= +github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= +github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ= +github.com/containerd/ttrpc v1.1.2 h1:4jH6OQDQqjfVD2b5TJS5TxmGuLGmp5WW7KtW2TWOP7c= +github.com/containerd/ttrpc v1.1.2/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= +github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY= github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= +github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw= +github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y= +github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containerd/zfs v0.0.0-20210324211415-d5c4544f0433/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= +github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8= +github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= +github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4= +github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= +github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= +github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= +github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -155,16 +285,20 @@ github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v20.10.12+incompatible h1:lZlz0uzG+GH+c0plStMUdF/qk3ppmgnswpR5EbqzVGA= github.com/docker/cli v20.10.12+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v0.0.0-20191216044856-a8371794149d h1:jC8tT/S0OGx2cswpeUTn4gOIea8P08lD3VFQT0cOZ50= github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.24+incompatible h1:Ugvxm7a8+Gz6vqQYQQ2W7GYq5EUPaAiuPgIfVyI3dYE= github.com/docker/docker v20.10.24+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= @@ -176,11 +310,13 @@ github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= -github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= +github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -199,10 +335,12 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc= github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= @@ -223,6 +361,7 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= @@ -234,15 +373,19 @@ github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= @@ -250,12 +393,19 @@ github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= +github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -264,6 +414,7 @@ github.com/golang-migrate/migrate/v4 v4.16.1/go.mod h1:qXiwa/3Zeqaltm1MxOCZDYysW github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -277,8 +428,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -317,9 +468,11 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -332,8 +485,10 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -344,13 +499,18 @@ github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg= github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QGdLI4y34qQGjGWO0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= @@ -362,11 +522,13 @@ github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c h1:fEE5/5VNnYUoBOj github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c/go.mod h1:ObS/W+h8RYb1Y7fYivughjxojTmIu5iAIjSrSLCLeqE= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= @@ -385,11 +547,16 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -419,9 +586,13 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -433,25 +604,35 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= +github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2 h1:g+4J5sZg6osfvEfkRZxJ1em0VT95/UOZgi/l7zi1/oE= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -469,8 +650,12 @@ github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/sys/mountinfo v0.4.1 h1:1O+1cHA1aujwEwwVMa2Xm2l+gIpUHyd3+D+d7LZh1kM= +github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= +github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= +github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -482,6 +667,7 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= @@ -489,27 +675,56 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= +github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= -github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b h1:YWuSjZCQAPM8UUBLkYUk1e+rZcvWHJmFb6i6rM44Xs8= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= +github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= +github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/operator-framework/api v0.17.7 h1:NLn+Ieg+HaPrw75KbX4efllN21ofFArQzS3q8TDbQY0= github.com/operator-framework/api v0.17.7/go.mod h1:lnurXgadLnoZ7pufKMHkErr2BVOIZSpHtvEkHBcKvdk= github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k= @@ -522,28 +737,33 @@ github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= -github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= -github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= @@ -551,13 +771,19 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= @@ -570,15 +796,20 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sclevine/spec v1.2.0 h1:1Jwdf9jSfDl9NVmt8ndHqbTZ7XCCPbh1jI3hkDBHVYA= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= @@ -589,7 +820,9 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= @@ -597,6 +830,8 @@ github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -604,13 +839,16 @@ github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/y github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spiffe/go-spiffe/v2 v2.0.0 h1:y6N7BZAxgaFZYELyrIdxSMm2e2tWpzgQewUts9h1hfM= github.com/spiffe/go-spiffe/v2 v2.0.0/go.mod h1:TEfgrEcyFhuSuvqohJt6IxENUNeHfndWCCV1EX7UaVk= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -623,10 +861,29 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -647,8 +904,13 @@ github.com/zeebo/errs v1.2.2/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtC github.com/zeebo/errs v1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs= github.com/zeebo/errs v1.3.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -675,23 +937,28 @@ go.opentelemetry.io/otel/trace v1.10.0/go.mod h1:Sij3YYczqAdz+EhmGhE6TpTxUO5/F/A go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= @@ -733,6 +1000,7 @@ golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -750,7 +1018,9 @@ golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -765,11 +1035,14 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -806,24 +1079,38 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -832,20 +1119,32 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -859,15 +1158,20 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -907,15 +1211,18 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -954,6 +1261,7 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= @@ -962,6 +1270,7 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -975,12 +1284,14 @@ google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20230525154841-bd750badd5c6 h1:62QuyPXKEkZpjZesyj5K5jABl6MnSnWl+vNuT5oz90E= google.golang.org/genproto v0.0.0-20230525154841-bd750badd5c6/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= @@ -990,6 +1301,8 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -1023,6 +1336,7 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1031,13 +1345,19 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= @@ -1048,6 +1368,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -1057,8 +1378,11 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1066,34 +1390,62 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= +k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= +k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= k8s.io/api v0.27.2 h1:+H17AJpUMvl+clT+BPnKf0E3ksMAzoBBg7CntpSuADo= k8s.io/api v0.27.2/go.mod h1:ENmbocXfBT2ADujUXcBhHV55RIT31IIEvkntP6vZKS4= k8s.io/apiextensions-apiserver v0.27.2 h1:iwhyoeS4xj9Y7v8YExhUwbVuBhMr3Q4bd/laClBV6Bo= k8s.io/apiextensions-apiserver v0.27.2/go.mod h1:Oz9UdvGguL3ULgRdY9QMUzL2RZImotgxvGjdWRq6ZXQ= +k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= k8s.io/apimachinery v0.27.2 h1:vBjGaKKieaIreI+oQwELalVG4d8f3YAMNpWLzDXkxeg= k8s.io/apimachinery v0.27.2/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= +k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= +k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= +k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= k8s.io/apiserver v0.27.2 h1:p+tjwrcQEZDrEorCZV2/qE8osGTINPuS5ZNqWAvKm5E= k8s.io/apiserver v0.27.2/go.mod h1:EsOf39d75rMivgvvwjJ3OW/u9n1/BmUMK5otEOJrb1Y= +k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= +k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= +k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= k8s.io/client-go v0.27.2 h1:vDLSeuYvCHKeoQRhCXjxXO45nHVv2Ip4Fe0MfioMrhE= k8s.io/client-go v0.27.2/go.mod h1:tY0gVmUsHrAmjzHX9zs7eCjxcBsf8IiNe7KQ52biTcQ= +k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0= +k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= +k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= +k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= k8s.io/component-base v0.27.2 h1:neju+7s/r5O4x4/txeUONNTS9r1HsPbyoPBAtHsDCpo= k8s.io/component-base v0.27.2/go.mod h1:5UPk7EjfgrfgRIuDBFtsEFAe4DAvP3U+M8RTzoSJkpo= +k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= +k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= k8s.io/kubectl v0.27.1 h1:9T5c5KdpburYiW8XKQSH0Uly1kMNE90aGSnbYUZNdcA= k8s.io/kubectl v0.27.1/go.mod h1:QsAkSmrRsKTPlAFzF8kODGDl4p35BIwQnc9XFhkcsy8= +k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 h1:trsWhjU5jZrx6UvFu4WzQDrN7Pga4a7Qg+zcfcj64PA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2/go.mod h1:+qG7ISXqCDVVcyO8hLn12AKVYYUjM7ftlqsqmrhMZE0= sigs.k8s.io/controller-runtime v0.15.0 h1:ML+5Adt3qZnMSYxZ7gAverBLNPSMQEibtzAgp0UPojU= @@ -1102,7 +1454,9 @@ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMm sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kind v0.11.1 h1:pVzOkhUwMBrCB0Q/WllQDO3v14Y+o2V0tFgjTqIUjwA= sigs.k8s.io/kind v0.11.1/go.mod h1:fRpgVhtqAWrtLB9ED7zQahUimpUXuG/iHT88xYqEGIA= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/staging/operator-registry/pkg/cache/json.go b/staging/operator-registry/pkg/cache/json.go index 4327082794..7345a2b5ff 100644 --- a/staging/operator-registry/pkg/cache/json.go +++ b/staging/operator-registry/pkg/cache/json.go @@ -6,15 +6,17 @@ import ( "errors" "fmt" "hash/fnv" + "io" "io/fs" "os" "path/filepath" + "sort" "strings" "github.com/operator-framework/operator-registry/alpha/declcfg" "github.com/operator-framework/operator-registry/pkg/api" "github.com/operator-framework/operator-registry/pkg/registry" - "k8s.io/apimachinery/pkg/util/sets" + "github.com/sirupsen/logrus" ) var _ Cache = &JSON{} @@ -58,31 +60,66 @@ func (q *JSON) ListBundles(ctx context.Context) ([]*api.Bundle, error) { } func (q *JSON) SendBundles(_ context.Context, s registry.BundleSender) error { + var keys []apiBundleKey for _, pkg := range q.packageIndex { - channels := sets.KeySet(pkg.Channels) - for _, chName := range sets.List(channels) { - ch := pkg.Channels[chName] - - bundles := sets.KeySet(ch.Bundles) - for _, bName := range sets.List(bundles) { - b := ch.Bundles[bName] - apiBundle, err := q.loadAPIBundle(apiBundleKey{pkg.Name, ch.Name, b.Name}) - if err != nil { - return fmt.Errorf("convert bundle %q: %v", b.Name, err) - } - if apiBundle.BundlePath != "" { - // The SQLite-based server - // configures its querier to - // omit these fields when - // bundle path is set. - apiBundle.CsvJson = "" - apiBundle.Object = nil - } - if err := s.Send(apiBundle); err != nil { - return err - } + for _, ch := range pkg.Channels { + for _, b := range ch.Bundles { + keys = append(keys, apiBundleKey{pkg.Name, ch.Name, b.Name}) + } + } + } + sort.Slice(keys, func(i, j int) bool { + if keys[i].chName != keys[j].chName { + return keys[i].chName < keys[j].chName + } + if keys[i].pkgName != keys[j].pkgName { + return keys[i].pkgName < keys[j].pkgName + } + return keys[i].name < keys[j].name + }) + var files []*os.File + var readers []io.Reader + for _, key := range keys { + filename, ok := q.apiBundles[key] + if !ok { + return fmt.Errorf("package %q, channel %q, key %q not found", key.pkgName, key.chName, key.name) + } + file, err := os.Open(filename) + if err != nil { + return fmt.Errorf("failed to open file for package %q, channel %q, key %q: %w", key.pkgName, key.chName, key.name, err) + } + files = append(files, file) + readers = append(readers, file) + } + defer func() { + for _, file := range files { + if err := file.Close(); err != nil { + logrus.WithError(err).WithField("file", file.Name()).Warn("could not close file") } } + }() + multiReader := io.MultiReader(readers...) + decoder := json.NewDecoder(multiReader) + index := 0 + for { + var bundle api.Bundle + if err := decoder.Decode(&bundle); err == io.EOF { + break + } else if err != nil { + return fmt.Errorf("failed to decode file for package %q, channel %q, key %q: %w", keys[index].pkgName, keys[index].chName, keys[index].name, err) + } + if bundle.BundlePath != "" { + // The SQLite-based server + // configures its querier to + // omit these fields when + // key path is set. + bundle.CsvJson = "" + bundle.Object = nil + } + if err := s.Send(&bundle); err != nil { + return err + } + index += 1 } return nil } diff --git a/staging/operator-registry/alpha/declcfg/errors.go b/staging/operator-registry/pkg/prettyunmarshaler/prettyunmarshaler.go similarity index 83% rename from staging/operator-registry/alpha/declcfg/errors.go rename to staging/operator-registry/pkg/prettyunmarshaler/prettyunmarshaler.go index f5ef115233..2f740151a3 100644 --- a/staging/operator-registry/alpha/declcfg/errors.go +++ b/staging/operator-registry/pkg/prettyunmarshaler/prettyunmarshaler.go @@ -1,4 +1,4 @@ -package declcfg +package prettyunmarshaler import ( "bytes" @@ -8,29 +8,29 @@ import ( "strings" ) -type jsonUnmarshalError struct { +type JsonUnmarshalError struct { data []byte offset int64 err error } -func newJSONUnmarshalError(data []byte, err error) *jsonUnmarshalError { +func NewJSONUnmarshalError(data []byte, err error) *JsonUnmarshalError { var te *json.UnmarshalTypeError if errors.As(err, &te) { - return &jsonUnmarshalError{data: data, offset: te.Offset, err: te} + return &JsonUnmarshalError{data: data, offset: te.Offset, err: te} } var se *json.SyntaxError if errors.As(err, &se) { - return &jsonUnmarshalError{data: data, offset: se.Offset, err: se} + return &JsonUnmarshalError{data: data, offset: se.Offset, err: se} } - return &jsonUnmarshalError{data: data, offset: -1, err: err} + return &JsonUnmarshalError{data: data, offset: -1, err: err} } -func (e *jsonUnmarshalError) Error() string { +func (e *JsonUnmarshalError) Error() string { return e.err.Error() } -func (e *jsonUnmarshalError) Pretty() string { +func (e *JsonUnmarshalError) Pretty() string { if len(e.data) == 0 || e.offset < 0 || e.offset > int64(len(e.data)) { return e.err.Error() } diff --git a/staging/operator-registry/alpha/declcfg/errors_test.go b/staging/operator-registry/pkg/prettyunmarshaler/prettyunmarshaler_test.go similarity index 98% rename from staging/operator-registry/alpha/declcfg/errors_test.go rename to staging/operator-registry/pkg/prettyunmarshaler/prettyunmarshaler_test.go index 9da8f86b91..a322873193 100644 --- a/staging/operator-registry/alpha/declcfg/errors_test.go +++ b/staging/operator-registry/pkg/prettyunmarshaler/prettyunmarshaler_test.go @@ -1,4 +1,4 @@ -package declcfg +package prettyunmarshaler import ( "encoding/json" @@ -135,7 +135,7 @@ func TestJsonUnmarshalError(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - actualErr := newJSONUnmarshalError(tc.data, tc.inErr) + actualErr := NewJSONUnmarshalError(tc.data, tc.inErr) assert.Equal(t, tc.expectErrorString, actualErr.Error()) assert.Equal(t, tc.expectPrettyString, actualErr.Pretty()) }) diff --git a/staging/operator-registry/pkg/registry/csv.go b/staging/operator-registry/pkg/registry/csv.go index ec6f3e3239..8dcdf65adb 100644 --- a/staging/operator-registry/pkg/registry/csv.go +++ b/staging/operator-registry/pkg/registry/csv.go @@ -2,11 +2,13 @@ package registry import ( "encoding/json" + "errors" "fmt" - "io/ioutil" "os" "path" + prettyunmarshaler "github.com/operator-framework/operator-registry/pkg/prettyunmarshaler" + v1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -82,7 +84,7 @@ type ClusterServiceVersion struct { // ReadCSVFromBundleDirectory tries to parse every YAML file in the directory without inspecting sub-directories and // returns a CSV. According to the strict one CSV per bundle rule, func returns an error if more than one CSV is found. func ReadCSVFromBundleDirectory(bundleDir string) (*ClusterServiceVersion, error) { - dirContent, err := ioutil.ReadDir(bundleDir) + dirContent, err := os.ReadDir(bundleDir) if err != nil { return nil, fmt.Errorf("error reading bundle directory %s, %v", bundleDir, err) } @@ -412,3 +414,56 @@ func (csv *ClusterServiceVersion) GetSubstitutesFor() string { } return substitutesFor } + +func (csv *ClusterServiceVersion) UnmarshalJSON(data []byte) error { + + if err := csv.UnmarshalSpec(data); err != nil { + return err + } + if err := csv.UnmarshalTypeMeta(data); err != nil { + return err + } + if err := csv.UnmarshalObjectMeta(data); err != nil { + return err + } + + return nil +} + +func (csv *ClusterServiceVersion) UnmarshalSpec(data []byte) error { + var m map[string]json.RawMessage + if err := json.Unmarshal(data, &m); err != nil { + return errors.New(prettyunmarshaler.NewJSONUnmarshalError(data, err).Pretty()) + } + + spec, ok := m["spec"] + if !ok { + return nil + } + csv.Spec = spec + + return nil +} + +func (csv *ClusterServiceVersion) UnmarshalTypeMeta(data []byte) error { + var t metav1.TypeMeta + if err := json.Unmarshal(data, &t); err != nil { + return errors.New(prettyunmarshaler.NewJSONUnmarshalError(data, err).Pretty()) + } + csv.TypeMeta = t + + return nil +} + +func (csv *ClusterServiceVersion) UnmarshalObjectMeta(data []byte) error { + var o struct { + Metadata metav1.ObjectMeta `json:"metadata"` + } + if err := json.Unmarshal(data, &o); err != nil { + return errors.New(prettyunmarshaler.NewJSONUnmarshalError(data, err).Pretty()) + } + + csv.ObjectMeta = o.Metadata + + return nil +} diff --git a/vendor/github.com/cyphar/filepath-securejoin/.travis.yml b/vendor/github.com/cyphar/filepath-securejoin/.travis.yml deleted file mode 100644 index b94ff8cf92..0000000000 --- a/vendor/github.com/cyphar/filepath-securejoin/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (C) 2017 SUSE LLC. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -language: go -go: - - 1.13.x - - 1.16.x - - tip -arch: - - AMD64 - - ppc64le -os: - - linux - - osx - -script: - - go test -cover -v ./... - -notifications: - email: false diff --git a/vendor/github.com/cyphar/filepath-securejoin/README.md b/vendor/github.com/cyphar/filepath-securejoin/README.md index 3624617c89..4eca0f2355 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/README.md +++ b/vendor/github.com/cyphar/filepath-securejoin/README.md @@ -1,6 +1,6 @@ ## `filepath-securejoin` ## -[![Build Status](https://travis-ci.org/cyphar/filepath-securejoin.svg?branch=master)](https://travis-ci.org/cyphar/filepath-securejoin) +[![Build Status](https://github.com/cyphar/filepath-securejoin/actions/workflows/ci.yml/badge.svg)](https://github.com/cyphar/filepath-securejoin/actions/workflows/ci.yml) An implementation of `SecureJoin`, a [candidate for inclusion in the Go standard library][go#20126]. The purpose of this function is to be a "secure" diff --git a/vendor/github.com/cyphar/filepath-securejoin/VERSION b/vendor/github.com/cyphar/filepath-securejoin/VERSION index 7179039691..abd410582d 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/VERSION +++ b/vendor/github.com/cyphar/filepath-securejoin/VERSION @@ -1 +1 @@ -0.2.3 +0.2.4 diff --git a/vendor/github.com/cyphar/filepath-securejoin/join.go b/vendor/github.com/cyphar/filepath-securejoin/join.go index 7dd08dbbdf..aa32b85fb8 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/join.go +++ b/vendor/github.com/cyphar/filepath-securejoin/join.go @@ -39,17 +39,27 @@ func IsNotExist(err error) bool { // components in the returned string are not modified (in other words are not // replaced with symlinks on the filesystem) after this function has returned. // Such a symlink race is necessarily out-of-scope of SecureJoin. +// +// Volume names in unsafePath are always discarded, regardless if they are +// provided via direct input or when evaluating symlinks. Therefore: +// +// "C:\Temp" + "D:\path\to\file.txt" results in "C:\Temp\path\to\file.txt" func SecureJoinVFS(root, unsafePath string, vfs VFS) (string, error) { // Use the os.* VFS implementation if none was specified. if vfs == nil { vfs = osVFS{} } + unsafePath = filepath.FromSlash(unsafePath) var path bytes.Buffer n := 0 for unsafePath != "" { if n > 255 { - return "", &os.PathError{Op: "SecureJoin", Path: root + "/" + unsafePath, Err: syscall.ELOOP} + return "", &os.PathError{Op: "SecureJoin", Path: root + string(filepath.Separator) + unsafePath, Err: syscall.ELOOP} + } + + if v := filepath.VolumeName(unsafePath); v != "" { + unsafePath = unsafePath[len(v):] } // Next path component, p. diff --git a/vendor/github.com/emicklei/go-restful/v3/CHANGES.md b/vendor/github.com/emicklei/go-restful/v3/CHANGES.md index 02a73ccfd1..352018e703 100644 --- a/vendor/github.com/emicklei/go-restful/v3/CHANGES.md +++ b/vendor/github.com/emicklei/go-restful/v3/CHANGES.md @@ -1,5 +1,10 @@ # Change history of go-restful +## [v3.10.2] - 2023-03-09 + +- introduced MergePathStrategy to be able to revert behaviour of path concatenation to 3.9.0 + see comment in Readme how to customize this behaviour. + ## [v3.10.1] - 2022-11-19 - fix broken 3.10.0 by using path package for joining paths diff --git a/vendor/github.com/emicklei/go-restful/v3/README.md b/vendor/github.com/emicklei/go-restful/v3/README.md index 0625359dc4..85da90128e 100644 --- a/vendor/github.com/emicklei/go-restful/v3/README.md +++ b/vendor/github.com/emicklei/go-restful/v3/README.md @@ -96,6 +96,10 @@ There are several hooks to customize the behavior of the go-restful package. - Compression - Encoders for other serializers - Use [jsoniter](https://github.com/json-iterator/go) by building this package using a build tag, e.g. `go build -tags=jsoniter .` +- Use the variable `MergePathStrategy` to change the behaviour of composing the Route path given a root path and a local route path + - versions >= 3.10.1 has set the value to `PathJoinStrategy` that fixes a reported [security issue](https://github.com/advisories/GHSA-r48q-9g5r-8q2h) but may cause your services not to work correctly anymore. + - versions <= 3.9 had the behaviour that can be restored in newer versions by setting the value to `TrimSlashStrategy`. + - you can set value to a custom implementation (must implement MergePathStrategyFunc) ## Resources diff --git a/vendor/github.com/emicklei/go-restful/v3/route_builder.go b/vendor/github.com/emicklei/go-restful/v3/route_builder.go index 830ebf148e..827f471de0 100644 --- a/vendor/github.com/emicklei/go-restful/v3/route_builder.go +++ b/vendor/github.com/emicklei/go-restful/v3/route_builder.go @@ -353,8 +353,28 @@ func (b *RouteBuilder) Build() Route { return route } -func concatPath(path1, path2 string) string { - return path.Join(path1, path2) +type MergePathStrategyFunc func(rootPath, routePath string) string + +var ( + // behavior >= 3.10 + PathJoinStrategy = func(rootPath, routePath string) string { + return path.Join(rootPath, routePath) + } + + // behavior <= 3.9 + TrimSlashStrategy = func(rootPath, routePath string) string { + return strings.TrimRight(rootPath, "/") + "/" + strings.TrimLeft(routePath, "/") + } + + // MergePathStrategy is the active strategy for merging a Route path when building the routing of all WebServices. + // The value is set to PathJoinStrategy + // PathJoinStrategy is a strategy that is more strict [Security - PRISMA-2022-0227] + MergePathStrategy = PathJoinStrategy +) + +// merge two paths using the current (package global) merge path strategy. +func concatPath(rootPath, routePath string) string { + return MergePathStrategy(rootPath, routePath) } var anonymousFuncCount int32 diff --git a/vendor/github.com/operator-framework/api/crds/operators.coreos.com_catalogsources.yaml b/vendor/github.com/operator-framework/api/crds/operators.coreos.com_catalogsources.yaml index c3e2f6ce18..6b3b81cb77 100644 --- a/vendor/github.com/operator-framework/api/crds/operators.coreos.com_catalogsources.yaml +++ b/vendor/github.com/operator-framework/api/crds/operators.coreos.com_catalogsources.yaml @@ -532,8 +532,21 @@ spec: topologyKey: description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. type: string + extractContent: + description: ExtractContent configures the gRPC catalog Pod to extract catalog metadata from the provided index image and use a well-known version of the `opm` server to expose it. The catalog index image that this CatalogSource is configured to use *must* be using the file-based catalogs in order to utilize this feature. + type: object + required: + - cacheDir + - catalogDir + properties: + cacheDir: + description: CacheDir is the directory storing the pre-calculated API cache. + type: string + catalogDir: + description: CatalogDir is the directory storing the file-based catalog contents. + type: string memoryTarget: - description: "MemoryTarget configures the $GOMEMLIMIT value for the gRPC catalog Pod. This is a soft memory limit for the server, which the runtime will attempt to meet but makes no guarantees that it will do so. If this value is set, the Pod will have the following modifications made to the container running the server: - the $GOMEMLIMIT environment variable will be set to this value in bytes - the memory request will be set to this value - the memory limit will be set to 200% of this value \n This field should be set if it's desired to reduce the footprint of a catalog server as much as possible, or if a catalog being served is very large and needs more than the default allocation. If your index image has a file- system cache, determine a good approximation for this value by doubling the size of the package cache at /tmp/cache/cache/packages.json in the index image. \n This field is best-effort; if unset, no default will be used and no Pod memory limit or $GOMEMLIMIT value will be set." + description: "MemoryTarget configures the $GOMEMLIMIT value for the gRPC catalog Pod. This is a soft memory limit for the server, which the runtime will attempt to meet but makes no guarantees that it will do so. If this value is set, the Pod will have the following modifications made to the container running the server: - the $GOMEMLIMIT environment variable will be set to this value in bytes - the memory request will be set to this value \n This field should be set if it's desired to reduce the footprint of a catalog server as much as possible, or if a catalog being served is very large and needs more than the default allocation. If your index image has a file- system cache, determine a good approximation for this value by doubling the size of the package cache at /tmp/cache/cache/packages.json in the index image. \n This field is best-effort; if unset, no default will be used and no Pod memory limit or $GOMEMLIMIT value will be set." pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ anyOf: - type: integer diff --git a/vendor/github.com/operator-framework/api/crds/zz_defs.go b/vendor/github.com/operator-framework/api/crds/zz_defs.go index a391fce34b..6ce922fa00 100644 --- a/vendor/github.com/operator-framework/api/crds/zz_defs.go +++ b/vendor/github.com/operator-framework/api/crds/zz_defs.go @@ -85,7 +85,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _operatorsCoreosCom_catalogsourcesYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x7d\x69\x73\xdc\x36\x16\xe0\x77\xff\x8a\x57\xda\xd9\x92\x94\x74\x53\x76\x32\x95\x9d\x68\x72\x94\x46\x3e\x56\x15\x1f\x2a\x4b\xc9\xd4\x8e\xe5\xdd\xa0\xc9\xd7\xdd\x88\x48\x80\x01\x40\x49\x9d\xe3\xbf\x6f\xbd\x07\x80\x64\xdf\x87\xec\xd8\xae\x21\x3f\x24\x6a\x12\xe7\xbb\x2f\xc0\xa2\x94\x3f\xa1\xb1\x52\xab\x63\x10\xa5\xc4\x3b\x87\x8a\x7e\xd9\xe4\xfa\x1f\x36\x91\xfa\xe8\xe6\xd1\x83\x6b\xa9\xb2\x63\x38\xad\xac\xd3\xc5\x6b\xb4\xba\x32\x29\x3e\xc6\xa1\x54\xd2\x49\xad\x1e\x14\xe8\x44\x26\x9c\x38\x7e\x00\x20\x94\xd2\x4e\xd0\x6b\x4b\x3f\x01\x52\xad\x9c\xd1\x79\x8e\xa6\x3f\x42\x95\x5c\x57\x03\x1c\x54\x32\xcf\xd0\xf0\xe0\x71\xea\x9b\x87\xc9\xd7\xc9\xc3\x07\x00\xa9\x41\xee\x7e\x29\x0b\xb4\x4e\x14\xe5\x31\xa8\x2a\xcf\x1f\x00\x28\x51\xe0\x31\xa4\xc2\x89\x5c\x8f\xfc\x22\x6c\xa2\x4b\x34\xc2\x69\x63\x93\x54\x1b\xd4\xf4\xbf\xe2\x81\x2d\x31\xa5\xd9\x47\x46\x57\xe5\x31\x2c\x6c\xe3\xc7\x8b\x8b\x14\x0e\x47\xda\xc8\xf8\x1b\xa0\x0f\x3a\x2f\xf8\xef\xb0\x79\x3f\xed\x05\x4f\xcb\xef\x73\x69\xdd\x0f\xf3\xdf\x9e\x4b\xeb\xf8\x7b\x99\x57\x46\xe4\xb3\x0b\xe6\x4f\x76\xac\x8d\x7b\xd9\x4c\x4f\xd3\xa5\xc2\x59\x93\xfa\xcf\x52\x8d\xaa\x5c\x98\x99\xbe\x0f\x00\x6c\xaa\x4b\x3c\x06\xee\x5a\x8a\x14\xb3\x07\x00\x01\x84\x61\xa8\x3e\x88\x2c\x63\xb4\x88\xfc\xdc\x48\xe5\xd0\x9c\xea\xbc\x2a\x54\x3d\x15\xb5\xc9\xd0\xa6\x46\x96\x8e\x41\x7f\x39\x46\x28\x0d\x3a\x37\x61\x90\x80\x1e\x82\x1b\x63\x9c\xbb\xee\x05\xf0\x8b\xd5\xea\x5c\xb8\xf1\x31\x24\x04\xe1\x24\x93\xb6\xcc\xc5\x84\x56\xd3\x6a\xe5\xd1\xf4\xd8\x7f\x6b\xbd\x77\x13\x5a\xba\x75\x46\xaa\xd1\xaa\xa5\x50\xbb\xcd\xd7\xe0\x41\x73\x39\x29\xe7\x97\x30\xf3\x72\xd3\xf9\xcb\x6a\x90\x4b\x3b\x46\xb3\xf9\x22\xea\x2e\x73\x6b\x38\x5f\xf0\x65\xc9\x42\x5a\x83\x46\x86\x4a\xe6\x98\x61\x6e\x82\x93\xd1\xfc\x1e\x33\xe1\xe2\x4b\xdf\xe8\xe6\x91\xc8\xcb\xb1\x78\x14\x5e\xda\x74\x8c\x85\x68\xe8\x41\x97\xa8\x4e\xce\xcf\x7e\xfa\xf2\x62\xe6\x03\x4c\x43\x67\x8a\xce\x41\x5a\x10\x60\xb0\xd4\x56\x3a\x6d\x26\x04\xad\xd3\x8b\x9f\x6c\x0f\x4e\x5f\x3f\xb6\x3d\x10\x2a\xab\x19\x0f\x4a\x91\x5e\x8b\x11\xda\x64\x6e\xad\x7a\xf0\x0b\xa6\xae\xf5\xda\xe0\xaf\x95\x34\x98\xb5\x57\x41\xe0\x89\x30\x99\x79\x4d\xf0\x6f\xbd\x2a\x0d\xcd\xe9\x5a\x8c\xec\x9f\x96\x94\x9b\x7a\x3f\xb3\xc3\x7d\x02\x83\x6f\x07\x19\x09\x38\xb4\x4c\x02\x81\xc7\x30\x0b\xb0\xf3\xa4\x21\x2d\xed\xdf\xa0\x45\xe5\x45\x1e\xbd\x16\x2a\xec\x29\x81\x0b\x34\xd4\x91\xd8\xbd\xca\x33\x92\x84\x37\x68\x1c\x18\x4c\xf5\x48\xc9\xdf\xea\xd1\x2c\x38\xcd\xd3\xe4\xc2\xa1\x75\xc0\x5c\xab\x44\x0e\x37\x22\xaf\xd0\x83\xb2\x10\x13\x30\x48\xe3\x42\xa5\x5a\x23\x70\x13\x9b\xc0\x0b\x6d\x10\xa4\x1a\xea\x63\x18\x3b\x57\xda\xe3\xa3\xa3\x91\x74\x51\x86\xa7\xba\x28\x2a\x25\xdd\xe4\x88\xc5\xb1\x1c\x54\x24\x0e\x8f\x32\xbc\xc1\xfc\xc8\xca\x51\x5f\x98\x74\x2c\x1d\xa6\xae\x32\x78\x24\x4a\xd9\xe7\xc5\x2a\x96\xe3\x49\x91\xfd\x0f\x13\xa4\xbe\xdd\x9f\x01\xdf\x42\x62\x86\x28\x36\x57\xc2\x9a\x84\xa7\xa7\x22\xdf\xdd\xef\xa5\x01\x29\xbd\x22\xa8\xbc\x7e\x72\x71\x09\x71\x01\x1e\xec\x1e\xc2\x4d\x53\xdb\x00\x9b\x00\x25\xd5\x10\x8d\x6f\x39\x34\xba\xe0\x51\x50\x65\xa5\x96\xca\x79\x96\xce\x25\x2a\x07\xb6\x1a\x14\xd2\x59\xa6\x39\xb4\x8e\xf0\x90\xc0\x29\xab\x30\x18\x20\x54\x25\x71\x52\x96\xc0\x99\x82\x53\x51\x60\x7e\x2a\x2c\xbe\x77\x50\x13\x44\x6d\x9f\xc0\xb7\x39\xb0\xdb\x1a\x78\xbe\xc3\x1c\x8f\x01\x44\x0d\xb9\x51\xe3\x65\x4c\x09\x9e\x03\x17\x49\x60\x58\xc1\x8b\xf4\x88\x2c\x33\x68\x17\x7c\x98\x63\x48\xdf\xd0\xd3\xc9\x58\x5b\xc2\x9f\x70\xf0\xea\xf9\x0b\x48\x85\x82\xca\x22\x31\x4f\xaa\x95\x22\x82\x70\x1a\x04\xe9\xb2\x3e\xde\x49\xcb\x04\x64\x70\x24\xad\x33\x93\x04\x9e\x6a\x53\x08\x77\x0c\xdf\xc4\x57\x7d\x1e\x4e\x1b\x90\xe5\x77\xc7\xdf\x94\xda\xb8\xef\xe0\x95\xca\x27\x34\x68\x06\xb7\x63\x54\x70\x51\xef\x0d\xbe\x6d\xfd\x78\x66\xca\x34\x81\xb3\x91\xd2\x26\xb6\x24\xaa\x3a\x2b\xc4\x08\x61\x28\x31\x67\xba\xb6\xe8\x92\x59\x0c\xae\xc4\x22\x78\x73\x69\x28\x47\x2f\x44\xb9\x16\x34\xa7\xb1\x25\xcd\x45\xd3\xb7\x95\x77\xf3\xd1\x69\x26\x65\xda\x12\xfd\x29\xd2\x6b\x10\x61\x96\x42\x94\x7d\xcb\x6c\xd3\x02\xd3\x66\x10\x38\x8d\x03\x10\xfc\x9a\xd7\x67\x41\x72\x25\xdb\x6e\xbb\xbd\xb3\xad\xfb\x36\x66\xc8\x5a\xa0\xbd\x58\xa4\x45\x36\x98\x63\x64\xca\xf4\x5c\x67\x7e\xdb\x6b\x67\x79\xd6\x6e\x0d\x78\x57\x6a\x8b\x16\x32\x39\x1c\xa2\x21\xb9\xa3\x6f\xd0\x18\x99\xa1\x85\xa1\x36\x8c\xaf\x52\x67\xcc\x93\x35\xfe\xa6\x54\xed\xb9\xce\x36\x45\x0c\x4d\xcd\x0a\xc3\x13\x63\x20\xc3\xa5\xdb\x5d\xc8\xed\xb0\x86\x79\xe9\x11\x43\x36\xff\x27\x8b\xbf\xce\xc0\xe3\x24\x34\x8e\x94\x1a\x2c\xaa\x20\x3a\xf6\x2d\x6d\x7f\xdf\xd6\x63\x2e\x5a\xee\x06\x4b\xde\x64\xd9\xf4\x28\x9d\xe1\xc9\x9a\xe5\xcf\x6d\xe1\x31\xff\x18\xa0\xe5\xee\xf5\x52\x59\x83\x67\x55\xce\xa2\xa6\xca\xa7\x31\xba\x6c\x1f\x1b\xee\x65\xd3\xfd\xf8\x76\x38\x44\x63\x30\x7b\x5c\x11\xfd\x5e\xd4\xab\x0a\x42\xca\xbf\x7e\x72\x87\x69\xb5\x8c\xc7\x96\x6e\x9d\x8c\xe2\xb0\x4d\x34\x70\x2b\xf3\x3c\x4c\x47\x02\x25\x7e\xa0\xfd\xb2\x1d\x43\xe0\xb1\x5e\x48\x5b\xe1\xa4\x1d\x4e\x18\x1c\x35\xc0\xf0\x8e\x74\x36\x7b\x2c\x4c\xf1\x72\x28\x31\x83\xc1\x24\xa8\x6b\x12\x9e\x3d\x18\x54\x0e\xa4\x63\x5d\x9e\x8e\xb5\xb6\x08\xc2\xc3\x9d\xc7\xbd\x91\x9a\x2d\x25\xd0\x0a\x49\xfe\x14\xa4\x90\x03\xe3\xb4\x86\x4f\x78\xe5\x4d\x37\x69\xa1\x20\x89\x5f\xc3\x2a\x92\x23\x0d\x73\x2b\xdd\x98\x7f\x8c\xc8\xe4\x26\x2b\xcc\x56\x05\x0d\x7a\x8b\x72\x34\x76\xb6\x07\x32\xc1\x84\xb1\x8b\x22\x1d\xb7\x86\x2d\x10\x9d\x05\x91\xe7\x71\x09\x6d\x92\xf0\x7a\xb3\x20\x13\x05\x0e\x6a\x1b\x26\xd8\x1b\xbd\x5a\xaf\xce\x62\x6d\x21\xb8\x7a\x80\x2e\x4d\x0e\x7b\x90\xea\xa2\xac\x1c\xc1\x84\xd6\x38\x98\x80\x74\x64\x67\x7b\x7b\xc9\xe8\x6a\xe4\x77\x82\x79\x98\x38\x1a\xab\x5e\x33\x91\x70\x20\x1f\x51\x8d\x60\xcf\x6f\x6e\x2f\xda\x9f\x34\x9c\xf4\x9b\xe0\xfd\x15\xc2\xa5\xe3\x60\x02\xa7\xda\x18\xb4\xa5\x56\xdc\x93\xbf\x3c\x69\xd6\xf6\xcf\xba\xd3\x81\x3d\x6c\x80\x39\x96\xa3\x71\x84\xa5\x30\xc8\xef\xa6\x71\xb0\x8a\x47\x1a\x3e\x11\xc6\x4c\xf9\x92\x8b\x1e\xe9\xb0\x58\xc3\x25\x73\xa4\x7d\xa2\x00\x8b\xd2\x4d\x5a\x34\xd1\xc2\x9e\x43\x53\xd4\x30\x60\x04\x33\xbb\x5a\xbf\x3f\x59\x94\xb9\x4c\xa5\x0b\x14\x02\x0f\xe1\x80\x49\x44\x3a\x12\x65\xa0\x74\x5f\x97\x87\x09\x9c\x70\xf8\x62\x83\x09\x94\xae\xc7\x0f\x03\xd1\xa4\x56\x37\x63\xad\xdd\xdb\x86\x42\xc5\x3f\xcb\x6d\xba\xf9\xa7\x1f\xd6\x8f\x2a\x9d\xb5\xf2\x16\x37\xf7\x30\x59\xdb\x74\x53\xf1\x16\x5b\xc7\x35\x6c\xd2\x7a\x16\xd5\x9e\xa4\x2d\xe6\x98\x92\x4b\x4a\xb0\xef\x81\xb0\x56\xa7\x92\xac\xfc\x86\x68\xa7\x29\xdd\xef\x64\x3d\xec\x61\x5b\xf8\xc3\xd6\xfb\xa7\x67\x96\xf1\x36\xed\x37\x07\x8d\x5c\x92\xf1\x3b\x9c\x81\xca\x94\xc0\x1a\x4c\xf8\xeb\xbe\x85\x5c\x0c\x30\xb7\x9b\x01\x01\xb6\xe2\xda\xe6\xd9\x90\x7f\x97\x6e\x68\xe9\x46\x82\x8f\x59\x23\x9e\x84\x36\xf9\x66\x42\x2a\x1b\xfc\xe7\x1e\x08\xb8\xc6\x89\x77\xb5\xc9\x83\x8f\x81\x0b\x6e\x6c\xd0\xab\x1b\x22\x8e\x6b\x9c\x70\xa3\xe0\x77\x6f\xb1\xdc\xad\x89\xc3\x3f\xdb\xb0\x69\xf3\xf4\x69\xa1\x5b\xf6\x88\x9b\xde\xa2\xdb\xf6\xf4\xeb\x9f\x6b\x5c\x69\x79\x2d\x7a\xe6\x4c\x12\xa6\x49\xc6\x07\x23\x89\xf5\x57\xc4\xb1\x28\xcb\x5c\x22\xfb\xf3\x5b\x4e\xb3\xd2\x0b\x58\xf5\x44\xe8\xdd\x6b\x5f\xaf\xeb\x80\x86\x27\xc8\x7d\xeb\x89\x8f\x38\x7d\x2c\x4b\xef\xdf\x5a\x64\xc6\x8d\x91\x9f\x9f\x44\x2e\x9b\x50\x9b\x65\x3d\x7b\xa6\x7a\xf0\x52\x3b\xfa\xdf\x13\xf2\x84\x6d\x0f\x1e\x6b\xb4\x2f\xb5\xe3\x9f\x09\x3c\x73\x9e\xd6\x9f\x6f\x28\xd9\xde\x01\x80\xfc\x7a\xef\x05\x9e\x13\xe5\x65\x0a\x6d\xbf\x1d\x33\xb2\x09\x9c\x79\xb3\xa5\x66\x5c\x69\xe1\x4c\x91\x71\x18\xc0\xc0\x51\x3c\x6e\x1b\x86\x28\x2a\xcb\x41\x1e\xa5\x55\x9f\x6d\x80\x85\x63\x78\xe8\xd1\x38\x6d\xf8\xad\x18\x6e\xf9\x50\xcf\x38\xd6\xf0\x7c\x69\xe7\xb1\xb8\x61\x93\x4e\xaa\x51\x5e\x1b\x6f\x3d\xb8\x1d\xcb\x74\xec\xad\xee\x01\xfa\xd0\x60\x69\x90\x14\x96\xb0\x24\xaa\xe8\xcd\x08\x0d\x19\xbb\x32\x8e\xe7\x03\x93\xb9\x48\x31\x83\x8c\x4d\x4b\x1f\x64\x13\x0e\x47\x32\x85\x02\xcd\x08\xa1\x24\x4d\xb2\x1b\xf6\xb7\x13\xec\xfe\xd9\x5a\xbc\xb7\x27\xdc\x8a\xdc\x58\x45\x3e\x25\x5b\xf7\x2f\xd2\x8e\x6c\x57\x77\xda\xb1\xd3\x8e\x33\x4f\xa7\x1d\xeb\xa7\xd3\x8e\x6b\x9e\x4e\x3b\x76\xda\xf1\xbd\x6b\x47\xef\xcb\xee\xe0\x3c\xff\xdb\x87\x38\x66\xbd\x65\xd6\xb4\x31\x4d\x37\xed\x36\x93\xbe\xb9\x08\x02\xe7\x92\x5d\x6d\xe9\x93\x24\x46\xa8\x11\xc2\xa3\xfe\xa3\x87\x0f\xb7\x71\xaa\x03\x22\x37\xea\x31\x0c\x99\x1e\xa9\xdc\x97\x5f\xac\xec\xb1\x2c\xfe\xf6\x0e\xa2\xa6\x81\xc6\xeb\x40\xde\x94\xed\xb0\x24\xf0\xc9\xd2\x49\x69\x07\x05\x3a\x10\x6e\x2a\x54\x24\x0b\xec\xd5\xa9\x02\x26\xf8\x90\xa5\x8c\x11\xd8\x0c\xb4\x0a\x71\x3c\x02\x7e\xb2\xdb\x0a\x52\x14\x3e\xa5\x36\xc0\x7a\x15\xba\xa0\x59\xa5\x72\x91\x5d\x68\x09\x18\xa1\x02\x07\x98\x8c\x12\xc8\x2a\xee\x26\x54\x48\x9b\x1e\xfa\xd5\xda\x89\x75\x58\x70\x24\x57\x1b\xfe\x1f\x2d\xdb\x99\x09\x35\xc6\x1b\x54\xae\x12\x79\x3e\x01\xbc\x91\xa9\xab\xf7\xc7\x59\x5b\xe9\x7c\xb0\x7d\xb3\x10\xe1\x46\xa6\xc3\xe6\xe6\x42\x7f\x8e\x82\xed\x9a\x3e\xdb\x68\xfb\xb9\xb1\x37\xe1\xc9\x19\x5d\xe8\x77\x92\x2c\x35\x56\x1d\x8d\xeb\x63\xe0\xfc\x27\x13\xd7\xab\xd7\xeb\x43\xae\xb0\xb5\x24\xdb\x42\x7a\xcd\x9a\xa5\x55\x9e\x13\x61\xf8\x28\xec\xfc\x06\x16\x44\x47\xfd\x96\xa6\x88\xd9\x07\xde\x7d\x88\xf9\xe4\xe5\x63\x82\x0a\xb5\xb9\xd4\xa5\xce\xf5\x68\xd2\x86\xb4\x2f\x2f\x92\x45\x19\x83\xe3\x02\x6c\x35\x08\x46\x03\x91\xdf\xcb\x19\xd4\x74\x91\xbf\x2e\xf2\xd7\xf9\x36\x73\x4f\xe7\xdb\xd4\x4f\xe7\xdb\xac\x79\x3a\xdf\xa6\xf3\x6d\xba\xc8\x1f\x74\xda\x71\x05\x4c\x3a\xed\x08\x9d\x76\x5c\xba\xaf\x4e\x3b\xae\x04\x4f\xa7\x1d\x3b\xed\xb8\xe8\x29\x75\x76\x8f\x42\xc7\x52\x67\x2b\xea\x1c\x7d\xd4\x27\xd5\xfd\x5c\xa7\xc2\x85\xba\x7c\xea\x12\xe2\x7c\x56\x14\x3e\x10\xd5\x83\xdf\xb4\x42\x5f\xbc\x46\xb8\xe1\x70\x92\x76\x63\x34\xd4\xfc\xc0\x1e\xae\x2c\x6c\xea\xea\x24\xbb\x3a\xc9\x8f\xbe\x4e\x72\x2c\xac\xc7\xab\x17\x4a\xcb\xcb\x26\x5b\x0c\x79\x89\xa6\xf8\x44\xab\x26\x89\x5c\x02\xba\xf9\xc4\x53\x83\x52\xbf\xf3\x2c\xe4\x0b\x30\x3b\x9f\xde\x6f\xb0\x97\x79\x53\x22\xcb\x30\x83\x12\x4d\xdf\x93\x88\x86\xa1\x54\xd9\x82\xbd\x46\xf8\x7c\xd0\xea\xc7\xe9\x7d\x7c\xc0\x12\xc8\xe9\x85\xec\x10\x73\x6d\x07\x8e\xa7\x24\xfc\x47\x51\x10\xb9\xad\x55\xdf\x07\x17\x82\xbc\x3f\x6c\x68\xd7\x6f\x6f\x9a\xb3\x41\x1d\x43\xc2\xbb\xfb\x95\x6c\x96\xff\x5a\xa1\x99\xf0\xf9\x8f\xc6\x60\xad\xcf\xd6\x85\x1c\x99\xb4\x90\x0a\xeb\x35\xc5\xb6\xae\xe5\x96\x6e\xd4\x6e\x7e\xca\xee\x91\x68\x98\x85\xcb\xec\x50\xde\x27\x8d\x3e\xb8\x87\xd9\x42\x27\x7c\x41\x16\xa0\x89\xfe\x6f\xb5\x9e\x5d\x4d\xb7\x9d\x0c\xb7\x85\x44\xf1\x11\x3b\xe7\xb0\xbb\x83\x0e\x3b\x3b\xe9\xb0\x93\xa3\x0e\xbb\x3a\xeb\x70\x0f\x87\x1d\x76\x73\xda\x61\x96\x14\x08\x43\xc1\xca\x7a\x3f\xfe\x3b\xdc\xc7\x45\x85\x7b\xf8\xf1\x30\xbb\xd5\x9a\x4c\xcd\xfb\x72\xea\x99\xd6\xa7\xfc\xfa\xbf\x1a\x58\xbb\xf9\xf4\x30\x0b\xaa\xe0\x0c\x4b\x76\x68\x3f\x11\x0f\xff\x2f\x71\xb7\xe1\x5e\x2e\x37\xec\xee\x76\xc3\xee\x94\xc1\xaa\xee\x39\xa7\x53\xef\xab\x30\xfd\x28\x5e\x45\xf0\x19\xdc\x21\xfc\x4e\x9a\x80\xf1\xf2\x27\x94\x42\x1a\x4b\xf6\x5d\x88\x99\xb4\xbf\x05\xef\xbc\x3d\x4c\xe1\x8f\x10\x93\xa8\xbe\x11\x39\xe9\x1e\x5f\xc7\x11\xfc\x22\x1a\x7d\x56\x4d\xf7\xe0\x76\x4c\xde\x26\x49\xa9\xfa\xbc\xf3\xde\x35\x4e\xf6\x7a\x73\x84\xb4\x77\xa6\xf6\xbc\x8e\x9a\x23\x9d\x5a\xa1\x69\x95\x4f\x60\x8f\xbf\xed\xbd\x6b\xcd\xbe\x83\xe2\x6a\x5f\xa1\xb2\xab\x5e\xd8\x81\x4a\x54\xbc\xd6\xe5\xdd\x1b\x9b\x5e\x8b\xf8\xc4\x46\x9c\xc5\x36\x0a\x86\x4b\x2d\x5a\xca\xa5\xae\x1a\x61\x1a\xe3\xf7\x59\x74\x7e\x2b\x15\x6e\xba\x88\x67\xce\xc3\x60\x5e\x49\xcd\x97\x34\x05\xc4\x6b\x85\x96\x0d\x3b\xac\x43\x44\xad\xce\xdc\x36\xf1\xe5\x20\x8d\xb6\x53\xd9\x6c\x81\x48\xd3\x83\x6d\xc4\x02\x85\xb2\xb0\x17\x63\x4f\xfb\xb6\x69\xb1\x97\x34\xa7\xfb\xea\x11\x0f\x7e\xff\xf3\x70\xea\x44\x5f\x33\x60\x67\x69\x77\x96\x76\x67\x69\x6f\xd1\xab\xb3\xb4\x97\x3f\x9d\xa5\xbd\xc5\xd3\x59\xda\x9d\xa5\xbd\x6a\xe2\xce\xd2\xee\x2c\xed\xf5\x93\xef\x66\x69\xef\x5a\x27\xd4\xb6\x7b\x43\x72\xce\x5f\x64\x26\x9c\x4c\x9b\x1a\xa2\xd8\xca\xff\xf5\x6e\xed\xed\xb6\x2d\xbd\xd8\xda\x6e\x5b\xe4\x73\xbe\x45\xb2\xc6\xb4\xae\x8d\xef\xb9\x9e\xab\xad\xee\x8f\xab\x16\x6a\x07\xda\x68\x25\x14\x76\x24\x8e\xcb\x98\x0a\x0f\x17\xff\x0d\xb0\xc9\x93\x67\x70\x10\x33\x2e\x87\x04\x7c\xa5\xdd\xf4\x47\xe5\x64\xbf\x69\x51\xe7\x60\x38\xbd\x38\x75\xde\x66\x2a\x2d\x51\x67\xdd\xeb\x4c\x71\x83\x4f\x12\x21\x68\xa6\xd6\x20\x6d\xb8\xde\x90\xab\x25\x4c\xa5\x14\x8d\xaa\x55\x4c\x1f\x7b\x99\xe3\xef\xe3\x0b\x94\xe7\x8d\x25\x5e\x0f\x5b\x4c\x0d\x94\x5a\xf9\x4e\xe1\xfc\x15\x88\xa1\x94\x5f\xab\x90\x11\xa5\x37\x31\xeb\x1b\x89\x92\x77\x24\xeb\xd9\x13\x78\xc2\x74\xd8\x1e\x58\x5a\x86\x8f\xc8\x73\x7d\xbb\x8d\x48\xfa\xab\x8e\x45\xdd\x6e\x7d\x2c\x6a\x26\x7f\xd7\x9d\x8a\xfa\x2f\x39\x15\xc5\x1f\x3d\x0b\xbd\xf3\xe3\x51\xf0\xef\x70\x01\xa1\x41\x06\x55\x51\xe5\x4e\x96\x4d\xad\x94\xf5\x53\xe5\xde\xca\x1c\x86\xca\x93\x69\xba\xa4\xd9\x44\x3a\x9e\xa5\x4f\x1e\x8f\x6b\xab\x2c\x33\x6d\xa8\xee\x10\x79\x1e\xce\x14\x45\x93\xd4\x97\xb0\xc8\x0f\x5d\x99\xf0\x38\xdc\xd9\x5a\x7b\x33\x2c\x64\x0e\x48\x16\xe6\x84\x50\x92\x6a\x2b\x84\xa8\x77\x8a\x6e\x30\xaa\xde\x91\xbc\x41\xd5\x48\xd2\x03\x7b\x78\x18\x75\xf8\x3b\x95\xf0\xef\x45\x42\x7f\xd3\x92\xa4\xdf\x6d\x22\xa3\x79\x43\xb5\x94\x6e\xc0\xd7\xc8\xe8\x0f\x59\x82\xb1\x4d\x9e\x7f\xbb\x18\xc3\x0e\xf9\xfd\xbf\x30\xb7\xff\xe9\x9c\x2c\xfb\xc0\x11\xc6\x0f\x51\x5b\xff\xd1\x47\x15\xbb\xe2\xfa\xe6\xb9\x6f\x71\xfd\x7b\x8f\x1c\x7e\xd8\x1a\xfb\x4f\x20\x5a\xf8\x21\x6b\xec\xbb\x08\xe1\x4a\xa4\x7c\x6c\xa5\xef\xd3\xcf\x4e\x11\xc1\x2e\x1a\xb8\xb3\x16\xde\x52\xe1\xdc\x37\x0a\xb8\x25\x45\xec\x98\x67\xef\x72\xec\x7f\x4d\x8e\xbd\xb3\x78\x37\x7c\x3a\x8b\x77\x29\x50\x3a\x8b\x17\x3a\x8b\x77\xdd\xf6\x3a\x8b\x77\x25\x78\x3a\x8b\x77\x25\x52\x3a\x8b\xb7\xb3\x78\xe1\x53\xb3\x78\x77\xb9\xa5\xab\xcb\x75\xdf\x2b\xd7\xbd\xad\xb4\xd8\x4a\x46\x6c\x49\x07\x5b\xe7\xb6\xbb\xbc\xf6\xc7\x92\xd7\xde\xf8\xc0\xbf\x72\xf2\xbe\x87\xfe\xdb\xb8\x5a\x76\xf2\x5f\xdc\x68\x99\x41\x59\xb9\x70\x9e\xba\x3b\xfd\xff\x2e\x4e\xff\x4f\x41\xbe\xbb\x02\x60\xa3\x2b\x00\x96\xc1\xac\xbb\x07\xa0\xbb\x07\xe0\x1d\x27\xa1\xbb\x7b\x00\xba\x7b\x00\xba\x7b\x00\xe2\xd3\x9d\x4e\x82\xee\x74\xd2\x46\x4f\x77\x3a\x69\xf9\xd3\x9d\x4e\xfa\x68\xa3\xaf\xd0\x9d\x4e\xfa\xb8\x23\xb1\xd0\x9d\x4e\xea\xa2\xb3\x1b\x22\xea\x13\x3c\x9d\xd4\xdd\x03\xf0\xb1\xd6\x28\x40\x67\x69\x77\x96\x76\x67\x69\x77\x96\xf6\xea\xa7\xb3\xb4\xb7\x78\x3a\x4b\xbb\xb3\xb4\x57\x4d\xdc\x59\xda\x9d\xa5\xbd\x7e\xf2\xee\x1e\x80\x4f\xa8\x36\x02\xba\x7b\x00\xba\x7a\x89\xee\x1e\x80\xff\xde\x7b\x00\xa6\x72\xf7\x1f\xee\x32\x80\xed\x97\xd1\xdd\x08\xd0\xdd\x08\xd0\xdd\x08\xd0\xdd\x08\x10\x9f\xee\x46\x00\xff\x7c\x4c\xb1\xc6\xee\x7c\xd4\x52\xa0\x74\xe7\xa3\xa0\x3b\x1f\xb5\x6e\x7b\x9f\x40\xdc\xb0\x3b\x1f\xf5\x11\xc6\x0a\xbb\xf3\x51\x5d\x5c\x70\x16\x39\x9f\xc8\xf9\xa8\xee\x46\x80\x8f\x31\xdb\xde\x59\xbc\x1b\x3e\x9d\xc5\xbb\x14\x28\x9d\xc5\x0b\x9d\xc5\xbb\x6e\x7b\x9d\xc5\xbb\x12\x3c\x9d\xc5\xbb\x12\x29\x9d\xc5\xdb\x59\xbc\xf0\xa9\x59\xbc\xdd\x8d\x00\xdd\x8d\x00\xdd\x8d\x00\x9f\x62\x86\x7b\x2d\xa6\x0b\x2c\xb4\x99\x5c\x0a\x33\xc2\xa5\x59\xed\x29\x74\xee\xbd\x68\xf5\x20\x09\x39\x94\xa3\xca\x04\x03\xfc\x6f\xcf\x5e\xbd\x78\xf2\xe2\xf9\xd9\x8b\xb3\xcb\x00\xaf\xa1\xf6\x2e\xee\xe8\xf5\xf9\x29\xa4\xc2\x89\x5c\x8f\xe0\x5c\x67\x41\xe9\x7a\xeb\x5f\x0f\x5d\x58\x08\xe4\xb2\x90\xae\xee\x65\xd1\xdc\xa0\xe9\x05\xb8\x71\xf2\xbb\x52\x4e\x16\xe8\x53\xb7\xc2\x39\x62\x4d\x92\x03\x05\xa2\xe3\x73\xee\x85\xb8\x46\x02\x14\x8c\x2a\x61\x84\x72\x18\x51\x21\x9d\xef\x94\x69\xb0\x3a\x98\x0f\x32\xf8\x18\xb4\x0e\x8b\xc1\x52\x38\x8f\x99\xe1\xb1\xb8\xf1\x07\xaa\x87\x9a\x60\x4e\x44\x51\xe8\x4c\x0e\x65\xea\x8d\x3c\x28\x44\x56\x67\xfd\x82\xae\x40\x53\x13\x50\xb3\x81\x63\xe8\xcf\x81\x07\xd5\x8d\x34\x5a\xb1\x06\xbb\x11\x46\x8a\x41\x1e\x76\x35\xf0\x01\x01\x1e\xb7\x59\xa0\x82\xc1\x84\xfc\x1c\x3f\x52\x80\x56\x38\xf9\xbe\xa2\xdf\x54\x73\x0f\xdc\x99\xc6\x5f\x3c\x7c\xf8\x3f\xeb\xe3\xec\xbe\xd3\x95\xf2\xd8\xf1\x12\xb3\xe1\x5b\xea\x21\x87\x20\xdd\x3e\x71\x8c\x25\xcf\x87\x46\x30\x98\x55\x69\x84\x94\x76\xa5\x91\x5e\x2b\x8b\x1a\xe1\x1e\x0c\xc4\x5d\x45\x45\x0c\x40\x02\xc1\x5a\x39\xc8\xb1\x47\x6c\x2f\xdb\x6d\x07\x48\xc0\xe3\x1e\xcc\x9a\x37\x48\x2b\x27\x72\xf3\x12\x17\x91\x78\x5f\xf3\x59\x77\xe1\xf9\x3c\xc3\xa1\xa8\x72\xcf\x1a\x1e\x37\x8c\xdf\x89\xae\x48\x14\x64\x78\x07\xb2\x10\x23\x7f\xf6\x5e\xc0\x50\xe6\xd8\x8f\x39\xf4\x54\xa4\x63\xec\x41\x86\xa4\x5b\xa4\x42\x10\x30\xd2\x3a\x23\x15\x63\xf4\x9d\x2c\x78\xb4\x40\x8f\x35\x7c\x06\x13\xc8\x74\x35\xc8\x6b\x2c\xcb\xdf\x6a\xc9\x50\x8a\xf4\x9a\xe6\xe2\x81\x41\x38\x38\x72\x45\x79\xc4\xbf\xc2\x7f\x43\x0b\x9b\xfc\x62\xb5\x8a\xa2\xaa\xb5\xcc\x64\x06\xfe\xd2\xc2\x00\xad\xeb\xe3\x70\xa8\x8d\xfb\x27\x41\xab\x52\x4c\xad\x4a\xd7\x5b\x8f\x48\xad\x2c\x7a\x1d\xa7\x34\x13\xf2\x14\xe6\xb5\x59\xc0\xa1\x2d\x72\x48\xf6\x96\x48\x80\x92\x38\xcd\xa8\x63\xf8\xbf\x07\x57\x9f\xff\xd1\x3f\xfc\xfe\xe0\xe0\xcd\xc3\xfe\xd7\x6f\x3f\x3f\xb8\x4a\xf8\x8f\xcf\x0e\xbf\x3f\xfc\x23\xfe\xf8\xfc\xf0\xf0\xe0\xe0\xcd\x0f\x2f\x9e\x5d\x9e\x3f\x79\x2b\x0f\xff\x78\xa3\xaa\xe2\xda\xff\xfa\xe3\xe0\x0d\x3e\x79\xbb\xe1\x20\x87\x87\xdf\xff\x6d\xc9\x82\x84\x9a\xbc\x1a\x2e\x57\x46\xfd\x0d\x6b\x5e\xfa\x9b\xa8\xc2\xbb\xfe\x75\x35\x40\xa3\xd0\xa1\xed\x4b\xe5\xfa\xda\xf4\x7d\x87\x63\x70\xa6\xc2\x85\xdd\x48\xe2\xaf\x0b\x14\x4e\xc9\xd5\x97\xad\x0e\x33\x41\x91\x70\x53\x44\xf0\x59\x68\xca\x5a\x40\x92\x5e\xe5\xeb\x10\x5c\xa3\xaf\x12\xb8\x58\xd0\x93\xd5\x52\x68\xb1\x6f\xbd\x02\xb3\xb3\xe3\xcc\xd4\xc1\x78\xc1\xc9\x63\x2e\xd9\xc2\x06\x66\xec\x76\x46\xeb\x5a\x7c\x94\x46\x6a\x23\xdd\xe4\x34\x17\xd6\xbe\x14\x05\x6e\x04\xdd\xb3\x61\x63\x0c\xf4\x88\xd9\x48\x86\x07\xa5\xe5\x0d\xb4\x38\x2e\x4b\x0e\xd2\xb3\xad\xf6\x11\x42\xb1\x4d\xcd\x33\x91\xfb\xb4\x81\xdf\xd0\xe8\x70\xd1\x87\x41\xaf\xab\xe3\xe7\xd5\xc0\x5b\xb1\x57\x8b\x69\xc5\x7b\xd5\xca\xe1\x9d\x3b\x65\x65\xbb\x99\x96\xbe\x58\xd4\x15\x52\xa1\x68\xd9\x7c\xd1\xcb\x10\x7e\xce\x71\x24\xd2\xc9\xcf\xb4\xfc\x9f\x0d\xd2\x42\xc8\x16\xf9\xd9\x1b\xdb\xa7\x5e\x1e\x5f\x70\x25\xc2\x7e\xb8\xb9\xc7\x02\x4a\xbe\x98\x47\xaa\x5f\xbc\xe1\x52\xdb\x64\x86\xeb\xdb\x4a\x9d\x25\x04\xb9\x64\x66\xed\x2c\x93\xea\x8f\xb5\xb2\x7c\xf3\xd9\xdb\xb9\x96\xc1\x05\x23\x27\x8f\xd4\x6e\x9b\x3e\x4d\xc5\x02\x93\x04\x5b\xdc\x20\x9c\x64\x85\x64\xaf\x0f\x0e\xce\x2f\x4e\x0e\xa7\x76\x42\xfa\xda\xab\x98\x4c\xa3\x55\xfb\xce\x2b\xbd\x31\xda\xc6\xd3\x63\xb5\xc1\x85\x16\x9e\x5b\xb8\xd2\x22\xce\x49\x00\x63\xe7\x6f\x80\xf5\xe4\x17\x27\xf0\xf3\x40\x58\xcc\xa5\x42\x0f\xbb\xd2\xc8\x1b\x99\xe3\x88\x66\x6c\xc5\xad\xe1\xb4\x32\x06\x95\xcb\x27\xf1\x06\x98\xc5\x58\x91\x96\x04\xfa\x34\xb9\x45\xca\xaa\xad\xce\x1a\x59\xd4\xda\x62\x96\xc0\x05\xf7\x98\xf8\x10\x45\x68\xc7\xb8\x61\xbd\xb8\x0c\xb9\x60\xd0\xd2\xc0\x52\xf9\x5e\x32\xf3\x2a\x0e\x8d\x21\x97\x87\xab\xc2\x2a\xcb\x06\x70\x9e\xa1\xa9\xd5\x32\xab\x26\x1b\x4d\xb1\x94\x4d\x82\x50\x3a\x17\x00\xb3\x00\xf0\xcb\xf7\x3c\x6d\x54\x38\x5d\xaf\x97\xb5\xdf\x19\x2d\x6e\x58\xb9\xca\x20\xe9\x7f\xc6\x2e\xf3\x5c\x1b\x34\x33\x76\x4c\x7b\xfa\x5e\xbd\xec\x42\xc8\x40\x6a\x36\xce\x69\x70\x50\xc9\x9c\xbd\x40\x59\xef\xcf\x7a\x42\x16\xf5\x74\x7a\x08\xba\x2c\xc2\xf5\x4b\x55\x59\x6a\xe3\x1a\xdf\x20\x6d\xf3\x46\xb0\xdd\x17\x00\x80\x96\x55\x1a\x2c\x85\xa9\x25\xb6\x45\x48\xc7\x42\x91\xfa\xa7\x8d\xbe\xd0\x5c\x2a\xe7\xeb\x2d\x69\x5a\x31\xd0\x95\x63\x1a\x0b\xbc\x3a\xd4\x95\xca\x80\x84\xca\x31\x8c\x9d\x2b\xed\xf1\xd1\x51\xa3\x8f\x12\xa9\x8f\x32\x9d\xda\xa3\x54\xab\x14\x4b\x67\x8f\x22\x37\x1d\x95\x3a\xeb\xc7\x1f\x7d\x11\x99\xe4\x68\x7f\x99\x8e\xdf\x40\x13\x06\xc8\x1f\x83\xc7\xd5\x92\x56\xa8\xaa\x15\x97\xcd\xf4\x57\x77\xa6\x06\x0d\x18\x17\x36\x72\x3a\xe7\xab\x99\x56\x64\x60\xa6\x1d\xd0\xa6\x7d\x7d\x45\x52\x6d\x98\xb6\xa4\xdb\xbe\x6d\x0f\xbd\x5a\x68\xaf\x72\xcc\xd7\xb8\xe2\x73\xd7\x23\xb1\x6c\x23\x73\xaf\x59\x28\x1b\x00\xce\x09\xbe\x20\x89\x0c\x7a\xff\x85\xc4\x95\x9a\x00\xd1\xb3\x0b\xb7\x65\xb5\xae\x8f\x72\x86\xeb\x37\xbf\xa9\xa3\x69\x3d\x1c\x0e\x31\x75\xdf\x05\x7e\xae\xe3\x6a\xcc\xdc\x31\x02\xf6\x4d\xfc\xeb\xbb\xe5\x1e\xe5\x46\xc1\xaa\xcd\xd2\x0d\x7e\x49\xab\xc3\x08\x53\x10\x7a\xc2\x1d\x66\x54\xb6\x87\x80\x1f\x8b\xbd\x3f\x0e\xc8\x06\x9f\xd9\x07\x5f\x82\xbd\x43\x32\xa3\xd5\xd8\x06\x09\xd7\x92\xb6\xc1\x9f\x6e\x22\x7f\x08\x2f\x75\x28\x64\xc6\x1e\x9c\xf3\xdd\x52\xcd\x1b\x56\x64\x2f\xb5\x2f\x69\x5e\x6a\x17\xb5\xe1\xb6\x36\xce\xb2\x36\xe1\x32\x05\x90\x1f\x9a\xf4\x8a\xdf\xd9\x54\x7a\xa5\xa1\xe0\xa9\xe8\xd9\x2a\xc8\x5c\xe3\xa4\x09\xc9\x87\xe4\x0d\x47\xbc\x7a\x0d\x95\x44\xe3\xd3\x47\xd8\xff\x19\x6a\x12\x75\x31\x90\xca\x4f\xe6\x87\x8e\xa8\xe0\xd1\x23\x40\x55\xc6\x3f\x79\x9a\x77\x01\xae\xcd\xb2\x38\x53\x30\x7b\xb5\x45\xce\xa6\x8e\x02\x2f\xce\xd6\xb4\x52\x34\x4f\x7e\xad\x44\x9e\xc0\x63\x2f\x15\x79\xf7\xe1\x55\x68\x34\x17\xb5\xbe\x95\x79\x96\x0a\x93\xb1\x36\xf0\x3c\x0a\x56\x7b\xec\x89\xda\xe0\x88\xdc\xde\xe0\xc8\xdf\x9d\x06\xa5\x30\x4e\xa6\x55\x2e\x58\x6d\xe1\x48\x9b\xc9\x3b\x81\x68\x43\x34\x17\x98\x6a\x95\xad\x09\x24\x2e\x91\xae\xa1\x6f\x1b\xc6\x6c\x46\xa1\x91\xa1\x44\x58\x16\x38\x4b\xa4\x07\xd3\xce\x8d\x1e\x46\xae\xae\x59\xac\xe7\xad\x9a\x5b\xc9\x66\x59\xdb\x2b\x96\xfe\x8c\xc1\x61\x4b\x3c\xd6\x5c\x91\xc0\xbf\x26\x51\x5f\xf5\x40\xba\x18\x3d\x63\xbf\x39\xcc\x19\x48\x36\x00\xbb\x61\xa8\xa1\x36\x78\x83\x06\x0e\x32\xcd\x7d\xb8\x8c\xfe\x30\x81\xff\x90\x89\xef\x63\x10\x23\x5f\xf1\x1d\x48\x3c\x5a\x22\x8e\x2f\x3b\xe4\x28\xe2\x43\x38\xf0\xd5\xf7\xb2\x28\x30\x93\xc2\x61\x3e\x39\xf4\x05\x18\xb1\x7e\x7f\x13\xd4\x6d\x72\x68\xa3\x75\x58\xe3\xab\xbf\xaf\x68\xc9\x8b\xdd\x02\xb3\x3f\xc5\xc8\x58\x03\x19\x6f\x65\xce\xa0\xb0\xd6\x41\x7a\x45\x52\xae\x95\x84\x6b\xd9\x7e\x51\xcc\xd4\x08\xfe\x85\xe8\x40\x80\xc1\x11\x53\xb9\xa7\xdc\x7b\xd0\xb8\x4c\x17\x1f\x3a\x59\xa3\xd1\x56\xe7\xf5\xfb\x40\xe6\xff\x57\x7f\xcf\x84\x13\x4b\x1a\x78\x9c\x4f\xca\x45\xc1\x81\x75\x8a\xb2\x19\x7c\x19\xb2\x36\x88\xea\x86\xe9\x77\x1a\x81\x4d\xfd\x45\x3d\xa7\x5d\x6a\x0e\xa9\xf9\x3c\x6f\xc4\x77\xdf\xe0\x48\x5a\x67\x26\xad\x70\xa8\x0f\xbd\x39\x0d\x52\x59\x27\x94\x93\x2c\xd9\x20\xb6\xec\x87\xd8\x20\x99\xdf\x09\xbc\x22\x5f\x8b\x63\x58\xb7\xa4\xa6\xbd\x81\x7d\x39\x29\x11\xbe\x6d\xfd\x78\x66\xca\x94\x69\x2d\x08\x1a\x4f\x5c\x22\xcb\x0c\xda\x79\xf9\xb0\x88\x7c\x56\xee\x3f\xba\xf9\x6b\x41\xb0\x7f\x1e\x03\x02\x21\xb7\x64\xad\x1c\x91\x95\x19\x4f\x7b\xc5\xd8\xf0\x94\xb5\xe9\xbd\x02\xee\x28\x7f\x63\x6e\x2a\x6a\x25\x20\x5d\xb4\xfb\x53\xad\x6c\x55\xc4\xa2\x2d\xf2\x7a\x4a\x54\x19\xaa\x74\xc2\xc7\x03\xf2\x1b\x34\x09\xfc\x68\x09\x53\xf0\xbf\xe5\x88\xfc\xbe\x30\x69\xdb\x54\x8a\xa7\x4e\x66\x56\x20\x6d\xeb\xce\x4c\x2e\x43\x23\x1b\x28\x8e\x80\xd9\x4c\x7b\x1b\x53\xe1\xb3\x8b\xa8\x7c\xac\xf5\xb2\x3e\x95\x16\x83\xa0\x11\x2e\x9e\xe1\x69\x4b\x23\xed\x0f\x20\x95\xda\xca\x78\x5a\xa6\x96\xa3\x53\x27\xdb\xf4\xd0\x9f\x3b\xf3\xe3\x4e\x3b\xc2\x5c\x53\x31\xb3\x19\x76\xdc\x2a\xe5\x81\x8f\xed\x28\x4d\x14\x33\x0f\xfd\x50\x8b\xfa\xb9\x78\x11\xf1\xf4\x92\x1b\x99\x6e\x84\xba\xc6\x0c\x72\xbc\x93\xa9\x1e\x19\x51\x8e\x65\xca\x87\xab\x88\x4d\x39\x48\xc6\x47\xaa\x44\x81\xc9\xfe\x52\x42\x5b\x26\xc6\xcb\x6a\x90\x4b\x3b\xc6\x85\xb6\xcc\x4a\x1a\xb5\x98\x1a\x74\x0b\x25\xc8\x14\x89\x5e\xf8\x76\x8d\x52\x8e\x15\x29\x61\x80\x50\x71\xe5\x69\x8e\x19\x8f\x40\x9c\xa6\xc4\x48\x31\xad\xd1\x5c\x78\x5b\xc3\x30\x81\x33\x17\x03\xd3\xd4\xe3\x1a\xb1\xf4\x94\xc6\xa9\x51\x5b\x70\x4c\xc5\x4a\x95\xa2\x3f\x22\xe6\x8f\xda\x21\xc6\x30\xa3\x33\x12\xbd\x19\x84\x1c\xe0\x8f\xb8\x41\xe5\x16\x1b\x35\xab\xfd\xae\x15\x3e\xd7\x6a\x30\xd6\x32\x65\x3d\x24\x1b\x59\x14\x75\x22\xfd\x4d\xa0\xe4\x2f\xdb\x62\xd0\x9f\xe8\xbb\xf0\xa5\x25\xeb\x65\xcd\x8f\x53\xcd\x43\xc2\xd2\xc2\x58\xdf\x86\x91\x66\x99\x36\x44\x6c\x22\x6e\x33\x69\x53\xe2\x74\xcc\xe0\x54\x2b\x1b\x8f\xf5\x09\xe5\x4f\xea\xdd\x88\xdc\x93\x42\x1c\xb8\xd4\x39\xe7\x37\xb2\x2a\xba\x13\xbe\xfa\x0e\x8b\x01\xf2\x75\xbc\x36\x2e\x65\x89\x9a\x5b\xa3\x62\xd7\x69\xc1\xa8\x1f\xce\x75\x9e\xaf\xd6\x62\x2b\xfd\xd2\x4d\xbc\xd2\x08\x80\x8d\xaf\x42\x3f\x8b\x10\x0b\xb1\x38\xa2\xe9\x26\x83\xc4\xa4\x41\xa6\x6e\x0d\xd8\x01\xba\x5b\x44\x05\xe9\x18\xd3\x6b\xdb\xe4\x90\xf9\x62\xec\x19\xac\x85\xf8\xd3\xb4\xc4\xaa\xed\x29\xc2\x0a\x3b\x1a\x16\xd1\xa7\xcd\x14\xde\xb6\x63\x56\x0b\xd4\x0d\xa9\xe8\x1b\x21\x73\x31\xc8\xfd\x71\xd6\xfa\x57\xaf\xbd\x0e\x19\xf5\x79\x59\xe5\x79\x48\x22\x71\xd6\xd6\x19\x31\x1c\xca\x94\xd3\xe4\xd2\xf8\xa8\x6f\x50\x6c\x0b\xb7\xb0\xfe\xb2\xf6\x05\x1c\x61\x9d\x70\xd5\x1c\x8e\x56\x20\x78\x15\x62\xc9\x0f\x91\x4b\x03\x44\x33\x57\x1c\x4f\x39\x2b\xb4\x0c\xf4\xce\xd6\x54\xfc\x3b\x81\x97\xda\x85\x1b\xca\x5f\xa0\x25\xb5\xcb\x00\x7a\x8d\xc2\x6a\xd5\x92\xae\x6c\xfd\x1a\x39\x92\x4a\xe4\x61\x53\xed\xf8\x5e\xed\x7b\x08\x0e\x29\x17\x72\x64\x84\xab\x85\x62\xb3\xee\xa0\x5d\x82\x5e\xf4\x91\xd0\x04\x4e\xd4\x84\xf1\x3d\x44\xe1\x38\xe7\x2e\x95\x33\x3a\xab\x52\x0c\x19\xeb\xca\xb6\x07\x79\xa7\x62\x74\x3a\xbd\x70\x1a\x27\x69\x6a\xa4\x32\x74\x42\x86\x94\x92\x56\x08\xc2\x96\xe4\xc7\x45\x9a\xf4\xa1\xf0\x06\xc0\xac\x2c\x4e\xce\xcf\xe0\x75\x38\xec\x98\x40\xbf\xdf\xf7\x79\x4f\xeb\x4c\x95\xb2\x7e\x21\x16\x52\x59\xd0\x14\x9e\xfa\x78\x93\xa2\x55\x5e\x18\x22\x1f\xde\x04\x2b\x85\x1b\x43\xe2\x01\x9f\xb4\x40\x01\xf0\x94\x74\xcd\x9d\x28\x4a\xa2\xfb\x2b\xe5\xa5\xf7\x53\xad\x2f\x3c\x92\xfc\x9c\xbf\xc3\xd1\xd1\x2c\x4d\xe8\x01\x99\xa8\x21\x80\xc8\xa4\x31\xd4\x7a\xdf\x4e\x6f\x29\xa1\x8e\x3f\x28\x7d\xab\x16\xcd\xce\x73\x09\x83\xc7\x70\xb5\x77\x12\xb9\xef\x6a\xaf\x07\x57\x7b\xe7\x46\x8f\xb8\x6c\x4d\x8d\xae\x42\x1d\xda\xd5\xde\x63\x1c\x19\x91\x61\x76\xb5\x47\xc3\x7e\xce\xf5\x86\x2f\xd0\x8c\xf0\x07\x9c\x7c\xcb\x83\xd5\xaf\xa3\x46\xf8\xd6\x97\x26\xd2\x7b\x52\xc1\xa4\xa7\xbe\x2d\x44\x59\xbf\x78\x21\xca\xba\xf3\x69\x43\x67\x6f\xde\x16\xe8\xc4\xcd\xa3\xa4\xc1\xe8\xcf\xbf\x58\xad\x8e\xaf\xf6\x9a\xf5\xf7\x74\x21\xb9\xd2\x62\x72\xb5\x07\x53\xb3\x1e\x5f\xed\xf1\xbc\xf1\x7d\x5c\xe4\xf1\xd5\x1e\xcd\x44\xaf\x8d\x76\x7a\x50\x0d\x8f\xaf\xf6\xb8\x80\xa1\xf7\xa8\x67\xb0\xec\x91\xc1\xf4\x6d\x33\xc3\xd5\xde\xcf\x84\x93\xa3\xa3\x90\xc2\x08\x97\xbf\xff\xb9\x38\x58\xbd\x56\xee\xaf\xab\xcb\xee\x43\x2e\xac\xbb\x34\x42\x59\x9e\xff\x52\x16\x8b\xd3\xb8\xde\x97\x63\x7e\x5f\xfa\xdd\xb0\x0c\x58\xfa\xd9\x53\xc3\xd2\xcf\x4b\xb4\xe7\x26\x9a\x6b\x7e\x0f\x1b\x46\x9d\xe7\x3b\x36\x05\xdb\x64\xcf\xc5\x38\x4d\x8d\x1f\xd2\x01\xa1\x35\x86\x8b\x04\x88\xc5\x83\x7c\xe3\x72\x4c\xc6\x5b\xa8\xea\x69\x1c\xfc\xdb\x70\xc9\x00\x54\x2a\x43\x93\x73\xb2\xaa\x19\xd5\x67\x42\xb2\x04\x7c\xdc\x40\xd4\x51\x9a\x6b\x62\x24\xd6\x4e\xaa\x15\xbc\xf6\x85\x3f\x71\x44\x92\x1d\xe1\x9e\x05\x3f\x0c\x2b\xba\x34\xc5\xd2\xb1\xa6\xdb\x3d\xc5\x0c\xad\xa0\x0a\x59\x56\x7d\xb7\x9c\x3c\x02\x71\x6c\x08\xf8\xd0\xda\xe7\xf7\xc7\x55\x21\x48\x75\x88\x8c\x6b\x7f\xea\x6f\xde\x7d\xf3\xee\x96\x17\xa9\x3e\x29\xe4\x63\xfc\x11\x0f\x01\xd4\x41\x91\x88\xfa\x40\xcd\x9a\x88\xc9\x46\x9b\x2f\xc4\xdd\x73\x54\x23\x37\x3e\x86\x2f\xbf\xf8\x5f\x5f\xfd\x63\x49\x43\x2f\x18\x31\x7b\x86\x2a\xc4\x82\x36\x04\xc3\x7c\xc7\xd9\xa0\x61\x42\x52\x29\x13\x4e\x24\xa3\xa6\x4d\x1d\xe4\x6e\x28\xe8\x56\x70\xe1\x56\x50\x97\x55\x49\x70\x79\xca\x05\x80\xd6\x09\x95\x62\x8f\x8c\xa4\x85\x83\xc9\x5a\x80\xe7\x13\x78\xf4\x85\xff\x47\x52\x78\xea\x39\xf1\xfd\xe6\xee\x6d\xb2\x60\xc9\xd2\xc2\xd7\xbd\x99\xf5\x48\x0b\x84\x2a\x3d\x64\xc2\xf1\x2e\xa6\x41\xaf\x09\x63\x30\x60\x5e\x13\x62\xbd\xde\x75\x88\x5b\x17\x0f\xdc\x2c\x16\x58\x48\x25\x8b\xaa\x38\x86\x87\x4b\x9a\x78\x91\xb6\x21\x36\x7d\xe3\xc6\x10\x10\x24\xba\x46\x46\x14\x05\x97\xfa\xca\x0c\x95\x93\x43\xc9\x45\x03\x35\x69\xb3\xbb\xef\x3b\xc6\x1a\x94\x1a\x8a\x5c\x9e\x42\x72\xa8\x45\xec\xe7\xde\xce\x31\xac\x81\x43\xf6\x26\x6d\x0b\xa8\x49\x89\x9e\x1b\xbc\x03\x03\x78\x57\x7a\x53\xb5\x95\x86\x28\x50\x28\xa9\x46\xb6\xa9\xe7\x0a\xff\x40\x0e\x7d\xbc\x1d\x63\xc8\x9e\x63\x3b\x17\x94\x92\xb3\x94\xb1\xdf\x24\x9a\x9a\xc2\x8c\xc4\x8f\xb7\xd1\x67\x63\x9a\x64\x39\x16\x98\x9f\x0a\x8b\x91\x1b\xdb\xd5\x5c\xf1\xb6\x96\xfa\xf4\xc1\x3b\x63\xd5\x47\x0f\xbf\x58\x89\xf2\xba\xdd\xf2\x14\x5e\x5d\xe6\xf5\xe6\xa4\xff\x1f\xd1\xff\xed\xed\x41\xf8\xe3\x61\xff\xeb\xff\xd7\x3b\x7e\xfb\x59\xeb\xe7\xdb\xe5\xd5\x59\x8b\x8d\xf9\x25\xe4\x13\x94\x48\xb4\x13\x23\x46\x7b\xb1\x4a\xe5\xd2\x54\xd8\x83\xa7\x22\xb7\xd8\x83\x1f\x15\xab\x86\x7b\x02\x6d\x75\x86\x9a\xb4\xf2\x1e\xcd\xba\x2c\x53\x1e\x9a\xf0\x92\x56\xb7\x09\xcb\x5d\xe5\xbe\x6e\x06\xa4\x18\x6a\x68\x49\x1a\xd5\xa2\x33\x5f\xf2\x3c\xd4\x3a\x09\x16\x6e\x92\xea\xe2\xa8\xfe\xee\x4d\xeb\x17\x42\x4d\xa0\x11\x6b\xde\x28\x9d\xa5\x74\xeb\x48\x36\x89\xd4\x68\x6b\x9b\x7b\x48\x20\x97\xd7\x08\x27\x8d\xdf\x48\xc2\x72\x80\xa9\x60\x5b\xdc\x0c\xa4\x33\xc2\x07\x7d\xa3\x5d\xd9\x44\x94\x86\x55\x0e\x07\xe4\xae\x26\x5c\x48\x36\x27\x5d\xc3\x9d\x46\x62\x20\x73\xfe\xa7\x65\xc8\x95\x4e\xb5\x1a\xe6\x32\xb8\x00\x45\xa9\x8d\x13\xca\xc5\x83\x17\x23\xbc\xf3\xff\x9a\x95\x4f\x3b\x48\x0b\x07\x99\xb2\x8f\x1e\x7d\xf1\xe5\x45\x35\xc8\x74\x21\xa4\x7a\x5a\xb8\xa3\xc3\xef\x0f\x7e\xad\x44\xce\x59\xde\x97\xa2\xc0\xa7\x85\x5b\xfe\xef\x02\x6d\xad\x16\x1f\x7d\xb5\x01\x17\x1d\xbc\xf1\xbc\xf2\xf6\xe0\x4d\x3f\xfc\xf5\x59\x7c\x75\xf8\xfd\xc1\x55\xb2\xf2\xfb\xe1\x67\x47\x5c\x23\x59\xb3\xdc\xdb\x37\xfd\x86\xfd\x92\xb7\x9f\x1d\x7e\xdf\xfa\x76\xb8\x88\x19\xa7\x4a\x17\xc9\x0b\xe8\x17\xa2\xec\x5f\xe3\x64\x09\x73\x2e\x35\x47\xe7\x07\xf2\x10\x2b\x44\xb9\xc8\xfb\x1e\xca\xd1\x0b\x51\xbe\xc6\x21\x1a\x54\xe9\x42\x22\xbf\x67\x06\x86\xfc\x87\x15\x9f\xb8\x02\x6b\x87\xa8\x13\xe9\x1d\x1f\x69\x5b\x65\x4e\x6f\x40\x2d\x9b\xd9\x8f\x6a\x45\xfd\xe2\xda\x49\xea\x7d\xee\x3c\x42\xe4\xef\x9f\x7c\xfc\x68\xe7\x71\x2a\xb9\xd4\xd3\x9a\x8e\x61\x9e\x3d\xf6\xa6\x2f\x8b\x1e\x36\xe7\xc6\x9a\xfc\xbc\x4a\xc9\x5f\x2b\x84\xb3\xc7\xf5\x91\x5f\xa9\xd2\xbc\xe2\x4b\xc6\x7e\xfc\xf1\xec\x31\xf9\xef\xff\x0a\xe2\xe6\x16\x21\xd3\x6a\xdf\xc1\xab\x97\xcf\xff\x0f\x07\x03\xb8\x45\xcf\x2b\xf4\x70\xee\x30\x97\xc2\x87\xc9\x82\x02\x86\x7f\xa1\xaf\x93\xe3\x99\x53\x51\xd6\xf1\x13\x16\x77\x5c\x61\x95\x97\x96\x4f\x0f\x80\xad\x4c\x58\x1d\x0d\xec\x33\xbe\x7c\x3a\x29\xe4\x83\xe3\xc1\x87\x5c\xb8\xe5\xe7\x30\x56\x02\x2d\xd5\x4a\x61\xca\x49\x73\xb2\x02\xdf\x03\x7f\x10\x21\xbf\x0a\x36\x2b\xcf\xb1\x03\x33\x84\x84\xda\xce\x64\x41\x6b\x38\xf5\x3b\x7d\xef\x9c\x34\xb7\xdf\x9d\x66\xf4\xf1\x4c\xce\x6c\xbe\x5e\x13\x7f\x9e\x2b\xe3\x9a\x76\x9d\xa7\xa2\x87\x21\xb6\x5a\x27\x47\xc7\xc2\xc2\x00\x51\x71\x38\xd7\x47\xff\x50\x05\xaa\xc3\x26\x10\x5b\x95\x7d\xa7\xfb\xd9\x62\xe4\xad\x81\xdc\x7a\xa8\xad\xf0\x5c\x67\x4e\xef\x6f\xeb\xa8\xde\x8e\x27\x8b\x60\x60\x9b\xcb\xcc\x6a\x1b\x64\xdb\x8d\x2d\x77\x4c\x66\xa2\xba\xec\x59\x84\xa0\x46\xf0\x33\xe6\x97\x44\xde\xe3\x54\x64\xc3\x69\xce\xe6\x4d\x47\xf6\xb6\x5f\xa3\x47\xf3\x05\x9a\x1b\xb9\x93\xf2\x5b\xc7\x98\xa9\xaf\x33\x39\x79\xff\x6c\x45\xa6\xd7\xce\x93\x70\xe8\x2f\xd5\x6b\xd2\x37\x2b\xeb\xdf\x19\x82\xab\xaa\xfc\xb7\x19\x63\x5b\x65\xe9\xa5\xc9\xd4\x21\x0f\xeb\xb4\xe1\x94\x7b\xfb\x5d\x35\xa8\x0d\xe5\x66\xf4\xe0\x03\xc1\xef\x7f\x3e\xf8\xff\x01\x00\x00\xff\xff\x3e\xcb\x2d\xc0\x3f\xed\x00\x00") +var _operatorsCoreosCom_catalogsourcesYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x7d\x79\x73\x1c\x37\x92\xef\xff\xfa\x14\x19\x7c\x1b\x41\xd2\xd3\x5d\x94\x3c\x1b\xf3\x76\x38\x3e\x82\x43\xc9\x7e\x0c\xeb\x60\x88\xb2\x37\xde\x8a\x7a\x4f\xe8\xaa\xec\x6e\x98\x55\x40\x19\x40\x91\x6c\xcf\xcc\x77\xdf\xc8\x04\x50\x47\xdf\xdd\x94\x2c\x29\xb6\xea\x0f\x9b\x5d\x85\x33\x91\xc8\xfc\xe5\x01\x48\x94\xf2\x17\x34\x56\x6a\x75\x0a\xa2\x94\x78\xef\x50\xd1\x2f\x9b\xdc\xfc\x87\x4d\xa4\x3e\xb9\x7d\xf2\xe8\x46\xaa\xec\x14\xce\x2b\xeb\x74\xf1\x1a\xad\xae\x4c\x8a\x4f\x71\x2c\x95\x74\x52\xab\x47\x05\x3a\x91\x09\x27\x4e\x1f\x01\x08\xa5\xb4\x13\xf4\xda\xd2\x4f\x80\x54\x2b\x67\x74\x9e\xa3\x19\x4e\x50\x25\x37\xd5\x08\x47\x95\xcc\x33\x34\xdc\x78\xec\xfa\xf6\x71\xf2\xd7\xe4\xf1\x23\x80\xd4\x20\x57\x7f\x23\x0b\xb4\x4e\x14\xe5\x29\xa8\x2a\xcf\x1f\x01\x28\x51\xe0\x29\xa4\xc2\x89\x5c\x4f\xfc\x20\x6c\xa2\x4b\x34\xc2\x69\x63\x93\x54\x1b\xd4\xf4\xbf\xe2\x91\x2d\x31\xa5\xde\x27\x46\x57\xe5\x29\x2c\x2d\xe3\xdb\x8b\x83\x14\x0e\x27\xda\xc8\xf8\x1b\x60\x08\x3a\x2f\xf8\xef\x30\x79\xdf\xed\x15\x77\xcb\xef\x73\x69\xdd\x4f\x8b\xdf\x9e\x4b\xeb\xf8\x7b\x99\x57\x46\xe4\xf3\x03\xe6\x4f\x76\xaa\x8d\x7b\xd9\x74\x4f\xdd\xa5\xc2\x59\x93\xfa\xcf\x52\x4d\xaa\x5c\x98\xb9\xba\x8f\x00\x6c\xaa\x4b\x3c\x05\xae\x5a\x8a\x14\xb3\x47\x00\x81\x84\xa1\xa9\x21\x88\x2c\xe3\x65\x11\xf9\xa5\x91\xca\xa1\x39\xd7\x79\x55\xa8\xba\x2b\x2a\x93\xa1\x4d\x8d\x2c\x1d\x93\xfe\xcd\x14\xa1\x34\xe8\xdc\x8c\x49\x02\x7a\x0c\x6e\x8a\xb1\xef\xba\x16\xc0\xaf\x56\xab\x4b\xe1\xa6\xa7\x90\x10\x85\x93\x4c\xda\x32\x17\x33\x1a\x4d\xab\x94\x5f\xa6\xa7\xfe\x5b\xeb\xbd\x9b\xd1\xd0\xad\x33\x52\x4d\xd6\x0d\x85\xca\x6d\x3f\x06\x4f\x9a\x37\xb3\x72\x71\x08\x73\x2f\xb7\xed\xbf\xac\x46\xb9\xb4\x53\x34\xdb\x0f\xa2\xae\xb2\x30\x86\xcb\x25\x5f\x56\x0c\xa4\xd5\x68\xdc\x50\xc9\xc2\x66\x58\xe8\xe0\x6c\xb2\x38\xc7\x4c\xb8\xf8\xd2\x17\xba\x7d\x22\xf2\x72\x2a\x9e\x84\x97\x36\x9d\x62\x21\x1a\x7e\xd0\x25\xaa\xb3\xcb\x8b\x5f\xfe\x7c\x35\xf7\x01\xba\xd4\xe9\xf0\x39\x48\x0b\x02\x0c\x96\xda\x4a\xa7\xcd\x8c\xa8\x75\x7e\xf5\x8b\x1d\xc0\xf9\xeb\xa7\x76\x00\x42\x65\xf5\xc6\x83\x52\xa4\x37\x62\x82\x36\x59\x18\xab\x1e\xfd\x8a\xa9\x6b\xbd\x36\xf8\x5b\x25\x0d\x66\xed\x51\x10\x79\x22\x4d\xe6\x5e\x13\xfd\x5b\xaf\x4a\x43\x7d\xba\xd6\x46\xf6\x4f\x4b\xca\x75\xde\xcf\xcd\xf0\x90\xc8\xe0\xcb\x41\x46\x02\x0e\x2d\xb3\x40\xd8\x63\x98\x05\xda\x79\xd6\x90\x96\xe6\x6f\xd0\xa2\xf2\x22\x8f\x5e\x0b\x15\xe6\x94\xc0\x15\x1a\xaa\x48\xdb\xbd\xca\x33\x92\x84\xb7\x68\x1c\x18\x4c\xf5\x44\xc9\xdf\xeb\xd6\x2c\x38\xcd\xdd\xe4\xc2\xa1\x75\xc0\xbb\x56\x89\x1c\x6e\x45\x5e\xa1\x27\x65\x21\x66\x60\x90\xda\x85\x4a\xb5\x5a\xe0\x22\x36\x81\x17\xda\x20\x48\x35\xd6\xa7\x30\x75\xae\xb4\xa7\x27\x27\x13\xe9\xa2\x0c\x4f\x75\x51\x54\x4a\xba\xd9\x09\x8b\x63\x39\xaa\x48\x1c\x9e\x64\x78\x8b\xf9\x89\x95\x93\xa1\x30\xe9\x54\x3a\x4c\x5d\x65\xf0\x44\x94\x72\xc8\x83\x55\x2c\xc7\x93\x22\xfb\x5f\x26\x48\x7d\x7b\x38\x47\xbe\xa5\xcc\x0c\x51\x6c\xae\xa5\x35\x09\x4f\xcf\x45\xbe\xba\x9f\x4b\x43\x52\x7a\x45\x54\x79\xfd\xec\xea\x0d\xc4\x01\x78\xb2\x7b\x0a\x37\x45\x6d\x43\x6c\x22\x94\x54\x63\x34\xbe\xe4\xd8\xe8\x82\x5b\x41\x95\x95\x5a\x2a\xe7\xb7\x74\x2e\x51\x39\xb0\xd5\xa8\x90\xce\x32\xcf\xa1\x75\xb4\x0e\x09\x9c\xb3\x0a\x83\x11\x42\x55\xd2\x4e\xca\x12\xb8\x50\x70\x2e\x0a\xcc\xcf\x85\xc5\x8f\x4e\x6a\xa2\xa8\x1d\x12\xf9\xb6\x27\x76\x5b\x03\x2f\x56\x58\xd8\x63\x00\x51\x43\x6e\x55\x78\xd5\xa6\x04\xbf\x03\x97\x49\x60\x58\xb3\x17\xe9\x11\x59\x66\xd0\x2e\xf9\xb0\xb0\x21\x7d\x41\xcf\x27\x53\x6d\x69\xfd\x84\x83\x57\xcf\x5f\x40\x2a\x14\x54\x16\x69\xf3\xa4\x5a\x29\x62\x08\xa7\x41\x90\x2e\x1b\xe2\xbd\xb4\xcc\x40\x06\x27\xd2\x3a\x33\x4b\xe0\x07\x6d\x0a\xe1\x4e\xe1\x9b\xf8\x6a\xc8\xcd\x69\x03\xb2\xfc\xee\xf4\x9b\x52\x1b\xf7\x1d\xbc\x52\xf9\x8c\x1a\xcd\xe0\x6e\x8a\x0a\xae\xea\xb9\xc1\xb7\xad\x1f\x3f\x9a\x32\x4d\xe0\x62\xa2\xb4\x89\x25\x89\xab\x2e\x0a\x31\x41\x18\x4b\xcc\x99\xaf\x2d\xba\x64\x7e\x05\xd7\xae\x22\x78\xb8\x34\x96\x93\x17\xa2\xdc\x48\x9a\xf3\x58\x92\xfa\xa2\xee\xdb\xca\xbb\xf9\xe8\x34\xb3\x32\x4d\x89\xfe\x14\xe9\x0d\x88\xd0\x4b\x21\xca\xa1\xe5\x6d\xd3\x22\xd3\x76\x14\x38\x8f\x0d\x10\xfd\x9a\xd7\x17\x41\x72\x25\xbb\x4e\xbb\x3d\xb3\x9d\xeb\x36\x30\x64\x23\xd1\x5e\x2c\xd3\x22\x5b\xf4\x31\x31\x65\x7a\xa9\x33\x3f\xed\x8d\xbd\xfc\xd8\x2e\x0d\x78\x5f\x6a\x8b\x16\x32\x39\x1e\xa3\x21\xb9\xa3\x6f\xd1\x18\x99\xa1\x85\xb1\x36\xbc\x5e\xa5\xce\x78\x4f\xd6\xeb\xd7\x51\xb5\x97\x3a\xdb\x76\x61\xa8\x6b\x56\x18\x9e\x19\x03\x1b\xae\x9c\xee\xd2\xdd\x0e\x1b\x36\x2f\x3d\x62\xcc\xf0\x7f\xb6\xfc\xeb\x1c\x3d\xce\x42\xe1\xc8\xa9\x01\x51\x05\xd1\x71\x68\x69\xfa\x87\xb6\x6e\x73\xd9\x70\xb7\x18\xf2\x36\xc3\xa6\x47\xe9\x0c\xcf\x36\x0c\x7f\x61\x0a\x4f\xf9\xc7\x08\x2d\x57\xaf\x87\xca\x1a\x3c\xab\x72\x16\x35\x55\xde\x5d\xd1\x55\xf3\xd8\x72\x2e\xdb\xce\xc7\x97\xc3\x31\x1a\x83\xd9\xd3\x8a\xf8\xf7\xaa\x1e\x55\x10\x52\xfe\xf5\xb3\x7b\x4c\xab\x55\x7b\x6c\xe5\xd4\x09\x14\x87\x69\xa2\x81\x3b\x99\xe7\xa1\x3b\x12\x28\xf1\x03\xcd\x97\x71\x0c\x91\xc7\x7a\x21\x6d\x85\x93\x76\x3c\x63\x72\xd4\x04\xc3\x7b\xd2\xd9\x6c\xb1\x30\xc7\xcb\xb1\xc4\x0c\x46\xb3\xa0\xae\x49\x78\x0e\x60\x54\x39\x90\x8e\x75\x79\x3a\xd5\xda\x22\x08\x4f\x77\x6e\xf7\x56\x6a\x46\x4a\xa0\x15\x92\xfc\x29\x48\x21\x87\x8d\xd3\x6a\x3e\xe1\x91\x37\xd5\xa4\x85\x82\x24\x7e\x4d\xab\xc8\x8e\xd4\xcc\x9d\x74\x53\xfe\x31\x21\xc8\x4d\x28\xcc\x56\x05\x35\x7a\x87\x72\x32\x75\x76\x00\x32\xc1\x84\x57\x17\x45\x3a\x6d\x35\x5b\x20\x3a\x0b\x22\xcf\xe3\x10\xda\x2c\xe1\xf5\x66\x41\x10\x05\x8e\x6a\x0c\x13\xf0\xc6\xa0\xd6\xab\xf3\xab\xb6\x94\x5c\x03\x40\x97\x26\xc7\x03\x48\x75\x51\x56\x8e\x68\x42\x63\x1c\xcd\x40\x3a\xc2\xd9\x1e\x2f\x19\x5d\x4d\xfc\x4c\x30\x0f\x1d\x47\xb0\xea\x35\x13\x09\x07\xb2\x11\xd5\x04\x0e\xfc\xe4\x0e\x22\xfe\xa4\xe6\xa4\x9f\x04\xcf\xaf\x10\x2e\x9d\x06\x08\x9c\x6a\x63\xd0\x96\x5a\x71\x4d\xfe\xf2\xac\x19\xdb\xdf\xea\x4a\x47\xf6\xb8\x21\xe6\x54\x4e\xa6\x91\x96\xc2\x20\xbf\xeb\xae\xc1\xba\x3d\xd2\xec\x13\x61\x4c\xc7\x96\x5c\xf6\x48\x87\xc5\x86\x5d\xb2\xc0\xda\x67\x0a\xb0\x28\xdd\xac\xc5\x13\xad\xd5\x73\x68\x8a\x9a\x06\xbc\xc0\xbc\x5d\xad\x9f\x9f\x2c\xca\x5c\xa6\xd2\x05\x0e\x81\xc7\x70\xc4\x2c\x22\x1d\x89\x32\x50\x7a\xa8\xcb\xe3\x04\xce\xd8\x7d\xb1\x45\x07\x4a\xd7\xed\x87\x86\xa8\x53\xab\x9b\xb6\x36\xce\x6d\x4b\xa1\xe2\x9f\xd5\x98\x6e\xf1\x19\x86\xf1\xa3\x4a\xe7\x51\xde\xf2\xe2\x9e\x26\x1b\x8b\x6e\x2b\xde\x62\xe9\x38\x86\x6d\x4a\xcf\x2f\xb5\x67\x69\x8b\x39\xa6\x64\x92\x12\xed\x07\x20\xac\xd5\xa9\x24\x94\xdf\x30\x6d\x97\xd3\xfd\x4c\x36\xd3\x1e\x76\xa5\x3f\xec\x3c\x7f\x7a\xe6\x37\xde\xb6\xf5\x16\xa8\x91\x4b\x02\xbf\xe3\x39\xaa\x74\x04\xd6\x68\xc6\x5f\x0f\x2d\xe4\x62\x84\xb9\xdd\x8e\x08\xb0\xd3\xae\x6d\x9e\x2d\xf7\xef\xca\x09\xad\x9c\x48\xb0\x31\xeb\x85\x27\xa1\x4d\xb6\x99\x90\xca\x06\xfb\x79\x00\x02\x6e\x70\xe6\x4d\x6d\xb2\xe0\xa3\xe3\x82\x0b\x1b\xf4\xea\x86\x98\xe3\x06\x67\x5c\x28\xd8\xdd\x3b\x0c\x77\x67\xe6\xf0\xcf\x2e\xdb\xb4\x79\x86\x34\xd0\x1d\x6b\xc4\x49\xef\x50\x6d\x77\xfe\xf5\xcf\x0d\xae\x45\x5e\xcb\x9e\x05\x48\xc2\x3c\xc9\xeb\xc1\x8b\xc4\xfa\x2b\xae\xb1\x28\xcb\x5c\x22\xdb\xf3\x3b\x76\xb3\xd6\x0a\x58\xf7\x44\xea\x3d\x68\x5e\xaf\x6b\x87\x86\x67\xc8\x43\xeb\x99\x8f\x76\xfa\x54\x96\xde\xbe\xb5\xc8\x1b\x37\x7a\x7e\x7e\x11\xb9\x6c\x5c\x6d\x96\xf5\xec\x85\x1a\xc0\x4b\xed\xe8\x7f\xcf\xc8\x12\xb6\x03\x78\xaa\xd1\xbe\xd4\x8e\x7f\x26\xf0\xa3\xf3\xbc\xfe\x7c\x4b\xc9\xf6\x01\x08\xe4\xc7\xfb\x20\xf2\x9c\x29\x2f\x53\x68\xfa\x6d\x9f\x91\x4d\xe0\xc2\xc3\x96\x7a\xe3\x4a\x0b\x17\x8a\xc0\x61\x20\x03\x7b\xf1\xb8\x6c\x68\xa2\xa8\x2c\x3b\x79\x94\x56\x43\xc6\x00\x4b\xdb\xf0\xd4\xa3\x76\xda\xf4\x5b\xd3\xdc\xea\xa6\x7e\x64\x5f\xc3\xf3\x95\x95\xa7\xe2\x96\x21\x9d\x54\x93\xbc\x06\x6f\x03\xb8\x9b\xca\x74\xea\x51\xf7\x08\xbd\x6b\xb0\x34\x48\x0a\x4b\x58\x12\x55\xf4\x66\x82\x86\xc0\xae\x8c\xed\x79\xc7\x64\x2e\x52\xcc\x20\x63\x68\xe9\x9d\x6c\xc2\xe1\x44\xa6\x50\xa0\x99\x20\x94\xa4\x49\xf6\x5b\xfd\xdd\x04\xbb\x7f\x76\x16\xef\xed\x0e\x77\x62\x37\x56\x91\x3f\x10\xd6\xfd\x83\xb4\x23\xe3\xea\x5e\x3b\xf6\xda\x71\xee\xe9\xb5\x63\xfd\xf4\xda\x71\xc3\xd3\x6b\xc7\x5e\x3b\x7e\x74\xed\xe8\x6d\xd9\x3d\x8c\xe7\xff\xf4\x2e\x8e\x79\x6b\x99\x35\x6d\x0c\xd3\x75\xcd\x66\xd2\x37\x57\x41\xe0\xbc\x61\x53\x5b\xfa\x20\x89\x11\x6a\x82\xf0\x64\xf8\xe4\xf1\xe3\x5d\x8c\xea\xb0\x90\x5b\xd5\x18\x87\x48\x8f\x54\xee\xcf\x5f\xaf\xad\xb1\xca\xff\xf6\x01\xbc\xa6\x81\xc7\x6b\x47\x5e\x07\x3b\xac\x70\x7c\xb2\x74\x52\xda\x41\x81\x0e\x84\xeb\xb8\x8a\x64\x81\x83\x3a\x54\xc0\x0c\x1f\xa2\x94\xd1\x03\x9b\x81\x56\xc1\x8f\x47\xc4\x4f\xf6\x1b\x41\x8a\xc2\x87\xd4\x46\x58\x8f\x42\x17\xd4\xab\x54\x2e\x6e\x17\x1a\x02\x46\xaa\xc0\x11\x26\x93\x04\xb2\x8a\xab\x09\x15\xc2\xa6\xc7\x7e\xb4\x76\x66\x1d\x16\xec\xc9\xd5\x86\xff\x47\xc3\x76\x66\x46\x85\xf1\x16\x95\xab\x44\x9e\xcf\x00\x6f\x65\xea\xea\xf9\x71\xd4\x56\x3a\xef\x6c\xdf\xce\x45\xb8\x15\x74\xd8\x1e\x2e\x0c\x17\x38\xd8\x6e\xa8\xb3\x8b\xb6\x5f\x68\x7b\x9b\x3d\x39\xa7\x0b\xfd\x4c\x92\x95\x60\xd5\x51\xbb\xde\x07\xce\x7f\x32\x73\xbd\x7a\xbd\xd9\xe5\x0a\x3b\x4b\xb2\x1d\xa4\xd7\x3c\x2c\xad\xf2\x9c\x18\xc3\x7b\x61\x17\x27\xb0\xc4\x3b\xea\xa7\xd4\x61\x66\xef\x78\xf7\x2e\xe6\xb3\x97\x4f\x89\x2a\x54\xe6\x8d\x2e\x75\xae\x27\xb3\x36\xa5\x7d\x7a\x91\x2c\xca\xe8\x1c\x17\x60\xab\x51\x00\x0d\xc4\x7e\x2f\xe7\x96\xa6\xf7\xfc\xf5\x9e\xbf\xde\xb6\x59\x78\x7a\xdb\xa6\x7e\x7a\xdb\x66\xc3\xd3\xdb\x36\xbd\x6d\xd3\x7b\xfe\xa0\xd7\x8e\x6b\x68\xd2\x6b\x47\xe8\xb5\xe3\xca\x79\xf5\xda\x71\x2d\x79\x7a\xed\xd8\x6b\xc7\x65\x4f\xa9\xb3\x07\x24\x3a\x96\x3a\x5b\x93\xe7\xe8\xbd\x3e\xa9\x1e\xe6\x3a\x15\x2e\xe4\xe5\x53\x95\xe0\xe7\xb3\xa2\xf0\x8e\xa8\x01\xfc\xae\x15\xfa\xe4\x35\x5a\x1b\x76\x27\x69\x37\x45\x43\xc5\x8f\xec\xf1\xda\xc4\xa6\x3e\x4f\xb2\xcf\x93\xfc\xec\xf3\x24\xa7\xc2\xfa\x75\xf5\x42\x69\x75\xda\x64\x6b\x43\xbe\x41\x53\x7c\xa1\x59\x93\xc4\x2e\x61\xb9\xf9\xc4\x53\xb3\xa4\x7e\xe6\x59\x88\x17\x60\x76\xd9\x9d\x6f\xc0\xcb\x3c\x29\x91\x65\x98\x41\x89\x66\xe8\x59\x44\xc3\x58\xaa\x6c\xc9\x5c\x23\x7d\x3e\x69\xf6\x63\x77\x1e\x9f\x30\x05\xb2\x3b\x90\x3d\x7c\xae\x6d\xc7\x71\x47\xc2\x7f\x16\x09\x91\xbb\xa2\xfa\x21\xb8\xe0\xe4\xfd\x69\x4b\x5c\xbf\x3b\x34\x67\x40\x1d\x5d\xc2\xfb\xdb\x95\x0c\xcb\x7f\xab\xd0\xcc\xf8\xfc\x47\x03\x58\xeb\xb3\x75\x21\x46\x26\x2d\xa4\xc2\x7a\x4d\xb1\xab\x69\xb9\xa3\x19\xb5\x9f\x9d\xb2\xbf\x27\x1a\xe6\xe9\x32\xdf\x94\xb7\x49\xa3\x0d\xee\x69\xb6\xd4\x08\x5f\x12\x05\x68\xbc\xff\x3b\x8d\x67\x5f\xe8\xb6\x17\x70\x5b\xca\x14\x9f\xb1\x71\x0e\xfb\x1b\xe8\xb0\xb7\x91\x0e\x7b\x19\xea\xb0\xaf\xb1\x0e\x0f\x30\xd8\x61\x3f\xa3\x1d\xe6\x59\x81\x56\x28\xa0\xac\x8f\x63\xbf\xc3\x43\x4c\x54\x78\x80\x1d\x0f\xf3\x53\xad\xd9\xd4\x7c\x2c\xa3\x9e\x79\xbd\x63\xd7\xff\xd1\xc4\xda\xcf\xa6\x87\x79\x52\x05\x63\x58\xb2\x41\xfb\x85\x58\xf8\x7f\x88\xb9\x0d\x0f\x32\xb9\x61\x7f\xb3\x1b\xf6\xe7\x0c\x56\x75\xcf\x39\x9c\xfa\x50\x85\xe9\x5b\xf1\x2a\x82\xcf\xe0\x8e\xe1\x1f\xa4\x09\x78\x5d\xfe\x05\xa5\x90\xc6\x12\xbe\x0b\x3e\x93\xf6\xb7\x60\x9d\xb7\x9b\x29\xfc\x11\x62\x12\xd5\xb7\x22\x27\xdd\xe3\xf3\x38\x82\x5d\x44\xad\xcf\xab\xe9\x01\xdc\x4d\xc9\xda\x24\x29\x55\x9f\x77\x3e\xb8\xc1\xd9\xc1\x60\x81\x91\x0e\x2e\xd4\x81\xd7\x51\x0b\xac\x53\x2b\x34\xad\xf2\x19\x1c\xf0\xb7\x83\x0f\xad\xd9\xf7\x50\x5c\xed\x2b\x54\xf6\xd5\x0b\x7b\x70\x89\x8a\xd7\xba\x7c\x78\xb0\xe9\xb5\x88\x0f\x6c\xc4\x5e\x6c\xa3\x60\x38\xd5\xa2\xa5\x5c\xea\xac\x11\xe6\x31\x7e\x9f\x45\xe3\xb7\x52\xe1\xa6\x8b\x78\xe6\x3c\x34\xe6\x95\xd4\x62\x4a\x53\x58\x78\xad\xd0\x32\xb0\xc3\xda\x45\xd4\xaa\xcc\x65\x13\x9f\x0e\xd2\x68\x3b\x95\xcd\x27\x88\x34\x35\x18\x23\x16\x28\x94\x85\x83\xe8\x7b\x3a\xb4\x4d\x89\x83\xa4\x39\xdd\x57\xb7\x78\xf4\x8f\x7f\x1d\x77\x4e\xf4\x35\x0d\xf6\x48\xbb\x47\xda\x3d\xd2\xde\xa1\x56\x8f\xb4\x57\x3f\x3d\xd2\xde\xe1\xe9\x91\x76\x8f\xb4\xd7\x75\xdc\x23\xed\x1e\x69\x6f\xee\x7c\x3f\xa4\xbd\x6f\x9e\x50\x1b\xf7\x86\xe0\x9c\xbf\xc8\x4c\x38\x99\x36\x39\x44\xb1\x94\xff\xeb\xc3\xe2\xed\x36\x96\x5e\x8e\xb6\xdb\x88\x7c\xc1\xb6\x48\x36\x40\xeb\x1a\x7c\x2f\xd4\x5c\x8f\xba\x3f\xaf\x5c\xa8\x3d\x78\xa3\x15\x50\xd8\x93\x39\xde\xc4\x50\x78\xb8\xf8\x6f\x84\x4d\x9c\x3c\x83\xa3\x18\x71\x39\x26\xe2\x2b\xed\xba\x1f\x95\x93\xc3\xa6\x44\x1d\x83\xe1\xf0\x62\xe7\xbc\x4d\x27\x2c\x51\x47\xdd\xeb\x48\x71\xb3\x9e\x24\x42\xd0\x74\xc6\x20\x6d\xb8\xde\x90\xb3\x25\x4c\xa5\x14\xb5\xaa\x55\x0c\x1f\x7b\x99\xe3\xef\xe3\x0b\x9c\xe7\xc1\x12\x8f\x87\x11\x53\x43\xa5\x56\xbc\x53\x38\x7f\x05\x62\x48\xe5\xd7\x2a\x44\x44\xe9\x4d\x8c\xfa\x46\xa6\xe4\x19\xc9\xba\xf7\x04\x9e\x31\x1f\xb6\x1b\x96\x96\xe9\x23\xf2\x5c\xdf\xed\x22\x92\xfe\xa8\x63\x51\x77\x3b\x1f\x8b\x9a\x8b\xdf\xf5\xa7\xa2\xfe\x87\x9c\x8a\xe2\x8f\x7e\x0b\x7d\xf0\xe3\x51\xf0\x9f\xe1\x02\x42\x83\x4c\xaa\xa2\xca\x9d\x2c\x9b\x5c\x29\xeb\xbb\xca\x3d\xca\x1c\x87\xcc\x93\x2e\x5f\x52\x6f\x22\x9d\xce\xf3\x27\xb7\xc7\xb9\x55\x96\x37\x6d\xc8\xee\x10\x79\x1e\xce\x14\x45\x48\xea\x53\x58\xe4\xa7\xce\x4c\x78\x1a\xee\x6c\xad\xad\x19\x16\x32\x47\x24\x0b\x73\x5a\x50\x92\x6a\x6b\x84\xa8\x37\x8a\x6e\x31\xaa\xde\x89\xbc\x45\xd5\x48\xd2\x23\x7b\x7c\x1c\x75\xf8\x07\x95\xf0\x1f\x45\x42\x7f\xd3\x92\xa4\xdf\x6d\x23\xa3\x79\x42\xb5\x94\x6e\xc8\xd7\xc8\xe8\x4f\x99\x82\xb1\x4b\x9c\x7f\x37\x1f\xc3\x1e\xf1\xfd\x3f\x30\xb6\xff\xe5\x9c\x2c\xfb\xc4\x1e\xc6\x4f\x91\x5b\xff\xd9\x7b\x15\xfb\xe4\xfa\xe6\x79\x68\x72\xfd\x47\xf7\x1c\x7e\xda\x1c\xfb\x2f\xc0\x5b\xf8\x29\x73\xec\x7b\x0f\xe1\xda\x45\xf9\xdc\x52\xdf\xbb\xcf\x5e\x1e\xc1\xde\x1b\xb8\xb7\x16\xde\x51\xe1\x3c\xd4\x0b\xb8\x23\x47\xec\x19\x67\xef\x63\xec\x7f\x4c\x8c\xbd\x47\xbc\x5b\x3e\x3d\xe2\x5d\x49\x94\x1e\xf1\x42\x8f\x78\x37\x4d\xaf\x47\xbc\x6b\xc9\xd3\x23\xde\xb5\x8b\xd2\x23\xde\x1e\xf1\xc2\x97\x86\x78\xf7\xb9\xa5\xab\x8f\x75\x3f\x28\xd6\xbd\xab\xb4\xd8\x49\x46\xec\xc8\x07\x3b\xc7\xb6\xfb\xb8\xf6\xe7\x12\xd7\xde\xfa\xc0\xbf\x72\xf2\xa1\x87\xfe\xdb\x6b\xb5\xea\xe4\xbf\xb8\xd5\x32\x83\xb2\x72\xe1\x3c\x75\x7f\xfa\xff\x43\x9c\xfe\xef\x50\xbe\xbf\x02\x60\xab\x2b\x00\x56\xd1\xac\xbf\x07\xa0\xbf\x07\xe0\x03\x07\xa1\xfb\x7b\x00\xfa\x7b\x00\xfa\x7b\x00\xe2\xd3\x9f\x4e\x82\xfe\x74\xd2\x56\x4f\x7f\x3a\x69\xf5\xd3\x9f\x4e\xfa\x6c\xbd\xaf\xd0\x9f\x4e\xfa\xbc\x3d\xb1\xd0\x9f\x4e\xea\xbd\xb3\x5b\x2e\xd4\x17\x78\x3a\xa9\xbf\x07\xe0\x73\xcd\x51\x80\x1e\x69\xf7\x48\xbb\x47\xda\x3d\xd2\x5e\xff\xf4\x48\x7b\x87\xa7\x47\xda\x3d\xd2\x5e\xd7\x71\x8f\xb4\x7b\xa4\xbd\xb9\xf3\xfe\x1e\x80\x2f\x28\x37\x02\xfa\x7b\x00\xfa\x7c\x89\xfe\x1e\x80\xff\xb9\xf7\x00\x74\x62\xf7\x9f\xee\x32\x80\xdd\x87\xd1\xdf\x08\xd0\xdf\x08\xd0\xdf\x08\xd0\xdf\x08\x10\x9f\xfe\x46\x00\xff\x7c\x4e\xbe\xc6\xfe\x7c\xd4\x4a\xa2\xf4\xe7\xa3\xa0\x3f\x1f\xb5\x69\x7a\x5f\x80\xdf\xb0\x3f\x1f\xf5\x19\xfa\x0a\xfb\xf3\x51\xbd\x5f\x70\x7e\x71\xbe\x90\xf3\x51\xfd\x8d\x00\x9f\x63\xb4\xbd\x47\xbc\x5b\x3e\x3d\xe2\x5d\x49\x94\x1e\xf1\x42\x8f\x78\x37\x4d\xaf\x47\xbc\x6b\xc9\xd3\x23\xde\xb5\x8b\xd2\x23\xde\x1e\xf1\xc2\x97\x86\x78\xfb\x1b\x01\xfa\x1b\x01\xfa\x1b\x01\xbe\xc4\x08\xf7\xc6\x95\xc6\x7b\x67\x44\xea\xce\xb5\x72\xa8\x56\xc6\xb5\x3b\x0b\xfa\xac\x53\x85\x84\xe4\x58\x4e\x2a\x13\x30\xf8\xe4\xf5\xe5\x39\xa4\xc2\x89\x5c\x4f\xe0\x52\xf3\x26\x0d\x9d\xd4\xaf\x0b\x74\x22\x13\x4e\xf8\x90\x24\x2f\xa8\xd1\xb7\x32\xe3\xcd\x9a\xe1\x3d\xc8\x42\x4c\x90\x37\x58\xc5\x87\xd5\xef\x30\xcf\x87\x37\x4a\xdf\x29\xb8\x45\x63\x5b\xdb\xfd\xbd\x2e\x8b\xf7\x60\xd1\xdc\xfa\x53\xf4\x78\x5f\xd2\x62\x49\xe7\x25\x46\xec\xb1\xdd\x6c\x13\x8b\x3b\xf7\x5f\xaf\xfc\x31\x72\x69\x9b\xb9\xf0\xb0\xa9\xef\xaf\x08\x2a\x7c\x45\x4c\x5b\xd9\xc8\x6b\x63\x99\xe3\x70\x24\x2c\x66\xb1\x7d\x4b\x1c\xa7\x4d\xe6\xc7\x50\x39\x99\xcb\xdf\x31\x48\x1d\x14\xae\x32\xb8\x6a\xb9\xb6\xd0\x03\x9b\x8d\x8c\x21\xa4\x22\x9d\xe2\x53\xb9\xda\x3c\x18\xc6\xa1\xae\x2e\xb4\x8d\xbd\x10\xfb\xd9\xfa\xd6\x88\xf3\x50\x21\x5a\x04\x99\x34\xbc\x45\x67\x60\x9d\x36\x91\xa2\xa5\xc1\x61\x2a\xf2\xb4\xca\x79\x43\x9e\x5d\x5e\xf8\x9e\x36\xdf\xfb\xb0\x41\x88\x35\x93\xde\x61\xc4\xb1\xca\xfa\x31\x2f\x72\x01\xe3\x05\x36\xd4\x1f\x32\xec\x02\x0b\x6d\x66\x6f\x84\x99\xe0\x76\xfb\xf1\xe0\x45\xab\xc6\xfc\x76\xfc\xb7\x1f\x5f\xbd\x78\xf6\xe2\xf9\xc5\x8b\x8b\x37\x41\x82\x8d\xb5\x59\xba\x51\x03\x0c\xf6\xf6\xb8\x1e\xbb\x30\x10\xc8\x65\x21\x5d\x5d\xcb\xef\xb4\x41\x90\x64\x9c\x8e\x52\x29\x27\x0b\xf4\xc9\x14\xc2\x39\x52\x96\xb4\x0b\x0a\x44\xc7\x37\x4f\x14\xe2\x06\x49\x74\xc1\xa4\x12\x46\x28\x87\x51\x38\x4a\xe7\x2b\x65\x1a\xac\x0e\x80\x5e\x06\xab\x9f\xc6\x61\x31\x60\xf7\xcb\x98\xab\x31\x15\xb7\xfe\x8a\x83\xb1\x26\x29\x48\x4b\x51\xe8\x4c\x8e\x65\xea\xcd\x2e\x28\x44\x56\xc7\xe1\x03\x7a\x43\x53\x8b\xf4\x66\x02\xa7\x30\x5c\x20\x0f\xaa\x5b\x69\xb4\x62\x4c\x79\x2b\x8c\x14\xa3\x3c\xcc\x6a\xe4\x5d\x74\xdc\x6e\x33\x40\x05\xa3\x99\x43\x1b\x5a\x0a\xd4\x0a\x77\x51\xac\xa9\x77\xad\x3c\xa1\x3d\x1c\x69\x94\x22\x95\x94\x63\x90\xee\x90\xd4\x91\x95\x41\x08\x19\xcc\xaa\x34\x4e\x5a\xbb\xd2\x48\x0f\x79\x45\xbd\x76\x41\xf8\x09\x0b\x45\x45\xda\x85\xb4\xad\xb5\x72\x94\xe3\x80\x74\xaa\x6c\x97\x1d\x21\xd1\x81\x6b\xb0\xde\xbb\x45\x5a\x61\xe2\x1c\x0f\x67\x10\x49\xb1\x6a\xbe\x48\x42\x78\x25\x9a\xe1\x58\x54\xb9\xd7\x3b\x9e\xcc\xbc\x54\x33\x5d\x99\x8e\x58\x9d\x0a\xe2\x1c\xde\x15\x31\x41\x85\xf7\xf0\x00\x32\x24\xe0\x26\x15\x49\xf2\x89\xd6\x19\xe1\x37\xa3\xef\x65\xc1\xad\x05\xd6\xaa\xe9\x33\x9a\x41\xa6\xab\x51\x5e\x2f\x18\x89\xd2\x20\xed\x4b\x91\xde\x50\x5f\xdc\x30\x08\x07\x27\xae\x28\x4f\xf8\x57\xf8\x6f\x28\x61\x93\x5f\xad\x56\x11\x07\xb4\x86\x99\xcc\xd1\x5f\x5a\x18\xa1\x75\x43\x1c\x8f\xb5\x71\x7f\x23\x6a\x55\x8a\x19\x4f\xe9\x7a\xea\x71\x31\x2b\xda\xec\x4c\x27\xcd\x3c\xd9\xd9\x21\xda\x2c\xd9\x6c\x2d\x36\x48\x0e\x56\xc9\x5d\xda\x34\x46\x9d\xc2\xff\x3b\xba\xfe\xd3\x3f\x87\xc7\xdf\x1f\x1d\xbd\x7d\x3c\xfc\xeb\xbb\x3f\x1d\x5d\x27\xfc\xc7\x57\xc7\xdf\x1f\xff\x33\xfe\xf8\xd3\xf1\xf1\xd1\xd1\xdb\x9f\x5e\xfc\xf8\xe6\xf2\xd9\x3b\x79\xfc\xcf\xb7\xaa\x2a\x6e\xfc\xaf\x7f\x1e\xbd\xc5\x67\xef\xb6\x6c\xe4\xf8\xf8\xfb\x7f\x5b\x31\x20\xa1\x66\xaf\xc6\xeb\xb4\xcd\x76\x09\x65\xc3\x6d\x44\xf4\xfd\xf0\xa6\x1a\xa1\x51\xe8\xd0\x0e\xa5\x72\x43\x6d\x86\xbe\xc2\x29\x38\x53\xe1\xd2\x6a\x04\xa7\x36\x79\xe1\x3b\x22\xf2\x65\xab\xc2\x9c\xc7\x31\x5c\xc3\x12\x1c\x02\xd4\x65\x2d\xeb\x4a\x8f\x5e\xc6\xb4\xb8\x11\x0c\x26\x70\xb5\xa4\x26\x63\xbe\x50\xe2\xd0\x7a\x74\x68\xe7\xdb\x99\x4b\x32\xf3\x32\x90\xdb\xdc\x1f\x1b\xec\x66\x11\x6e\x5c\x8f\xd2\x48\x6d\xa4\x9b\x9d\xe7\xc2\xda\x97\xa2\xc0\xad\xa8\x7b\x31\x6e\x90\xf6\x80\x36\x1b\x89\xe3\xa0\x7f\xbc\xf5\x13\xdb\x65\xc9\x41\x20\xb6\x55\x3e\x52\x28\x96\xa9\xf7\x4c\xdc\x7d\xda\xc0\xef\x68\x74\xb8\x45\xc7\xa0\x07\xc2\xf1\xf3\x7a\xe2\xad\x99\xab\xc5\xb4\xe2\xb9\x92\xd2\xbe\x27\x38\x3b\x96\x93\xed\x14\xee\xd5\xb2\xaa\x90\x0a\x45\xc3\xe6\x5b\x94\xc6\xf0\x3e\xc7\x89\x48\x67\xef\x69\xf8\xef\x0d\xd2\x40\x08\xe8\xbf\xf7\xb8\xb4\x83\x3c\x0f\xc3\xb5\x58\x16\x50\xf2\xad\x57\x52\xfd\xea\xad\x82\xda\xe0\x31\x9c\x3c\x5a\xea\x2c\x21\xca\x25\x73\x63\x67\x99\x54\x7f\xac\xf5\xde\xdb\xaf\xde\x2d\x94\x0c\xfe\x0d\xa7\xbd\x1d\xd1\xe6\x4f\x53\xb1\xc0\x24\xc1\x16\x27\x08\x67\x59\x21\xd9\xa5\x02\x47\x97\x57\x67\xc7\x9d\x99\x90\xea\xf5\x2a\x26\xd3\x68\xd5\xa1\xf3\xca\x6e\x8a\xb6\x71\xa3\xb0\xda\xe0\x2c\x26\xbf\x5b\x38\x8d\x29\xf6\x49\x04\x63\xcf\xca\x08\xeb\xce\xaf\xce\xe0\x3d\x81\xaa\x5c\x2a\xf4\xb4\x2b\x8d\xbc\x95\x39\x4e\xa8\xc7\x56\x50\x08\xce\x2b\x63\x50\xb9\x7c\x16\xaf\x57\x5a\xbe\x2a\xd2\x92\x40\xef\xb2\x5b\xe4\xac\xda\xa4\xab\x17\x8b\x4a\x5b\xcc\x12\xb8\xe2\x1a\x33\xef\xff\x0b\xe5\x78\x6d\x58\x2f\xae\x5a\x5c\x30\x68\xa9\x61\xa9\x7c\x2d\x99\x79\x15\x87\xc6\x68\x13\x52\x2e\xbd\x1d\xa1\x73\x32\x16\x6a\xf3\x84\x54\x93\x8d\xa8\x2a\x65\x48\x10\xf2\x52\x03\x61\x96\x10\x7e\xf5\x9c\xbb\xa0\xc2\xe9\x7a\xbc\xac\xfd\x2e\x68\x70\xe3\x8a\xac\x92\xda\x9a\xe2\x3d\xd7\x26\xcd\x1c\x7e\x69\x77\x3f\x68\xec\x38\x21\x03\xab\xd9\xd8\xa7\xc1\x51\x25\x73\x76\xb1\x48\xd3\x98\x47\xcc\xc8\xa2\x6d\xbc\xe9\xb2\x08\x77\x9b\x55\x65\xa9\x8d\x6b\x0c\xef\xb4\x63\x95\x79\xc3\x78\x09\x01\x68\x58\xa5\xc1\x52\x98\x5a\x62\x5b\x84\x74\x2a\x14\xa9\x7f\x9a\xe8\x0b\xcd\x79\xa8\x3e\x99\x99\xba\x15\x23\x5d\x39\xe6\xb1\xb0\x57\xc7\xba\x52\x19\x90\x50\x39\x85\xa9\x73\xa5\x3d\x3d\x39\x69\xf4\x51\x22\xf5\x49\xa6\x53\x7b\x92\x6a\x95\x62\xe9\xec\x49\xdc\x4d\x27\xa5\xce\x86\xf1\xc7\x50\xc4\x4d\x72\x72\xb8\x4a\xc7\x6f\xa1\x09\x03\xe5\x4f\xc1\xaf\xd5\x8a\x52\xa8\xaa\x35\x37\x39\x0d\xd7\x57\xa6\x02\x0d\x19\x97\x16\x72\x3a\xe7\x7b\xcf\xd6\x84\x37\xbb\xde\x9d\xa6\x7c\x7d\xff\x58\x0d\x4c\x5b\xd2\xed\xd0\xb6\x9b\x5e\x2f\xb4\xd7\x79\xbd\x36\xf8\xb9\x16\xee\x1e\x63\xd9\x46\x70\xaf\x19\x28\x03\x00\xe7\x04\xdf\x3e\x46\xd8\xdc\x7f\x21\x71\xa5\x66\x40\xfc\xec\xc2\x55\x74\xad\xbb\xd9\x9c\xe1\xe4\xe8\x6f\x6a\x57\xf5\x00\xc7\x63\x4c\xdd\x77\x2d\xbf\x40\xed\x90\xaa\xdd\xcb\xdf\xc4\xbf\xbe\x5b\x6d\x12\x6e\xe5\x09\xde\x2e\x96\xe7\x87\xb4\xde\x47\xd7\x75\xe5\x70\x85\x39\x95\xed\x29\xe0\xdb\x62\x43\x8e\xa3\x1d\xc1\x21\xe5\x3d\x9b\x01\xef\x90\xcc\x68\x15\xb6\x41\xc2\xb5\xa4\x6d\x70\x56\x35\x6e\x75\x84\x97\x3a\x9c\x12\xc0\x01\x5c\xf2\xc5\x6d\xcd\x1b\x56\x64\x2f\xb5\x3f\x2f\xb0\xd6\xfa\xdf\xda\x89\xb9\x31\x9a\xd9\x21\xc8\x4f\x4d\xec\xd2\xcf\xac\x13\xbb\x6c\x38\xb8\xe3\x9a\x5e\x47\x99\x1b\x9c\x35\xf1\xae\x10\x19\x65\x77\xf2\xa0\xe1\x92\x08\x3e\x7d\xf8\xea\x6f\x21\xe1\x57\x17\x23\xa9\x7c\x67\xbe\xe9\xb8\x14\xdc\x7a\x24\xa8\xca\xf8\x27\x77\xf3\x21\xc8\xb5\x5d\x88\xb4\x43\xb3\x57\x3b\x04\x44\xeb\x10\xcb\xf2\x50\x68\x2b\xfe\xf9\xec\xb7\x4a\xe4\x09\x3c\xf5\x52\x91\x67\x1f\x5e\x85\x42\x0b\x21\xa1\x3b\x99\x67\xa9\x30\x19\x6b\x03\xbf\x47\xc1\x6a\xbf\x7a\xa2\x06\x1c\x71\xb7\x37\x6b\xe4\x2f\x26\x84\x52\x18\x27\xd3\x2a\x17\xac\xb6\x70\xa2\xcd\xec\x83\x50\xb4\x61\x9a\x2b\x4c\xb5\xca\x36\x78\xe9\x57\x48\xd7\x50\xb7\x4d\x63\x86\x51\x68\x64\xc8\xbf\x97\x05\xce\x33\xe9\x51\xd7\xb8\xd1\xe3\xb8\xab\xeb\x2d\x36\xf0\xa8\xe6\x4e\x5a\x6c\x07\x49\xa4\x05\xe9\x0f\xf0\x1c\xb7\xc4\x63\xbd\x2b\x12\xf8\xfb\x2c\xea\xab\x01\x48\x17\x5d\xd3\x6c\x37\x87\x3e\x03\xcb\x06\x62\x37\x1b\x6a\xac\x0d\xde\xa2\x81\xa3\x4c\x73\x1d\x3e\xa3\x72\x9c\xc0\x7f\x11\xc4\xf7\x3e\x88\x89\x3f\x4e\x11\x58\x3c\x22\x11\xc7\x37\x89\xb2\x8b\xfe\x31\x1c\xf9\xa3\x2d\xb2\x28\x30\x93\xc2\x61\x3e\x3b\xf6\xd9\x4d\xf1\x70\xcc\x36\x4b\xb7\xcd\x89\xa8\xd6\x49\xa8\xbf\xfc\xfb\x9a\x92\x3c\xd8\x1d\x56\xf6\x97\xe8\xe4\x6a\x28\xe3\x51\xe6\xdc\x12\xd6\x3a\x48\xaf\x89\x78\xb7\x22\xdc\x2d\xec\x17\xc5\x4c\xbd\xc0\xbf\x12\x1f\x08\x30\x38\x61\x2e\xf7\x9c\xfb\x00\x1e\x97\xe9\xf2\x13\x5d\x1b\x34\xda\x7a\x7f\xf6\x10\x08\xfe\xff\xe5\xdf\x33\xe1\xc4\x8a\x02\x7e\xcd\x67\xe5\x32\xe7\xc0\x26\x45\xd9\x34\xbe\x6a\xb1\xb6\x70\xd0\x86\xee\xf7\x6a\x81\xa1\xfe\xb2\x9a\x5d\x93\x9a\x5d\x6a\x3e\x89\x22\xae\xf7\xd0\xe0\x44\x5a\x67\x66\x2d\xcf\x66\x88\x68\x68\x90\xca\x3a\xa1\x9c\x64\xc9\x06\xb1\xe4\x30\xf8\x06\x09\x7e\x27\xf0\x8a\x6c\x2d\xf6\x61\xdd\x91\x9a\xf6\x00\xfb\xcd\xac\x44\xf8\xb6\xf5\xe3\x47\x53\xa6\xcc\x6b\x41\xd0\x78\xe6\x12\x59\x66\xd0\x2e\xca\x87\x65\xec\xb3\x76\xfe\xd1\xcc\xdf\x48\x82\xc3\xcb\xe8\x10\x08\x81\x5b\x6b\xe5\x84\x50\x66\x3c\x4a\x19\xdd\xbc\x1d\xb4\xe9\xad\x02\xae\xe8\x43\x30\x58\xd4\x4a\x40\xba\x88\xfb\x53\xad\x6c\x55\xc4\x8c\x48\xb2\x7a\x4a\x54\x19\xaa\x74\xc6\x67\x6f\xf2\x5b\x34\x09\xfc\x6c\x69\xa5\xe0\xff\xc8\x09\xd9\x7d\xa1\xd3\x36\x54\x8a\x61\xa4\xb9\x11\x48\xdb\xba\x90\x96\x73\x3c\x09\x03\xc5\x16\x5a\xe1\x82\x70\xc8\x27\xe6\x99\xcc\x0f\xa2\xf2\xbe\xd6\x37\xf5\x91\xcf\xe8\x04\x8d\x74\xf1\x1b\x9e\xa6\x34\xd1\x3e\x94\x56\x6a\x2b\xe3\x51\xb4\x5a\x8e\x76\x8e\x8d\xea\xb1\x3f\xd4\xe9\xdb\xed\x1a\xc2\x9c\xb0\x34\x37\x19\x36\xdc\x2a\xe5\x89\x8f\x6d\x2f\x4d\x14\x33\x8f\xbb\x91\xb6\x76\x3d\x17\x6f\xf9\xee\x0e\xb9\x91\xe9\x46\xa8\x1b\xcc\x20\xc7\x7b\x99\xea\x89\x11\xe5\x54\xa6\x7c\x72\xd1\xc7\x55\x08\xab\x3b\x1f\x3b\x4f\x0e\x57\x32\xda\x2a\x31\x5e\x56\xa3\x5c\xda\x29\x2e\xc5\x32\x6b\x79\xd4\x62\x6a\xd0\x2d\x95\x20\x1d\x16\xbd\xf2\xe5\x1a\xa5\x1c\xd3\xbd\x42\x03\x21\x9d\xd1\xf3\x1c\x6f\x3c\x22\x71\x9a\xd2\x46\x8a\x11\x8a\xe6\x36\xe9\x9a\x86\x09\x5c\xb8\xe8\x98\xa6\x1a\x37\x88\xa5\xe7\x34\xce\x3b\xb0\x05\xfb\x54\xac\x54\x29\xfa\xf3\x97\xfe\x1c\x2b\x62\x74\x33\x3a\x23\xd1\xc3\x20\x64\x07\x7f\x5c\x1b\x54\x6e\x39\xa8\x59\x6f\x77\xad\xb1\xb9\xd6\x93\xb1\x96\x29\x9b\x29\xd9\xc8\xa2\xa8\x13\xe9\x6f\x22\x25\x7f\xd9\x75\x05\xfd\x71\xd9\x2b\x9f\xb7\xb5\x59\xd6\xfc\xdc\x29\x1e\xb2\x01\x2c\x4c\xf5\x5d\x68\x69\x7e\xd3\x06\x8f\x4d\x5c\xdb\x4c\xda\x94\x76\x3a\x66\x70\xae\x95\x8d\x67\x66\x85\xf2\xc7\x60\x6f\x45\xee\x59\x21\x36\x5c\xea\x9c\xe3\x1b\x59\x15\xcd\x09\x9f\xda\x8a\xc5\x08\xf9\xae\x6b\x1b\x87\xb2\x42\xcd\x6d\x50\xb1\x9b\xb4\x60\xd4\x0f\x97\x3a\xcf\xd7\x6b\xb1\xb5\x76\xe9\x36\x56\x69\x24\xc0\xd6\xf1\xd7\x8b\x48\xb1\xe0\x8b\x23\x9e\x6e\x22\x48\xcc\x1a\x04\x75\x6b\xc2\x8e\xd0\xdd\x21\x2a\x48\xa7\x98\xde\xd8\x26\x41\x83\x6f\x9d\x9f\x5b\xb5\xe0\x7f\xea\x4a\xac\x1a\x4f\xd1\xaa\xb0\xa1\x61\x11\x7d\xd8\x4c\xe1\xdd\x7c\xc2\xc1\xa2\xb0\x17\xb7\x42\xe6\x62\x94\xfb\xb3\xe2\xf5\xaf\x41\x7b\x1c\x32\xea\xf3\xb2\xca\xf3\x10\x44\xe2\x00\xac\x33\x62\x3c\x96\x29\xe7\xa0\x70\x98\xb9\x49\x6b\x5a\x3a\x85\xbd\x42\xcb\xd6\x09\x57\x2d\xac\xd1\x9a\x05\x5e\xb7\xb0\x64\x87\xc8\x95\x0e\xa2\xb9\xfb\xc3\x3b\xc6\x0a\x0d\x03\xbd\xb1\xd5\xf1\x7f\x27\xf0\x52\xbb\x90\x97\xf1\x02\xad\x8d\xb9\x1f\xaf\x51\x58\xad\x5a\xd2\x95\xd1\xaf\x91\x13\xa9\x44\x1e\x26\xd5\xf6\xef\xd5\xb6\x87\x60\x97\x72\x21\x27\x46\xb8\x5a\x28\x36\xe3\x0e\xda\x25\xe8\x45\xef\x09\x4d\xe0\x4c\xcd\x78\xbd\x43\xc2\x06\xb5\xec\x8c\xce\xaa\x14\x43\xf0\xb9\xb2\xed\x46\x3e\xa8\x18\xed\x86\x17\xce\x63\x27\x4d\x02\x62\x86\x4e\xc8\x10\x52\xd2\x0a\x41\xd8\x92\xec\xb8\xc8\x93\xde\x15\xde\x10\x98\x95\xc5\xd9\xe5\x05\xbc\x0e\x27\x89\x13\x18\x0e\x87\x3e\xee\x69\x9d\xa9\x52\xd6\x2f\xb4\x85\x54\x16\x34\x85\xe7\x3e\x9f\x6f\xd3\xca\xdd\x0d\x9e\x0f\x0f\xc1\x4a\xe1\xa6\x90\x78\xc2\x27\x2d\x52\x00\xfc\x40\xba\xe6\x5e\x14\x25\xf1\xfd\xb5\xf2\xd2\xfb\x07\xad\xaf\xfc\x22\xf9\x3e\xff\x01\x27\x27\xf3\x3c\xa1\x47\x04\x51\x83\x03\x91\x59\x63\xac\xf5\xa1\xed\x4e\x29\xa1\x8a\x3f\x71\xfa\xcf\x92\xde\xb9\x2f\x61\xf0\x14\xae\x0f\xce\xe2\xee\xbb\x3e\x18\xc0\xf5\xc1\xa5\xd1\x13\xce\x09\x55\x93\xeb\x90\xe4\x79\x7d\xf0\x14\x27\x46\x64\x98\x5d\x1f\x50\xb3\x7f\xe2\x64\xde\x17\x68\x26\xf8\x13\xce\xbe\xe5\xc6\xea\xd7\x51\x23\x7c\xeb\xf3\x7e\xe9\x3d\xa9\x60\xd2\x53\xdf\x16\xa2\xac\x5f\xbc\x10\x65\x5d\xf9\xbc\xe1\xb3\xb7\xef\x0a\x74\xe2\xf6\x49\xd2\xac\xe8\xfb\x5f\xad\x56\xa7\xd7\x07\xcd\xf8\x07\xba\x90\x9c\x34\x31\xbb\x3e\x80\x4e\xaf\xa7\xd7\x07\xdc\x6f\x7c\x1f\x07\x79\x7a\x7d\x40\x3d\xd1\x6b\xa3\x9d\x1e\x55\xe3\xd3\xeb\x03\xce\x45\x18\x3c\x19\x18\x2c\x07\x04\x98\xbe\x6d\x7a\xb8\x3e\x78\x4f\x6b\x72\x72\x12\x42\x18\xe1\x5f\x56\xf8\xd7\x72\x67\xf5\x46\xb9\xbf\x29\x1f\x69\x08\xb9\xb0\xee\x8d\x11\xca\x72\xff\x6f\x64\xb1\x3c\x8c\xeb\x6d\x39\xde\xef\x2b\xbf\x1b\x96\x01\x2b\x3f\x7b\x6e\x58\xf9\x79\x85\xf6\xdc\x46\x73\x2d\xce\x61\x4b\xaf\xf3\x62\xc5\xe6\x34\x04\xe1\xb9\xe8\xa7\xa9\xd7\x87\x74\x40\x28\x8d\xe1\x96\x0e\xda\xe2\x41\xbe\x71\xae\x33\xaf\x5b\x48\xd0\x69\x0c\xfc\xbb\x70\x83\x07\x54\x2a\x43\x93\x73\xb0\xaa\x69\xd5\x47\x42\xb2\x04\xbc\xdf\x40\xd4\x5e\x1a\xce\xa3\x63\xed\xa4\x5a\xce\x6b\x9f\xc3\x13\x5b\x24\xd9\x11\x2e\x31\xf1\xcd\xb0\xa2\x4b\x53\x2c\x1d\x6b\xba\xfd\x43\xcc\xd0\x72\xaa\x10\xb2\x1a\xba\xd5\xec\x11\x98\x63\x4b\xc2\x87\xd2\x3e\xbe\x3f\xad\x0a\x41\xaa\x43\x64\x9c\xc6\x53\x7f\xf3\xe6\x9b\x37\xb7\xbc\x48\xf5\x41\x21\xef\xe3\x8f\xeb\x10\x48\x1d\x14\x89\xa8\x4f\xab\x6d\xf0\x98\x6c\x35\xf9\x42\xdc\x3f\x47\x35\x71\xd3\x53\xf8\xf3\xd7\xff\xfb\x2f\xff\xb1\xa2\xa0\x17\x8c\x98\xfd\x88\x2a\xf8\x82\xb6\x24\xc3\x62\xc5\x79\xa7\x61\x12\xf3\x2f\x93\x49\x53\xa6\x76\x72\x37\x1c\x74\x27\x38\x07\x2b\xa8\xcb\xaa\x24\xba\xfc\xc0\xd9\xb5\xd6\x09\x95\xe2\x80\x40\xd2\xd2\xc6\x64\x2d\xc0\xf3\x19\x3c\xf9\xda\xff\x0b\x44\xdc\xf5\x82\xf8\x7e\x7b\xff\x2e\x59\x32\x64\x69\xe1\xaf\x83\xb9\xf1\x48\x0b\xb4\x54\x7a\xcc\x8c\xe3\x4d\x4c\x83\x5e\x13\x46\x67\xc0\xa2\x26\xc4\x7a\xbc\x9b\x16\x6e\x93\x3f\x70\x3b\x5f\x60\x21\x95\x2c\xaa\xe2\x14\x1e\xaf\xcc\xe7\x24\x91\xb6\xe5\x6a\xfa\xc2\x0d\x10\x10\x24\xba\x26\x46\x14\x05\xe7\xd1\xcb\x0c\x95\x93\x63\xc9\x49\x03\x35\x6b\xb3\xb9\xef\x2b\xc6\x1c\x94\x9a\x8a\x9c\x9e\x42\x72\xa8\xc5\xec\x97\x1e\xe7\x18\xd6\xc0\x21\x7a\x93\xb6\x05\xd4\xac\x44\xbf\x1b\xbc\x01\x03\x78\x5f\x7a\xa8\xda\x0a\x43\x14\x28\x94\x54\x13\xdb\xe4\x73\x85\x7f\x7d\x8a\x3e\xde\x4d\x31\x44\xcf\xb1\x1d\x0b\x4a\xc9\x58\xca\xd8\x6e\x12\x4d\x7a\x20\x27\x80\x7a\x8c\x3e\xef\xd3\x24\xe4\x58\x60\x7e\x2e\x2c\xc6\xdd\xd8\xce\xe6\x8a\x57\x21\xd5\x47\x7b\x3e\xd8\x56\x7d\xf2\xf8\xeb\xb5\x4b\x5e\x97\x5b\x1d\xc2\xab\xd3\xbc\xde\x9e\x0d\xff\x4b\x0c\x7f\x7f\x77\x14\xfe\x78\x3c\xfc\xeb\xff\x1f\x9c\xbe\xfb\xaa\xf5\xf3\xdd\xea\xec\xac\xe5\x60\x7e\x05\xfb\x04\x25\x12\x71\x62\x5c\xd1\x41\xcc\x52\x79\x63\x2a\x1c\xc0\x0f\x22\xb7\x38\x80\x9f\x15\xab\x86\x07\x12\x6d\x7d\x84\x9a\xb4\xf2\x01\xf5\xba\x2a\x52\x1e\x8a\xf0\x90\xd6\x97\x09\xc3\x5d\x67\xbe\x6e\x47\xa4\xe8\x6a\x68\x49\x1a\xd5\xe2\x33\x7f\x9e\x60\xac\x75\x12\x10\x6e\x92\xea\xe2\xa4\xfe\xee\xa1\xf5\x0b\xa1\x66\xd0\x88\x35\x0f\x4a\xe7\x39\xdd\x72\xc2\xbc\x48\x8d\xb6\xb6\xb9\xe4\x07\x72\x79\x83\x70\xd6\xd8\x8d\x24\x2c\x47\x98\x0a\xc6\xe2\x66\x24\x9d\x11\xde\xe9\x1b\x71\x65\xe3\x51\x1a\x57\x39\x1c\x91\xb9\x9a\x70\x22\xd9\x82\x74\x0d\x17\x86\x89\x91\xcc\xf9\xdf\x6d\x22\x53\x3a\xd5\x6a\x9c\xcb\x60\x02\x14\xa5\x36\x4e\x28\x17\x4f\x35\x4d\xf0\xde\xff\x53\x71\x3e\xec\x20\x2d\x1c\x65\xca\x3e\x79\xf2\xf5\x9f\xaf\xaa\x51\xa6\x0b\x21\xd5\x0f\x85\x3b\x39\xfe\xfe\xe8\xb7\x4a\xe4\x1c\xe5\x7d\x29\x0a\xfc\xa1\x70\xab\xff\xd1\xad\x9d\xd5\xe2\x93\xbf\x6c\xb1\x8b\x8e\xde\xfa\xbd\xf2\xee\xe8\xed\x30\xfc\xf5\x55\x7c\x75\xfc\xfd\xd1\x75\xb2\xf6\xfb\xf1\x57\x27\x9c\x23\x59\x6f\xb9\x77\x6f\x87\xcd\xf6\x4b\xde\x7d\x75\xfc\x7d\xeb\xdb\xf1\xb2\xcd\xd8\x49\x5d\x24\x2b\x60\x58\x88\x72\x78\x83\xb3\x15\x9b\x73\x25\x1c\x5d\x6c\xc8\x53\xac\x10\xe5\x32\xeb\x7b\x2c\x27\x2f\x44\xf9\x1a\xc7\x68\x50\xa5\x4b\x99\xfc\x81\x11\x18\xb2\x1f\xd6\x7c\xe2\x0c\xac\x3d\xbc\x4e\xa4\x77\xbc\xa7\x6d\x1d\x9c\xde\x82\x5b\xb6\xc3\x8f\x6a\x4d\xfe\xe2\xc6\x4e\xea\x79\xee\xdd\x42\xdc\xdf\xbf\x78\xff\xd1\xde\xed\x54\x72\xa5\xa5\xd5\xf5\x61\x5e\x3c\xf5\xd0\x97\x45\x0f\xc3\xb9\xa9\x26\x3b\xaf\x52\xf2\xb7\x0a\xe1\xe2\x69\x7d\x9e\x5e\xaa\x34\xaf\xf8\x06\xbf\x9f\x7f\xbe\x78\x4a\xf6\xfb\xdf\x83\xb8\xb9\x43\xc8\xb4\x3a\x74\xf0\xea\xe5\xf3\xff\xcb\xce\x00\x2e\x31\xf0\x0a\x3d\x1c\xea\xcd\xa5\xf0\x6e\xb2\xa0\x80\xe1\xef\xe8\xf3\xe4\xb8\xe7\x54\x94\xb5\xff\x84\xc5\x1d\x67\x58\xe5\xa5\xe5\x83\x00\x60\x2b\x13\x46\x47\x0d\xfb\x88\x2f\x1f\xfd\x0b\xf1\xe0\x78\x86\x81\x4f\x82\xec\x95\xdc\x99\x6a\xa5\x30\xe5\xa0\x39\xa1\xc0\x8f\xb0\x3f\x88\x91\x5f\x05\xcc\xca\x7d\xec\xb1\x19\x42\x40\x6d\x6f\xb6\xa0\x31\x9c\xfb\x99\x7e\xf4\x9d\xb4\x30\xdf\xbd\x7a\xf4\xfe\x4c\x8e\x6c\xbe\xde\xe0\x7f\x5e\x48\xe3\xea\x9a\xce\x73\xe7\xb6\xd8\xb7\x5a\x07\x47\xa7\xc2\xc2\x08\x51\xb1\x3b\xd7\x7b\xff\x50\x05\xae\xc3\xc6\x11\x5b\x95\x43\xa7\x87\xd9\xf2\xc5\xdb\x40\xb9\xcd\x54\x5b\x63\xb9\xce\x5d\x8d\xb1\xab\xa1\x7a\x37\x9d\x2d\xa3\x81\x6d\x6e\x0a\xac\x31\xc8\xae\x13\x5b\x6d\x98\xcc\x79\x75\xd9\xb2\x08\x4e\x8d\x60\x67\x2c\x0e\x89\xac\xc7\x8e\x67\xc3\x69\x8e\xe6\x75\x3d\x7b\xbb\x8f\xd1\x2f\xf3\x15\x9a\x5b\xb9\x97\xf2\xdb\xb4\x31\x53\x9f\x67\x72\xf6\xf1\xb7\x15\x41\xaf\xbd\x3b\x61\xd7\x5f\xaa\x37\x84\x6f\xd6\xe6\xbf\x33\x05\xd7\x65\xf9\xef\xd2\xc6\xae\xca\xd2\x4b\x93\xce\x21\x0f\xeb\xb4\xe1\x90\x7b\xfb\x5d\x35\xaa\x81\x72\xd3\x7a\xb0\x81\xe0\x1f\xff\x7a\xf4\xdf\x01\x00\x00\xff\xff\xf5\x4e\x26\xd1\x9c\xf0\x00\x00") func operatorsCoreosCom_catalogsourcesYamlBytes() ([]byte, error) { return bindataRead( diff --git a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/catalogsource_types.go b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/catalogsource_types.go index 53bd40ca40..b94f045d88 100644 --- a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/catalogsource_types.go +++ b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/catalogsource_types.go @@ -152,7 +152,6 @@ type GrpcPodConfig struct { // will have the following modifications made to the container running the server: // - the $GOMEMLIMIT environment variable will be set to this value in bytes // - the memory request will be set to this value - // - the memory limit will be set to 200% of this value // // This field should be set if it's desired to reduce the footprint of a catalog server as much as possible, or if // a catalog being served is very large and needs more than the default allocation. If your index image has a file- @@ -160,7 +159,22 @@ type GrpcPodConfig struct { // /tmp/cache/cache/packages.json in the index image. // // This field is best-effort; if unset, no default will be used and no Pod memory limit or $GOMEMLIMIT value will be set. + // +optional MemoryTarget *resource.Quantity `json:"memoryTarget,omitempty"` + + // ExtractContent configures the gRPC catalog Pod to extract catalog metadata from the provided index image and + // use a well-known version of the `opm` server to expose it. The catalog index image that this CatalogSource is + // configured to use *must* be using the file-based catalogs in order to utilize this feature. + // +optional + ExtractContent *ExtractContentConfig `json:"extractContent,omitempty"` +} + +// ExtractContentConfig configures context extraction from a file-based catalog index image. +type ExtractContentConfig struct { + // CacheDir is the directory storing the pre-calculated API cache. + CacheDir string `json:"cacheDir"` + // CatalogDir is the directory storing the file-based catalog contents. + CatalogDir string `json:"catalogDir"` } // UpdateStrategy holds all the different types of catalog source update strategies diff --git a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/zz_generated.deepcopy.go index b4459a00a4..de6ec2b826 100644 --- a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/zz_generated.deepcopy.go +++ b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/zz_generated.deepcopy.go @@ -690,6 +690,21 @@ func (in *DependentStatus) DeepCopy() *DependentStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtractContentConfig) DeepCopyInto(out *ExtractContentConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtractContentConfig. +func (in *ExtractContentConfig) DeepCopy() *ExtractContentConfig { + if in == nil { + return nil + } + out := new(ExtractContentConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GRPCConnectionState) DeepCopyInto(out *GRPCConnectionState) { *out = *in @@ -738,6 +753,11 @@ func (in *GrpcPodConfig) DeepCopyInto(out *GrpcPodConfig) { x := (*in).DeepCopy() *out = &x } + if in.ExtractContent != nil { + in, out := &in.ExtractContent, &out.ExtractContent + *out = new(ExtractContentConfig) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GrpcPodConfig. diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/copy-content/main.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/copy-content/main.go new file mode 100644 index 0000000000..94c4046ef0 --- /dev/null +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/copy-content/main.go @@ -0,0 +1,39 @@ +package main + +import ( + "flag" + "fmt" + "os" + + "github.com/otiai10/copy" +) + +func main() { + catalogSource := flag.String("catalog.from", "", "Path to catalog contents to copy.") + catalogDestination := flag.String("catalog.to", "", "Path to where catalog contents should be copied.") + cacheSource := flag.String("cache.from", "", "Path to cache contents to copy.") + cacheDestination := flag.String("cache.to", "", "Path to where cache contents should be copied.") + flag.Parse() + + for flagName, value := range map[string]*string{ + "catalog.from": catalogSource, + "catalog.to": catalogDestination, + "cache.from": cacheSource, + "cache.to": cacheDestination, + } { + if value == nil || *value == "" { + fmt.Printf("--%s is required", flagName) + os.Exit(1) + } + } + + for from, to := range map[string]string{ + *catalogSource: *catalogDestination, + *cacheSource: *cacheDestination, + } { + if err := copy.Copy(from, to); err != nil { + fmt.Printf("failed to copy %s to %s: %s\n", from, to, err) + os.Exit(1) + } + } +} diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/olm/main.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/olm/main.go index c0b6868f2b..4473496787 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/olm/main.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/olm/main.go @@ -11,6 +11,7 @@ import ( configclientset "github.com/openshift/client-go/config/clientset/versioned" configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/validatingroundtripper" "github.com/sirupsen/logrus" "github.com/spf13/pflag" corev1 "k8s.io/api/core/v1" @@ -139,6 +140,9 @@ func main() { } config := mgr.GetConfig() + // create a config that validates we're creating objects with labels + validatingConfig := validatingroundtripper.Wrap(config) + versionedConfigClient, err := configclientset.NewForConfig(config) if err != nil { logger.WithError(err).Fatal("error configuring openshift proxy client") @@ -147,7 +151,7 @@ func main() { if err != nil { logger.WithError(err).Fatal("error configuring config client") } - opClient, err := operatorclient.NewClientFromRestConfig(config) + opClient, err := operatorclient.NewClientFromRestConfig(validatingConfig) if err != nil { logger.WithError(err).Fatal("error configuring operator client") } diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go index 37686e8627..79f67ab177 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go @@ -86,11 +86,19 @@ func newBundleUnpackResult(lookup *operatorsv1alpha1.BundleLookup) *BundleUnpack func (c *ConfigMapUnpacker) job(cmRef *corev1.ObjectReference, bundlePath string, secrets []corev1.LocalObjectReference, annotationUnpackTimeout time.Duration) *batchv1.Job { job := &batchv1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + }, + }, Spec: batchv1.JobSpec{ //ttlSecondsAfterFinished: 0 // can use in the future to not have to clean up job Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Name: cmRef.Name, + Labels: map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + }, }, Spec: corev1.PodSpec{ // With restartPolicy = "OnFailure" when the spec.backoffLimit is reached, the job controller will delete all @@ -687,6 +695,7 @@ func (c *ConfigMapUnpacker) ensureRole(cmRef *corev1.ObjectReference) (role *rba fresh.SetNamespace(cmRef.Namespace) fresh.SetName(cmRef.Name) fresh.SetOwnerReferences([]metav1.OwnerReference{ownerRef(cmRef)}) + fresh.SetLabels(map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}) role, err = c.roleLister.Roles(fresh.GetNamespace()).Get(fresh.GetName()) if err != nil { @@ -730,6 +739,7 @@ func (c *ConfigMapUnpacker) ensureRoleBinding(cmRef *corev1.ObjectReference) (ro fresh.SetNamespace(cmRef.Namespace) fresh.SetName(cmRef.Name) fresh.SetOwnerReferences([]metav1.OwnerReference{ownerRef(cmRef)}) + fresh.SetLabels(map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}) roleBinding, err = c.rbLister.RoleBindings(fresh.GetNamespace()).Get(fresh.GetName()) if err != nil { diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/certresources.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/certresources.go index f48e62b771..1a2dcbca7d 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/certresources.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/certresources.go @@ -251,6 +251,7 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo service.SetName(ServiceName(deploymentName)) service.SetNamespace(i.owner.GetNamespace()) ownerutil.AddNonBlockingOwner(service, i.owner) + service.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}) existingService, err := i.strategyClient.GetOpLister().CoreV1().ServiceLister().Services(i.owner.GetNamespace()).Get(service.GetName()) if err == nil { @@ -366,6 +367,7 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo } secretRole.SetName(secret.GetName()) secretRole.SetNamespace(i.owner.GetNamespace()) + secretRole.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}) existingSecretRole, err := i.strategyClient.GetOpLister().RbacV1().RoleLister().Roles(i.owner.GetNamespace()).Get(secretRole.GetName()) if err == nil { @@ -412,6 +414,7 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo } secretRoleBinding.SetName(secret.GetName()) secretRoleBinding.SetNamespace(i.owner.GetNamespace()) + secretRoleBinding.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}) existingSecretRoleBinding, err := i.strategyClient.GetOpLister().RbacV1().RoleBindingLister().RoleBindings(i.owner.GetNamespace()).Get(secretRoleBinding.GetName()) if err == nil { @@ -454,6 +457,7 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo }, } authDelegatorClusterRoleBinding.SetName(service.GetName() + "-system:auth-delegator") + authDelegatorClusterRoleBinding.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}) existingAuthDelegatorClusterRoleBinding, err := i.strategyClient.GetOpLister().RbacV1().ClusterRoleBindingLister().Get(authDelegatorClusterRoleBinding.GetName()) if err == nil { @@ -502,6 +506,7 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo } authReaderRoleBinding.SetName(service.GetName() + "-auth-reader") authReaderRoleBinding.SetNamespace(KubeSystem) + authReaderRoleBinding.SetLabels(map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}) existingAuthReaderRoleBinding, err := i.strategyClient.GetOpLister().RbacV1().RoleBindingLister().RoleBindings(KubeSystem).Get(authReaderRoleBinding.GetName()) if err == nil { diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/deployment.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/deployment.go index 43aab8e1ce..12e8044b25 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/deployment.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/deployment.go @@ -152,6 +152,10 @@ func (i *StrategyDeploymentInstaller) deploymentForSpec(name string, spec appsv1 dep.Spec.Template.SetAnnotations(annotations) // Set custom labels before CSV owner labels + if dep.Labels == nil { + dep.Labels = map[string]string{} + } + dep.Labels[OLMManagedLabelKey] = OLMManagedLabelValue dep.SetLabels(specLabels) ownerutil.AddNonBlockingOwner(dep, i.owner) diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/webhook.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/webhook.go index 74c1987516..a152434ced 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/webhook.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/webhook.go @@ -67,11 +67,11 @@ func (i *StrategyDeploymentInstaller) createOrUpdateWebhook(caPEM []byte, desc v switch desc.Type { case v1alpha1.ValidatingAdmissionWebhook: - i.createOrUpdateValidatingWebhook(ogNamespacelabelSelector, caPEM, desc) + return i.createOrUpdateValidatingWebhook(ogNamespacelabelSelector, caPEM, desc) case v1alpha1.MutatingAdmissionWebhook: - i.createOrUpdateMutatingWebhook(ogNamespacelabelSelector, caPEM, desc) + return i.createOrUpdateMutatingWebhook(ogNamespacelabelSelector, caPEM, desc) case v1alpha1.ConversionWebhook: - i.createOrUpdateConversionWebhook(caPEM, desc) + return i.createOrUpdateConversionWebhook(caPEM, desc) } return nil } @@ -287,6 +287,7 @@ func addWebhookLabels(object metav1.Object, webhookDesc v1alpha1.WebhookDescript } labels[WebhookDescKey] = webhookDesc.GenerateName labels[WebhookHashKey] = HashWebhookDesc(webhookDesc) + labels[OLMManagedLabelKey] = OLMManagedLabelValue object.SetLabels(labels) return nil diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go index aa7eb9668b..615f2267e3 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go @@ -11,16 +11,18 @@ import ( "sync" "time" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/labeller" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/validatingroundtripper" errorwrap "github.com/pkg/errors" "github.com/sirupsen/logrus" "google.golang.org/grpc/connectivity" + batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" "k8s.io/apiextensions-apiserver/pkg/apiserver/validation" - extinf "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -32,8 +34,14 @@ import ( utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apimachinery/pkg/util/yaml" + batchv1applyconfigurations "k8s.io/client-go/applyconfigurations/batch/v1" + corev1applyconfigurations "k8s.io/client-go/applyconfigurations/core/v1" + rbacv1applyconfigurations "k8s.io/client-go/applyconfigurations/rbac/v1" "k8s.io/client-go/dynamic" "k8s.io/client-go/informers" + "k8s.io/client-go/metadata" + "k8s.io/client-go/metadata/metadatainformer" + "k8s.io/client-go/metadata/metadatalister" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/record" @@ -138,14 +146,22 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo return nil, err } + // create a config that validates we're creating objects with labels + validatingConfig := validatingroundtripper.Wrap(config) + // Create a new client for dynamic types (CRs) - dynamicClient, err := dynamic.NewForConfig(config) + dynamicClient, err := dynamic.NewForConfig(validatingConfig) + if err != nil { + return nil, err + } + + metadataClient, err := metadata.NewForConfig(config) if err != nil { return nil, err } // Create a new queueinformer-based operator. - opClient, err := operatorclient.NewClientFromRestConfig(config) + opClient, err := operatorclient.NewClientFromRestConfig(validatingConfig) if err != nil { return nil, err } @@ -169,6 +185,11 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo return nil, err } + canFilter, err := labeller.Validate(ctx, logger, metadataClient) + if err != nil { + return nil, err + } + // Allocate the new instance of an Operator. op := &Operator{ Operator: queueOperator, @@ -194,7 +215,7 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo op.sources = grpc.NewSourceStore(logger, 10*time.Second, 10*time.Minute, op.syncSourceState) op.sourceInvalidator = resolver.SourceProviderFromRegistryClientProvider(op.sources, logger) resolverSourceProvider := NewOperatorGroupToggleSourceProvider(op.sourceInvalidator, logger, op.lister.OperatorsV1().OperatorGroupLister()) - op.reconciler = reconciler.NewRegistryReconcilerFactory(lister, opClient, configmapRegistryImage, op.now, ssaClient, workloadUserID) + op.reconciler = reconciler.NewRegistryReconcilerFactory(lister, opClient, configmapRegistryImage, op.now, ssaClient, workloadUserID, opmImage, utilImage) res := resolver.NewOperatorStepResolver(lister, crClient, operatorNamespace, resolverSourceProvider, logger) op.resolver = resolver.NewInstrumentedResolver(res, metrics.RegisterDependencyResolutionSuccess, metrics.RegisterDependencyResolutionFailure) @@ -344,7 +365,14 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo } // Wire k8s sharedIndexInformers - k8sInformerFactory := informers.NewSharedInformerFactoryWithOptions(op.opClient.KubernetesInterface(), resyncPeriod()) + k8sInformerFactory := informers.NewSharedInformerFactoryWithOptions(op.opClient.KubernetesInterface(), resyncPeriod(), func() []informers.SharedInformerOption { + if !canFilter { + return nil + } + return []informers.SharedInformerOption{informers.WithTweakListOptions(func(options *metav1.ListOptions) { + options.LabelSelector = labels.SelectorFromSet(labels.Set{install.OLMManagedLabelKey: install.OLMManagedLabelValue}).String() + })} + }()...) sharedIndexInformers := []cache.SharedIndexInformer{} // Wire Roles @@ -352,21 +380,114 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo op.lister.RbacV1().RegisterRoleLister(metav1.NamespaceAll, roleInformer.Lister()) sharedIndexInformers = append(sharedIndexInformers, roleInformer.Informer()) + labelObjects := func(gvr schema.GroupVersionResource, informer cache.SharedIndexInformer, sync queueinformer.LegacySyncHandler) error { + if canFilter { + return nil + } + queue := workqueue.NewRateLimitingQueueWithConfig(workqueue.DefaultControllerRateLimiter(), workqueue.RateLimitingQueueConfig{ + Name: gvr.String(), + }) + queueInformer, err := queueinformer.NewQueueInformer( + ctx, + queueinformer.WithQueue(queue), + queueinformer.WithLogger(op.logger), + queueinformer.WithInformer(informer), + queueinformer.WithSyncer(sync.ToSyncer()), + ) + if err != nil { + return err + } + + if err := op.RegisterQueueInformer(queueInformer); err != nil { + return err + } + + return nil + } + + rolesgvk := rbacv1.SchemeGroupVersion.WithResource("roles") + if err := labelObjects(rolesgvk, roleInformer.Informer(), labeller.ObjectLabeler[*rbacv1.Role, *rbacv1applyconfigurations.RoleApplyConfiguration]( + ctx, op.logger, labeller.Filter(rolesgvk), + rbacv1applyconfigurations.Role, + func(namespace string, ctx context.Context, cfg *rbacv1applyconfigurations.RoleApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.Role, error) { + return op.opClient.KubernetesInterface().RbacV1().Roles(namespace).Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + if err := labelObjects(rolesgvk, roleInformer.Informer(), labeller.ContentHashLabeler[*rbacv1.Role, *rbacv1applyconfigurations.RoleApplyConfiguration]( + ctx, op.logger, labeller.ContentHashFilter, + func(role *rbacv1.Role) (string, error) { + return resolver.PolicyRuleHashLabelValue(role.Rules) + }, + rbacv1applyconfigurations.Role, + func(namespace string, ctx context.Context, cfg *rbacv1applyconfigurations.RoleApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.Role, error) { + return op.opClient.KubernetesInterface().RbacV1().Roles(namespace).Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + // Wire RoleBindings roleBindingInformer := k8sInformerFactory.Rbac().V1().RoleBindings() op.lister.RbacV1().RegisterRoleBindingLister(metav1.NamespaceAll, roleBindingInformer.Lister()) sharedIndexInformers = append(sharedIndexInformers, roleBindingInformer.Informer()) + rolebindingsgvk := rbacv1.SchemeGroupVersion.WithResource("rolebindings") + if err := labelObjects(rolebindingsgvk, roleBindingInformer.Informer(), labeller.ObjectLabeler[*rbacv1.RoleBinding, *rbacv1applyconfigurations.RoleBindingApplyConfiguration]( + ctx, op.logger, labeller.Filter(rolebindingsgvk), + rbacv1applyconfigurations.RoleBinding, + func(namespace string, ctx context.Context, cfg *rbacv1applyconfigurations.RoleBindingApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.RoleBinding, error) { + return op.opClient.KubernetesInterface().RbacV1().RoleBindings(namespace).Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + if err := labelObjects(rolebindingsgvk, roleBindingInformer.Informer(), labeller.ContentHashLabeler[*rbacv1.RoleBinding, *rbacv1applyconfigurations.RoleBindingApplyConfiguration]( + ctx, op.logger, labeller.ContentHashFilter, + func(roleBinding *rbacv1.RoleBinding) (string, error) { + return resolver.RoleReferenceAndSubjectHashLabelValue(roleBinding.RoleRef, roleBinding.Subjects) + }, + rbacv1applyconfigurations.RoleBinding, + func(namespace string, ctx context.Context, cfg *rbacv1applyconfigurations.RoleBindingApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.RoleBinding, error) { + return op.opClient.KubernetesInterface().RbacV1().RoleBindings(namespace).Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + // Wire ServiceAccounts serviceAccountInformer := k8sInformerFactory.Core().V1().ServiceAccounts() op.lister.CoreV1().RegisterServiceAccountLister(metav1.NamespaceAll, serviceAccountInformer.Lister()) sharedIndexInformers = append(sharedIndexInformers, serviceAccountInformer.Informer()) + serviceaccountsgvk := corev1.SchemeGroupVersion.WithResource("serviceaccounts") + if err := labelObjects(serviceaccountsgvk, serviceAccountInformer.Informer(), labeller.ObjectLabeler[*corev1.ServiceAccount, *corev1applyconfigurations.ServiceAccountApplyConfiguration]( + ctx, op.logger, labeller.Filter(serviceaccountsgvk), + corev1applyconfigurations.ServiceAccount, + func(namespace string, ctx context.Context, cfg *corev1applyconfigurations.ServiceAccountApplyConfiguration, opts metav1.ApplyOptions) (*corev1.ServiceAccount, error) { + return op.opClient.KubernetesInterface().CoreV1().ServiceAccounts(namespace).Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + // Wire Services serviceInformer := k8sInformerFactory.Core().V1().Services() op.lister.CoreV1().RegisterServiceLister(metav1.NamespaceAll, serviceInformer.Lister()) sharedIndexInformers = append(sharedIndexInformers, serviceInformer.Informer()) + servicesgvk := corev1.SchemeGroupVersion.WithResource("services") + if err := labelObjects(servicesgvk, serviceInformer.Informer(), labeller.ObjectLabeler[*corev1.Service, *corev1applyconfigurations.ServiceApplyConfiguration]( + ctx, op.logger, labeller.Filter(servicesgvk), + corev1applyconfigurations.Service, + func(namespace string, ctx context.Context, cfg *corev1applyconfigurations.ServiceApplyConfiguration, opts metav1.ApplyOptions) (*corev1.Service, error) { + return op.opClient.KubernetesInterface().CoreV1().Services(namespace).Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + // Wire Pods for CatalogSource catsrcReq, err := labels.NewRequirement(reconciler.CatalogSourceLabelKey, selection.Exists, nil) if err != nil { @@ -381,6 +502,17 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo op.lister.CoreV1().RegisterPodLister(metav1.NamespaceAll, csPodInformer.Lister()) sharedIndexInformers = append(sharedIndexInformers, csPodInformer.Informer()) + podsgvk := corev1.SchemeGroupVersion.WithResource("pods") + if err := labelObjects(podsgvk, csPodInformer.Informer(), labeller.ObjectLabeler[*corev1.Pod, *corev1applyconfigurations.PodApplyConfiguration]( + ctx, op.logger, labeller.Filter(podsgvk), + corev1applyconfigurations.Pod, + func(namespace string, ctx context.Context, cfg *corev1applyconfigurations.PodApplyConfiguration, opts metav1.ApplyOptions) (*corev1.Pod, error) { + return op.opClient.KubernetesInterface().CoreV1().Pods(namespace).Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + // Wire Pods for BundleUnpack job buReq, err := labels.NewRequirement(bundle.BundleUnpackPodLabel, selection.Exists, nil) if err != nil { @@ -405,6 +537,19 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo jobInformer := k8sInformerFactory.Batch().V1().Jobs() sharedIndexInformers = append(sharedIndexInformers, jobInformer.Informer()) + jobsgvk := batchv1.SchemeGroupVersion.WithResource("jobs") + if err := labelObjects(jobsgvk, jobInformer.Informer(), labeller.ObjectLabeler[*batchv1.Job, *batchv1applyconfigurations.JobApplyConfiguration]( + ctx, op.logger, labeller.JobFilter(func(namespace, name string) (metav1.Object, error) { + return configMapInformer.Lister().ConfigMaps(namespace).Get(name) + }), + batchv1applyconfigurations.Job, + func(namespace string, ctx context.Context, cfg *batchv1applyconfigurations.JobApplyConfiguration, opts metav1.ApplyOptions) (*batchv1.Job, error) { + return op.opClient.KubernetesInterface().BatchV1().Jobs(namespace).Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + // Generate and register QueueInformers for k8s resources k8sSyncer := queueinformer.LegacySyncHandler(op.syncObject).ToSyncerWithDelete(op.handleDeletion) for _, informer := range sharedIndexInformers { @@ -443,13 +588,23 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo return nil, err } - // Register CustomResourceDefinition QueueInformer - crdInformer := extinf.NewSharedInformerFactory(op.opClient.ApiextensionsInterface(), resyncPeriod()).Apiextensions().V1().CustomResourceDefinitions() - op.lister.APIExtensionsV1().RegisterCustomResourceDefinitionLister(crdInformer.Lister()) + // Register CustomResourceDefinition QueueInformer. Object metadata requests are used + // by this informer in order to reduce cached size. + gvr := apiextensionsv1.SchemeGroupVersion.WithResource("customresourcedefinitions") + crdInformer := metadatainformer.NewFilteredMetadataInformer( + metadataClient, + gvr, + metav1.NamespaceAll, + resyncPeriod(), + cache.Indexers{}, + nil, + ).Informer() + crdLister := metadatalister.New(crdInformer.GetIndexer(), gvr) + op.lister.APIExtensionsV1().RegisterCustomResourceDefinitionLister(crdLister) crdQueueInformer, err := queueinformer.NewQueueInformer( ctx, queueinformer.WithLogger(op.logger), - queueinformer.WithInformer(crdInformer.Informer()), + queueinformer.WithInformer(crdInformer), queueinformer.WithSyncer(queueinformer.LegacySyncHandler(op.syncObject).ToSyncerWithDelete(op.handleDeletion)), ) if err != nil { @@ -459,6 +614,14 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo return nil, err } + customresourcedefinitionsgvk := apiextensionsv1.SchemeGroupVersion.WithResource("customresourcedefinitions") + if err := labelObjects(customresourcedefinitionsgvk, crdInformer, labeller.ObjectPatchLabeler( + ctx, op.logger, labeller.Filter(customresourcedefinitionsgvk), + op.opClient.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Patch, + )); err != nil { + return nil, err + } + // Namespace sync for resolving subscriptions namespaceInformer := informers.NewSharedInformerFactory(op.opClient.KubernetesInterface(), resyncPeriod()).Core().V1().Namespaces() op.lister.CoreV1().RegisterNamespaceLister(namespaceInformer.Lister()) @@ -2096,6 +2259,10 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { // Attempt to create the CSV. csv.SetNamespace(namespace) + if csv.Labels == nil { + csv.Labels = map[string]string{} + } + csv.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue status, err := ensurer.EnsureClusterServiceVersion(&csv) if err != nil { @@ -2121,6 +2288,10 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { // Attempt to create the Subscription sub.SetNamespace(namespace) + if sub.Labels == nil { + sub.Labels = map[string]string{} + } + sub.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue status, err := ensurer.EnsureSubscription(&sub) if err != nil { @@ -2151,6 +2322,10 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { } s.SetOwnerReferences(updated) s.SetNamespace(namespace) + if s.Labels == nil { + s.Labels = map[string]string{} + } + s.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue status, err := ensurer.EnsureBundleSecret(plan.Namespace, &s) if err != nil { @@ -2175,6 +2350,11 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { return errorwrap.Wrapf(err, "error parsing step manifest: %s", step.Resource.Name) } + if cr.Labels == nil { + cr.Labels = map[string]string{} + } + cr.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue + status, err := ensurer.EnsureClusterRole(&cr, step) if err != nil { return err @@ -2189,6 +2369,10 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { if err != nil { return errorwrap.Wrapf(err, "error parsing step manifest: %s", step.Resource.Name) } + if rb.Labels == nil { + rb.Labels = map[string]string{} + } + rb.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue status, err := ensurer.EnsureClusterRoleBinding(&rb, step) if err != nil { @@ -2212,6 +2396,10 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { } r.SetOwnerReferences(updated) r.SetNamespace(namespace) + if r.Labels == nil { + r.Labels = map[string]string{} + } + r.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue status, err := ensurer.EnsureRole(plan.Namespace, &r) if err != nil { @@ -2235,6 +2423,10 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { } rb.SetOwnerReferences(updated) rb.SetNamespace(namespace) + if rb.Labels == nil { + rb.Labels = map[string]string{} + } + rb.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue status, err := ensurer.EnsureRoleBinding(plan.Namespace, &rb) if err != nil { @@ -2258,6 +2450,10 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { } sa.SetOwnerReferences(updated) sa.SetNamespace(namespace) + if sa.Labels == nil { + sa.Labels = map[string]string{} + } + sa.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue status, err := ensurer.EnsureServiceAccount(namespace, &sa) if err != nil { @@ -2289,6 +2485,10 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { } s.SetOwnerReferences(updated) s.SetNamespace(namespace) + if s.Labels == nil { + s.Labels = map[string]string{} + } + s.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue status, err := ensurer.EnsureService(namespace, &s) if err != nil { @@ -2319,6 +2519,10 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { } cfg.SetOwnerReferences(updated) cfg.SetNamespace(namespace) + if cfg.Labels == nil { + cfg.Labels = map[string]string{} + } + cfg.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue status, err := ensurer.EnsureConfigMap(plan.Namespace, &cfg) if err != nil { @@ -2378,6 +2582,12 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { } } } + l := unstructuredObject.GetLabels() + if l == nil { + l = map[string]string{} + } + l[install.OLMManagedLabelKey] = install.OLMManagedLabelValue + unstructuredObject.SetLabels(l) // Set up the dynamic client ResourceInterface and set ownerrefs var resourceInterface dynamic.ResourceInterface diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/step.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/step.go index 54abd56bf9..d3f54f1827 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/step.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/step.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" "github.com/pkg/errors" "github.com/sirupsen/logrus" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -128,6 +129,10 @@ func (b *builder) NewCRDV1Step(client apiextensionsv1client.ApiextensionsV1Inter } setInstalledAlongsideAnnotation(b.annotator, crd, b.plan.GetNamespace(), step.Resolving, b.csvLister, crd) + if crd.Labels == nil { + crd.Labels = map[string]string{} + } + crd.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue _, createError := client.CustomResourceDefinitions().Create(context.TODO(), crd, metav1.CreateOptions{}) if apierrors.IsAlreadyExists(createError) { @@ -211,6 +216,10 @@ func (b *builder) NewCRDV1Beta1Step(client apiextensionsv1beta1client.Apiextensi } setInstalledAlongsideAnnotation(b.annotator, crd, b.plan.GetNamespace(), step.Resolving, b.csvLister, crd) + if crd.Labels == nil { + crd.Labels = map[string]string{} + } + crd.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue _, createError := client.CustomResourceDefinitions().Create(context.TODO(), crd, metav1.CreateOptions{}) if apierrors.IsAlreadyExists(createError) { diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/step_ensurer.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/step_ensurer.go index 91c309f97a..3369aa6561 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/step_ensurer.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/step_ensurer.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" errorwrap "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -91,6 +92,9 @@ func (o *StepEnsurer) EnsureSecret(operatorNamespace, planNamespace, name string ObjectMeta: metav1.ObjectMeta{ Name: secret.Name, Namespace: planNamespace, + Labels: map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + }, }, Data: secret.Data, Type: secret.Type, diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/internal/alongside/alongside.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/internal/alongside/alongside.go index 5004650b27..7517cf2777 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/internal/alongside/alongside.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/internal/alongside/alongside.go @@ -10,7 +10,7 @@ import ( ) const ( - prefix = "operatorframework.io/installed-alongside-" + AnnotationPrefix = "operatorframework.io/installed-alongside-" ) // NamespacedName is a reference to an object by namespace and name. @@ -33,7 +33,7 @@ type Annotator struct{} func (a Annotator) FromObject(o Annotatable) []NamespacedName { var result []NamespacedName for k, v := range o.GetAnnotations() { - if !strings.HasPrefix(k, prefix) { + if !strings.HasPrefix(k, AnnotationPrefix) { continue } tokens := strings.Split(v, "/") @@ -55,7 +55,7 @@ func (a Annotator) ToObject(o Annotatable, nns []NamespacedName) { annotations := o.GetAnnotations() for key := range annotations { - if strings.HasPrefix(key, prefix) { + if strings.HasPrefix(key, AnnotationPrefix) { delete(annotations, key) } } @@ -82,5 +82,5 @@ func key(n NamespacedName) string { hasher.Write([]byte(n.Namespace)) hasher.Write([]byte{'/'}) hasher.Write([]byte(n.Name)) - return fmt.Sprintf("%s%x", prefix, hasher.Sum64()) + return fmt.Sprintf("%s%x", AnnotationPrefix, hasher.Sum64()) } diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/labeller/filters.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/labeller/filters.go new file mode 100644 index 0000000000..4bdbfece31 --- /dev/null +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/labeller/filters.go @@ -0,0 +1,128 @@ +package labeller + +import ( + "context" + "fmt" + "strings" + "sync" + + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler" + "github.com/sirupsen/logrus" + "golang.org/x/sync/errgroup" + appsv1 "k8s.io/api/apps/v1" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/metadata" + + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/internal/alongside" +) + +func ContentHashFilter(object metav1.Object) bool { + return HasOLMOwnerRef(object) && !hasHashLabel(object) +} + +func Filter(gvr schema.GroupVersionResource) func(metav1.Object) bool { + if f, ok := filters[gvr]; ok { + return f + } + return func(object metav1.Object) bool { + return false + } +} + +func JobFilter(getConfigMap func(namespace, name string) (metav1.Object, error)) func(object metav1.Object) bool { + return func(object metav1.Object) bool { + for _, ownerRef := range object.GetOwnerReferences() { + if ownerRef.APIVersion == corev1.SchemeGroupVersion.String() && ownerRef.Kind == "ConfigMap" { + cm, err := getConfigMap(object.GetNamespace(), ownerRef.Name) + if err != nil { + return false + } + return HasOLMOwnerRef(cm) + } + } + return false + } +} + +var filters = map[schema.GroupVersionResource]func(metav1.Object) bool{ + corev1.SchemeGroupVersion.WithResource("services"): HasOLMOwnerRef, + corev1.SchemeGroupVersion.WithResource("pods"): func(object metav1.Object) bool { + _, ok := object.GetLabels()[reconciler.CatalogSourceLabelKey] + return ok + }, + corev1.SchemeGroupVersion.WithResource("serviceaccounts"): func(object metav1.Object) bool { + return HasOLMOwnerRef(object) || HasOLMLabel(object) + }, + appsv1.SchemeGroupVersion.WithResource("deployments"): HasOLMOwnerRef, + rbacv1.SchemeGroupVersion.WithResource("roles"): HasOLMOwnerRef, + rbacv1.SchemeGroupVersion.WithResource("rolebindings"): HasOLMOwnerRef, + rbacv1.SchemeGroupVersion.WithResource("clusterroles"): HasOLMOwnerRef, + rbacv1.SchemeGroupVersion.WithResource("clusterrolebindings"): HasOLMOwnerRef, + apiextensionsv1.SchemeGroupVersion.WithResource("customresourcedefinitions"): func(object metav1.Object) bool { + for key := range object.GetAnnotations() { + if strings.HasPrefix(key, alongside.AnnotationPrefix) { + return true + } + } + return false + }, +} + +func Validate(ctx context.Context, logger *logrus.Logger, metadataClient metadata.Interface) (bool, error) { + okLock := sync.Mutex{} + var ok bool + g, ctx := errgroup.WithContext(ctx) + allFilters := map[schema.GroupVersionResource]func(metav1.Object) bool{} + for gvr, filter := range filters { + allFilters[gvr] = filter + } + allFilters[batchv1.SchemeGroupVersion.WithResource("jobs")] = JobFilter(func(namespace, name string) (metav1.Object, error) { + return metadataClient.Resource(corev1.SchemeGroupVersion.WithResource("configmaps")).Namespace(namespace).Get(ctx, name, metav1.GetOptions{}) + }) + + for _, gvr := range []schema.GroupVersionResource{ + rbacv1.SchemeGroupVersion.WithResource("roles"), + rbacv1.SchemeGroupVersion.WithResource("rolebindings"), + rbacv1.SchemeGroupVersion.WithResource("clusterroles"), + rbacv1.SchemeGroupVersion.WithResource("clusterrolebindings"), + } { + previous := allFilters[gvr] + allFilters[gvr] = func(object metav1.Object) bool { + return previous != nil && previous(object) && ContentHashFilter(object) + } + } + for gvr, filter := range allFilters { + gvr, filter := gvr, filter + g.Go(func() error { + list, err := metadataClient.Resource(gvr).List(ctx, metav1.ListOptions{}) + if err != nil { + return fmt.Errorf("failed to list %s: %w", gvr.String(), err) + } + var count int + for _, item := range list.Items { + if filter(&item) && !hasLabel(&item) { + count++ + } + } + if count > 0 { + logger.WithFields(logrus.Fields{ + "gvr": gvr.String(), + "nonconforming": count, + }).Info("found nonconforming items") + } + okLock.Lock() + ok = ok && count == 0 + okLock.Unlock() + return nil + }) + } + if err := g.Wait(); err != nil { + return false, err + } + return ok, nil +} diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/labeller/labels.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/labeller/labels.go new file mode 100644 index 0000000000..8c2af67c9d --- /dev/null +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/labeller/labels.go @@ -0,0 +1,159 @@ +package labeller + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + jsonpatch "github.com/evanphx/json-patch" + "github.com/sirupsen/logrus" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + + operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" + operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + operatorsv1alpha2 "github.com/operator-framework/api/pkg/operators/v1alpha2" + + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/decorators" + "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil" + "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer" +) + +type ApplyConfig[T any] interface { + WithLabels(map[string]string) T +} + +type Client[A ApplyConfig[A], T metav1.Object] interface { + Apply(ctx context.Context, cfg ApplyConfig[A], opts metav1.ApplyOptions) (result T, err error) +} + +func hasLabel(obj metav1.Object) bool { + value, ok := obj.GetLabels()[install.OLMManagedLabelKey] + return ok && value == install.OLMManagedLabelValue +} + +func ObjectLabeler[T metav1.Object, A ApplyConfig[A]]( + ctx context.Context, + logger *logrus.Logger, + check func(metav1.Object) bool, + applyConfigFor func(name, namespace string) A, + apply func(namespace string, ctx context.Context, cfg A, opts metav1.ApplyOptions) (T, error), +) queueinformer.LegacySyncHandler { + return func(obj interface{}) error { + cast, ok := obj.(T) + if !ok { + err := fmt.Errorf("wrong type %T, expected %T: %#v", obj, new(T), obj) + logger.WithError(err).Error("casting failed") + return fmt.Errorf("casting failed: %w", err) + } + + if !check(cast) || hasLabel(cast) { + return nil + } + + cfg := applyConfigFor(cast.GetName(), cast.GetNamespace()) + cfg.WithLabels(map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + }) + + _, err := apply(cast.GetNamespace(), ctx, cfg, metav1.ApplyOptions{}) + return err + } +} + +// CRDs did not have applyconfigurations generated for them on accident, we can remove this when +// https://github.com/kubernetes/kubernetes/pull/120177 lands +func ObjectPatchLabeler( + ctx context.Context, + logger *logrus.Logger, + check func(metav1.Object) bool, + patch func(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *apiextensionsv1.CustomResourceDefinition, err error), +) func( + obj interface{}, +) error { + return func(obj interface{}) error { + cast, ok := obj.(*apiextensionsv1.CustomResourceDefinition) + if !ok { + err := fmt.Errorf("wrong type %T, expected %T: %#v", obj, new(*apiextensionsv1.CustomResourceDefinition), obj) + logger.WithError(err).Error("casting failed") + return fmt.Errorf("casting failed: %w", err) + } + + if !check(cast) || hasLabel(cast) { + return nil + } + + uid := cast.GetUID() + rv := cast.GetResourceVersion() + + // to ensure they appear in the patch as preconditions + previous := cast.DeepCopy() + previous.SetUID("") + previous.SetResourceVersion("") + + oldData, err := json.Marshal(previous) + if err != nil { + return fmt.Errorf("failed to Marshal old data for %s/%s: %w", previous.GetNamespace(), previous.GetName(), err) + } + + // to ensure they appear in the patch as preconditions + updated := cast.DeepCopy() + updated.SetUID(uid) + updated.SetResourceVersion(rv) + labels := updated.GetLabels() + if labels == nil { + labels = map[string]string{} + } + labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue + updated.SetLabels(labels) + + newData, err := json.Marshal(updated) + if err != nil { + return fmt.Errorf("failed to Marshal old data for %s/%s: %w", updated.GetNamespace(), updated.GetName(), err) + } + + patchBytes, err := jsonpatch.CreateMergePatch(oldData, newData) + if err != nil { + return fmt.Errorf("failed to create patch for %s/%s: %w", cast.GetNamespace(), cast.GetName(), err) + } + + _, err = patch(ctx, cast.GetName(), types.MergePatchType, patchBytes, metav1.PatchOptions{}) + return err + } +} + +// HasOLMOwnerRef determines if an object is owned by another object in the OLM Groups. +// This checks both classical OwnerRefs and the "OLM OwnerRef" in labels to handle +// cluster-scoped resources. +func HasOLMOwnerRef(object metav1.Object) bool { + for _, ref := range object.GetOwnerReferences() { + for _, gv := range []schema.GroupVersion{ + operatorsv1.GroupVersion, + operatorsv1alpha1.SchemeGroupVersion, + operatorsv1alpha2.GroupVersion, + } { + if ref.APIVersion == gv.String() { + return true + } + } + } + hasOLMOwnerLabels := true + for _, label := range []string{ownerutil.OwnerKey, ownerutil.OwnerNamespaceKey, ownerutil.OwnerKind} { + _, exists := object.GetLabels()[label] + hasOLMOwnerLabels = hasOLMOwnerLabels && exists + } + return hasOLMOwnerLabels +} + +func HasOLMLabel(object metav1.Object) bool { + for key := range object.GetLabels() { + if strings.HasPrefix(key, decorators.ComponentLabelKeyPrefix) { + return true + } + } + return false +} diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/labeller/rbac.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/labeller/rbac.go new file mode 100644 index 0000000000..6e64791ca7 --- /dev/null +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/labeller/rbac.go @@ -0,0 +1,56 @@ +package labeller + +import ( + "context" + "fmt" + + "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver" + "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil" + "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer" + "github.com/sirupsen/logrus" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func hasHashLabel(obj metav1.Object) bool { + _, ok := obj.GetLabels()[resolver.ContentHashLabelKey] + return ok +} + +func ContentHashLabeler[T metav1.Object, A ApplyConfig[A]]( + ctx context.Context, + logger *logrus.Logger, + check func(metav1.Object) bool, + hasher func(object T) (string, error), + applyConfigFor func(name, namespace string) A, + apply func(namespace string, ctx context.Context, cfg A, opts metav1.ApplyOptions) (T, error), +) queueinformer.LegacySyncHandler { + return func(obj interface{}) error { + cast, ok := obj.(T) + if !ok { + err := fmt.Errorf("wrong type %T, expected %T: %#v", obj, new(T), obj) + logger.WithError(err).Error("casting failed") + return fmt.Errorf("casting failed: %w", err) + } + + if _, _, ok := ownerutil.GetOwnerByKindLabel(cast, v1alpha1.ClusterServiceVersionKind); !ok { + return nil + } + + if !check(cast) || hasHashLabel(cast) { + return nil + } + + hash, err := hasher(cast) + if err != nil { + return fmt.Errorf("failed to calculate hash: %w", err) + } + + cfg := applyConfigFor(cast.GetName(), cast.GetNamespace()) + cfg.WithLabels(map[string]string{ + resolver.ContentHashLabelKey: hash, + }) + _, err = apply(cast.GetNamespace(), ctx, cfg, metav1.ApplyOptions{}) + return err + } +} diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/apiservices.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/apiservices.go index c71b5594f3..cb052f510f 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/apiservices.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/apiservices.go @@ -228,6 +228,7 @@ func (a *Operator) areAPIServicesAvailable(csv *v1alpha1.ClusterServiceVersion) for _, desc := range csv.Spec.APIServiceDefinitions.Owned { apiService, err := a.lister.APIRegistrationV1().APIServiceLister().Get(desc.GetName()) if apierrors.IsNotFound(err) { + a.logger.Debugf("APIRegistration APIService %s not found", desc.GetName()) return false, nil } @@ -236,10 +237,12 @@ func (a *Operator) areAPIServicesAvailable(csv *v1alpha1.ClusterServiceVersion) } if !install.IsAPIServiceAvailable(apiService) { + a.logger.Debugf("APIService not available for %s", desc.GetName()) return false, nil } if ok, err := a.isGVKRegistered(desc.Group, desc.Version, desc.Kind); !ok || err != nil { + a.logger.Debugf("%s.%s/%s not registered for %s", desc.Group, desc.Version, desc.Kind, desc.GetName()) return false, err } } diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/operator.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/operator.go index c8aa9ea09a..824f5940ee 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/operator.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/operator.go @@ -7,21 +7,25 @@ import ( "strings" "time" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/labeller" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/plugins" "github.com/sirupsen/logrus" admissionregistrationv1 "k8s.io/api/admissionregistration/v1" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - extinf "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/selection" utilerrors "k8s.io/apimachinery/pkg/util/errors" utilruntime "k8s.io/apimachinery/pkg/util/runtime" + appsv1applyconfigurations "k8s.io/client-go/applyconfigurations/apps/v1" + rbacv1applyconfigurations "k8s.io/client-go/applyconfigurations/rbac/v1" "k8s.io/client-go/informers" k8sscheme "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/metadata/metadatainformer" @@ -136,6 +140,11 @@ func newOperatorWithConfig(ctx context.Context, config *operatorConfig) (*Operat return nil, err } + canFilter, err := labeller.Validate(ctx, config.logger, config.metadataClient) + if err != nil { + return nil, err + } + op := &Operator{ Operator: queueOperator, clock: config.clock, @@ -309,7 +318,17 @@ func newOperatorWithConfig(ctx context.Context, config *operatorConfig) (*Operat } // Wire Deployments - k8sInformerFactory := informers.NewSharedInformerFactoryWithOptions(op.opClient.KubernetesInterface(), config.resyncPeriod(), informers.WithNamespace(namespace)) + k8sInformerFactory := informers.NewSharedInformerFactoryWithOptions(op.opClient.KubernetesInterface(), config.resyncPeriod(), func() []informers.SharedInformerOption { + opts := []informers.SharedInformerOption{ + informers.WithNamespace(namespace), + } + if canFilter { + opts = append(opts, informers.WithTweakListOptions(func(options *metav1.ListOptions) { + options.LabelSelector = labels.SelectorFromSet(labels.Set{install.OLMManagedLabelKey: install.OLMManagedLabelValue}).String() + })) + } + return opts + }()...) depInformer := k8sInformerFactory.Apps().V1().Deployments() informersByNamespace[namespace].DeploymentInformer = depInformer op.lister.AppsV1().RegisterDeploymentLister(namespace, depInformer.Lister()) @@ -428,6 +447,42 @@ func newOperatorWithConfig(ctx context.Context, config *operatorConfig) (*Operat } } + labelObjects := func(gvr schema.GroupVersionResource, informer cache.SharedIndexInformer, sync queueinformer.LegacySyncHandler) error { + if canFilter { + return nil + } + queue := workqueue.NewRateLimitingQueueWithConfig(workqueue.DefaultControllerRateLimiter(), workqueue.RateLimitingQueueConfig{ + Name: gvr.String(), + }) + queueInformer, err := queueinformer.NewQueueInformer( + ctx, + queueinformer.WithQueue(queue), + queueinformer.WithLogger(op.logger), + queueinformer.WithInformer(informer), + queueinformer.WithSyncer(sync.ToSyncer()), + ) + if err != nil { + return err + } + + if err := op.RegisterQueueInformer(queueInformer); err != nil { + return err + } + + return nil + } + + deploymentsgvk := appsv1.SchemeGroupVersion.WithResource("deployments") + if err := labelObjects(deploymentsgvk, informersByNamespace[metav1.NamespaceAll].DeploymentInformer.Informer(), labeller.ObjectLabeler[*appsv1.Deployment, *appsv1applyconfigurations.DeploymentApplyConfiguration]( + ctx, op.logger, labeller.Filter(deploymentsgvk), + appsv1applyconfigurations.Deployment, + func(namespace string, ctx context.Context, cfg *appsv1applyconfigurations.DeploymentApplyConfiguration, opts metav1.ApplyOptions) (*appsv1.Deployment, error) { + return op.opClient.KubernetesInterface().AppsV1().Deployments(namespace).Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + // add queue for all namespaces as well objGCQueue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), fmt.Sprintf("%s/obj-gc", "")) op.objGCQueueSet.Set("", objGCQueue) @@ -465,7 +520,14 @@ func newOperatorWithConfig(ctx context.Context, config *operatorConfig) (*Operat return nil, err } - k8sInformerFactory := informers.NewSharedInformerFactory(op.opClient.KubernetesInterface(), config.resyncPeriod()) + k8sInformerFactory := informers.NewSharedInformerFactoryWithOptions(op.opClient.KubernetesInterface(), config.resyncPeriod(), func() []informers.SharedInformerOption { + if !canFilter { + return nil + } + return []informers.SharedInformerOption{informers.WithTweakListOptions(func(options *metav1.ListOptions) { + options.LabelSelector = labels.SelectorFromSet(labels.Set{install.OLMManagedLabelKey: install.OLMManagedLabelValue}).String() + })} + }()...) clusterRoleInformer := k8sInformerFactory.Rbac().V1().ClusterRoles() informersByNamespace[metav1.NamespaceAll].ClusterRoleInformer = clusterRoleInformer op.lister.RbacV1().RegisterClusterRoleLister(clusterRoleInformer.Lister()) @@ -482,6 +544,33 @@ func newOperatorWithConfig(ctx context.Context, config *operatorConfig) (*Operat return nil, err } + clusterrolesgvk := rbacv1.SchemeGroupVersion.WithResource("clusterroles") + if err := labelObjects(clusterrolesgvk, clusterRoleInformer.Informer(), labeller.ObjectLabeler[*rbacv1.ClusterRole, *rbacv1applyconfigurations.ClusterRoleApplyConfiguration]( + ctx, op.logger, labeller.Filter(clusterrolesgvk), + func(name, _ string) *rbacv1applyconfigurations.ClusterRoleApplyConfiguration { + return rbacv1applyconfigurations.ClusterRole(name) + }, + func(_ string, ctx context.Context, cfg *rbacv1applyconfigurations.ClusterRoleApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.ClusterRole, error) { + return op.opClient.KubernetesInterface().RbacV1().ClusterRoles().Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + if err := labelObjects(clusterrolesgvk, clusterRoleInformer.Informer(), labeller.ContentHashLabeler[*rbacv1.ClusterRole, *rbacv1applyconfigurations.ClusterRoleApplyConfiguration]( + ctx, op.logger, labeller.ContentHashFilter, + func(clusterRole *rbacv1.ClusterRole) (string, error) { + return resolver.PolicyRuleHashLabelValue(clusterRole.Rules) + }, + func(name, _ string) *rbacv1applyconfigurations.ClusterRoleApplyConfiguration { + return rbacv1applyconfigurations.ClusterRole(name) + }, + func(_ string, ctx context.Context, cfg *rbacv1applyconfigurations.ClusterRoleApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.ClusterRole, error) { + return op.opClient.KubernetesInterface().RbacV1().ClusterRoles().Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + clusterRoleBindingInformer := k8sInformerFactory.Rbac().V1().ClusterRoleBindings() informersByNamespace[metav1.NamespaceAll].ClusterRoleBindingInformer = clusterRoleBindingInformer op.lister.RbacV1().RegisterClusterRoleBindingLister(clusterRoleBindingInformer.Lister()) @@ -498,6 +587,33 @@ func newOperatorWithConfig(ctx context.Context, config *operatorConfig) (*Operat return nil, err } + clusterrolebindingssgvk := rbacv1.SchemeGroupVersion.WithResource("clusterrolebindings") + if err := labelObjects(clusterrolebindingssgvk, clusterRoleBindingInformer.Informer(), labeller.ObjectLabeler[*rbacv1.ClusterRoleBinding, *rbacv1applyconfigurations.ClusterRoleBindingApplyConfiguration]( + ctx, op.logger, labeller.Filter(clusterrolebindingssgvk), + func(name, _ string) *rbacv1applyconfigurations.ClusterRoleBindingApplyConfiguration { + return rbacv1applyconfigurations.ClusterRoleBinding(name) + }, + func(_ string, ctx context.Context, cfg *rbacv1applyconfigurations.ClusterRoleBindingApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.ClusterRoleBinding, error) { + return op.opClient.KubernetesInterface().RbacV1().ClusterRoleBindings().Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + if err := labelObjects(clusterrolebindingssgvk, clusterRoleBindingInformer.Informer(), labeller.ContentHashLabeler[*rbacv1.ClusterRoleBinding, *rbacv1applyconfigurations.ClusterRoleBindingApplyConfiguration]( + ctx, op.logger, labeller.ContentHashFilter, + func(clusterRoleBinding *rbacv1.ClusterRoleBinding) (string, error) { + return resolver.RoleReferenceAndSubjectHashLabelValue(clusterRoleBinding.RoleRef, clusterRoleBinding.Subjects) + }, + func(name, _ string) *rbacv1applyconfigurations.ClusterRoleBindingApplyConfiguration { + return rbacv1applyconfigurations.ClusterRoleBinding(name) + }, + func(_ string, ctx context.Context, cfg *rbacv1applyconfigurations.ClusterRoleBindingApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.ClusterRoleBinding, error) { + return op.opClient.KubernetesInterface().RbacV1().ClusterRoleBindings().Apply(ctx, cfg, opts) + }, + )); err != nil { + return nil, err + } + // register namespace queueinformer namespaceInformer := k8sInformerFactory.Core().V1().Namespaces() informersByNamespace[metav1.NamespaceAll].NamespaceInformer = namespaceInformer @@ -541,14 +657,25 @@ func newOperatorWithConfig(ctx context.Context, config *operatorConfig) (*Operat return nil, err } - // Register CustomResourceDefinition QueueInformer - crdInformer := extinf.NewSharedInformerFactory(op.opClient.ApiextensionsInterface(), config.resyncPeriod()).Apiextensions().V1().CustomResourceDefinitions() + // Register CustomResourceDefinition QueueInformer. Object metadata requests are used + // by this informer in order to reduce cached size. + gvr := apiextensionsv1.SchemeGroupVersion.WithResource("customresourcedefinitions") + crdInformer := metadatainformer.NewFilteredMetadataInformer( + config.metadataClient, + gvr, + metav1.NamespaceAll, + config.resyncPeriod(), + cache.Indexers{}, + nil, + ).Informer() + crdLister := metadatalister.New(crdInformer.GetIndexer(), gvr) informersByNamespace[metav1.NamespaceAll].CRDInformer = crdInformer - op.lister.APIExtensionsV1().RegisterCustomResourceDefinitionLister(crdInformer.Lister()) + informersByNamespace[metav1.NamespaceAll].CRDLister = crdLister + op.lister.APIExtensionsV1().RegisterCustomResourceDefinitionLister(crdLister) crdQueueInformer, err := queueinformer.NewQueueInformer( ctx, queueinformer.WithLogger(op.logger), - queueinformer.WithInformer(crdInformer.Informer()), + queueinformer.WithInformer(crdInformer), queueinformer.WithSyncer(k8sSyncer), ) if err != nil { @@ -1183,7 +1310,7 @@ func (a *Operator) handleClusterServiceVersionDeletion(obj interface{}) { } for i, crdName := range desc.ConversionCRDs { - crd, err := a.lister.APIExtensionsV1().CustomResourceDefinitionLister().Get(crdName) + crd, err := a.opClient.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), crdName, metav1.GetOptions{}) if err != nil { logger.Errorf("error getting CRD %v which was defined in CSVs spec.WebhookDefinition[%d]: %v\n", crdName, i, err) continue diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go index 745048cbb0..92c70c649f 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go @@ -2,35 +2,49 @@ package olm import ( "context" + "crypto/sha256" "fmt" "hash/fnv" + "math/big" "reflect" "strings" - utillabels "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/labels" + "k8s.io/apimachinery/pkg/api/equality" + "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/errors" + utillabels "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/labels" + operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" "github.com/operator-framework/api/pkg/operators/v1alpha1" + opregistry "github.com/operator-framework/operator-registry/pkg/registry" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/decorators" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/cache" hashutil "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/hash" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil" - opregistry "github.com/operator-framework/operator-registry/pkg/registry" ) const ( AdminSuffix = "admin" EditSuffix = "edit" ViewSuffix = "view" + + // kubeResourceNameLimit is the maximum length of a Kubernetes resource name + kubeResourceNameLimit = 253 + + // operatorGroupClusterRoleNameFmt template for ClusterRole names owned by OperatorGroups\ + // e.g. olm.og.my-group.admin- + operatorGroupClusterRoleNameFmt = "olm.og.%s.%s-%s" ) var ( @@ -65,6 +79,8 @@ func (a *Operator) syncOperatorGroups(obj interface{}) error { "namespace": op.GetNamespace(), }) + logger.Infof("syncing OperatorGroup %s/%s", op.GetNamespace(), op.GetName()) + // Query OG in this namespace groups, err := a.lister.OperatorsV1().OperatorGroupLister().OperatorGroups(op.GetNamespace()).List(labels.Everything()) if err != nil { @@ -382,7 +398,8 @@ func (a *Operator) ensureProvidedAPIClusterRole(namePrefix, suffix string, verbs // Matches aggregation rules on the bootstrap ClusterRoles. // https://github.com/kubernetes/kubernetes/blob/61847eab61788fb0543b4cf147773c9da646ed2f/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go#L232 fmt.Sprintf("rbac.authorization.k8s.io/aggregate-to-%s", suffix): "true", - aggregationLabel: "true", + aggregationLabel: "true", + install.OLMManagedLabelKey: install.OLMManagedLabelValue, }, OwnerReferences: []metav1.OwnerReference{ownerutil.NonBlockingOwner(api)}, }, @@ -422,6 +439,7 @@ func (a *Operator) ensureClusterRolesForCSV(csv *v1alpha1.ClusterServiceVersion) if err != nil { return fmt.Errorf("crd %q not found: %s", owned.Name, err.Error()) } + crd.SetGroupVersionKind(apiextensionsv1.SchemeGroupVersion.WithKind("customresourcedefinition")) nameGroupPair := strings.SplitN(owned.Name, ".", 2) // -> etcdclusters etcd.database.coreos.com if len(nameGroupPair) != 2 { return fmt.Errorf("invalid parsing of name '%v', got %v", owned.Name, nameGroupPair) @@ -978,58 +996,88 @@ func (a *Operator) updateNamespaceList(op *operatorsv1.OperatorGroup) ([]string, return namespaceList, nil } -func (a *Operator) ensureOpGroupClusterRole(op *operatorsv1.OperatorGroup, suffix string, apis cache.APISet) error { - clusterRole := &rbacv1.ClusterRole{ - ObjectMeta: metav1.ObjectMeta{ - Name: strings.Join([]string{op.GetName(), suffix}, "-"), - }, - } - var selectors []metav1.LabelSelector - for api := range apis { - aggregationLabel, err := aggregationLabelFromAPIKey(api, suffix) - if err != nil { - return err - } - selectors = append(selectors, metav1.LabelSelector{ - MatchLabels: map[string]string{ - aggregationLabel: "true", - }, - }) +func (a *Operator) getClusterRoleName(op *operatorsv1.OperatorGroup, roleType string) (string, error) { + roleSuffix := hash(fmt.Sprintf("%s/%s/%s", op.GetNamespace(), op.GetName(), roleType)) + // calculate how many characters are left for the operator group name + nameLimit := kubeResourceNameLimit - len(strings.Replace(operatorGroupClusterRoleNameFmt, "%s", "", -1)) - len(roleType) - len(roleSuffix) + if len(op.GetName()) < nameLimit { + return fmt.Sprintf(operatorGroupClusterRoleNameFmt, op.GetName(), roleType, roleSuffix), nil } - if len(selectors) > 0 { - clusterRole.AggregationRule = &rbacv1.AggregationRule{ - ClusterRoleSelectors: selectors, - } + return fmt.Sprintf(operatorGroupClusterRoleNameFmt, op.GetName()[:nameLimit], roleType, roleSuffix), nil +} + +func (a *Operator) ensureOpGroupClusterRole(op *operatorsv1.OperatorGroup, suffix string, apis cache.APISet) error { + // create target cluster role spec + var clusterRole *rbacv1.ClusterRole + clusterRoleName, err := a.getClusterRoleName(op, suffix) + if err != nil { + return err } - err := ownerutil.AddOwnerLabels(clusterRole, op) + aggregationRule, err := a.getClusterRoleAggregationRule(apis, suffix) if err != nil { return err } - existingRole, err := a.lister.RbacV1().ClusterRoleLister().Get(clusterRole.Name) + // get existing cluster role for this level (suffix: admin, edit, view)) + existingRole, err := a.lister.RbacV1().ClusterRoleLister().Get(clusterRoleName) if err != nil && !apierrors.IsNotFound(err) { return err } - if apierrors.IsNotFound(err) { - existingRole, err = a.opClient.KubernetesInterface().RbacV1().ClusterRoles().Create(context.TODO(), clusterRole, metav1.CreateOptions{}) - if err == nil { + + if existingRole != nil { + // if the existing role conforms to the naming convention, check for skew + cp := existingRole.DeepCopy() + if err := ownerutil.AddOwnerLabels(cp, op); err != nil { + return err + } + + // ensure that the labels and aggregation rules are correct + if labels.Equals(existingRole.Labels, cp.Labels) && equality.Semantic.DeepEqual(existingRole.AggregationRule, aggregationRule) { return nil } - if !apierrors.IsAlreadyExists(err) { - a.logger.WithError(err).Errorf("Create cluster role failed: %v", clusterRole) - return err + + cp.AggregationRule = aggregationRule + if _, err := a.opClient.UpdateClusterRole(cp); err != nil { + a.logger.WithError(err).Errorf("update existing cluster role failed: %v", clusterRole) } + return err } - if existingRole != nil && labels.Equals(existingRole.Labels, clusterRole.Labels) && reflect.DeepEqual(existingRole.AggregationRule, clusterRole.AggregationRule) { - return nil + clusterRole = &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: clusterRoleName, + }, + AggregationRule: aggregationRule, } - if _, err := a.opClient.UpdateClusterRole(clusterRole); err != nil { - a.logger.WithError(err).Errorf("Update existing cluster role failed: %v", clusterRole) + if err := ownerutil.AddOwnerLabels(clusterRole, op); err != nil { return err } - return nil + + a.logger.Infof("creating cluster role: %s owned by operator group: %s/%s", clusterRole.GetName(), op.GetNamespace(), op.GetName()) + _, err = a.opClient.KubernetesInterface().RbacV1().ClusterRoles().Create(context.TODO(), clusterRole, metav1.CreateOptions{}) + return err +} + +func (a *Operator) getClusterRoleAggregationRule(apis cache.APISet, suffix string) (*rbacv1.AggregationRule, error) { + var selectors []metav1.LabelSelector + for api := range apis { + aggregationLabel, err := aggregationLabelFromAPIKey(api, suffix) + if err != nil { + return nil, err + } + selectors = append(selectors, metav1.LabelSelector{ + MatchLabels: map[string]string{ + aggregationLabel: "true", + }, + }) + } + if len(selectors) > 0 { + return &rbacv1.AggregationRule{ + ClusterRoleSelectors: selectors, + }, nil + } + return nil, nil } func (a *Operator) ensureOpGroupClusterRoles(op *operatorsv1.OperatorGroup, apis cache.APISet) error { @@ -1126,3 +1174,13 @@ func csvCopyPrototype(src, dst *v1alpha1.ClusterServiceVersion) { dst.Status.Reason = v1alpha1.CSVReasonCopied dst.Status.Message = fmt.Sprintf("The operator is running in %s but is managing this namespace", src.GetNamespace()) } + +func hash(s string) string { + return toBase62(sha256.Sum224([]byte(s))) +} + +func toBase62(hash [28]byte) string { + var i big.Int + i.SetBytes(hash[:]) + return i.Text(62) +} diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/plugins/operator_plugin.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/plugins/operator_plugin.go index 8ab49e4d91..0f38f0543b 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/plugins/operator_plugin.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/plugins/operator_plugin.go @@ -11,7 +11,6 @@ import ( "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer" "github.com/sirupsen/logrus" - extensionsv1informers "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1" appsv1informers "k8s.io/client-go/informers/apps/v1" corev1informers "k8s.io/client-go/informers/core/v1" rbacv1informers "k8s.io/client-go/informers/rbac/v1" @@ -49,7 +48,8 @@ type Informers struct { ClusterRoleBindingInformer rbacv1informers.ClusterRoleBindingInformer NamespaceInformer corev1informers.NamespaceInformer APIServiceInformer apiregistrationv1informers.APIServiceInformer - CRDInformer extensionsv1informers.CustomResourceDefinitionInformer + CRDInformer cache.SharedIndexInformer + CRDLister metadatalister.Lister } // OperatorConfig gives access to required configuration from the host operator diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/requirements.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/requirements.go index f4d408121c..0c288b8e36 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/requirements.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/requirements.go @@ -1,6 +1,7 @@ package olm import ( + "context" "encoding/json" "fmt" "strings" @@ -94,7 +95,7 @@ func (a *Operator) requirementStatus(strategyDetailsDeployment *v1alpha1.Strateg } // check if CRD exists - this verifies group, version, and kind, so no need for GVK check via discovery - crd, err := a.lister.APIExtensionsV1().CustomResourceDefinitionLister().Get(r.Name) + crd, err := a.opClient.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), r.Name, metav1.GetOptions{}) if err != nil { status.Status = v1alpha1.RequirementStatusReasonNotPresent status.Message = "CRD is not present" diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go index 45e85e44cb..c805977c01 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go @@ -5,11 +5,12 @@ import ( "reflect" "github.com/go-logr/logr" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" - meta "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -128,6 +129,9 @@ func (r *OperatorConditionReconciler) ensureOperatorConditionRole(operatorCondit ObjectMeta: metav1.ObjectMeta{ Name: operatorCondition.GetName(), Namespace: operatorCondition.GetNamespace(), + Labels: map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + }, }, Rules: []rbacv1.PolicyRule{ { @@ -176,6 +180,9 @@ func (r *OperatorConditionReconciler) ensureOperatorConditionRoleBinding(operato ObjectMeta: metav1.ObjectMeta{ Name: operatorCondition.GetName(), Namespace: operatorCondition.GetNamespace(), + Labels: map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + }, }, Subjects: subjects, RoleRef: rbacv1.RoleRef{ diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/validatingroundtripper/validating_round_tripper.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/validatingroundtripper/validating_round_tripper.go new file mode 100644 index 0000000000..c9c1cbd395 --- /dev/null +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/validatingroundtripper/validating_round_tripper.go @@ -0,0 +1,53 @@ +package validatingroundtripper + +import ( + "fmt" + "net/http" + "os" + + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/util/yaml" + "k8s.io/client-go/rest" +) + +type validatingRoundTripper struct { + delegate http.RoundTripper +} + +func (rt *validatingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + if req.Method == "POST" { + b, err := req.GetBody() + if err != nil { + panic(err) + } + dec := yaml.NewYAMLOrJSONDecoder(b, 10) + unstructuredObject := &unstructured.Unstructured{} + if err := dec.Decode(unstructuredObject); err != nil { + panic(fmt.Errorf("error decoding object to an unstructured object: %w", err)) + } + gvk := unstructuredObject.GroupVersionKind() + if gvk.Kind != "Event" { + if labels := unstructuredObject.GetLabels(); labels[install.OLMManagedLabelKey] != install.OLMManagedLabelValue { + panic(fmt.Errorf("%s.%s/%v %s/%s does not have labels[%s]=%s", gvk.Kind, gvk.Group, gvk.Version, unstructuredObject.GetNamespace(), unstructuredObject.GetName(), install.OLMManagedLabelKey, install.OLMManagedLabelValue)) + } + } + } + return rt.delegate.RoundTrip(req) +} + +var _ http.RoundTripper = (*validatingRoundTripper)(nil) + +// Wrap is meant to be used in developer environments and CI to make it easy to find places +// where we accidentally create Kubernetes objects without our management label. +func Wrap(cfg *rest.Config) *rest.Config { + if _, set := os.LookupEnv("CI"); !set { + return cfg + } + + cfgCopy := *cfg + cfgCopy.Wrap(func(rt http.RoundTripper) http.RoundTripper { + return &validatingRoundTripper{delegate: rt} + }) + return &cfgCopy +} diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler/configmap.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler/configmap.go index 11a87a8746..1b6a97b075 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler/configmap.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler/configmap.go @@ -5,6 +5,7 @@ import ( "context" "fmt" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" "github.com/pkg/errors" "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" @@ -52,7 +53,8 @@ const ( func (s *configMapCatalogSourceDecorator) Labels() map[string]string { labels := map[string]string{ - CatalogSourceLabelKey: s.GetName(), + CatalogSourceLabelKey: s.GetName(), + install.OLMManagedLabelKey: install.OLMManagedLabelValue, } if s.Spec.SourceType == v1alpha1.SourceTypeInternal || s.Spec.SourceType == v1alpha1.SourceTypeConfigmap { labels[ConfigMapRVLabelKey] = s.Status.ConfigMapResource.ResourceVersion @@ -93,7 +95,9 @@ func (s *configMapCatalogSourceDecorator) Service() *corev1.Service { }, } - labels := map[string]string{} + labels := map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + } hash := HashServiceSpec(svc.Spec) labels[ServiceHashLabelKey] = hash svc.SetLabels(labels) @@ -102,7 +106,7 @@ func (s *configMapCatalogSourceDecorator) Service() *corev1.Service { } func (s *configMapCatalogSourceDecorator) Pod(image string) *corev1.Pod { - pod := Pod(s.CatalogSource, "configmap-registry-server", image, "", s.Labels(), s.Annotations(), 5, 5, s.runAsUser) + pod := Pod(s.CatalogSource, "configmap-registry-server", "", "", image, "", s.Labels(), s.Annotations(), 5, 5, s.runAsUser) pod.Spec.ServiceAccountName = s.GetName() + ConfigMapServerPostfix pod.Spec.Containers[0].Command = []string{"configmap-server", "-c", s.Spec.ConfigMap, "-n", s.GetNamespace()} ownerutil.AddOwner(pod, s.CatalogSource, false, true) @@ -114,6 +118,9 @@ func (s *configMapCatalogSourceDecorator) ServiceAccount() *corev1.ServiceAccoun ObjectMeta: metav1.ObjectMeta{ Name: s.serviceAccountName(), Namespace: s.GetNamespace(), + Labels: map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + }, }, } ownerutil.AddOwner(sa, s.CatalogSource, false, false) @@ -125,6 +132,9 @@ func (s *configMapCatalogSourceDecorator) Role() *rbacv1.Role { ObjectMeta: metav1.ObjectMeta{ Name: s.roleName(), Namespace: s.GetNamespace(), + Labels: map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + }, }, Rules: []rbacv1.PolicyRule{ { @@ -144,6 +154,9 @@ func (s *configMapCatalogSourceDecorator) RoleBinding() *rbacv1.RoleBinding { ObjectMeta: metav1.ObjectMeta{ Name: s.GetName() + "-server-configmap-reader", Namespace: s.GetNamespace(), + Labels: map[string]string{ + install.OLMManagedLabelKey: install.OLMManagedLabelValue, + }, }, Subjects: []rbacv1.Subject{ { diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc.go index 117c081b23..b92658f5ab 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc.go @@ -4,8 +4,10 @@ import ( "context" "fmt" "hash/fnv" + "strings" "time" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" "github.com/pkg/errors" "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" @@ -33,6 +35,8 @@ const ( type grpcCatalogSourceDecorator struct { *v1alpha1.CatalogSource createPodAsUser int64 + opmImage string + utilImage string } type UpdateNotReadyErr struct { @@ -58,7 +62,8 @@ func (s *grpcCatalogSourceDecorator) SelectorForUpdate() labels.Selector { func (s *grpcCatalogSourceDecorator) Labels() map[string]string { return map[string]string{ - CatalogSourceLabelKey: s.GetName(), + CatalogSourceLabelKey: s.GetName(), + install.OLMManagedLabelKey: install.OLMManagedLabelValue, } } @@ -70,7 +75,7 @@ func (s *grpcCatalogSourceDecorator) Annotations() map[string]string { func (s *grpcCatalogSourceDecorator) Service() *corev1.Service { svc := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: s.GetName(), + Name: strings.ReplaceAll(s.GetName(), ".", "-"), Namespace: s.GetNamespace(), }, Spec: corev1.ServiceSpec{ @@ -88,6 +93,7 @@ func (s *grpcCatalogSourceDecorator) Service() *corev1.Service { labels := map[string]string{} hash := HashServiceSpec(svc.Spec) labels[ServiceHashLabelKey] = hash + labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue svc.SetLabels(labels) ownerutil.AddOwner(svc, s.CatalogSource, false, false) return svc @@ -107,6 +113,7 @@ func (s *grpcCatalogSourceDecorator) ServiceAccount() *corev1.ServiceAccount { ObjectMeta: metav1.ObjectMeta{ Name: s.GetName(), Namespace: s.GetNamespace(), + Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, OwnerReferences: []metav1.OwnerReference{ { Name: s.GetName(), @@ -123,7 +130,7 @@ func (s *grpcCatalogSourceDecorator) ServiceAccount() *corev1.ServiceAccount { } func (s *grpcCatalogSourceDecorator) Pod(saName string) *corev1.Pod { - pod := Pod(s.CatalogSource, "registry-server", s.Spec.Image, saName, s.Labels(), s.Annotations(), 5, 10, s.createPodAsUser) + pod := Pod(s.CatalogSource, "registry-server", s.opmImage, s.utilImage, s.Spec.Image, saName, s.Labels(), s.Annotations(), 5, 10, s.createPodAsUser) ownerutil.AddOwner(pod, s.CatalogSource, false, true) return pod } @@ -134,6 +141,8 @@ type GrpcRegistryReconciler struct { OpClient operatorclient.ClientInterface SSAClient *controllerclient.ServerSideApplier createPodAsUser int64 + opmImage string + utilImage string } var _ RegistryReconciler = &GrpcRegistryReconciler{} @@ -191,16 +200,25 @@ func (c *GrpcRegistryReconciler) currentPodsWithCorrectImageAndSpec(source grpcC found := []*corev1.Pod{} newPod := source.Pod(saName) for _, p := range pods { - if p.Spec.Containers[0].Image == source.Spec.Image && podHashMatch(p, newPod) { + if correctImages(source, p) && podHashMatch(p, newPod) { found = append(found, p) } } return found } +func correctImages(source grpcCatalogSourceDecorator, pod *corev1.Pod) bool { + if source.CatalogSource.Spec.GrpcPodConfig != nil && source.CatalogSource.Spec.GrpcPodConfig.ExtractContent != nil { + return pod.Spec.InitContainers[0].Image == source.utilImage && + pod.Spec.InitContainers[1].Image == source.CatalogSource.Spec.Image && + pod.Spec.Containers[0].Image == source.opmImage + } + return pod.Spec.Containers[0].Image == source.CatalogSource.Spec.Image +} + // EnsureRegistryServer ensures that all components of registry server are up to date. func (c *GrpcRegistryReconciler) EnsureRegistryServer(catalogSource *v1alpha1.CatalogSource) error { - source := grpcCatalogSourceDecorator{catalogSource, c.createPodAsUser} + source := grpcCatalogSourceDecorator{CatalogSource: catalogSource, createPodAsUser: c.createPodAsUser, opmImage: c.opmImage, utilImage: c.utilImage} // if service status is nil, we force create every object to ensure they're created the first time overwrite := source.Status.RegistryServiceStatus == nil || !isRegistryServiceStatusValid(&source) @@ -449,7 +467,7 @@ func (c *GrpcRegistryReconciler) removePods(pods []*corev1.Pod, namespace string // CheckRegistryServer returns true if the given CatalogSource is considered healthy; false otherwise. func (c *GrpcRegistryReconciler) CheckRegistryServer(catalogSource *v1alpha1.CatalogSource) (healthy bool, err error) { - source := grpcCatalogSourceDecorator{catalogSource, c.createPodAsUser} + source := grpcCatalogSourceDecorator{CatalogSource: catalogSource, createPodAsUser: c.createPodAsUser, opmImage: c.opmImage, utilImage: c.utilImage} // Check on registry resources // TODO: add gRPC health check if len(c.currentPodsWithCorrectImageAndSpec(source, source.ServiceAccount().GetName())) < 1 || diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler/reconciler.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler/reconciler.go index 88a421a713..d2f120de20 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler/reconciler.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler/reconciler.go @@ -4,7 +4,9 @@ package reconciler import ( "fmt" "hash/fnv" + "path/filepath" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -63,6 +65,8 @@ type registryReconcilerFactory struct { ConfigMapServerImage string SSAClient *controllerclient.ServerSideApplier createPodAsUser int64 + opmImage string + utilImage string } // ReconcilerForSource returns a RegistryReconciler based on the configuration of the given CatalogSource. @@ -85,6 +89,8 @@ func (r *registryReconcilerFactory) ReconcilerForSource(source *operatorsv1alpha OpClient: r.OpClient, SSAClient: r.SSAClient, createPodAsUser: r.createPodAsUser, + opmImage: r.opmImage, + utilImage: r.utilImage, } } else if source.Spec.Address != "" { return &GrpcAddressRegistryReconciler{ @@ -96,7 +102,7 @@ func (r *registryReconcilerFactory) ReconcilerForSource(source *operatorsv1alpha } // NewRegistryReconcilerFactory returns an initialized RegistryReconcilerFactory. -func NewRegistryReconcilerFactory(lister operatorlister.OperatorLister, opClient operatorclient.ClientInterface, configMapServerImage string, now nowFunc, ssaClient *controllerclient.ServerSideApplier, createPodAsUser int64) RegistryReconcilerFactory { +func NewRegistryReconcilerFactory(lister operatorlister.OperatorLister, opClient operatorclient.ClientInterface, configMapServerImage string, now nowFunc, ssaClient *controllerclient.ServerSideApplier, createPodAsUser int64, opmImage, utilImage string) RegistryReconcilerFactory { return ®istryReconcilerFactory{ now: now, Lister: lister, @@ -104,10 +110,12 @@ func NewRegistryReconcilerFactory(lister operatorlister.OperatorLister, opClient ConfigMapServerImage: configMapServerImage, SSAClient: ssaClient, createPodAsUser: createPodAsUser, + opmImage: opmImage, + utilImage: utilImage, } } -func Pod(source *operatorsv1alpha1.CatalogSource, name string, img string, saName string, labels map[string]string, annotations map[string]string, readinessDelay int32, livenessDelay int32, runAsUser int64) *corev1.Pod { +func Pod(source *operatorsv1alpha1.CatalogSource, name, opmImg, utilImage, img, saName string, labels, annotations map[string]string, readinessDelay, livenessDelay int32, runAsUser int64) *corev1.Pod { // make a copy of the labels and annotations to avoid mutating the input parameters podLabels := make(map[string]string) podAnnotations := make(map[string]string) @@ -115,6 +123,7 @@ func Pod(source *operatorsv1alpha1.CatalogSource, name string, img string, saNam for key, value := range labels { podLabels[key] = value } + podLabels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue for key, value := range annotations { podAnnotations[key] = value @@ -227,9 +236,6 @@ func Pod(source *operatorsv1alpha1.CatalogSource, name string, img string, saNam if pod.Spec.Containers[0].Resources.Limits == nil { pod.Spec.Containers[0].Resources.Limits = map[corev1.ResourceName]resource.Quantity{} } - double := *grpcPodConfig.MemoryTarget - double.Add(double.DeepCopy()) - pod.Spec.Containers[0].Resources.Limits[corev1.ResourceMemory] = double grpcPodConfig.MemoryTarget.Format = resource.BinarySI pod.Spec.Containers[0].Env = append(pod.Spec.Containers[0].Env, corev1.EnvVar{ @@ -237,6 +243,58 @@ func Pod(source *operatorsv1alpha1.CatalogSource, name string, img string, saNam Value: grpcPodConfig.MemoryTarget.String() + "B", // k8s resources use Mi, GOMEMLIMIT wants MiB }) } + + // Reconfigure pod to extract content + if grpcPodConfig.ExtractContent != nil { + pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{ + Name: "utilities", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, corev1.Volume{ + Name: "catalog-content", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }) + const utilitiesPath = "/utilities" + utilitiesVolumeMount := corev1.VolumeMount{ + Name: "utilities", + MountPath: utilitiesPath, + } + const catalogPath = "/extracted-catalog" + contentVolumeMount := corev1.VolumeMount{ + Name: "catalog-content", + MountPath: catalogPath, + } + pod.Spec.InitContainers = append(pod.Spec.InitContainers, corev1.Container{ + Name: "extract-utilities", + Image: utilImage, + Command: []string{"cp"}, + Args: []string{"/bin/copy-content", fmt.Sprintf("%s/copy-content", utilitiesPath)}, + VolumeMounts: []corev1.VolumeMount{utilitiesVolumeMount}, + }, corev1.Container{ + Name: "extract-content", + Image: img, + Command: []string{utilitiesPath + "/copy-content"}, + Args: []string{ + "--catalog.from=" + grpcPodConfig.ExtractContent.CatalogDir, + "--catalog.to=" + fmt.Sprintf("%s/catalog", catalogPath), + "--cache.from=" + grpcPodConfig.ExtractContent.CacheDir, + "--cache.to=" + fmt.Sprintf("%s/cache", catalogPath), + }, + VolumeMounts: []corev1.VolumeMount{utilitiesVolumeMount, contentVolumeMount}, + }) + + pod.Spec.Containers[0].Image = opmImg + pod.Spec.Containers[0].Command = []string{"/bin/opm"} + pod.Spec.Containers[0].Args = []string{ + "serve", + filepath.Join(catalogPath, "catalog"), + "--cache-dir=" + filepath.Join(catalogPath, "cache"), + } + pod.Spec.Containers[0].VolumeMounts = append(pod.Spec.Containers[0].VolumeMounts, contentVolumeMount) + } } // Set priorityclass if its annotation exists diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/rbac.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/rbac.go index 45012df0e4..f0079e5016 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/rbac.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/rbac.go @@ -1,8 +1,11 @@ package resolver import ( + "crypto/sha256" + "encoding/json" "fmt" "hash/fnv" + "math/big" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -62,6 +65,37 @@ func (o *OperatorPermissions) AddClusterRoleBinding(clusterRoleBinding *rbacv1.C o.ClusterRoleBindings = append(o.ClusterRoleBindings, clusterRoleBinding) } +const ContentHashLabelKey = "olm.permissions.hash" + +func PolicyRuleHashLabelValue(rules []rbacv1.PolicyRule) (string, error) { + raw, err := json.Marshal(rules) + if err != nil { + return "", err + } + return toBase62(sha256.Sum224(raw)), nil +} + +func RoleReferenceAndSubjectHashLabelValue(roleRef rbacv1.RoleRef, subjects []rbacv1.Subject) (string, error) { + var container = struct { + RoleRef rbacv1.RoleRef + Subjects []rbacv1.Subject + }{ + RoleRef: roleRef, + Subjects: subjects, + } + raw, err := json.Marshal(&container) + if err != nil { + return "", err + } + return toBase62(sha256.Sum224(raw)), nil +} + +func toBase62(hash [28]byte) string { + var i big.Int + i.SetBytes(hash[:]) + return i.Text(62) +} + func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[string]*OperatorPermissions, error) { permissions := map[string]*OperatorPermissions{} @@ -100,6 +134,11 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri }, Rules: permission.Rules, } + hash, err := PolicyRuleHashLabelValue(permission.Rules) + if err != nil { + return nil, fmt.Errorf("failed to hash permission rules: %w", err) + } + role.Labels[ContentHashLabelKey] = hash permissions[permission.ServiceAccountName].AddRole(role) // Create RoleBinding @@ -120,6 +159,11 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri Namespace: csv.GetNamespace(), }}, } + hash, err = RoleReferenceAndSubjectHashLabelValue(roleBinding.RoleRef, roleBinding.Subjects) + if err != nil { + return nil, fmt.Errorf("failed to hash binding content: %w", err) + } + roleBinding.Labels[ContentHashLabelKey] = hash permissions[permission.ServiceAccountName].AddRoleBinding(roleBinding) } @@ -142,6 +186,11 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri }, Rules: permission.Rules, } + hash, err := PolicyRuleHashLabelValue(permission.Rules) + if err != nil { + return nil, fmt.Errorf("failed to hash permission rules: %w", err) + } + role.Labels[ContentHashLabelKey] = hash permissions[permission.ServiceAccountName].AddClusterRole(role) // Create ClusterRoleBinding @@ -162,6 +211,11 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri Namespace: csv.GetNamespace(), }}, } + hash, err = RoleReferenceAndSubjectHashLabelValue(roleBinding.RoleRef, roleBinding.Subjects) + if err != nil { + return nil, fmt.Errorf("failed to hash binding content: %w", err) + } + roleBinding.Labels[ContentHashLabelKey] = hash permissions[permission.ServiceAccountName].AddClusterRoleBinding(roleBinding) } return permissions, nil diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorlister/customresourcedefinition.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorlister/customresourcedefinition.go index 07c60a9126..69cac64e34 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorlister/customresourcedefinition.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorlister/customresourcedefinition.go @@ -4,20 +4,30 @@ import ( "fmt" "sync" - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - aextv1 "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/metadata/metadatalister" ) // UnionCustomResourceDefinitionLister is a custom implementation of an CustomResourceDefinition lister that allows a new -// Lister to be registered on the fly. This Lister lists both v1 and v1beta1 APIVersion (at the newer version) CRDs. +// Lister to be registered on the fly. type UnionCustomResourceDefinitionLister struct { - CustomResourceDefinitionLister aextv1.CustomResourceDefinitionLister + CustomResourceDefinitionLister metadatalister.Lister CustomResourceDefinitionLock sync.RWMutex } +func (ucl *UnionCustomResourceDefinitionLister) Namespace(namespace string) metadatalister.NamespaceLister { + ucl.CustomResourceDefinitionLock.RLock() + defer ucl.CustomResourceDefinitionLock.RUnlock() + + if ucl.CustomResourceDefinitionLister == nil { + panic(fmt.Errorf("no CustomResourceDefinition lister registered")) + } + return ucl.CustomResourceDefinitionLister.Namespace(namespace) +} + // List lists all CustomResourceDefinitions in the indexer. -func (ucl *UnionCustomResourceDefinitionLister) List(selector labels.Selector) (ret []*apiextensionsv1.CustomResourceDefinition, err error) { +func (ucl *UnionCustomResourceDefinitionLister) List(selector labels.Selector) (ret []*metav1.PartialObjectMetadata, err error) { ucl.CustomResourceDefinitionLock.RLock() defer ucl.CustomResourceDefinitionLock.RUnlock() @@ -28,7 +38,7 @@ func (ucl *UnionCustomResourceDefinitionLister) List(selector labels.Selector) ( } // Get retrieves the CustomResourceDefinition with the given name -func (ucl *UnionCustomResourceDefinitionLister) Get(name string) (*apiextensionsv1.CustomResourceDefinition, error) { +func (ucl *UnionCustomResourceDefinitionLister) Get(name string) (*metav1.PartialObjectMetadata, error) { ucl.CustomResourceDefinitionLock.RLock() defer ucl.CustomResourceDefinitionLock.RUnlock() @@ -39,17 +49,17 @@ func (ucl *UnionCustomResourceDefinitionLister) Get(name string) (*apiextensions } // RegisterCustomResourceDefinitionLister registers a new CustomResourceDefinitionLister -func (ucl *UnionCustomResourceDefinitionLister) RegisterCustomResourceDefinitionLister(lister aextv1.CustomResourceDefinitionLister) { +func (ucl *UnionCustomResourceDefinitionLister) RegisterCustomResourceDefinitionLister(lister metadatalister.Lister) { ucl.CustomResourceDefinitionLock.Lock() defer ucl.CustomResourceDefinitionLock.Unlock() ucl.CustomResourceDefinitionLister = lister } -func (l *apiExtensionsV1Lister) RegisterCustomResourceDefinitionLister(lister aextv1.CustomResourceDefinitionLister) { +func (l *apiExtensionsV1Lister) RegisterCustomResourceDefinitionLister(lister metadatalister.Lister) { l.customResourceDefinitionLister.RegisterCustomResourceDefinitionLister(lister) } -func (l *apiExtensionsV1Lister) CustomResourceDefinitionLister() aextv1.CustomResourceDefinitionLister { +func (l *apiExtensionsV1Lister) CustomResourceDefinitionLister() metadatalister.Lister { return l.customResourceDefinitionLister } diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorlister/lister.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorlister/lister.go index 0bf77a89e4..388f38ddaf 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorlister/lister.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorlister/lister.go @@ -1,10 +1,10 @@ package operatorlister import ( - aextv1 "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1" appsv1 "k8s.io/client-go/listers/apps/v1" corev1 "k8s.io/client-go/listers/core/v1" rbacv1 "k8s.io/client-go/listers/rbac/v1" + "k8s.io/client-go/metadata/metadatalister" aregv1 "k8s.io/kube-aggregator/pkg/client/listers/apiregistration/v1" v1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/listers/operators/v1" @@ -88,8 +88,8 @@ type APIRegistrationV1Lister interface { //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . APIExtensionsV1Lister type APIExtensionsV1Lister interface { - RegisterCustomResourceDefinitionLister(lister aextv1.CustomResourceDefinitionLister) - CustomResourceDefinitionLister() aextv1.CustomResourceDefinitionLister + RegisterCustomResourceDefinitionLister(lister metadatalister.Lister) + CustomResourceDefinitionLister() metadatalister.Lister } //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . OperatorsV1alpha1Lister diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorstatus/status.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorstatus/status.go index 4067392c6e..bb0b092d85 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorstatus/status.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorstatus/status.go @@ -228,7 +228,7 @@ func MonitorClusterStatus(name string, syncCh <-chan error, stopCh <-chan struct // if we've reported success, we can sleep longer, otherwise we want to keep watching for // successful if successfulSyncs > 0 { - time.Sleep(5 * time.Minute) + time.Sleep(25 * time.Second) } }, 5*time.Second, stopCh) diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil/util.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil/util.go index 24ff1afe2e..352b2a8025 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil/util.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil/util.go @@ -20,10 +20,9 @@ import ( ) const ( - OwnerKey = "olm.owner" - OwnerNamespaceKey = "olm.owner.namespace" - OwnerKind = "olm.owner.kind" - OwnerPackageServer = "packageserver" + OwnerKey = "olm.owner" + OwnerNamespaceKey = "olm.owner.namespace" + OwnerKind = "olm.owner.kind" ) var ( @@ -272,6 +271,11 @@ func CSVOwnerSelector(owner *operatorsv1alpha1.ClusterServiceVersion) labels.Sel return labels.SelectorFromSet(OwnerLabel(owner, operatorsv1alpha1.ClusterServiceVersionKind)) } +// OperatorGroupOwnerSelector returns a label selector to find generated objects owned by owner +func OperatorGroupOwnerSelector(owner *operatorsv1.OperatorGroup) labels.Selector { + return labels.SelectorFromSet(OwnerLabel(owner, operatorsv1.OperatorGroupKind)) +} + // AddOwner adds an owner to the ownerref list. func AddOwner(object metav1.Object, owner Owner, blockOwnerDeletion, isController bool) { // Most of the time we won't have TypeMeta on the object, so we infer it for types we know about diff --git a/vendor/github.com/operator-framework/operator-registry/alpha/declcfg/declcfg.go b/vendor/github.com/operator-framework/operator-registry/alpha/declcfg/declcfg.go index 994d47a0b7..f688574b1c 100644 --- a/vendor/github.com/operator-framework/operator-registry/alpha/declcfg/declcfg.go +++ b/vendor/github.com/operator-framework/operator-registry/alpha/declcfg/declcfg.go @@ -6,6 +6,8 @@ import ( "errors" "fmt" + prettyunmarshaler "github.com/operator-framework/operator-registry/pkg/prettyunmarshaler" + "golang.org/x/text/cases" utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" @@ -107,7 +109,7 @@ func (m *Meta) UnmarshalJSON(blob []byte) error { // that eat our error type and return a generic error, such that we lose the // ability to errors.As to get this error on the other side. For now, just return // a string error that includes the pretty printed message. - return errors.New(newJSONUnmarshalError(blob, err).Pretty()) + return errors.New(prettyunmarshaler.NewJSONUnmarshalError(blob, err).Pretty()) } // TODO: this function ensures we do not break backwards compatibility with diff --git a/vendor/github.com/operator-framework/operator-registry/alpha/template/composite/composite.go b/vendor/github.com/operator-framework/operator-registry/alpha/template/composite/composite.go index ce2cd0f4dd..41a287c08a 100644 --- a/vendor/github.com/operator-framework/operator-registry/alpha/template/composite/composite.go +++ b/vendor/github.com/operator-framework/operator-registry/alpha/template/composite/composite.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "io" - "net/http" "net/url" "os" "path/filepath" @@ -14,23 +13,6 @@ import ( "k8s.io/apimachinery/pkg/util/yaml" ) -type BuilderMap map[string]Builder - -type CatalogBuilderMap map[string]BuilderMap - -type builderFunc func(BuilderConfig) Builder - -type Template struct { - catalogFile io.Reader - contributionFile io.Reader - validate bool - outputType string - registry image.Registry - registeredBuilders map[string]builderFunc -} - -type TemplateOption func(t *Template) - func WithCatalogFile(catalogFile io.Reader) TemplateOption { return func(t *Template) { t.catalogFile = catalogFile @@ -79,10 +61,6 @@ func NewTemplate(opts ...TemplateOption) *Template { return temp } -type HttpGetter interface { - Get(url string) (*http.Response, error) -} - // FetchCatalogConfig will fetch the catalog configuration file from the given path. // The path can be a local file path OR a URL that returns the raw contents of the catalog // configuration file. @@ -100,7 +78,7 @@ func FetchCatalogConfig(path string, httpGetter HttpGetter) (io.ReadCloser, erro } } else { // Evalute remote catalog config - // If URi is valid, execute fetch + // If URI is valid, execute fetch tempResp, err := httpGetter.Get(catalogURI.String()) if err != nil { return nil, fmt.Errorf("fetching remote catalog config file %q: %v", path, err) @@ -111,26 +89,37 @@ func FetchCatalogConfig(path string, httpGetter HttpGetter) (io.ReadCloser, erro return tempCatalog, nil } -// TODO(everettraven): do we need the context here? If so, how should it be used? -func (t *Template) Render(ctx context.Context, validate bool) error { +func (t *Template) Parse() (*Specs, error) { + var s Specs - catalogFile, err := t.parseCatalogsSpec() + catalogSpec, err := t.parseCatalogsSpec() if err != nil { - return err + return nil, err + } + s.CatalogSpec = catalogSpec + + contributionSpec, err := t.parseContributionSpec() + if err != nil { + return nil, err } + s.ContributionSpec = contributionSpec + + return &s, nil +} - contributionFile, err := t.parseContributionSpec() +func (t *Template) Render(ctx context.Context, validate bool) error { + specs, err := t.Parse() if err != nil { return err } - catalogBuilderMap, err := t.newCatalogBuilderMap(catalogFile.Catalogs, t.outputType) + catalogBuilderMap, err := t.newCatalogBuilderMap(specs.CatalogSpec.Catalogs, t.outputType) if err != nil { return err } // TODO(everettraven): should we return aggregated errors? - for _, component := range contributionFile.Components { + for _, component := range specs.ContributionSpec.Components { if builderMap, ok := (*catalogBuilderMap)[component.Name]; ok { if builder, ok := builderMap[component.Strategy.Template.Schema]; ok { // run the builder corresponding to the schema diff --git a/vendor/github.com/operator-framework/operator-registry/alpha/template/composite/types.go b/vendor/github.com/operator-framework/operator-registry/alpha/template/composite/types.go index 5295a5ddfd..93b53883c5 100644 --- a/vendor/github.com/operator-framework/operator-registry/alpha/template/composite/types.go +++ b/vendor/github.com/operator-framework/operator-registry/alpha/template/composite/types.go @@ -1,6 +1,12 @@ package composite -import "encoding/json" +import ( + "encoding/json" + "io" + "net/http" + + "github.com/operator-framework/operator-registry/pkg/image" +) type TemplateDefinition struct { Schema string @@ -27,3 +33,29 @@ type CustomConfig struct { Args []string Output string } + +type BuilderMap map[string]Builder + +type CatalogBuilderMap map[string]BuilderMap + +type builderFunc func(BuilderConfig) Builder + +type Template struct { + catalogFile io.Reader + contributionFile io.Reader + validate bool + outputType string + registry image.Registry + registeredBuilders map[string]builderFunc +} + +type TemplateOption func(t *Template) + +type Specs struct { + CatalogSpec *CatalogConfig + ContributionSpec *CompositeConfig +} + +type HttpGetter interface { + Get(url string) (*http.Response, error) +} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/cache/json.go b/vendor/github.com/operator-framework/operator-registry/pkg/cache/json.go index 4327082794..7345a2b5ff 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/cache/json.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/cache/json.go @@ -6,15 +6,17 @@ import ( "errors" "fmt" "hash/fnv" + "io" "io/fs" "os" "path/filepath" + "sort" "strings" "github.com/operator-framework/operator-registry/alpha/declcfg" "github.com/operator-framework/operator-registry/pkg/api" "github.com/operator-framework/operator-registry/pkg/registry" - "k8s.io/apimachinery/pkg/util/sets" + "github.com/sirupsen/logrus" ) var _ Cache = &JSON{} @@ -58,31 +60,66 @@ func (q *JSON) ListBundles(ctx context.Context) ([]*api.Bundle, error) { } func (q *JSON) SendBundles(_ context.Context, s registry.BundleSender) error { + var keys []apiBundleKey for _, pkg := range q.packageIndex { - channels := sets.KeySet(pkg.Channels) - for _, chName := range sets.List(channels) { - ch := pkg.Channels[chName] - - bundles := sets.KeySet(ch.Bundles) - for _, bName := range sets.List(bundles) { - b := ch.Bundles[bName] - apiBundle, err := q.loadAPIBundle(apiBundleKey{pkg.Name, ch.Name, b.Name}) - if err != nil { - return fmt.Errorf("convert bundle %q: %v", b.Name, err) - } - if apiBundle.BundlePath != "" { - // The SQLite-based server - // configures its querier to - // omit these fields when - // bundle path is set. - apiBundle.CsvJson = "" - apiBundle.Object = nil - } - if err := s.Send(apiBundle); err != nil { - return err - } + for _, ch := range pkg.Channels { + for _, b := range ch.Bundles { + keys = append(keys, apiBundleKey{pkg.Name, ch.Name, b.Name}) + } + } + } + sort.Slice(keys, func(i, j int) bool { + if keys[i].chName != keys[j].chName { + return keys[i].chName < keys[j].chName + } + if keys[i].pkgName != keys[j].pkgName { + return keys[i].pkgName < keys[j].pkgName + } + return keys[i].name < keys[j].name + }) + var files []*os.File + var readers []io.Reader + for _, key := range keys { + filename, ok := q.apiBundles[key] + if !ok { + return fmt.Errorf("package %q, channel %q, key %q not found", key.pkgName, key.chName, key.name) + } + file, err := os.Open(filename) + if err != nil { + return fmt.Errorf("failed to open file for package %q, channel %q, key %q: %w", key.pkgName, key.chName, key.name, err) + } + files = append(files, file) + readers = append(readers, file) + } + defer func() { + for _, file := range files { + if err := file.Close(); err != nil { + logrus.WithError(err).WithField("file", file.Name()).Warn("could not close file") } } + }() + multiReader := io.MultiReader(readers...) + decoder := json.NewDecoder(multiReader) + index := 0 + for { + var bundle api.Bundle + if err := decoder.Decode(&bundle); err == io.EOF { + break + } else if err != nil { + return fmt.Errorf("failed to decode file for package %q, channel %q, key %q: %w", keys[index].pkgName, keys[index].chName, keys[index].name, err) + } + if bundle.BundlePath != "" { + // The SQLite-based server + // configures its querier to + // omit these fields when + // key path is set. + bundle.CsvJson = "" + bundle.Object = nil + } + if err := s.Send(&bundle); err != nil { + return err + } + index += 1 } return nil } diff --git a/vendor/github.com/operator-framework/operator-registry/alpha/declcfg/errors.go b/vendor/github.com/operator-framework/operator-registry/pkg/prettyunmarshaler/prettyunmarshaler.go similarity index 83% rename from vendor/github.com/operator-framework/operator-registry/alpha/declcfg/errors.go rename to vendor/github.com/operator-framework/operator-registry/pkg/prettyunmarshaler/prettyunmarshaler.go index f5ef115233..2f740151a3 100644 --- a/vendor/github.com/operator-framework/operator-registry/alpha/declcfg/errors.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/prettyunmarshaler/prettyunmarshaler.go @@ -1,4 +1,4 @@ -package declcfg +package prettyunmarshaler import ( "bytes" @@ -8,29 +8,29 @@ import ( "strings" ) -type jsonUnmarshalError struct { +type JsonUnmarshalError struct { data []byte offset int64 err error } -func newJSONUnmarshalError(data []byte, err error) *jsonUnmarshalError { +func NewJSONUnmarshalError(data []byte, err error) *JsonUnmarshalError { var te *json.UnmarshalTypeError if errors.As(err, &te) { - return &jsonUnmarshalError{data: data, offset: te.Offset, err: te} + return &JsonUnmarshalError{data: data, offset: te.Offset, err: te} } var se *json.SyntaxError if errors.As(err, &se) { - return &jsonUnmarshalError{data: data, offset: se.Offset, err: se} + return &JsonUnmarshalError{data: data, offset: se.Offset, err: se} } - return &jsonUnmarshalError{data: data, offset: -1, err: err} + return &JsonUnmarshalError{data: data, offset: -1, err: err} } -func (e *jsonUnmarshalError) Error() string { +func (e *JsonUnmarshalError) Error() string { return e.err.Error() } -func (e *jsonUnmarshalError) Pretty() string { +func (e *JsonUnmarshalError) Pretty() string { if len(e.data) == 0 || e.offset < 0 || e.offset > int64(len(e.data)) { return e.err.Error() } diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/registry/csv.go b/vendor/github.com/operator-framework/operator-registry/pkg/registry/csv.go index ec6f3e3239..8dcdf65adb 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/registry/csv.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/registry/csv.go @@ -2,11 +2,13 @@ package registry import ( "encoding/json" + "errors" "fmt" - "io/ioutil" "os" "path" + prettyunmarshaler "github.com/operator-framework/operator-registry/pkg/prettyunmarshaler" + v1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -82,7 +84,7 @@ type ClusterServiceVersion struct { // ReadCSVFromBundleDirectory tries to parse every YAML file in the directory without inspecting sub-directories and // returns a CSV. According to the strict one CSV per bundle rule, func returns an error if more than one CSV is found. func ReadCSVFromBundleDirectory(bundleDir string) (*ClusterServiceVersion, error) { - dirContent, err := ioutil.ReadDir(bundleDir) + dirContent, err := os.ReadDir(bundleDir) if err != nil { return nil, fmt.Errorf("error reading bundle directory %s, %v", bundleDir, err) } @@ -412,3 +414,56 @@ func (csv *ClusterServiceVersion) GetSubstitutesFor() string { } return substitutesFor } + +func (csv *ClusterServiceVersion) UnmarshalJSON(data []byte) error { + + if err := csv.UnmarshalSpec(data); err != nil { + return err + } + if err := csv.UnmarshalTypeMeta(data); err != nil { + return err + } + if err := csv.UnmarshalObjectMeta(data); err != nil { + return err + } + + return nil +} + +func (csv *ClusterServiceVersion) UnmarshalSpec(data []byte) error { + var m map[string]json.RawMessage + if err := json.Unmarshal(data, &m); err != nil { + return errors.New(prettyunmarshaler.NewJSONUnmarshalError(data, err).Pretty()) + } + + spec, ok := m["spec"] + if !ok { + return nil + } + csv.Spec = spec + + return nil +} + +func (csv *ClusterServiceVersion) UnmarshalTypeMeta(data []byte) error { + var t metav1.TypeMeta + if err := json.Unmarshal(data, &t); err != nil { + return errors.New(prettyunmarshaler.NewJSONUnmarshalError(data, err).Pretty()) + } + csv.TypeMeta = t + + return nil +} + +func (csv *ClusterServiceVersion) UnmarshalObjectMeta(data []byte) error { + var o struct { + Metadata metav1.ObjectMeta `json:"metadata"` + } + if err := json.Unmarshal(data, &o); err != nil { + return errors.New(prettyunmarshaler.NewJSONUnmarshalError(data, err).Pretty()) + } + + csv.ObjectMeta = o.Metadata + + return nil +} diff --git a/vendor/github.com/otiai10/copy/.gitignore b/vendor/github.com/otiai10/copy/.gitignore index 5b5ae0a524..a793485586 100644 --- a/vendor/github.com/otiai10/copy/.gitignore +++ b/vendor/github.com/otiai10/copy/.gitignore @@ -1,3 +1,9 @@ -testdata.copy +test/data.copy +test/owned-by-root coverage.txt vendor +.vagrant +.idea/ + +# Test Specific +test/data/case16/large.file diff --git a/vendor/github.com/otiai10/copy/README.md b/vendor/github.com/otiai10/copy/README.md index 5ad7c57ca9..1cc8fc8c82 100644 --- a/vendor/github.com/otiai10/copy/README.md +++ b/vendor/github.com/otiai10/copy/README.md @@ -1,14 +1,108 @@ # copy +[![Go Reference](https://pkg.go.dev/badge/github.com/otiai10/copy.svg)](https://pkg.go.dev/github.com/otiai10/copy) [![Actions Status](https://github.com/otiai10/copy/workflows/Go/badge.svg)](https://github.com/otiai10/copy/actions) -[![codecov](https://codecov.io/gh/otiai10/copy/branch/master/graph/badge.svg)](https://codecov.io/gh/otiai10/copy) -[![GoDoc](https://godoc.org/github.com/otiai10/copy?status.svg)](https://godoc.org/github.com/otiai10/copy) +[![codecov](https://codecov.io/gh/otiai10/copy/branch/main/graph/badge.svg)](https://codecov.io/gh/otiai10/copy) +[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/otiai10/copy/blob/main/LICENSE) +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fotiai10%2Fcopy.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fotiai10%2Fcopy?ref=badge_shield) +[![CodeQL](https://github.com/otiai10/copy/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/otiai10/copy/actions/workflows/codeql-analysis.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/otiai10/copy)](https://goreportcard.com/report/github.com/otiai10/copy) +[![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/otiai10/copy?sort=semver)](https://pkg.go.dev/github.com/otiai10/copy) +[![Docker Test](https://github.com/otiai10/copy/actions/workflows/docker-test.yml/badge.svg)](https://github.com/otiai10/copy/actions/workflows/docker-test.yml) +[![Vagrant Test](https://github.com/otiai10/copy/actions/workflows/vagrant-test.yml/badge.svg)](https://github.com/otiai10/copy/actions/workflows/vagrant-test.yml) `copy` copies directories recursively. -Example: +# Example Usage ```go -err := Copy("your/directory", "your/directory.copy") +package main + +import ( + "fmt" + cp "github.com/otiai10/copy" +) + +func main() { + err := cp.Copy("your/src", "your/dest") + fmt.Println(err) // nil +} +``` + +# Advanced Usage + +```go +// Options specifies optional actions on copying. +type Options struct { + + // OnSymlink can specify what to do on symlink + OnSymlink func(src string) SymlinkAction + + // OnDirExists can specify what to do when there is a directory already existing in destination. + OnDirExists func(src, dest string) DirExistsAction + + // OnError can let users decide how to handle errors (e.g., you can suppress specific error). + OnError func(src, dest, string, err error) error + + // Skip can specify which files should be skipped + Skip func(srcinfo os.FileInfo, src, dest string) (bool, error) + + // PermissionControl can control permission of + // every entry. + // When you want to add permission 0222, do like + // + // PermissionControl = AddPermission(0222) + // + // or if you even don't want to touch permission, + // + // PermissionControl = DoNothing + // + // By default, PermissionControl = PreservePermission + PermissionControl PermissionControlFunc + + // Sync file after copy. + // Useful in case when file must be on the disk + // (in case crash happens, for example), + // at the expense of some performance penalty + Sync bool + + // Preserve the atime and the mtime of the entries + // On linux we can preserve only up to 1 millisecond accuracy + PreserveTimes bool + + // Preserve the uid and the gid of all entries. + PreserveOwner bool + + // The byte size of the buffer to use for copying files. + // If zero, the internal default buffer of 32KB is used. + // See https://golang.org/pkg/io/#CopyBuffer for more information. + CopyBufferSize uint + + // If you want to add some limitation on reading src file, + // you can wrap the src and provide new reader, + // such as `RateLimitReader` in the test case. + WrapReader func(src io.Reader) io.Reader + + // If given, copy.Copy refers to this fs.FS instead of the OS filesystem. + // e.g., You can use embed.FS to copy files from embedded filesystem. + FS fs.FS +} +``` + +```go +// For example... +opt := Options{ + Skip: func(info os.FileInfo, src, dest string) (bool, error) { + return strings.HasSuffix(src, ".git"), nil + }, +} +err := Copy("your/directory", "your/directory.copy", opt) ``` + +# Issues + +- https://github.com/otiai10/copy/issues + + +## License +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fotiai10%2Fcopy.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fotiai10%2Fcopy?ref=badge_large) \ No newline at end of file diff --git a/vendor/github.com/otiai10/copy/copy.go b/vendor/github.com/otiai10/copy/copy.go index 0ff0e5b258..085db78249 100644 --- a/vendor/github.com/otiai10/copy/copy.go +++ b/vendor/github.com/otiai10/copy/copy.go @@ -2,50 +2,69 @@ package copy import ( "io" + "io/fs" "io/ioutil" "os" "path/filepath" + "time" ) -const ( - // tmpPermissionForDirectory makes the destination directory writable, - // so that stuff can be copied recursively even if any original directory is NOT writable. - // See https://github.com/otiai10/copy/pull/9 for more information. - tmpPermissionForDirectory = os.FileMode(0755) -) +type timespec struct { + Mtime time.Time + Atime time.Time + Ctime time.Time +} // Copy copies src to dest, doesn't matter if src is a directory or a file. -func Copy(src, dest string, opt ...Options) error { +func Copy(src, dest string, opts ...Options) error { + opt := assureOptions(src, dest, opts...) + if opt.FS != nil { + info, err := fs.Stat(opt.FS, src) + if err != nil { + return onError(src, dest, err, opt) + } + return switchboard(src, dest, info, opt) + } info, err := os.Lstat(src) if err != nil { - return err + return onError(src, dest, err, opt) } - return switchboard(src, dest, info, assure(opt...)) + return switchboard(src, dest, info, opt) } // switchboard switches proper copy functions regarding file type, etc... // If there would be anything else here, add a case to this switchboard. -func switchboard(src, dest string, info os.FileInfo, opt Options) error { +func switchboard(src, dest string, info os.FileInfo, opt Options) (err error) { + if info.Mode()&os.ModeDevice != 0 && !opt.Specials { + return onError(src, dest, err, opt) + } + switch { case info.Mode()&os.ModeSymlink != 0: - return onsymlink(src, dest, info, opt) + err = onsymlink(src, dest, opt) case info.IsDir(): - return dcopy(src, dest, info, opt) + err = dcopy(src, dest, info, opt) + case info.Mode()&os.ModeNamedPipe != 0: + err = pcopy(dest, info) default: - return fcopy(src, dest, info, opt) + err = fcopy(src, dest, info, opt) } + + return onError(src, dest, err, opt) } -// copy decide if this src should be copied or not. +// copyNextOrSkip decide if this src should be copied or not. // Because this "copy" could be called recursively, // "info" MUST be given here, NOT nil. -func copy(src, dest string, info os.FileInfo, opt Options) error { - skip, err := opt.Skip(src) - if err != nil { - return err - } - if skip { - return nil +func copyNextOrSkip(src, dest string, info os.FileInfo, opt Options) error { + if opt.Skip != nil { + skip, err := opt.Skip(info, src, dest) + if err != nil { + return err + } + if skip { + return nil + } } return switchboard(src, dest, info, opt) } @@ -55,6 +74,20 @@ func copy(src, dest string, info os.FileInfo, opt Options) error { // and file permission. func fcopy(src, dest string, info os.FileInfo, opt Options) (err error) { + var readcloser io.ReadCloser + if opt.FS != nil { + readcloser, err = opt.FS.Open(src) + } else { + readcloser, err = os.Open(src) + } + if err != nil { + if os.IsNotExist(err) { + return nil + } + return + } + defer fclose(readcloser, &err) + if err = os.MkdirAll(filepath.Dir(dest), os.ModePerm); err != nil { return } @@ -65,24 +98,47 @@ func fcopy(src, dest string, info os.FileInfo, opt Options) (err error) { } defer fclose(f, &err) - if err = os.Chmod(f.Name(), info.Mode()|opt.AddPermission); err != nil { - return + chmodfunc, err := opt.PermissionControl(info, dest) + if err != nil { + return err } + chmodfunc(&err) - s, err := os.Open(src) - if err != nil { - return + var buf []byte = nil + var w io.Writer = f + var r io.Reader = readcloser + + if opt.WrapReader != nil { + r = opt.WrapReader(r) } - defer fclose(s, &err) - if _, err = io.Copy(f, s); err != nil { - return + if opt.CopyBufferSize != 0 { + buf = make([]byte, opt.CopyBufferSize) + // Disable using `ReadFrom` by io.CopyBuffer. + // See https://github.com/otiai10/copy/pull/60#discussion_r627320811 for more details. + w = struct{ io.Writer }{f} + // r = struct{ io.Reader }{s} + } + + if _, err = io.CopyBuffer(w, r, buf); err != nil { + return err } if opt.Sync { err = f.Sync() } + if opt.PreserveOwner { + if err := preserveOwner(src, dest, info); err != nil { + return err + } + } + if opt.PreserveTimes { + if err := preserveTimes(info, dest); err != nil { + return err + } + } + return } @@ -90,48 +146,104 @@ func fcopy(src, dest string, info os.FileInfo, opt Options) (err error) { // with scanning contents inside the directory // and pass everything to "copy" recursively. func dcopy(srcdir, destdir string, info os.FileInfo, opt Options) (err error) { - - originalMode := info.Mode() + if skip, err := onDirExists(opt, srcdir, destdir); err != nil { + return err + } else if skip { + return nil + } // Make dest dir with 0755 so that everything writable. - if err = os.MkdirAll(destdir, tmpPermissionForDirectory); err != nil { - return + chmodfunc, err := opt.PermissionControl(info, destdir) + if err != nil { + return err + } + defer chmodfunc(&err) + + var contents []os.FileInfo + if opt.FS != nil { + entries, err := fs.ReadDir(opt.FS, srcdir) + if err != nil { + return err + } + for _, e := range entries { + info, err := e.Info() + if err != nil { + return err + } + contents = append(contents, info) + } + } else { + contents, err = ioutil.ReadDir(srcdir) } - // Recover dir mode with original one. - defer chmod(destdir, originalMode|opt.AddPermission, &err) - contents, err := ioutil.ReadDir(srcdir) if err != nil { + if os.IsNotExist(err) { + return nil + } return } for _, content := range contents { cs, cd := filepath.Join(srcdir, content.Name()), filepath.Join(destdir, content.Name()) - if err = copy(cs, cd, content, opt); err != nil { + if err = copyNextOrSkip(cs, cd, content, opt); err != nil { // If any error, exit immediately return } } + if opt.PreserveTimes { + if err := preserveTimes(info, destdir); err != nil { + return err + } + } + + if opt.PreserveOwner { + if err := preserveOwner(srcdir, destdir, info); err != nil { + return err + } + } + return } -func onsymlink(src, dest string, info os.FileInfo, opt Options) error { +func onDirExists(opt Options, srcdir, destdir string) (bool, error) { + _, err := os.Stat(destdir) + if err == nil && opt.OnDirExists != nil && destdir != opt.intent.dest { + switch opt.OnDirExists(srcdir, destdir) { + case Replace: + if err := os.RemoveAll(destdir); err != nil { + return false, err + } + case Untouchable: + return true, nil + } // case "Merge" is default behaviour. Go through. + } else if err != nil && !os.IsNotExist(err) { + return true, err // Unwelcome error type...! + } + return false, nil +} +func onsymlink(src, dest string, opt Options) error { switch opt.OnSymlink(src) { case Shallow: - return lcopy(src, dest) + if err := lcopy(src, dest); err != nil { + return err + } + if opt.PreserveTimes { + return preserveLtimes(src, dest) + } + return nil case Deep: orig, err := os.Readlink(src) if err != nil { return err } - info, err = os.Lstat(orig) + info, err := os.Lstat(orig) if err != nil { return err } - return copy(orig, dest, info, opt) + return copyNextOrSkip(orig, dest, info, opt) case Skip: fallthrough default: @@ -144,6 +256,9 @@ func onsymlink(src, dest string, info os.FileInfo, opt Options) error { func lcopy(src, dest string) error { src, err := os.Readlink(src) if err != nil { + if os.IsNotExist(err) { + return nil + } return err } return os.Symlink(src, dest) @@ -152,33 +267,18 @@ func lcopy(src, dest string) error { // fclose ANYHOW closes file, // with asiging error raised during Close, // BUT respecting the error already reported. -func fclose(f *os.File, reported *error) { +func fclose(f io.Closer, reported *error) { if err := f.Close(); *reported == nil { *reported = err } } -// chmod ANYHOW changes file mode, -// with asiging error raised during Chmod, -// BUT respecting the error already reported. -func chmod(dir string, mode os.FileMode, reported *error) { - if err := os.Chmod(dir, mode); *reported == nil { - *reported = err +// onError lets caller to handle errors +// occured when copying a file. +func onError(src, dest string, err error, opt Options) error { + if opt.OnError == nil { + return err } -} -// assure Options struct, should be called only once. -// All optional values MUST NOT BE nil/zero after assured. -func assure(opts ...Options) Options { - if len(opts) == 0 { - return getDefaultOptions() - } - defopt := getDefaultOptions() - if opts[0].OnSymlink == nil { - opts[0].OnSymlink = defopt.OnSymlink - } - if opts[0].Skip == nil { - opts[0].Skip = defopt.Skip - } - return opts[0] + return opt.OnError(src, dest, err) } diff --git a/vendor/github.com/otiai10/copy/copy_namedpipes.go b/vendor/github.com/otiai10/copy/copy_namedpipes.go new file mode 100644 index 0000000000..615ddcd554 --- /dev/null +++ b/vendor/github.com/otiai10/copy/copy_namedpipes.go @@ -0,0 +1,18 @@ +//go:build !windows && !plan9 && !netbsd && !aix && !illumos && !solaris && !js +// +build !windows,!plan9,!netbsd,!aix,!illumos,!solaris,!js + +package copy + +import ( + "os" + "path/filepath" + "syscall" +) + +// pcopy is for just named pipes +func pcopy(dest string, info os.FileInfo) error { + if err := os.MkdirAll(filepath.Dir(dest), os.ModePerm); err != nil { + return err + } + return syscall.Mkfifo(dest, uint32(info.Mode())) +} diff --git a/vendor/github.com/otiai10/copy/copy_namedpipes_x.go b/vendor/github.com/otiai10/copy/copy_namedpipes_x.go new file mode 100644 index 0000000000..38dd9dc724 --- /dev/null +++ b/vendor/github.com/otiai10/copy/copy_namedpipes_x.go @@ -0,0 +1,15 @@ +//go:build windows || plan9 || netbsd || aix || illumos || solaris || js +// +build windows plan9 netbsd aix illumos solaris js + +package copy + +import ( + "os" +) + +// TODO: check plan9 netbsd aix illumos solaris in future + +// pcopy is for just named pipes. Windows doesn't support them +func pcopy(dest string, info os.FileInfo) error { + return nil +} diff --git a/vendor/github.com/otiai10/copy/fileinfo_go1.15.go b/vendor/github.com/otiai10/copy/fileinfo_go1.15.go new file mode 100644 index 0000000000..c0708eaf11 --- /dev/null +++ b/vendor/github.com/otiai10/copy/fileinfo_go1.15.go @@ -0,0 +1,17 @@ +//go:build !go1.16 +// +build !go1.16 + +package copy + +import "os" + +// This is a cloned definition of os.FileInfo (go1.15) or fs.FileInfo (go1.16~) +// A FileInfo describes a file and is returned by Stat. +type fileInfo interface { + // Name() string // base name of the file + // Size() int64 // length in bytes for regular files; system-dependent for others + Mode() os.FileMode // file mode bits + // ModTime() time.Time // modification time + IsDir() bool // abbreviation for Mode().IsDir() + Sys() interface{} // underlying data source (can return nil) +} diff --git a/vendor/github.com/otiai10/copy/fileinfo_go1.16.go b/vendor/github.com/otiai10/copy/fileinfo_go1.16.go new file mode 100644 index 0000000000..01b3fd2499 --- /dev/null +++ b/vendor/github.com/otiai10/copy/fileinfo_go1.16.go @@ -0,0 +1,17 @@ +//go:build go1.16 +// +build go1.16 + +package copy + +import "io/fs" + +// This is a cloned definition of os.FileInfo (go1.15) or fs.FileInfo (go1.16~) +// A FileInfo describes a file and is returned by Stat. +type fileInfo interface { + // Name() string // base name of the file + // Size() int64 // length in bytes for regular files; system-dependent for others + Mode() fs.FileMode // file mode bits + // ModTime() time.Time // modification time + IsDir() bool // abbreviation for Mode().IsDir() + Sys() interface{} // underlying data source (can return nil) +} diff --git a/vendor/github.com/otiai10/copy/options.go b/vendor/github.com/otiai10/copy/options.go index 21504cd1f0..1b4e508332 100644 --- a/vendor/github.com/otiai10/copy/options.go +++ b/vendor/github.com/otiai10/copy/options.go @@ -1,21 +1,74 @@ package copy -import "os" +import ( + "io" + "io/fs" + "os" +) // Options specifies optional actions on copying. type Options struct { + // OnSymlink can specify what to do on symlink OnSymlink func(src string) SymlinkAction + + // OnDirExists can specify what to do when there is a directory already existing in destination. + OnDirExists func(src, dest string) DirExistsAction + + // OnErr lets called decide whether or not to continue on particular copy error. + OnError func(src, dest string, err error) error + // Skip can specify which files should be skipped - Skip func(src string) (bool, error) + Skip func(srcinfo os.FileInfo, src, dest string) (bool, error) + + // Specials includes special files to be copied. default false. + Specials bool + // AddPermission to every entities, // NO MORE THAN 0777 + // @OBSOLETE + // Use `PermissionControl = AddPermission(perm)` instead AddPermission os.FileMode + + // PermissionControl can preserve or even add permission to + // every entries, for example + // + // opt.PermissionControl = AddPermission(0222) + // + // See permission_control.go for more detail. + PermissionControl PermissionControlFunc + // Sync file after copy. // Useful in case when file must be on the disk // (in case crash happens, for example), // at the expense of some performance penalty Sync bool + + // Preserve the atime and the mtime of the entries. + // On linux we can preserve only up to 1 millisecond accuracy. + PreserveTimes bool + + // Preserve the uid and the gid of all entries. + PreserveOwner bool + + // The byte size of the buffer to use for copying files. + // If zero, the internal default buffer of 32KB is used. + // See https://golang.org/pkg/io/#CopyBuffer for more information. + CopyBufferSize uint + + // If you want to add some limitation on reading src file, + // you can wrap the src and provide new reader, + // such as `RateLimitReader` in the test case. + WrapReader func(src io.Reader) io.Reader + + // If given, copy.Copy refers to this fs.FS instead of the OS filesystem. + // e.g., You can use embed.FS to copy files from embedded filesystem. + FS fs.FS + + intent struct { + src string + dest string + } } // SymlinkAction represents what to do on symlink. @@ -30,17 +83,61 @@ const ( Skip ) +// DirExistsAction represents what to do on dest dir. +type DirExistsAction int + +const ( + // Merge preserves or overwrites existing files under the dir (default behavior). + Merge DirExistsAction = iota + // Replace deletes all contents under the dir and copy src files. + Replace + // Untouchable does nothing for the dir, and leaves it as it is. + Untouchable +) + // getDefaultOptions provides default options, // which would be modified by usage-side. -func getDefaultOptions() Options { +func getDefaultOptions(src, dest string) Options { return Options{ OnSymlink: func(string) SymlinkAction { return Shallow // Do shallow copy }, - Skip: func(string) (bool, error) { - return false, nil // Don't skip - }, - AddPermission: 0, // Add nothing - Sync: false, // Do not sync + OnDirExists: nil, // Default behavior is "Merge". + OnError: nil, // Default is "accept error" + Skip: nil, // Do not skip anything + AddPermission: 0, // Add nothing + PermissionControl: PerservePermission, // Just preserve permission + Sync: false, // Do not sync + Specials: false, // Do not copy special files + PreserveTimes: false, // Do not preserve the modification time + CopyBufferSize: 0, // Do not specify, use default bufsize (32*1024) + WrapReader: nil, // Do not wrap src files, use them as they are. + intent: struct { + src string + dest string + }{src, dest}, + } +} + +// assureOptions struct, should be called only once. +// All optional values MUST NOT BE nil/zero after assured. +func assureOptions(src, dest string, opts ...Options) Options { + defopt := getDefaultOptions(src, dest) + if len(opts) == 0 { + return defopt + } + if opts[0].OnSymlink == nil { + opts[0].OnSymlink = defopt.OnSymlink + } + if opts[0].Skip == nil { + opts[0].Skip = defopt.Skip + } + if opts[0].AddPermission > 0 { + opts[0].PermissionControl = AddPermission(opts[0].AddPermission) + } else if opts[0].PermissionControl == nil { + opts[0].PermissionControl = PerservePermission } + opts[0].intent.src = defopt.intent.src + opts[0].intent.dest = defopt.intent.dest + return opts[0] } diff --git a/vendor/github.com/otiai10/copy/permission_control.go b/vendor/github.com/otiai10/copy/permission_control.go new file mode 100644 index 0000000000..97ae12d8e0 --- /dev/null +++ b/vendor/github.com/otiai10/copy/permission_control.go @@ -0,0 +1,48 @@ +package copy + +import ( + "os" +) + +const ( + // tmpPermissionForDirectory makes the destination directory writable, + // so that stuff can be copied recursively even if any original directory is NOT writable. + // See https://github.com/otiai10/copy/pull/9 for more information. + tmpPermissionForDirectory = os.FileMode(0755) +) + +type PermissionControlFunc func(srcinfo fileInfo, dest string) (chmodfunc func(*error), err error) + +var ( + AddPermission = func(perm os.FileMode) PermissionControlFunc { + return func(srcinfo fileInfo, dest string) (func(*error), error) { + orig := srcinfo.Mode() + if srcinfo.IsDir() { + if err := os.MkdirAll(dest, tmpPermissionForDirectory); err != nil { + return func(*error) {}, err + } + } + return func(err *error) { + chmod(dest, orig|perm, err) + }, nil + } + } + PerservePermission PermissionControlFunc = AddPermission(0) + DoNothing PermissionControlFunc = func(srcinfo fileInfo, dest string) (func(*error), error) { + if srcinfo.IsDir() { + if err := os.MkdirAll(dest, srcinfo.Mode()); err != nil { + return func(*error) {}, err + } + } + return func(*error) {}, nil + } +) + +// chmod ANYHOW changes file mode, +// with asiging error raised during Chmod, +// BUT respecting the error already reported. +func chmod(dir string, mode os.FileMode, reported *error) { + if err := os.Chmod(dir, mode); *reported == nil { + *reported = err + } +} diff --git a/vendor/github.com/otiai10/copy/preserve_ltimes.go b/vendor/github.com/otiai10/copy/preserve_ltimes.go new file mode 100644 index 0000000000..cc006d3750 --- /dev/null +++ b/vendor/github.com/otiai10/copy/preserve_ltimes.go @@ -0,0 +1,20 @@ +//go:build !windows && !plan9 && !js +// +build !windows,!plan9,!js + +package copy + +import ( + "golang.org/x/sys/unix" +) + +func preserveLtimes(src, dest string) error { + info := new(unix.Stat_t) + if err := unix.Lstat(src, info); err != nil { + return err + } + + return unix.Lutimes(dest, []unix.Timeval{ + unix.NsecToTimeval(info.Atim.Nano()), + unix.NsecToTimeval(info.Mtim.Nano()), + }) +} diff --git a/vendor/github.com/otiai10/copy/preserve_ltimes_x.go b/vendor/github.com/otiai10/copy/preserve_ltimes_x.go new file mode 100644 index 0000000000..02aec40be6 --- /dev/null +++ b/vendor/github.com/otiai10/copy/preserve_ltimes_x.go @@ -0,0 +1,8 @@ +//go:build windows || js || plan9 +// +build windows js plan9 + +package copy + +func preserveLtimes(src, dest string) error { + return nil // Unsupported +} diff --git a/vendor/github.com/otiai10/copy/preserve_owner.go b/vendor/github.com/otiai10/copy/preserve_owner.go new file mode 100644 index 0000000000..13ec4f5793 --- /dev/null +++ b/vendor/github.com/otiai10/copy/preserve_owner.go @@ -0,0 +1,23 @@ +//go:build !windows && !plan9 +// +build !windows,!plan9 + +package copy + +import ( + "os" + "syscall" +) + +func preserveOwner(src, dest string, info fileInfo) (err error) { + if info == nil { + if info, err = os.Stat(src); err != nil { + return err + } + } + if stat, ok := info.Sys().(*syscall.Stat_t); ok { + if err := os.Chown(dest, int(stat.Uid), int(stat.Gid)); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/otiai10/copy/preserve_owner_x.go b/vendor/github.com/otiai10/copy/preserve_owner_x.go new file mode 100644 index 0000000000..9d8257400b --- /dev/null +++ b/vendor/github.com/otiai10/copy/preserve_owner_x.go @@ -0,0 +1,8 @@ +//go:build windows || plan9 +// +build windows plan9 + +package copy + +func preserveOwner(src, dest string, info fileInfo) (err error) { + return nil +} diff --git a/vendor/github.com/otiai10/copy/preserve_times.go b/vendor/github.com/otiai10/copy/preserve_times.go new file mode 100644 index 0000000000..d89b128980 --- /dev/null +++ b/vendor/github.com/otiai10/copy/preserve_times.go @@ -0,0 +1,11 @@ +package copy + +import "os" + +func preserveTimes(srcinfo os.FileInfo, dest string) error { + spec := getTimeSpec(srcinfo) + if err := os.Chtimes(dest, spec.Atime, spec.Mtime); err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/otiai10/copy/stat_times.go b/vendor/github.com/otiai10/copy/stat_times.go new file mode 100644 index 0000000000..75f45f6e29 --- /dev/null +++ b/vendor/github.com/otiai10/copy/stat_times.go @@ -0,0 +1,22 @@ +//go:build !windows && !darwin && !freebsd && !plan9 && !netbsd && !js +// +build !windows,!darwin,!freebsd,!plan9,!netbsd,!js + +// TODO: add more runtimes + +package copy + +import ( + "os" + "syscall" + "time" +) + +func getTimeSpec(info os.FileInfo) timespec { + stat := info.Sys().(*syscall.Stat_t) + times := timespec{ + Mtime: info.ModTime(), + Atime: time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec)), + Ctime: time.Unix(int64(stat.Ctim.Sec), int64(stat.Ctim.Nsec)), + } + return times +} diff --git a/vendor/github.com/otiai10/copy/stat_times_darwin.go b/vendor/github.com/otiai10/copy/stat_times_darwin.go new file mode 100644 index 0000000000..d4c23d8ef2 --- /dev/null +++ b/vendor/github.com/otiai10/copy/stat_times_darwin.go @@ -0,0 +1,20 @@ +//go:build darwin +// +build darwin + +package copy + +import ( + "os" + "syscall" + "time" +) + +func getTimeSpec(info os.FileInfo) timespec { + stat := info.Sys().(*syscall.Stat_t) + times := timespec{ + Mtime: info.ModTime(), + Atime: time.Unix(stat.Atimespec.Sec, stat.Atimespec.Nsec), + Ctime: time.Unix(stat.Ctimespec.Sec, stat.Ctimespec.Nsec), + } + return times +} diff --git a/vendor/github.com/otiai10/copy/stat_times_freebsd.go b/vendor/github.com/otiai10/copy/stat_times_freebsd.go new file mode 100644 index 0000000000..5309334ef9 --- /dev/null +++ b/vendor/github.com/otiai10/copy/stat_times_freebsd.go @@ -0,0 +1,20 @@ +//go:build freebsd +// +build freebsd + +package copy + +import ( + "os" + "syscall" + "time" +) + +func getTimeSpec(info os.FileInfo) timespec { + stat := info.Sys().(*syscall.Stat_t) + times := timespec{ + Mtime: info.ModTime(), + Atime: time.Unix(int64(stat.Atimespec.Sec), int64(stat.Atimespec.Nsec)), + Ctime: time.Unix(int64(stat.Ctimespec.Sec), int64(stat.Ctimespec.Nsec)), + } + return times +} diff --git a/vendor/github.com/otiai10/copy/stat_times_js.go b/vendor/github.com/otiai10/copy/stat_times_js.go new file mode 100644 index 0000000000..c645771cab --- /dev/null +++ b/vendor/github.com/otiai10/copy/stat_times_js.go @@ -0,0 +1,20 @@ +//go:build js +// +build js + +package copy + +import ( + "os" + "syscall" + "time" +) + +func getTimeSpec(info os.FileInfo) timespec { + stat := info.Sys().(*syscall.Stat_t) + times := timespec{ + Mtime: info.ModTime(), + Atime: time.Unix(int64(stat.Atime), int64(stat.AtimeNsec)), + Ctime: time.Unix(int64(stat.Ctime), int64(stat.CtimeNsec)), + } + return times +} diff --git a/vendor/github.com/otiai10/copy/stat_times_windows.go b/vendor/github.com/otiai10/copy/stat_times_windows.go new file mode 100644 index 0000000000..d6a84a7693 --- /dev/null +++ b/vendor/github.com/otiai10/copy/stat_times_windows.go @@ -0,0 +1,19 @@ +//go:build windows +// +build windows + +package copy + +import ( + "os" + "syscall" + "time" +) + +func getTimeSpec(info os.FileInfo) timespec { + stat := info.Sys().(*syscall.Win32FileAttributeData) + return timespec{ + Mtime: time.Unix(0, stat.LastWriteTime.Nanoseconds()), + Atime: time.Unix(0, stat.LastAccessTime.Nanoseconds()), + Ctime: time.Unix(0, stat.CreationTime.Nanoseconds()), + } +} diff --git a/vendor/github.com/otiai10/copy/stat_times_x.go b/vendor/github.com/otiai10/copy/stat_times_x.go new file mode 100644 index 0000000000..886ddd3fd0 --- /dev/null +++ b/vendor/github.com/otiai10/copy/stat_times_x.go @@ -0,0 +1,18 @@ +//go:build plan9 || netbsd +// +build plan9 netbsd + +package copy + +import ( + "os" +) + +// TODO: check plan9 netbsd in future +func getTimeSpec(info os.FileInfo) timespec { + times := timespec{ + Mtime: info.ModTime(), + Atime: info.ModTime(), + Ctime: info.ModTime(), + } + return times +} diff --git a/vendor/github.com/otiai10/copy/test/data/case18/assets/README.md b/vendor/github.com/otiai10/copy/test/data/case18/assets/README.md new file mode 100644 index 0000000000..5570c7ff58 --- /dev/null +++ b/vendor/github.com/otiai10/copy/test/data/case18/assets/README.md @@ -0,0 +1 @@ +# Hello \ No newline at end of file diff --git a/vendor/github.com/otiai10/copy/test_setup.go b/vendor/github.com/otiai10/copy/test_setup.go new file mode 100644 index 0000000000..64a5292788 --- /dev/null +++ b/vendor/github.com/otiai10/copy/test_setup.go @@ -0,0 +1,20 @@ +//go:build !windows && !plan9 && !netbsd && !aix && !illumos && !solaris && !js +// +build !windows,!plan9,!netbsd,!aix,!illumos,!solaris,!js + +package copy + +import ( + "os" + "syscall" + "testing" +) + +func setup(m *testing.M) { + os.RemoveAll("test/data.copy") + os.MkdirAll("test/data.copy", os.ModePerm) + os.Symlink("test/data/case01", "test/data/case03/case01") + os.Chmod("test/data/case07/dir_0555", 0o555) + os.Chmod("test/data/case07/file_0444", 0o444) + syscall.Mkfifo("test/data/case11/foo/bar", 0o555) + Copy("test/data/case18/assets", "test/data/case18/assets.backup") +} diff --git a/vendor/github.com/otiai10/copy/test_setup_x.go b/vendor/github.com/otiai10/copy/test_setup_x.go new file mode 100644 index 0000000000..4c35b144b1 --- /dev/null +++ b/vendor/github.com/otiai10/copy/test_setup_x.go @@ -0,0 +1,17 @@ +//go:build windows || plan9 || netbsd || aix || illumos || solaris || js +// +build windows plan9 netbsd aix illumos solaris js + +package copy + +import ( + "os" + "testing" +) + +func setup(m *testing.M) { + os.RemoveAll("test/data.copy") + os.MkdirAll("test/data.copy", os.ModePerm) + os.Symlink("test/data/case01", "test/data/case03/case01") + os.Chmod("test/data/case07/dir_0555", 0555) + os.Chmod("test/data/case07/file_0444", 0444) +} diff --git a/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/interface.go b/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/interface.go deleted file mode 100644 index 1bdd40e26c..0000000000 --- a/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/interface.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package apiextensions - -import ( - v1 "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1" - v1beta1 "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1beta1" - internalinterfaces "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/internalinterfaces" -) - -// Interface provides access to each of this group's versions. -type Interface interface { - // V1beta1 provides access to shared informers for resources in V1beta1. - V1beta1() v1beta1.Interface - // V1 provides access to shared informers for resources in V1. - V1() v1.Interface -} - -type group struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// V1beta1 returns a new v1beta1.Interface. -func (g *group) V1beta1() v1beta1.Interface { - return v1beta1.New(g.factory, g.namespace, g.tweakListOptions) -} - -// V1 returns a new v1.Interface. -func (g *group) V1() v1.Interface { - return v1.New(g.factory, g.namespace, g.tweakListOptions) -} diff --git a/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1/customresourcedefinition.go b/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1/customresourcedefinition.go deleted file mode 100644 index 7d1b571112..0000000000 --- a/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1/customresourcedefinition.go +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1 - -import ( - "context" - time "time" - - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - clientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" - internalinterfaces "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/internalinterfaces" - v1 "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" -) - -// CustomResourceDefinitionInformer provides access to a shared informer and lister for -// CustomResourceDefinitions. -type CustomResourceDefinitionInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1.CustomResourceDefinitionLister -} - -type customResourceDefinitionInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// NewCustomResourceDefinitionInformer constructs a new informer for CustomResourceDefinition type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewCustomResourceDefinitionInformer(client clientset.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredCustomResourceDefinitionInformer(client, resyncPeriod, indexers, nil) -} - -// NewFilteredCustomResourceDefinitionInformer constructs a new informer for CustomResourceDefinition type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredCustomResourceDefinitionInformer(client clientset.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.ApiextensionsV1().CustomResourceDefinitions().List(context.TODO(), options) - }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.ApiextensionsV1().CustomResourceDefinitions().Watch(context.TODO(), options) - }, - }, - &apiextensionsv1.CustomResourceDefinition{}, - resyncPeriod, - indexers, - ) -} - -func (f *customResourceDefinitionInformer) defaultInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredCustomResourceDefinitionInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *customResourceDefinitionInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&apiextensionsv1.CustomResourceDefinition{}, f.defaultInformer) -} - -func (f *customResourceDefinitionInformer) Lister() v1.CustomResourceDefinitionLister { - return v1.NewCustomResourceDefinitionLister(f.Informer().GetIndexer()) -} diff --git a/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1/interface.go b/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1/interface.go deleted file mode 100644 index d96e2099ae..0000000000 --- a/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1/interface.go +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1 - -import ( - internalinterfaces "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/internalinterfaces" -) - -// Interface provides access to all the informers in this group version. -type Interface interface { - // CustomResourceDefinitions returns a CustomResourceDefinitionInformer. - CustomResourceDefinitions() CustomResourceDefinitionInformer -} - -type version struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// CustomResourceDefinitions returns a CustomResourceDefinitionInformer. -func (v *version) CustomResourceDefinitions() CustomResourceDefinitionInformer { - return &customResourceDefinitionInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} -} diff --git a/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1beta1/customresourcedefinition.go b/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1beta1/customresourcedefinition.go deleted file mode 100644 index 489c87ae90..0000000000 --- a/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1beta1/customresourcedefinition.go +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1beta1 - -import ( - "context" - time "time" - - apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" - clientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" - internalinterfaces "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/internalinterfaces" - v1beta1 "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1beta1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" -) - -// CustomResourceDefinitionInformer provides access to a shared informer and lister for -// CustomResourceDefinitions. -type CustomResourceDefinitionInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1beta1.CustomResourceDefinitionLister -} - -type customResourceDefinitionInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// NewCustomResourceDefinitionInformer constructs a new informer for CustomResourceDefinition type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewCustomResourceDefinitionInformer(client clientset.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredCustomResourceDefinitionInformer(client, resyncPeriod, indexers, nil) -} - -// NewFilteredCustomResourceDefinitionInformer constructs a new informer for CustomResourceDefinition type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredCustomResourceDefinitionInformer(client clientset.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options v1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.ApiextensionsV1beta1().CustomResourceDefinitions().List(context.TODO(), options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.ApiextensionsV1beta1().CustomResourceDefinitions().Watch(context.TODO(), options) - }, - }, - &apiextensionsv1beta1.CustomResourceDefinition{}, - resyncPeriod, - indexers, - ) -} - -func (f *customResourceDefinitionInformer) defaultInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredCustomResourceDefinitionInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *customResourceDefinitionInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&apiextensionsv1beta1.CustomResourceDefinition{}, f.defaultInformer) -} - -func (f *customResourceDefinitionInformer) Lister() v1beta1.CustomResourceDefinitionLister { - return v1beta1.NewCustomResourceDefinitionLister(f.Informer().GetIndexer()) -} diff --git a/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1beta1/interface.go b/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1beta1/interface.go deleted file mode 100644 index f78edbb593..0000000000 --- a/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1beta1/interface.go +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1beta1 - -import ( - internalinterfaces "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/internalinterfaces" -) - -// Interface provides access to all the informers in this group version. -type Interface interface { - // CustomResourceDefinitions returns a CustomResourceDefinitionInformer. - CustomResourceDefinitions() CustomResourceDefinitionInformer -} - -type version struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// CustomResourceDefinitions returns a CustomResourceDefinitionInformer. -func (v *version) CustomResourceDefinitions() CustomResourceDefinitionInformer { - return &customResourceDefinitionInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} -} diff --git a/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/factory.go b/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/factory.go deleted file mode 100644 index e2243ef6c6..0000000000 --- a/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/factory.go +++ /dev/null @@ -1,251 +0,0 @@ -/* -Copyright The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package externalversions - -import ( - reflect "reflect" - sync "sync" - time "time" - - clientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" - apiextensions "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions" - internalinterfaces "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/internalinterfaces" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - cache "k8s.io/client-go/tools/cache" -) - -// SharedInformerOption defines the functional option type for SharedInformerFactory. -type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory - -type sharedInformerFactory struct { - client clientset.Interface - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc - lock sync.Mutex - defaultResync time.Duration - customResync map[reflect.Type]time.Duration - - informers map[reflect.Type]cache.SharedIndexInformer - // startedInformers is used for tracking which informers have been started. - // This allows Start() to be called multiple times safely. - startedInformers map[reflect.Type]bool - // wg tracks how many goroutines were started. - wg sync.WaitGroup - // shuttingDown is true when Shutdown has been called. It may still be running - // because it needs to wait for goroutines. - shuttingDown bool -} - -// WithCustomResyncConfig sets a custom resync period for the specified informer types. -func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { - return func(factory *sharedInformerFactory) *sharedInformerFactory { - for k, v := range resyncConfig { - factory.customResync[reflect.TypeOf(k)] = v - } - return factory - } -} - -// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. -func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { - return func(factory *sharedInformerFactory) *sharedInformerFactory { - factory.tweakListOptions = tweakListOptions - return factory - } -} - -// WithNamespace limits the SharedInformerFactory to the specified namespace. -func WithNamespace(namespace string) SharedInformerOption { - return func(factory *sharedInformerFactory) *sharedInformerFactory { - factory.namespace = namespace - return factory - } -} - -// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. -func NewSharedInformerFactory(client clientset.Interface, defaultResync time.Duration) SharedInformerFactory { - return NewSharedInformerFactoryWithOptions(client, defaultResync) -} - -// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. -// Listers obtained via this SharedInformerFactory will be subject to the same filters -// as specified here. -// Deprecated: Please use NewSharedInformerFactoryWithOptions instead -func NewFilteredSharedInformerFactory(client clientset.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { - return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) -} - -// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. -func NewSharedInformerFactoryWithOptions(client clientset.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { - factory := &sharedInformerFactory{ - client: client, - namespace: v1.NamespaceAll, - defaultResync: defaultResync, - informers: make(map[reflect.Type]cache.SharedIndexInformer), - startedInformers: make(map[reflect.Type]bool), - customResync: make(map[reflect.Type]time.Duration), - } - - // Apply all options - for _, opt := range options { - factory = opt(factory) - } - - return factory -} - -func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { - f.lock.Lock() - defer f.lock.Unlock() - - if f.shuttingDown { - return - } - - for informerType, informer := range f.informers { - if !f.startedInformers[informerType] { - f.wg.Add(1) - // We need a new variable in each loop iteration, - // otherwise the goroutine would use the loop variable - // and that keeps changing. - informer := informer - go func() { - defer f.wg.Done() - informer.Run(stopCh) - }() - f.startedInformers[informerType] = true - } - } -} - -func (f *sharedInformerFactory) Shutdown() { - f.lock.Lock() - f.shuttingDown = true - f.lock.Unlock() - - // Will return immediately if there is nothing to wait for. - f.wg.Wait() -} - -func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { - informers := func() map[reflect.Type]cache.SharedIndexInformer { - f.lock.Lock() - defer f.lock.Unlock() - - informers := map[reflect.Type]cache.SharedIndexInformer{} - for informerType, informer := range f.informers { - if f.startedInformers[informerType] { - informers[informerType] = informer - } - } - return informers - }() - - res := map[reflect.Type]bool{} - for informType, informer := range informers { - res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) - } - return res -} - -// InternalInformerFor returns the SharedIndexInformer for obj using an internal -// client. -func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { - f.lock.Lock() - defer f.lock.Unlock() - - informerType := reflect.TypeOf(obj) - informer, exists := f.informers[informerType] - if exists { - return informer - } - - resyncPeriod, exists := f.customResync[informerType] - if !exists { - resyncPeriod = f.defaultResync - } - - informer = newFunc(f.client, resyncPeriod) - f.informers[informerType] = informer - - return informer -} - -// SharedInformerFactory provides shared informers for resources in all known -// API group versions. -// -// It is typically used like this: -// -// ctx, cancel := context.Background() -// defer cancel() -// factory := NewSharedInformerFactory(client, resyncPeriod) -// defer factory.WaitForStop() // Returns immediately if nothing was started. -// genericInformer := factory.ForResource(resource) -// typedInformer := factory.SomeAPIGroup().V1().SomeType() -// factory.Start(ctx.Done()) // Start processing these informers. -// synced := factory.WaitForCacheSync(ctx.Done()) -// for v, ok := range synced { -// if !ok { -// fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v) -// return -// } -// } -// -// // Creating informers can also be created after Start, but then -// // Start must be called again: -// anotherGenericInformer := factory.ForResource(resource) -// factory.Start(ctx.Done()) -type SharedInformerFactory interface { - internalinterfaces.SharedInformerFactory - - // Start initializes all requested informers. They are handled in goroutines - // which run until the stop channel gets closed. - Start(stopCh <-chan struct{}) - - // Shutdown marks a factory as shutting down. At that point no new - // informers can be started anymore and Start will return without - // doing anything. - // - // In addition, Shutdown blocks until all goroutines have terminated. For that - // to happen, the close channel(s) that they were started with must be closed, - // either before Shutdown gets called or while it is waiting. - // - // Shutdown may be called multiple times, even concurrently. All such calls will - // block until all goroutines have terminated. - Shutdown() - - // WaitForCacheSync blocks until all started informers' caches were synced - // or the stop channel gets closed. - WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool - - // ForResource gives generic access to a shared informer of the matching type. - ForResource(resource schema.GroupVersionResource) (GenericInformer, error) - - // InternalInformerFor returns the SharedIndexInformer for obj using an internal - // client. - InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer - - Apiextensions() apiextensions.Interface -} - -func (f *sharedInformerFactory) Apiextensions() apiextensions.Interface { - return apiextensions.New(f, f.namespace, f.tweakListOptions) -} diff --git a/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/generic.go b/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/generic.go deleted file mode 100644 index 86f79cd417..0000000000 --- a/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/generic.go +++ /dev/null @@ -1,67 +0,0 @@ -/* -Copyright The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package externalversions - -import ( - "fmt" - - v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - v1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" - schema "k8s.io/apimachinery/pkg/runtime/schema" - cache "k8s.io/client-go/tools/cache" -) - -// GenericInformer is type of SharedIndexInformer which will locate and delegate to other -// sharedInformers based on type -type GenericInformer interface { - Informer() cache.SharedIndexInformer - Lister() cache.GenericLister -} - -type genericInformer struct { - informer cache.SharedIndexInformer - resource schema.GroupResource -} - -// Informer returns the SharedIndexInformer. -func (f *genericInformer) Informer() cache.SharedIndexInformer { - return f.informer -} - -// Lister returns the GenericLister. -func (f *genericInformer) Lister() cache.GenericLister { - return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) -} - -// ForResource gives generic access to a shared informer of the matching type -// TODO extend this to unknown resources with a client pool -func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { - switch resource { - // Group=apiextensions.k8s.io, Version=v1 - case v1.SchemeGroupVersion.WithResource("customresourcedefinitions"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Apiextensions().V1().CustomResourceDefinitions().Informer()}, nil - - // Group=apiextensions.k8s.io, Version=v1beta1 - case v1beta1.SchemeGroupVersion.WithResource("customresourcedefinitions"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Apiextensions().V1beta1().CustomResourceDefinitions().Informer()}, nil - - } - - return nil, fmt.Errorf("no informer found for %v", resource) -} diff --git a/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go b/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go deleted file mode 100644 index da6eadaa7f..0000000000 --- a/vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package internalinterfaces - -import ( - time "time" - - clientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - cache "k8s.io/client-go/tools/cache" -) - -// NewInformerFunc takes clientset.Interface and time.Duration to return a SharedIndexInformer. -type NewInformerFunc func(clientset.Interface, time.Duration) cache.SharedIndexInformer - -// SharedInformerFactory a small interface to allow for adding an informer without an import cycle -type SharedInformerFactory interface { - Start(stopCh <-chan struct{}) - InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer -} - -// TweakListOptionsFunc is a function that transforms a v1.ListOptions. -type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/vendor/k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1/customresourcedefinition.go b/vendor/k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1/customresourcedefinition.go deleted file mode 100644 index d83c58bc62..0000000000 --- a/vendor/k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1/customresourcedefinition.go +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1 - -import ( - v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" -) - -// CustomResourceDefinitionLister helps list CustomResourceDefinitions. -// All objects returned here must be treated as read-only. -type CustomResourceDefinitionLister interface { - // List lists all CustomResourceDefinitions in the indexer. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1.CustomResourceDefinition, err error) - // Get retrieves the CustomResourceDefinition from the index for a given name. - // Objects returned here must be treated as read-only. - Get(name string) (*v1.CustomResourceDefinition, error) - CustomResourceDefinitionListerExpansion -} - -// customResourceDefinitionLister implements the CustomResourceDefinitionLister interface. -type customResourceDefinitionLister struct { - indexer cache.Indexer -} - -// NewCustomResourceDefinitionLister returns a new CustomResourceDefinitionLister. -func NewCustomResourceDefinitionLister(indexer cache.Indexer) CustomResourceDefinitionLister { - return &customResourceDefinitionLister{indexer: indexer} -} - -// List lists all CustomResourceDefinitions in the indexer. -func (s *customResourceDefinitionLister) List(selector labels.Selector) (ret []*v1.CustomResourceDefinition, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1.CustomResourceDefinition)) - }) - return ret, err -} - -// Get retrieves the CustomResourceDefinition from the index for a given name. -func (s *customResourceDefinitionLister) Get(name string) (*v1.CustomResourceDefinition, error) { - obj, exists, err := s.indexer.GetByKey(name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1.Resource("customresourcedefinition"), name) - } - return obj.(*v1.CustomResourceDefinition), nil -} diff --git a/vendor/k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1/expansion_generated.go b/vendor/k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1/expansion_generated.go deleted file mode 100644 index 609d86be39..0000000000 --- a/vendor/k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1/expansion_generated.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1 - -// CustomResourceDefinitionListerExpansion allows custom methods to be added to -// CustomResourceDefinitionLister. -type CustomResourceDefinitionListerExpansion interface{} diff --git a/vendor/k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1beta1/customresourcedefinition.go b/vendor/k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1beta1/customresourcedefinition.go deleted file mode 100644 index c57fd40d8f..0000000000 --- a/vendor/k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1beta1/customresourcedefinition.go +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1beta1 - -import ( - v1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" -) - -// CustomResourceDefinitionLister helps list CustomResourceDefinitions. -// All objects returned here must be treated as read-only. -type CustomResourceDefinitionLister interface { - // List lists all CustomResourceDefinitions in the indexer. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1beta1.CustomResourceDefinition, err error) - // Get retrieves the CustomResourceDefinition from the index for a given name. - // Objects returned here must be treated as read-only. - Get(name string) (*v1beta1.CustomResourceDefinition, error) - CustomResourceDefinitionListerExpansion -} - -// customResourceDefinitionLister implements the CustomResourceDefinitionLister interface. -type customResourceDefinitionLister struct { - indexer cache.Indexer -} - -// NewCustomResourceDefinitionLister returns a new CustomResourceDefinitionLister. -func NewCustomResourceDefinitionLister(indexer cache.Indexer) CustomResourceDefinitionLister { - return &customResourceDefinitionLister{indexer: indexer} -} - -// List lists all CustomResourceDefinitions in the indexer. -func (s *customResourceDefinitionLister) List(selector labels.Selector) (ret []*v1beta1.CustomResourceDefinition, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.CustomResourceDefinition)) - }) - return ret, err -} - -// Get retrieves the CustomResourceDefinition from the index for a given name. -func (s *customResourceDefinitionLister) Get(name string) (*v1beta1.CustomResourceDefinition, error) { - obj, exists, err := s.indexer.GetByKey(name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1beta1.Resource("customresourcedefinition"), name) - } - return obj.(*v1beta1.CustomResourceDefinition), nil -} diff --git a/vendor/k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1beta1/expansion_generated.go b/vendor/k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1beta1/expansion_generated.go deleted file mode 100644 index 429782deb0..0000000000 --- a/vendor/k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1beta1/expansion_generated.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1beta1 - -// CustomResourceDefinitionListerExpansion allows custom methods to be added to -// CustomResourceDefinitionLister. -type CustomResourceDefinitionListerExpansion interface{} diff --git a/vendor/modules.txt b/vendor/modules.txt index 572308f4ba..8b2f2b1b93 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -163,7 +163,7 @@ github.com/coreos/go-systemd/v22/journal # github.com/cpuguy83/go-md2man/v2 v2.0.2 ## explicit; go 1.11 github.com/cpuguy83/go-md2man/v2/md2man -# github.com/cyphar/filepath-securejoin v0.2.3 +# github.com/cyphar/filepath-securejoin v0.2.4 ## explicit; go 1.13 github.com/cyphar/filepath-securejoin # github.com/davecgh/go-spew v1.1.1 @@ -226,7 +226,7 @@ github.com/docker/go-metrics # github.com/docker/go-units v0.5.0 ## explicit github.com/docker/go-units -# github.com/emicklei/go-restful/v3 v3.10.1 +# github.com/emicklei/go-restful/v3 v3.10.2 ## explicit; go 1.13 github.com/emicklei/go-restful/v3 github.com/emicklei/go-restful/v3/log @@ -642,7 +642,7 @@ github.com/openshift/client-go/config/informers/externalversions/config github.com/openshift/client-go/config/informers/externalversions/config/v1 github.com/openshift/client-go/config/informers/externalversions/internalinterfaces github.com/openshift/client-go/config/listers/config/v1 -# github.com/operator-framework/api v0.17.8-0.20230803152844-704ae942c4a9 => ./staging/api +# github.com/operator-framework/api v0.17.8-0.20230908201838-28c6773d2b74 => ./staging/api ## explicit; go 1.19 github.com/operator-framework/api/crds github.com/operator-framework/api/pkg/constraints @@ -663,6 +663,7 @@ github.com/operator-framework/api/pkg/validation/internal # github.com/operator-framework/operator-lifecycle-manager v0.0.0-00010101000000-000000000000 => ./staging/operator-lifecycle-manager ## explicit; go 1.20 github.com/operator-framework/operator-lifecycle-manager/cmd/catalog +github.com/operator-framework/operator-lifecycle-manager/cmd/copy-content github.com/operator-framework/operator-lifecycle-manager/cmd/olm github.com/operator-framework/operator-lifecycle-manager/cmd/package-server github.com/operator-framework/operator-lifecycle-manager/pkg/api/client @@ -695,11 +696,13 @@ github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operator github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/decorators github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/internal/alongside github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/internal/pruning +github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/labeller github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/overrides github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/overrides/inject github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/plugins github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/openshift +github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/validatingroundtripper github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/grpc github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler @@ -754,8 +757,8 @@ github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/stor github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/version github.com/operator-framework/operator-lifecycle-manager/pkg/version github.com/operator-framework/operator-lifecycle-manager/util/cpb -# github.com/operator-framework/operator-registry v1.27.1 => ./staging/operator-registry -## explicit; go 1.19 +# github.com/operator-framework/operator-registry v1.29.0 => ./staging/operator-registry +## explicit; go 1.20 github.com/operator-framework/operator-registry/alpha/action github.com/operator-framework/operator-registry/alpha/declcfg github.com/operator-framework/operator-registry/alpha/model @@ -805,12 +808,13 @@ github.com/operator-framework/operator-registry/pkg/lib/semver github.com/operator-framework/operator-registry/pkg/lib/tmp github.com/operator-framework/operator-registry/pkg/lib/validation github.com/operator-framework/operator-registry/pkg/mirror +github.com/operator-framework/operator-registry/pkg/prettyunmarshaler github.com/operator-framework/operator-registry/pkg/registry github.com/operator-framework/operator-registry/pkg/server github.com/operator-framework/operator-registry/pkg/sqlite github.com/operator-framework/operator-registry/pkg/sqlite/migrations -# github.com/otiai10/copy v1.2.0 -## explicit; go 1.12 +# github.com/otiai10/copy v1.12.0 +## explicit; go 1.18 github.com/otiai10/copy # github.com/pbnjay/strptime v0.0.0-20140226051138-5c05b0d668c9 ## explicit @@ -1424,13 +1428,6 @@ k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1 k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1 -k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions -k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions -k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1 -k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1beta1 -k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/internalinterfaces -k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1 -k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1beta1 # k8s.io/apimachinery v0.27.2 ## explicit; go 1.20 k8s.io/apimachinery/pkg/api/equality