diff --git a/.github/workflows/porch-e2e.yml b/.github/workflows/porch-e2e.yml deleted file mode 100644 index c6ebe360ec..0000000000 --- a/.github/workflows/porch-e2e.yml +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2022 The kpt 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. - -name: Porch End-to-End Tests -on: - push: - paths-ignore: - - "docs/**" - - "site/**" - - "demos/**" - - "Formula/**" - - "mdtogo/**" - - "package-examples/**" - - "release/**" - - "scripts/**" - - "commands/**" - - "internal/cmd**" - - "porch/docs/**" - - "porch/config/samples/**" - pull_request: - paths-ignore: - - "docs/**" - - "site/**" - - "demos/**" - - "Formula/**" - - "mdtogo/**" - - "package-examples/**" - - "release/**" - - "scripts/**" - - "commands/**" - - "internal/cmd**" - - "porch/docs/**" - - "porch/config/samples/**" - -jobs: - tests: - name: Porch End-to-End Tests - runs-on: ubuntu-latest - strategy: - matrix: - image: - - "kindest/node:v1.23.4@sha256:0e34f0d0fd448aa2f2819cfd74e99fe5793a6e4938b328f657c8e3f81ee0dfb9" - - steps: - - name: Free up disk space - run: sudo rm -rf /usr/share/dotnet && sudo rm -rf /opt/ghc && sudo rm -rf "/usr/local/share/boost" && sudo rm -rf "$AGENT_TOOLSDIRECTORY" - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version: '>=1.21.6' - - name: Checkout Porch - uses: actions/checkout@v3 - - name: Build kpt - run: go install . - - name: Build Docker Images - run: IMAGE_REPO=porch-kind IMAGE_TAG=${GITHUB_SHA:0:8} make build-images - working-directory: ./porch - - name: Install KinD - uses: engineerd/setup-kind@aa272fe2a7309878ffc2a81c56cfe3ef108ae7d0 # v0.5.0 - with: - version: "v0.13.0" - image: ${{ matrix.image }} - - name: Load Images - run: | - kind load docker-image porch-kind/porch-server:${GITHUB_SHA:0:8} - kind load docker-image porch-kind/porch-controllers:${GITHUB_SHA:0:8} - kind load docker-image porch-kind/porch-function-runner:${GITHUB_SHA:0:8} - kind load docker-image porch-kind/porch-wrapper-server:${GITHUB_SHA:0:8} - kind load docker-image porch-kind/test-git-server:${GITHUB_SHA:0:8} - - name: Install Porch - run: | - echo ${KUBECONFIG} - IMAGE_REPO=porch-kind IMAGE_TAG=${GITHUB_SHA:0:8} make deployment-config - kubectl apply --wait --recursive --filename ./.build/deploy - kubectl rollout status deployment function-runner --namespace porch-system - kubectl rollout status deployment porch-controllers --namespace porch-system - kubectl rollout status deployment porch-server --namespace porch-system - working-directory: ./porch - - name: Wait For Server - run: | - for i in {1..10}; do - sleep $i - if kubectl api-resources; then - echo "Server is up" - break - fi - done - - name: e2e test - run: E2E=1 go test -v -timeout 20m . - working-directory: ./porch/test/e2e - - name: Porch CLI e2e test - run: make test-porch - - name: porch e2e logs - if: always() - run: | - name=$(kubectl -n porch-system get pod -l app=porch-server -o custom-columns=NAME:.metadata.name --no-headers=true) - kubectl -n porch-system logs $name > porch-e2e-server.log - - name: Archive logs - if: always() - uses: actions/upload-artifact@v3 - with: - name: porch-e2e-server.log - path: porch-e2e-server.log diff --git a/.github/workflows/porch.yml b/.github/workflows/porch.yml deleted file mode 100644 index 615ba94377..0000000000 --- a/.github/workflows/porch.yml +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2022 The kpt 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. - -name: Porch - -on: - push: - paths-ignore: - - "docs/**" - - "site/**" - pull_request: - paths-ignore: - - "docs/**" - - "site/**" - -jobs: - tests: - name: Porch Unit Tests - runs-on: ubuntu-latest - steps: - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version: '>=1.21.6' - - name: Run Porch Unit Tests - uses: actions/checkout@v3 - - name: Verify format / headers etc - run: scripts/verify-fix-all.sh - working-directory: ./porch - - name: Build - run: make porch - working-directory: ./porch - - name: Test - run: make test - working-directory: ./porch - - name: Tidy - run: make tidy diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 53119bf60a..a0a2602308 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -104,8 +104,7 @@ Coming soon ### Package Orchestrator -Package orchestrator code live under `porch` directory in this repo. Please see the -[developer docs for porch](porch/docs/development.md) to learn more. +Package orchestrator code has been moved to the Nephio project: https://github.com/nephio-project/porch ### Function Catalog diff --git a/commands/alpha/alphacmd.go b/commands/alpha/alphacmd.go index 0a5ee9bced..87931dea0a 100644 --- a/commands/alpha/alphacmd.go +++ b/commands/alpha/alphacmd.go @@ -19,10 +19,7 @@ import ( "github.com/GoogleContainerTools/kpt/commands/alpha/license" "github.com/GoogleContainerTools/kpt/commands/alpha/live" - "github.com/GoogleContainerTools/kpt/commands/alpha/repo" "github.com/GoogleContainerTools/kpt/commands/alpha/rollouts" - "github.com/GoogleContainerTools/kpt/commands/alpha/rpkg" - "github.com/GoogleContainerTools/kpt/commands/alpha/sync" "github.com/GoogleContainerTools/kpt/commands/alpha/wasm" "github.com/GoogleContainerTools/kpt/internal/docs/generated/alphadocs" @@ -49,9 +46,6 @@ func GetCommand(ctx context.Context, _, version string) *cobra.Command { } alpha.AddCommand( - repo.NewCommand(ctx, version), - rpkg.NewCommand(ctx, version), - sync.NewCommand(ctx, version), wasm.NewCommand(ctx, version), live.GetCommand(ctx, "", version), license.NewCommand(ctx, version), diff --git a/commands/alpha/repo/get/command.go b/commands/alpha/repo/get/command.go deleted file mode 100644 index da62311a8d..0000000000 --- a/commands/alpha/repo/get/command.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2022 The kpt 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. - -package get - -import ( - "context" - "strings" - - "github.com/GoogleContainerTools/kpt/internal/docs/generated/repodocs" - "github.com/GoogleContainerTools/kpt/internal/errors" - "github.com/GoogleContainerTools/kpt/internal/options" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/cli-runtime/pkg/printers" - "k8s.io/client-go/rest" - "k8s.io/kubectl/pkg/cmd/get" -) - -const ( - command = "cmdrepoget" -) - -func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command { - return newRunner(ctx, rcg).Command -} - -func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner { - r := &runner{ - ctx: ctx, - getFlags: options.Get{ConfigFlags: rcg}, - printFlags: get.NewGetPrintFlags(), - } - c := &cobra.Command{ - Use: "get [REPOSITORY_NAME]", - Aliases: []string{"ls", "list"}, - Short: repodocs.GetShort, - Long: repodocs.GetShort + "\n" + repodocs.GetLong, - Example: repodocs.GetExamples, - PreRunE: r.preRunE, - RunE: r.runE, - Hidden: porch.HidePorchCommands, - } - r.Command = c - - // Create flags - r.getFlags.AddFlags(c) - r.printFlags.AddFlags(c) - return r -} - -type runner struct { - ctx context.Context - Command *cobra.Command - - // Flags - getFlags options.Get - printFlags *get.PrintFlags - - requestTable bool -} - -func (r *runner) preRunE(cmd *cobra.Command, _ []string) error { - outputOption := cmd.Flags().Lookup("output").Value.String() - if strings.Contains(outputOption, "custom-columns") || outputOption == "yaml" || strings.Contains(outputOption, "json") { - r.requestTable = false - } else { - r.requestTable = true - } - return nil -} - -func (r *runner) runE(cmd *cobra.Command, args []string) error { - const op errors.Op = command + ".runE" - - // For some reason our use of k8s libraries result in error when decoding - // RepositoryList when we use strongly typed data. Therefore for now we - // use unstructured communication. - // The error is: `no kind "RepositoryList" is registered for the internal - // version of group "config.porch.kpt.dev" in scheme`. Of course there _is_ - // no such kind since CRDs seem to have only versioned resources. - b, err := r.getFlags.ResourceBuilder() - if err != nil { - return err - } - - // TODO: Support table mode over proto - // TODO: Print namespace in multi-namespace mode - b = b.Unstructured() - - if len(args) > 0 { - b.ResourceNames("repository", args...) - } else { - b = b.SelectAllParam(true). - ResourceTypes("repository") - } - - b = b.ContinueOnError().Latest().Flatten() - - if r.requestTable { - b = b.TransformRequests(func(req *rest.Request) { - req.SetHeader("Accept", strings.Join([]string{ - "application/json;as=Table;g=meta.k8s.io;v=v1", - "application/json", - }, ",")) - }) - } - res := b.Do() - if err := res.Err(); err != nil { - return errors.E(op, err) - } - - infos, err := res.Infos() - if err != nil { - return errors.E(op, err) - } - - printer, err := r.printFlags.ToPrinter() - if err != nil { - return errors.E(op, err) - } - - if r.requestTable { - printer = &get.TablePrinter{ - Delegate: printer, - } - } - - w := printers.GetNewTabWriter(cmd.OutOrStdout()) - - for _, i := range infos { - if err := printer.PrintObj(i.Object, w); err != nil { - return errors.E(op, err) - } - } - - if err := w.Flush(); err != nil { - return errors.E(op, err) - } - - return nil -} diff --git a/commands/alpha/repo/reg/command.go b/commands/alpha/repo/reg/command.go deleted file mode 100644 index df1c5c6255..0000000000 --- a/commands/alpha/repo/reg/command.go +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2022 The kpt 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. - -package reg - -import ( - "context" - "fmt" - "strings" - - "github.com/GoogleContainerTools/kpt/internal/docs/generated/repodocs" - "github.com/GoogleContainerTools/kpt/internal/errors" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/spf13/cobra" - coreapi "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/cli-runtime/pkg/genericclioptions" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - command = "cmdreporeg" -) - -func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner { - r := &runner{ - ctx: ctx, - cfg: rcg, - } - c := &cobra.Command{ - Use: "reg REPOSITORY", - Aliases: []string{"register"}, - Short: repodocs.RegShort, - Long: repodocs.RegShort + "\n" + repodocs.RegLong, - Example: repodocs.RegExamples, - PreRunE: r.preRunE, - RunE: r.runE, - Hidden: porch.HidePorchCommands, - } - r.Command = c - - c.Flags().StringVar(&r.directory, "directory", "/", "Directory within the repository where to look for packages.") - c.Flags().StringVar(&r.branch, "branch", "main", "Branch in the repository where finalized packages are committed.") - c.Flags().BoolVar(&r.createBranch, "create-branch", false, "Create the package branch if it doesn't already exist.") - c.Flags().StringVar(&r.name, "name", "", "Name of the package repository. If unspecified, will use the name portion (last segment) of the repository URL.") - c.Flags().StringVar(&r.description, "description", "", "Brief description of the package repository.") - c.Flags().BoolVar(&r.deployment, "deployment", false, "Repository is a deployment repository; packages in a deployment repository are considered deployment-ready.") - c.Flags().StringVar(&r.username, "repo-basic-username", "", "Username for repository authentication using basic auth.") - c.Flags().StringVar(&r.password, "repo-basic-password", "", "Password for repository authentication using basic auth.") - c.Flags().BoolVar(&r.workloadIdentity, "repo-workload-identity", false, "Use workload identity for authentication with the repo") - - return r -} - -func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command { - return newRunner(ctx, rcg).Command -} - -type runner struct { - ctx context.Context - cfg *genericclioptions.ConfigFlags - client client.Client - Command *cobra.Command - - // Flags - directory string - branch string - createBranch bool - name string - description string - deployment bool - username string - password string - workloadIdentity bool -} - -func (r *runner) preRunE(_ *cobra.Command, _ []string) error { - const op errors.Op = command + ".preRunE" - client, err := porch.CreateClientWithFlags(r.cfg) - if err != nil { - return errors.E(op, err) - } - r.client = client - return nil -} - -func (r *runner) runE(_ *cobra.Command, args []string) error { - const op errors.Op = command + ".runE" - - if len(args) == 0 { - return errors.E(op, "repository is required positional argument") - } - - repository := args[0] - - var git *configapi.GitRepository - var oci *configapi.OciRepository - var rt configapi.RepositoryType - - if strings.HasPrefix(repository, "oci://") { - rt = configapi.RepositoryTypeOCI - oci = &configapi.OciRepository{ - Registry: repository[6:], - } - if r.name == "" { - r.name = porch.LastSegment(repository) - } - } else { - rt = configapi.RepositoryTypeGit - // TODO: better parsing. - // t, err := parse.GitParseArgs(r.ctx, []string{repository, "."}) - // if err != nil { - // return errors.E(op, err) - // } - git = &configapi.GitRepository{ - Repo: repository, - Branch: r.branch, - CreateBranch: r.createBranch, - Directory: r.directory, - } - - if r.name == "" { - r.name = porch.LastSegment(repository) - } - } - - secret, err := r.buildAuthSecret() - if err != nil { - return err - } - if secret != nil { - if err := r.client.Create(r.ctx, secret); err != nil { - return errors.E(op, err) - } - - if git != nil { - git.SecretRef.Name = secret.Name - } - if oci != nil { - oci.SecretRef.Name = secret.Name - } - } - - if err := r.client.Create(r.ctx, &configapi.Repository{ - TypeMeta: metav1.TypeMeta{ - Kind: "Repository", - APIVersion: configapi.GroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: r.name, - Namespace: *r.cfg.Namespace, - }, - Spec: configapi.RepositorySpec{ - Description: r.description, - Type: rt, - Content: configapi.RepositoryContentPackage, - Deployment: r.deployment, - Git: git, - Oci: oci, - }, - }); err != nil { - return errors.E(op, err) - } - - return nil -} - -func (r *runner) buildAuthSecret() (*coreapi.Secret, error) { - var basicAuth bool - var workloadIdentity bool - - if r.username != "" || r.password != "" { - basicAuth = true - } - - workloadIdentity = r.workloadIdentity - - if workloadIdentity && basicAuth { - return nil, fmt.Errorf("both username/password and workload identity specified") - } - - switch { - case workloadIdentity: - return &coreapi.Secret{ - TypeMeta: metav1.TypeMeta{ - Kind: "Secret", - APIVersion: coreapi.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("%s-auth", r.name), - Namespace: *r.cfg.Namespace, - }, - Data: map[string][]byte{}, - Type: "kpt.dev/workload-identity-auth", - }, nil - case basicAuth: - return &coreapi.Secret{ - TypeMeta: metav1.TypeMeta{ - Kind: "Secret", - APIVersion: coreapi.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("%s-auth", r.name), - Namespace: *r.cfg.Namespace, - }, - Data: map[string][]byte{ - "username": []byte(r.username), - "password": []byte(r.password), - }, - Type: coreapi.SecretTypeBasicAuth, - }, nil - } - return nil, nil -} diff --git a/commands/alpha/repo/reg/command_test.go b/commands/alpha/repo/reg/command_test.go deleted file mode 100644 index d69ffa87c0..0000000000 --- a/commands/alpha/repo/reg/command_test.go +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright 2022 The kpt 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. - -package reg - -import ( - "encoding/json" - "flag" - "io" - "net/http" - "net/http/httptest" - "os" - "path/filepath" - "strings" - "testing" - - fakeprinter "github.com/GoogleContainerTools/kpt/pkg/printer/fake" - "github.com/google/go-cmp/cmp" - "gopkg.in/yaml.v3" - "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/client-go/rest" -) - -var ( - update = flag.Bool("update", false, "update golden files") -) - -func TestMain(m *testing.M) { - flag.Parse() - os.Exit(m.Run()) -} - -type httpAction struct { - method string - path string - wantRequest string - sendResponse string -} - -type testcase struct { - name string - args []string - actions []httpAction // http request to expect and responses to send back -} - -func TestRepoReg(t *testing.T) { - testdata, err := filepath.Abs(filepath.Join(".", "testdata")) - if err != nil { - t.Fatalf("Failed to find testdata: %v", err) - } - - for _, tc := range []testcase{ - { - name: "SimpleRegister", - args: []string{"https://github.com/platkrm/test-blueprints"}, - actions: []httpAction{ - { - method: http.MethodPost, - path: "/apis/config.porch.kpt.dev/v1alpha1/namespaces/default/repositories", - wantRequest: "simple-repository.yaml", - sendResponse: "simple-repository.yaml", - }, - }, - }, - { - name: "AuthRegister", - args: []string{"https://github.com/platkrm/test-blueprints.git", "--repo-basic-username=test-username", "--repo-basic-password=test-password"}, - actions: []httpAction{ - { - method: http.MethodPost, - path: "/api/v1/namespaces/default/secrets", - wantRequest: "auth-secret.yaml", - sendResponse: "auth-secret.yaml", - }, - { - method: http.MethodPost, - path: "/apis/config.porch.kpt.dev/v1alpha1/namespaces/default/repositories", - wantRequest: "auth-repository.yaml", - sendResponse: "auth-repository.yaml", - }, - }, - }, - { - name: "FullRegister", - args: []string{ - "https://github.com/platkrm/test-blueprints.git", - "--name=repository-resource-name", - "--description=\"Test Repository Description\"", - "--deployment", - "--directory=/catalog", - "--branch=main-branch", - "--create-branch", - "--namespace=repository-namespace", - }, - actions: []httpAction{ - { - method: http.MethodPost, - path: "/apis/config.porch.kpt.dev/v1alpha1/namespaces/repository-namespace/repositories", - wantRequest: "full-repository.yaml", - sendResponse: "full-repository.yaml", - }, - }, - }, - } { - t.Run(tc.name, func(t *testing.T) { - // Create fake Porch Server - porch := createFakePorch(t, tc.actions, func(action httpAction, w http.ResponseWriter, r *http.Request) { - // TODO: contents of this function is generic; move to shared utility in testutil. - var requestBody []byte - switch r.Header.Get("Content-Encoding") { - case "": - b, err := io.ReadAll(r.Body) - if err != nil { - t.Fatalf("Failed to read request body: %v", err) - } - requestBody = b - - default: - t.Fatalf("unhandled content-encoding %q", r.Header.Get("Content-Encoding")) - } - - var body interface{} - switch r.Header.Get("Content-Type") { - case "application/json": - if err := json.Unmarshal(requestBody, &body); err != nil { - t.Fatalf("Failed to unmarshal body: %v\n%s\n", err, string(requestBody)) - } - - // case "application/vnd.kubernetes.protobuf": - // Proto encoding is not handled https://kubernetes.io/docs/reference/using-api/api-concepts/#protobuf-encoding - - default: - t.Fatalf("unhandled content-type %q", r.Header.Get("Content-Type")) - } - - wantFile := filepath.Join(testdata, action.wantRequest) - - if *update { - data, err := yaml.Marshal(body) - if err != nil { - t.Fatalf("Failed to marshal request body as YAML: %v", err) - } - if err := os.WriteFile(wantFile, data, 0644); err != nil { - t.Fatalf("Failed to update golden file %q: %v", wantFile, err) - } - } - - var want interface{} - wantBytes, err := os.ReadFile(wantFile) - if err != nil { - t.Fatalf("Failed to reead golden file %q: %v", wantFile, err) - } - if err := yaml.Unmarshal(wantBytes, &want); err != nil { - t.Fatalf("Failed to unmarshal expected body %q: %v", wantFile, err) - } - - if !cmp.Equal(want, body) { - t.Errorf("Unexpected request body for %q (-want, +got) %s", r.RequestURI, cmp.Diff(want, body)) - } - - respData, err := os.ReadFile(filepath.Join(testdata, action.sendResponse)) - if err != nil { - t.Fatalf("Failed to read response file %q: %v", action.sendResponse, err) - } - var resp interface{} - if err := yaml.Unmarshal(respData, &resp); err != nil { - t.Fatalf("Failed to unmarshal desired response %q: %v", action.sendResponse, err) - } - respJSON, err := json.Marshal(resp) - if err != nil { - t.Fatalf("Failed to marshal response body as JSON: %v", err) - } - - w.Header().Add("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - if _, err := w.Write(respJSON); err != nil { - t.Errorf("Failed to write resonse body %q: %v", action.sendResponse, err) - } - }) - - // Create a test HTTP server. - server := httptest.NewServer(porch) - defer server.Close() - - // Create Kubeconfig - url := server.URL - usePersistentConfig := false - rcg := genericclioptions.NewConfigFlags(usePersistentConfig) - rcg.APIServer = &url - rcg.WrapConfigFn = func(restConfig *rest.Config) *rest.Config { - // Force use of JSON encoding - restConfig.ContentType = "application/json" - return restConfig - } - namespace := "default" - rcg.Namespace = &namespace - ctx := fakeprinter.CtxWithDefaultPrinter() - - cmd := NewCommand(ctx, rcg) - rcg.AddFlags(cmd.PersistentFlags()) // Add global flags - cmd.SetArgs(tc.args) - if err := cmd.Execute(); err != nil { - t.Errorf("Executing repo register %s failed: %v", strings.Join(tc.args, " "), err) - } - }) - } -} - -func createFakePorch(t *testing.T, actions []httpAction, handler func(action httpAction, w http.ResponseWriter, r *http.Request)) *fakePorch { - actionMap := map[request]httpAction{} - for _, a := range actions { - actionMap[request{ - method: a.method, - url: a.path, - }] = a - } - return &fakePorch{ - T: t, - actions: actionMap, - handler: handler, - } -} - -// TODO: Move the below to shared testing utility -type request struct { - method, url string -} - -type fakePorch struct { - *testing.T - actions map[request]httpAction - handler func(action httpAction, w http.ResponseWriter, r *http.Request) -} - -var _ http.Handler = &fakePorch{} - -func (p *fakePorch) ServeHTTP(w http.ResponseWriter, r *http.Request) { - p.Logf("%s\n", r.RequestURI) - action, ok := p.actions[request{method: r.Method, url: r.URL.Path}] - if !ok { - p.Logf("handler not found for method %q url %q", r.Method, r.URL.Path) - w.WriteHeader(http.StatusNotFound) - return - } - p.handler(action, w, r) -} diff --git a/commands/alpha/repo/reg/testdata/auth-repository.yaml b/commands/alpha/repo/reg/testdata/auth-repository.yaml deleted file mode 100644 index a7deb45c94..0000000000 --- a/commands/alpha/repo/reg/testdata/auth-repository.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Repository -metadata: - creationTimestamp: null - name: test-blueprints - namespace: default -spec: - content: Package - git: - branch: main - directory: / - repo: https://github.com/platkrm/test-blueprints.git - secretRef: - name: test-blueprints-auth - type: git -status: {} diff --git a/commands/alpha/repo/reg/testdata/auth-secret.yaml b/commands/alpha/repo/reg/testdata/auth-secret.yaml deleted file mode 100644 index e1cc11d8a7..0000000000 --- a/commands/alpha/repo/reg/testdata/auth-secret.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v1 -data: - password: dGVzdC1wYXNzd29yZA== - username: dGVzdC11c2VybmFtZQ== -kind: Secret -metadata: - creationTimestamp: null - name: test-blueprints-auth - namespace: default -type: kubernetes.io/basic-auth diff --git a/commands/alpha/repo/reg/testdata/full-repository.yaml b/commands/alpha/repo/reg/testdata/full-repository.yaml deleted file mode 100644 index a3650ae640..0000000000 --- a/commands/alpha/repo/reg/testdata/full-repository.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Repository -metadata: - creationTimestamp: null - name: repository-resource-name - namespace: repository-namespace -spec: - content: Package - deployment: true - description: '"Test Repository Description"' - git: - branch: main-branch - createBranch: true - directory: /catalog - repo: https://github.com/platkrm/test-blueprints.git - secretRef: - name: "" - type: git -status: {} diff --git a/commands/alpha/repo/reg/testdata/simple-repository.yaml b/commands/alpha/repo/reg/testdata/simple-repository.yaml deleted file mode 100644 index 9739eb97b3..0000000000 --- a/commands/alpha/repo/reg/testdata/simple-repository.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Repository -metadata: - creationTimestamp: null - name: test-blueprints - namespace: default -spec: - content: Package - git: - branch: main - directory: / - repo: https://github.com/platkrm/test-blueprints - secretRef: - name: "" - type: git -status: {} diff --git a/commands/alpha/repo/repocmd.go b/commands/alpha/repo/repocmd.go deleted file mode 100644 index f33c788197..0000000000 --- a/commands/alpha/repo/repocmd.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2022 The kpt 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. - -package repo - -import ( - "context" - "flag" - "fmt" - - "github.com/GoogleContainerTools/kpt/commands/alpha/repo/get" - "github.com/GoogleContainerTools/kpt/commands/alpha/repo/reg" - "github.com/GoogleContainerTools/kpt/commands/alpha/repo/unreg" - "github.com/GoogleContainerTools/kpt/internal/docs/generated/repodocs" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/client-go/rest" -) - -func NewCommand(ctx context.Context, version string) *cobra.Command { - repo := &cobra.Command{ - Use: "repo", - Aliases: []string{"repository"}, - Short: "[Alpha] " + repodocs.RepoShort, - Long: "[Alpha] " + repodocs.RepoLong, - RunE: func(cmd *cobra.Command, args []string) error { - h, err := cmd.Flags().GetBool("help") - if err != nil { - return err - } - if h { - return cmd.Help() - } - return cmd.Usage() - }, - Hidden: porch.HidePorchCommands, - } - - pf := repo.PersistentFlags() - - kubeflags := genericclioptions.NewConfigFlags(true) - kubeflags.AddFlags(pf) - - kubeflags.WrapConfigFn = func(rc *rest.Config) *rest.Config { - rc.UserAgent = fmt.Sprintf("kpt/%s", version) - return rc - } - - pf.AddGoFlagSet(flag.CommandLine) - - repo.AddCommand( - reg.NewCommand(ctx, kubeflags), - get.NewCommand(ctx, kubeflags), - unreg.NewCommand(ctx, kubeflags), - ) - - return repo -} diff --git a/commands/alpha/repo/unreg/command.go b/commands/alpha/repo/unreg/command.go deleted file mode 100644 index e498e6c951..0000000000 --- a/commands/alpha/repo/unreg/command.go +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2022 The kpt 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. - -package unreg - -import ( - "context" - "fmt" - - "github.com/GoogleContainerTools/kpt/internal/docs/generated/repodocs" - "github.com/GoogleContainerTools/kpt/internal/errors" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/spf13/cobra" - coreapi "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/cli-runtime/pkg/genericclioptions" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - command = "cmdrepounreg" -) - -func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command { - return newRunner(ctx, rcg).Command -} - -func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner { - r := &runner{ - ctx: ctx, - cfg: rcg, - } - c := &cobra.Command{ - Use: "unreg REPOSITORY [flags]", - Aliases: []string{"unregister"}, - Short: repodocs.UnregShort, - Long: repodocs.UnregShort + "\n" + repodocs.UnregLong, - Example: repodocs.UnregExamples, - PreRunE: r.preRunE, - RunE: r.runE, - Hidden: porch.HidePorchCommands, - } - r.Command = c - - c.Flags().BoolVar(&r.keepSecret, "keep-auth-secret", false, "Keep the auth secret associated with the repository registration, if any") - - return r -} - -type runner struct { - ctx context.Context - cfg *genericclioptions.ConfigFlags - client client.Client - Command *cobra.Command - - // Flags - keepSecret bool -} - -func (r *runner) preRunE(_ *cobra.Command, _ []string) error { - const op errors.Op = command + ".preRunE" - client, err := porch.CreateClientWithFlags(r.cfg) - if err != nil { - return errors.E(op, err) - } - r.client = client - return nil -} - -func (r *runner) runE(_ *cobra.Command, args []string) error { - const op errors.Op = command + ".runE" - - if len(args) == 0 { - return errors.E(op, fmt.Errorf("REPOSITORY is a required positional argument")) - } - - repository := args[0] - - var repo configapi.Repository - if err := r.client.Get(r.ctx, client.ObjectKey{ - Namespace: *r.cfg.Namespace, - Name: repository, - }, &repo); err != nil { - return errors.E(op, err) - } - if err := r.client.Delete(r.ctx, &configapi.Repository{ - TypeMeta: metav1.TypeMeta{ - Kind: "Repository", - APIVersion: configapi.GroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: repo.Name, - Namespace: repo.Namespace, - }, - }); err != nil { - return errors.E(op, err) - } - - if r.keepSecret { - return nil - } - - secret := getSecretName(&repo) - if secret == "" { - return nil - } - - if err := r.client.Delete(r.ctx, &coreapi.Secret{ - TypeMeta: metav1.TypeMeta{ - Kind: "Secret", - APIVersion: coreapi.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: secret, - Namespace: repo.Namespace, - }, - }); err != nil { - return errors.E(op, fmt.Errorf("failed to delete Secret %s: %w", secret, err)) - } - - return nil -} - -func getSecretName(repo *configapi.Repository) string { - if repo.Spec.Git != nil { - return repo.Spec.Git.SecretRef.Name - } - if repo.Spec.Oci != nil { - return repo.Spec.Oci.SecretRef.Name - } - return "" -} diff --git a/commands/alpha/rpkg/approve/command.go b/commands/alpha/rpkg/approve/command.go deleted file mode 100644 index ebfd0d63a5..0000000000 --- a/commands/alpha/rpkg/approve/command.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2022 The kpt 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. - -package approve - -import ( - "context" - "fmt" - "strings" - - "github.com/GoogleContainerTools/kpt/internal/docs/generated/rpkgdocs" - "github.com/GoogleContainerTools/kpt/internal/errors" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/client-go/rest" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - command = "cmdrpkgapprove" -) - -func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command { - return newRunner(ctx, rcg).Command -} - -func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner { - r := &runner{ - ctx: ctx, - cfg: rcg, - client: nil, - } - - c := &cobra.Command{ - Use: "approve PACKAGE", - Short: rpkgdocs.ApproveShort, - Long: rpkgdocs.ApproveShort + "\n" + rpkgdocs.ApproveLong, - Example: rpkgdocs.ApproveExamples, - PreRunE: r.preRunE, - RunE: r.runE, - Hidden: porch.HidePorchCommands, - } - r.Command = c - - return r -} - -type runner struct { - ctx context.Context - cfg *genericclioptions.ConfigFlags - client rest.Interface - Command *cobra.Command - - // Flags -} - -func (r *runner) preRunE(_ *cobra.Command, _ []string) error { - const op errors.Op = command + ".preRunE" - - client, err := porch.CreateRESTClient(r.cfg) - if err != nil { - return errors.E(op, err) - } - r.client = client - return nil -} - -func (r *runner) runE(_ *cobra.Command, args []string) error { - const op errors.Op = command + ".runE" - var messages []string - - namespace := *r.cfg.Namespace - - for _, name := range args { - if err := porch.UpdatePackageRevisionApproval(r.ctx, r.client, client.ObjectKey{ - Namespace: namespace, - Name: name, - }, v1alpha1.PackageRevisionLifecyclePublished); err != nil { - messages = append(messages, err.Error()) - fmt.Fprintf(r.Command.ErrOrStderr(), "%s failed (%s)\n", name, err) - } else { - fmt.Fprintf(r.Command.OutOrStderr(), "%s approved\n", name) - } - } - - if len(messages) > 0 { - return errors.E(op, fmt.Errorf("errors:\n %s", strings.Join(messages, "\n "))) - } - - return nil -} diff --git a/commands/alpha/rpkg/clone/command.go b/commands/alpha/rpkg/clone/command.go deleted file mode 100644 index 5c206055f7..0000000000 --- a/commands/alpha/rpkg/clone/command.go +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright 2022 The kpt 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. - -package clone - -import ( - "context" - "fmt" - "strings" - - "github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/util" - "github.com/GoogleContainerTools/kpt/internal/docs/generated/rpkgdocs" - "github.com/GoogleContainerTools/kpt/internal/errors" - "github.com/GoogleContainerTools/kpt/internal/util/parse" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/spf13/cobra" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/cli-runtime/pkg/genericclioptions" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - command = "cmdrpkgclone" -) - -var ( - strategies = []string{ - string(porchapi.ResourceMerge), - string(porchapi.FastForward), - string(porchapi.ForceDeleteReplace), - } -) - -func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command { - return newRunner(ctx, rcg).Command -} - -func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner { - r := &runner{ - ctx: ctx, - cfg: rcg, - } - c := &cobra.Command{ - Use: "clone SOURCE_PACKAGE NAME", - Short: rpkgdocs.CloneShort, - Long: rpkgdocs.CloneShort + "\n" + rpkgdocs.CloneLong, - Example: rpkgdocs.CloneExamples, - PreRunE: r.preRunE, - RunE: r.runE, - Hidden: porch.HidePorchCommands, - } - r.Command = c - - c.Flags().StringVar(&r.strategy, "strategy", string(porchapi.ResourceMerge), - "update strategy that should be used when updating this package; one of: "+strings.Join(strategies, ",")) - c.Flags().StringVar(&r.directory, "directory", "", "Directory within the repository where the upstream package is located.") - c.Flags().StringVar(&r.ref, "ref", "", "Branch in the repository where the upstream package is located.") - c.Flags().StringVar(&r.repository, "repository", "", "Repository to which package will be cloned (downstream repository).") - c.Flags().StringVar(&r.workspace, "workspace", "v1", "Workspace name of the downstream package.") - - return r -} - -type runner struct { - ctx context.Context - cfg *genericclioptions.ConfigFlags - client client.Client - Command *cobra.Command - - clone porchapi.PackageCloneTaskSpec - - // Flags - strategy string - directory string - ref string - repository string // Target repository - workspace string // Target workspaceName - target string // Target package name -} - -func (r *runner) preRunE(_ *cobra.Command, args []string) error { - const op errors.Op = command + ".preRunE" - client, err := porch.CreateClientWithFlags(r.cfg) - if err != nil { - return errors.E(op, err) - } - r.client = client - - mergeStrategy, err := toMergeStrategy(r.strategy) - if err != nil { - return errors.E(op, err) - } - r.clone.Strategy = mergeStrategy - - if len(args) < 2 { - return errors.E(op, fmt.Errorf("SOURCE_PACKAGE and NAME are required positional arguments; %d provided", len(args))) - } - - if r.repository == "" { - return errors.E(op, fmt.Errorf("--repository is required to specify downstream repository")) - } - - if r.workspace == "" { - return errors.E(op, fmt.Errorf("--workspace is required to specify downstream workspace name")) - } - - source := args[0] - target := args[1] - - pkgExists, err := util.PackageAlreadyExists(r.ctx, r.client, r.repository, target, *r.cfg.Namespace) - if err != nil { - return err - } - if pkgExists { - return fmt.Errorf("`clone` cannot create a new revision for package %q that already exists in repo %q; make subsequent revisions using `copy`", - target, r.repository) - } - - switch { - case strings.HasPrefix(source, "oci://"): - r.clone.Upstream.Type = porchapi.RepositoryTypeOCI - r.clone.Upstream.Oci = &porchapi.OciPackage{ - Image: source, - } - - case strings.Contains(source, "/"): - if parse.HasGitSuffix(source) { // extra parsing required - repo, dir, ref, err := parse.URL(source) - if err != nil { - return err - } - // throw error if values set by flags contradict values parsed from SOURCE_PACKAGE - if r.directory != "" && dir != "" && r.directory != dir { - return errors.E(op, fmt.Errorf("directory %s specified by --directory contradicts directory %s specified by SOURCE_PACKAGE", - r.directory, dir)) - } - if r.ref != "" && ref != "" && r.ref != ref { - return errors.E(op, fmt.Errorf("ref %s specified by --ref contradicts ref %s specified by SOURCE_PACKAGE", - r.ref, ref)) - } - // grab the values parsed from SOURCE_PACKAGE - if r.directory == "" { - r.directory = dir - } - if r.ref == "" { - r.ref = ref - } - source = repo + ".git" // parse.ParseURL removes the git suffix, we need to add it back - } - if r.ref == "" { - r.ref = "main" - } - if r.directory == "" { - r.directory = "/" - } - r.clone.Upstream.Type = porchapi.RepositoryTypeGit - r.clone.Upstream.Git = &porchapi.GitPackage{ - Repo: source, - Ref: r.ref, - Directory: r.directory, - } - // TODO: support authn - - default: - r.clone.Upstream.UpstreamRef = &porchapi.PackageRevisionRef{ - Name: source, - } - } - - r.target = target - return nil -} - -func (r *runner) runE(cmd *cobra.Command, _ []string) error { - const op errors.Op = command + ".runE" - - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: *r.cfg.Namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: r.target, - WorkspaceName: porchapi.WorkspaceName(r.workspace), - RepositoryName: r.repository, - Tasks: []porchapi.Task{ - { - Type: porchapi.TaskTypeClone, - Clone: &r.clone, - }, - }, - }, - } - if err := r.client.Create(r.ctx, pr); err != nil { - return errors.E(op, err) - } - - fmt.Fprintf(cmd.OutOrStdout(), "%s created\n", pr.Name) - return nil -} - -func toMergeStrategy(strategy string) (porchapi.PackageMergeStrategy, error) { - switch strategy { - case string(porchapi.ResourceMerge): - return porchapi.ResourceMerge, nil - case string(porchapi.FastForward): - return porchapi.FastForward, nil - case string(porchapi.ForceDeleteReplace): - return porchapi.ForceDeleteReplace, nil - default: - return "", fmt.Errorf("invalid strategy: %q", strategy) - } -} diff --git a/commands/alpha/rpkg/copy/command.go b/commands/alpha/rpkg/copy/command.go deleted file mode 100644 index 9e6b52f1a2..0000000000 --- a/commands/alpha/rpkg/copy/command.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2022 The kpt 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. - -package copy - -import ( - "context" - "fmt" - - "github.com/GoogleContainerTools/kpt/internal/docs/generated/rpkgdocs" - "github.com/GoogleContainerTools/kpt/internal/errors" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/spf13/cobra" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/cli-runtime/pkg/genericclioptions" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - command = "cmdrpkgcopy" -) - -func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command { - return newRunner(ctx, rcg).Command -} - -func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner { - r := &runner{ - ctx: ctx, - cfg: rcg, - } - r.Command = &cobra.Command{ - Use: "copy SOURCE_PACKAGE NAME", - Aliases: []string{"edit"}, - Short: rpkgdocs.CopyShort, - Long: rpkgdocs.CopyShort + "\n" + rpkgdocs.CopyLong, - Example: rpkgdocs.CopyExamples, - PreRunE: r.preRunE, - RunE: r.runE, - Hidden: porch.HidePorchCommands, - } - r.Command.Flags().StringVar(&r.workspace, "workspace", "", "Workspace name of the copy of the package.") - r.Command.Flags().BoolVar(&r.replayStrategy, "replay-strategy", false, "Use replay strategy for creating new package revision.") - return r -} - -type runner struct { - ctx context.Context - cfg *genericclioptions.ConfigFlags - client client.Client - Command *cobra.Command - - copy porchapi.PackageEditTaskSpec - - workspace string // Target package revision workspaceName - replayStrategy bool -} - -func (r *runner) preRunE(_ *cobra.Command, args []string) error { - const op errors.Op = command + ".preRunE" - client, err := porch.CreateClientWithFlags(r.cfg) - if err != nil { - return errors.E(op, err) - } - r.client = client - - if len(args) < 1 { - return errors.E(op, fmt.Errorf("SOURCE_PACKAGE is a required positional argument")) - } - if len(args) > 1 { - return errors.E(op, fmt.Errorf("too many arguments; SOURCE_PACKAGE is the only accepted positional arguments")) - } - - r.copy.Source = &porchapi.PackageRevisionRef{ - Name: args[0], - } - return nil -} - -func (r *runner) runE(cmd *cobra.Command, _ []string) error { - const op errors.Op = command + ".runE" - - revisionSpec, err := r.getPackageRevisionSpec() - if err != nil { - return errors.E(op, err) - } - - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: *r.cfg.Namespace, - }, - Spec: *revisionSpec, - } - if err := r.client.Create(r.ctx, pr); err != nil { - return errors.E(op, err) - } - fmt.Fprintf(cmd.OutOrStdout(), "%s created\n", pr.Name) - return nil -} - -func (r *runner) getPackageRevisionSpec() (*porchapi.PackageRevisionSpec, error) { - packageRevision := porchapi.PackageRevision{} - err := r.client.Get(r.ctx, types.NamespacedName{ - Name: r.copy.Source.Name, - Namespace: *r.cfg.Namespace, - }, &packageRevision) - if err != nil { - return nil, err - } - - if r.workspace == "" { - return nil, fmt.Errorf("--workspace is required to specify workspace name") - } - - spec := &porchapi.PackageRevisionSpec{ - PackageName: packageRevision.Spec.PackageName, - WorkspaceName: porchapi.WorkspaceName(r.workspace), - RepositoryName: packageRevision.Spec.RepositoryName, - } - - if len(packageRevision.Spec.Tasks) == 0 || !r.replayStrategy { - spec.Tasks = []porchapi.Task{ - { - Type: porchapi.TaskTypeEdit, - Edit: &porchapi.PackageEditTaskSpec{ - Source: &porchapi.PackageRevisionRef{ - Name: packageRevision.Name, - }, - }, - }, - } - } else { - spec.Tasks = packageRevision.Spec.Tasks - } - return spec, nil -} diff --git a/commands/alpha/rpkg/del/command.go b/commands/alpha/rpkg/del/command.go deleted file mode 100644 index 378c1abb64..0000000000 --- a/commands/alpha/rpkg/del/command.go +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2022 The kpt 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. - -package del - -import ( - "context" - "fmt" - "strings" - - "github.com/GoogleContainerTools/kpt/internal/docs/generated/rpkgdocs" - "github.com/GoogleContainerTools/kpt/internal/errors" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericclioptions" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - command = "cmdrpkgdel" -) - -func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner { - r := &runner{ - ctx: ctx, - cfg: rcg, - } - c := &cobra.Command{ - Use: "del PACKAGE", - Aliases: []string{"delete"}, - SuggestFor: []string{}, - Short: rpkgdocs.DelShort, - Long: rpkgdocs.DelShort + "\n" + rpkgdocs.DelLong, - Example: rpkgdocs.DelExamples, - PreRunE: r.preRunE, - RunE: r.runE, - Hidden: porch.HidePorchCommands, - } - r.Command = c - - // Create flags - - return r -} - -func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command { - return newRunner(ctx, rcg).Command -} - -type runner struct { - ctx context.Context - cfg *genericclioptions.ConfigFlags - client client.Client - Command *cobra.Command -} - -func (r *runner) preRunE(_ *cobra.Command, _ []string) error { - const op errors.Op = command + ".preRunE" - - client, err := porch.CreateClientWithFlags(r.cfg) - if err != nil { - return errors.E(op, err) - } - r.client = client - return nil -} - -func (r *runner) runE(_ *cobra.Command, args []string) error { - const op errors.Op = command + ".runE" - var messages []string - - for _, pkg := range args { - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: *r.cfg.Namespace, - Name: pkg, - }, - } - - if err := r.client.Delete(r.ctx, pr); err != nil { - messages = append(messages, err.Error()) - fmt.Fprintf(r.Command.ErrOrStderr(), "%s failed (%s)\n", pkg, err) - } else { - fmt.Fprintf(r.Command.OutOrStderr(), "%s deleted\n", pkg) - } - } - - if len(messages) > 0 { - return errors.E(op, fmt.Errorf("errors:\n %s", strings.Join(messages, "\n "))) - } - - return nil -} diff --git a/commands/alpha/rpkg/get/command.go b/commands/alpha/rpkg/get/command.go deleted file mode 100644 index 33f4c5230f..0000000000 --- a/commands/alpha/rpkg/get/command.go +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright 2022 The kpt 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. - -package get - -import ( - "context" - "fmt" - "strings" - - "github.com/GoogleContainerTools/kpt/internal/docs/generated/rpkgdocs" - "github.com/GoogleContainerTools/kpt/internal/errors" - "github.com/GoogleContainerTools/kpt/internal/options" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - "github.com/spf13/cobra" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/cli-runtime/pkg/printers" - "k8s.io/client-go/rest" - "k8s.io/klog/v2" - "k8s.io/kubectl/pkg/cmd/get" -) - -const ( - command = "cmdrpkgget" -) - -func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner { - r := &runner{ - ctx: ctx, - getFlags: options.Get{ConfigFlags: rcg}, - printFlags: get.NewGetPrintFlags(), - } - cmd := &cobra.Command{ - Use: "get", - Aliases: []string{"list"}, - SuggestFor: []string{}, - Short: rpkgdocs.GetShort, - Long: rpkgdocs.GetShort + "\n" + rpkgdocs.GetLong, - Example: rpkgdocs.GetExamples, - PreRunE: r.preRunE, - RunE: r.runE, - Hidden: porch.HidePorchCommands, - } - r.Command = cmd - - // Create flags - cmd.Flags().StringVar(&r.packageName, "name", "", "Name of the packages to get. Any package whose name contains this value will be included in the results.") - cmd.Flags().StringVar(&r.revision, "revision", "", "Revision of the packages to get. Any package whose revision matches this value will be included in the results.") - cmd.Flags().StringVar(&r.workspace, "workspace", "", - "WorkspaceName of the packages to get. Any package whose workspaceName matches this value will be included in the results.") - - r.getFlags.AddFlags(cmd) - r.printFlags.AddFlags(cmd) - return r -} - -func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command { - return newRunner(ctx, rcg).Command -} - -type runner struct { - ctx context.Context - getFlags options.Get - Command *cobra.Command - - // Flags - packageName string - revision string - workspace string - printFlags *get.PrintFlags - - requestTable bool -} - -func (r *runner) preRunE(cmd *cobra.Command, _ []string) error { - // Print the namespace if we're spanning namespaces - if r.getFlags.AllNamespaces { - r.printFlags.HumanReadableFlags.WithNamespace = true - } - - outputOption := cmd.Flags().Lookup("output").Value.String() - if strings.Contains(outputOption, "custom-columns") || outputOption == "yaml" || strings.Contains(outputOption, "json") { - r.requestTable = false - } else { - r.requestTable = true - } - return nil -} - -func (r *runner) runE(cmd *cobra.Command, args []string) error { - const op errors.Op = command + ".runE" - - var objs []runtime.Object - b, err := r.getFlags.ResourceBuilder() - if err != nil { - return err - } - - if r.requestTable { - scheme := runtime.NewScheme() - // Accept PartialObjectMetadata and Table - if err := metav1.AddMetaToScheme(scheme); err != nil { - return fmt.Errorf("error building runtime.Scheme: %w", err) - } - b = b.WithScheme(scheme, schema.GroupVersion{Version: "v1"}) - } else { - // We want to print the server version, not whatever version we happen to have compiled in - b = b.Unstructured() - } - - useSelectors := true - if len(args) > 0 { - b = b.ResourceNames("packagerevisions", args...) - // We can't pass selectors here, get an error "Error: selectors and the all flag cannot be used when passing resource/name arguments" - // TODO: cli-utils bug? I think there is a metadata.name field selector (used for single object watch) - useSelectors = false - } else { - b = b.ResourceTypes("packagerevisions") - } - - if useSelectors { - fieldSelector := fields.Everything() - if r.revision != "" { - fieldSelector = fields.OneTermEqualSelector("spec.revision", r.revision) - } - if r.workspace != "" { - fieldSelector = fields.OneTermEqualSelector("spec.workspaceName", r.workspace) - } - if r.packageName != "" { - fieldSelector = fields.OneTermEqualSelector("spec.packageName", r.packageName) - } - if s := fieldSelector.String(); s != "" { - b = b.FieldSelectorParam(s) - } else { - b = b.SelectAllParam(true) - } - } - - b = b.ContinueOnError(). - Latest(). - Flatten() - - if r.requestTable { - b = b.TransformRequests(func(req *rest.Request) { - req.SetHeader("Accept", strings.Join([]string{ - "application/json;as=Table;g=meta.k8s.io;v=v1", - "application/json", - }, ",")) - }) - } - - res := b.Do() - if err := res.Err(); err != nil { - return errors.E(op, err) - } - - infos, err := res.Infos() - if err != nil { - return errors.E(op, err) - } - - // Decode json objects in tables (likely PartialObjectMetadata) - for _, i := range infos { - if table, ok := i.Object.(*metav1.Table); ok { - for i := range table.Rows { - row := &table.Rows[i] - if row.Object.Object == nil && row.Object.Raw != nil { - u := &unstructured.Unstructured{} - if err := u.UnmarshalJSON(row.Object.Raw); err != nil { - klog.Warningf("error parsing raw object: %v", err) - } - row.Object.Object = u - } - } - } - } - - // Apply any filters we couldn't pass down as field selectors - for _, i := range infos { - switch obj := i.Object.(type) { - case *unstructured.Unstructured: - match, err := r.packageRevisionMatches(obj) - if err != nil { - return errors.E(op, err) - } - if match { - objs = append(objs, obj) - } - case *metav1.Table: - // Technically we should have applied this as a field-selector, so this might not be necessary - if err := r.filterTableRows(obj); err != nil { - return err - } - objs = append(objs, obj) - default: - return errors.E(op, fmt.Sprintf("Unrecognized response %T", obj)) - } - } - - printer, err := r.printFlags.ToPrinter() - if err != nil { - return errors.E(op, err) - } - - w := printers.GetNewTabWriter(cmd.OutOrStdout()) - for _, obj := range objs { - if err := printer.PrintObj(obj, w); err != nil { - return errors.E(op, err) - } - } - if err := w.Flush(); err != nil { - return errors.E(op, err) - } - - return nil -} - -func (r *runner) packageRevisionMatches(o *unstructured.Unstructured) (bool, error) { - packageName, _, err := unstructured.NestedString(o.Object, "spec", "packageName") - if err != nil { - return false, err - } - revision, _, err := unstructured.NestedString(o.Object, "spec", "revision") - if err != nil { - return false, err - } - workspace, _, err := unstructured.NestedString(o.Object, "spec", "workspaceName") - if err != nil { - return false, err - } - if r.packageName != "" && r.packageName != packageName { - return false, nil - } - if r.revision != "" && r.revision != revision { - return false, nil - } - if r.workspace != "" && r.workspace != workspace { - return false, nil - } - return true, nil -} - -func findColumn(cols []metav1.TableColumnDefinition, name string) int { - for i := range cols { - if cols[i].Name == name { - return i - } - } - return -1 -} - -func getStringCell(cells []interface{}, col int) (string, bool) { - if col < 0 { - return "", false - } - s, ok := cells[col].(string) - return s, ok -} - -func (r *runner) filterTableRows(table *metav1.Table) error { - filtered := make([]metav1.TableRow, 0, len(table.Rows)) - packageNameCol := findColumn(table.ColumnDefinitions, "Package") - revisionCol := findColumn(table.ColumnDefinitions, "Revision") - workspaceCol := findColumn(table.ColumnDefinitions, "WorkspaceName") - - for i := range table.Rows { - row := &table.Rows[i] - - if packageName, ok := getStringCell(row.Cells, packageNameCol); ok { - if r.packageName != "" && r.packageName != packageName { - continue - } - } - if revision, ok := getStringCell(row.Cells, revisionCol); ok { - if r.revision != "" && r.revision != revision { - continue - } - } - if workspace, ok := getStringCell(row.Cells, workspaceCol); ok { - if r.workspace != "" && r.workspace != workspace { - continue - } - } - - // Row matches - filtered = append(filtered, *row) - } - table.Rows = filtered - return nil -} diff --git a/commands/alpha/rpkg/init/command.go b/commands/alpha/rpkg/init/command.go deleted file mode 100644 index 3122c5e863..0000000000 --- a/commands/alpha/rpkg/init/command.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2022 The kpt 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. - -package init - -import ( - "context" - "fmt" - - "github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/util" - "github.com/GoogleContainerTools/kpt/internal/docs/generated/rpkgdocs" - "github.com/GoogleContainerTools/kpt/internal/errors" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/spf13/cobra" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/cli-runtime/pkg/genericclioptions" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - command = "cmdrpkginit" -) - -func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command { - return newRunner(ctx, rcg).Command -} - -func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner { - r := &runner{ - ctx: ctx, - cfg: rcg, - } - c := &cobra.Command{ - Use: "init PACKAGE_NAME", - Short: rpkgdocs.InitShort, - Long: rpkgdocs.InitShort + "\n" + rpkgdocs.InitLong, - Example: rpkgdocs.InitExamples, - PreRunE: r.preRunE, - RunE: r.runE, - Hidden: porch.HidePorchCommands, - } - r.Command = c - - c.Flags().StringVar(&r.Description, "description", "sample description", "short description of the package.") - c.Flags().StringSliceVar(&r.Keywords, "keywords", []string{}, "list of keywords for the package.") - c.Flags().StringVar(&r.Site, "site", "", "link to page with information about the package.") - c.Flags().StringVar(&r.repository, "repository", "", "Repository to which package will be created.") - c.Flags().StringVar(&r.workspace, "workspace", "", "Workspace name of the package.") - - return r -} - -type runner struct { - ctx context.Context - cfg *genericclioptions.ConfigFlags - client client.Client - Command *cobra.Command - - // Flags - Keywords []string - Description string - Site string - name string // Target package name - repository string // Target repository - workspace string // Target workspace name -} - -func (r *runner) preRunE(_ *cobra.Command, args []string) error { - const op errors.Op = command + ".preRunE" - - client, err := porch.CreateClientWithFlags(r.cfg) - if err != nil { - return errors.E(op, err) - } - r.client = client - - if len(args) < 1 { - return errors.E(op, "PACKAGE_NAME is a required positional argument") - } - - if r.repository == "" { - return errors.E(op, fmt.Errorf("--repository is required to specify target repository")) - } - - if r.workspace == "" { - return errors.E(op, fmt.Errorf("--workspace is required to specify workspace name")) - } - - r.name = args[0] - pkgExists, err := util.PackageAlreadyExists(r.ctx, r.client, r.repository, r.name, *r.cfg.Namespace) - if err != nil { - return err - } - if pkgExists { - return fmt.Errorf("`init` cannot create a new revision for package %q that already exists in repo %q; make subsequent revisions using `copy`", - r.name, r.repository) - } - return nil -} - -func (r *runner) runE(cmd *cobra.Command, _ []string) error { - const op errors.Op = command + ".runE" - - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: *r.cfg.Namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: r.name, - WorkspaceName: porchapi.WorkspaceName(r.workspace), - RepositoryName: r.repository, - Tasks: []porchapi.Task{ - { - Type: porchapi.TaskTypeInit, - Init: &porchapi.PackageInitTaskSpec{ - Description: r.Description, - Keywords: r.Keywords, - Site: r.Site, - }, - }, - }, - }, - Status: porchapi.PackageRevisionStatus{}, - } - if err := r.client.Create(r.ctx, pr); err != nil { - return errors.E(op, err) - } - - fmt.Fprintf(cmd.OutOrStdout(), "%s created\n", pr.Name) - return nil -} diff --git a/commands/alpha/rpkg/propose/command.go b/commands/alpha/rpkg/propose/command.go deleted file mode 100644 index a8121dfb8c..0000000000 --- a/commands/alpha/rpkg/propose/command.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2022 The kpt 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. - -package propose - -import ( - "context" - "fmt" - "strings" - - "github.com/GoogleContainerTools/kpt/internal/docs/generated/rpkgdocs" - "github.com/GoogleContainerTools/kpt/internal/errors" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericclioptions" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - command = "cmdrpkgpropose" -) - -func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command { - return newRunner(ctx, rcg).Command -} - -func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner { - r := &runner{ - ctx: ctx, - cfg: rcg, - client: nil, - } - - c := &cobra.Command{ - Use: "propose [PACKAGE ...] [flags]", - Short: rpkgdocs.ProposeShort, - Long: rpkgdocs.ProposeShort + "\n" + rpkgdocs.ProposeLong, - Example: rpkgdocs.ProposeExamples, - PreRunE: r.preRunE, - RunE: r.runE, - Hidden: porch.HidePorchCommands, - } - r.Command = c - - return r -} - -type runner struct { - ctx context.Context - cfg *genericclioptions.ConfigFlags - client client.Client - Command *cobra.Command - - // Flags -} - -func (r *runner) preRunE(_ *cobra.Command, _ []string) error { - const op errors.Op = command + ".preRunE" - - client, err := porch.CreateClientWithFlags(r.cfg) - if err != nil { - return errors.E(op, err) - } - r.client = client - return nil -} - -func (r *runner) runE(_ *cobra.Command, args []string) error { - const op errors.Op = command + ".runE" - var messages []string - namespace := *r.cfg.Namespace - - for _, name := range args { - pr := &v1alpha1.PackageRevision{} - if err := r.client.Get(r.ctx, client.ObjectKey{ - Namespace: namespace, - Name: name, - }, pr); err != nil { - return errors.E(op, err) - } - - switch pr.Spec.Lifecycle { - case v1alpha1.PackageRevisionLifecycleDraft: - // ok - case v1alpha1.PackageRevisionLifecycleProposed: - fmt.Fprintf(r.Command.OutOrStderr(), "%s is already proposed\n", name) - continue - default: - msg := fmt.Sprintf("cannot propose %s package", pr.Spec.Lifecycle) - messages = append(messages, msg) - fmt.Fprintln(r.Command.ErrOrStderr(), msg) - continue - } - - pr.Spec.Lifecycle = v1alpha1.PackageRevisionLifecycleProposed - if err := r.client.Update(r.ctx, pr); err != nil { - messages = append(messages, err.Error()) - fmt.Fprintf(r.Command.ErrOrStderr(), "%s failed (%s)\n", name, err) - } else { - fmt.Fprintf(r.Command.OutOrStderr(), "%s proposed\n", name) - } - } - - if len(messages) > 0 { - return errors.E(op, fmt.Errorf("errors:\n %s", strings.Join(messages, "\n "))) - } - - return nil -} diff --git a/commands/alpha/rpkg/proposedelete/command.go b/commands/alpha/rpkg/proposedelete/command.go deleted file mode 100644 index 1709eb0ae5..0000000000 --- a/commands/alpha/rpkg/proposedelete/command.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2022 The kpt 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. - -package proposedelete - -import ( - "context" - "fmt" - "strings" - - "github.com/GoogleContainerTools/kpt/internal/docs/generated/rpkgdocs" - "github.com/GoogleContainerTools/kpt/internal/errors" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericclioptions" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - command = "cmdrpkgpropose-delete" -) - -func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner { - r := &runner{ - ctx: ctx, - cfg: rcg, - } - c := &cobra.Command{ - Use: "propose-delete PACKAGE", - Aliases: []string{"propose-del"}, - Short: rpkgdocs.ProposeDeleteShort, - Long: rpkgdocs.ProposeDeleteShort + "\n" + rpkgdocs.ProposeDeleteLong, - Example: rpkgdocs.ProposeDeleteExamples, - SuggestFor: []string{}, - PreRunE: r.preRunE, - RunE: r.runE, - Hidden: porch.HidePorchCommands, - } - r.Command = c - - // Create flags - - return r -} - -func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command { - return newRunner(ctx, rcg).Command -} - -type runner struct { - ctx context.Context - cfg *genericclioptions.ConfigFlags - client client.Client - Command *cobra.Command -} - -func (r *runner) preRunE(_ *cobra.Command, _ []string) error { - const op errors.Op = command + ".preRunE" - - client, err := porch.CreateClientWithFlags(r.cfg) - if err != nil { - return errors.E(op, err) - } - r.client = client - return nil -} - -func (r *runner) runE(_ *cobra.Command, args []string) error { - const op errors.Op = command + ".runE" - var messages []string - namespace := *r.cfg.Namespace - - for _, name := range args { - pr := &v1alpha1.PackageRevision{} - if err := r.client.Get(r.ctx, client.ObjectKey{ - Namespace: namespace, - Name: name, - }, pr); err != nil { - return errors.E(op, err) - } - - switch pr.Spec.Lifecycle { - case v1alpha1.PackageRevisionLifecyclePublished: - // ok - case v1alpha1.PackageRevisionLifecycleDeletionProposed: - fmt.Fprintf(r.Command.OutOrStderr(), "%s is already proposed for deletion\n", name) - continue - default: - msg := fmt.Sprintf("can only propose published packages for deletion; package %s is not published", name) - messages = append(messages, msg) - fmt.Fprintln(r.Command.ErrOrStderr(), msg) - continue - } - - pr.Spec.Lifecycle = v1alpha1.PackageRevisionLifecycleDeletionProposed - if err := r.client.Update(r.ctx, pr); err != nil { - messages = append(messages, err.Error()) - fmt.Fprintf(r.Command.ErrOrStderr(), "%s failed (%s)\n", name, err) - } else { - fmt.Fprintf(r.Command.OutOrStderr(), "%s proposed for deletion\n", name) - } - } - - if len(messages) > 0 { - return errors.E(op, fmt.Errorf("errors:\n %s", strings.Join(messages, "\n "))) - } - - return nil -} diff --git a/commands/alpha/rpkg/pull/command.go b/commands/alpha/rpkg/pull/command.go deleted file mode 100644 index 3fc757181c..0000000000 --- a/commands/alpha/rpkg/pull/command.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright 2022 The kpt 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. - -package pull - -import ( - "context" - "io" - "os" - "path/filepath" - "sort" - "strings" - - "github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/util" - "github.com/GoogleContainerTools/kpt/internal/docs/generated/rpkgdocs" - "github.com/GoogleContainerTools/kpt/internal/errors" - "github.com/GoogleContainerTools/kpt/internal/util/cmdutil" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/pkg/printer" - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/cli-runtime/pkg/genericclioptions" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/kio/kioutil" -) - -const ( - command = "cmdrpkgpull" -) - -func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner { - r := &runner{ - ctx: ctx, - cfg: rcg, - } - c := &cobra.Command{ - Use: "pull PACKAGE [DIR]", - Aliases: []string{"source", "read"}, - SuggestFor: []string{}, - Short: rpkgdocs.PullShort, - Long: rpkgdocs.PullShort + "\n" + rpkgdocs.PullLong, - Example: rpkgdocs.PullExamples, - PreRunE: r.preRunE, - RunE: r.runE, - Hidden: porch.HidePorchCommands, - } - r.Command = c - return r -} - -func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command { - return newRunner(ctx, rcg).Command -} - -type runner struct { - ctx context.Context - cfg *genericclioptions.ConfigFlags - client client.Client - Command *cobra.Command - printer printer.Printer -} - -func (r *runner) preRunE(_ *cobra.Command, _ []string) error { - const op errors.Op = command + ".preRunE" - config, err := r.cfg.ToRESTConfig() - if err != nil { - return errors.E(op, err) - } - - scheme, err := createScheme() - if err != nil { - return errors.E(op, err) - } - - c, err := client.New(config, client.Options{Scheme: scheme}) - if err != nil { - return errors.E(op, err) - } - - r.client = c - r.printer = printer.FromContextOrDie(r.ctx) - return nil -} - -func (r *runner) runE(_ *cobra.Command, args []string) error { - const op errors.Op = command + ".runE" - - if len(args) == 0 { - return errors.E(op, "PACKAGE is a required positional argument") - } - - packageName := args[0] - - var resources porchapi.PackageRevisionResources - if err := r.client.Get(r.ctx, client.ObjectKey{ - Namespace: *r.cfg.Namespace, - Name: packageName, - }, &resources); err != nil { - return errors.E(op, err) - } - - if err := util.AddRevisionMetadata(&resources); err != nil { - return errors.E(op, err) - } - - if len(args) > 1 { - if err := writeToDir(resources.Spec.Resources, args[1]); err != nil { - return errors.E(op, err) - } - } else { - if err := writeToWriter(resources.Spec.Resources, r.printer.OutStream()); err != nil { - return errors.E(op, err) - } - } - return nil -} - -func writeToDir(resources map[string]string, dir string) error { - if err := cmdutil.CheckDirectoryNotPresent(dir); err != nil { - return err - } - if err := os.MkdirAll(dir, 0755); err != nil { - return err - } - - for k, v := range resources { - f := filepath.Join(dir, k) - d := filepath.Dir(f) - if err := os.MkdirAll(d, 0755); err != nil { - return err - } - if err := os.WriteFile(f, []byte(v), 0644); err != nil { - return err - } - } - return nil -} - -func writeToWriter(resources map[string]string, out io.Writer) error { - keys := make([]string, 0, len(resources)) - for k := range resources { - if !includeFile(k) { - continue - } - keys = append(keys, k) - } - sort.Strings(keys) - - // Create kio readers - inputs := []kio.Reader{} - for _, k := range keys { - v := resources[k] - inputs = append(inputs, &kio.ByteReader{ - Reader: strings.NewReader(v), - SetAnnotations: map[string]string{ - kioutil.PathAnnotation: k, - }, - DisableUnwrapping: true, - }) - } - - return kio.Pipeline{ - Inputs: inputs, - Outputs: []kio.Writer{ - kio.ByteWriter{ - Writer: out, - KeepReaderAnnotations: true, - WrappingKind: kio.ResourceListKind, - WrappingAPIVersion: kio.ResourceListAPIVersion, - Sort: true, - }, - }, - }.Execute() -} - -func createScheme() (*runtime.Scheme, error) { - scheme := runtime.NewScheme() - - for _, api := range (runtime.SchemeBuilder{ - porchapi.AddToScheme, - }) { - if err := api(scheme); err != nil { - return nil, err - } - } - return scheme, nil -} - -var matchResourceContents = append(kio.MatchAll, kptfilev1.KptFileName, kptfilev1.RevisionMetaDataFileName) - -func includeFile(path string) bool { - for _, m := range matchResourceContents { - // Only use the filename for the check for whether we should - // include the file. - f := filepath.Base(path) - if matched, err := filepath.Match(m, f); err == nil && matched { - return true - } - } - return false -} diff --git a/commands/alpha/rpkg/pull/command_test.go b/commands/alpha/rpkg/pull/command_test.go deleted file mode 100644 index ee8d60fb96..0000000000 --- a/commands/alpha/rpkg/pull/command_test.go +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright 2022 The kpt 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. - -package pull - -import ( - "bytes" - "strings" - "testing" - - "github.com/GoogleContainerTools/kpt/pkg/printer" - fakeprint "github.com/GoogleContainerTools/kpt/pkg/printer/fake" - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/google/go-cmp/cmp" - "github.com/spf13/cobra" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/cli-runtime/pkg/genericclioptions" - "sigs.k8s.io/controller-runtime/pkg/client/fake" -) - -func TestCmd(t *testing.T) { - pkgRevName := "repo-fjdos9u2nfe2f32" - ns := "ns" - - scheme, err := createScheme() - if err != nil { - t.Fatalf("error creating scheme: %v", err) - } - - testCases := map[string]struct { - resources map[string]string - output string - }{ - "simple package": { - resources: map[string]string{ - "Kptfile": strings.TrimSpace(` -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: bar - annotations: - config.kubernetes.io/local-config: "true" -info: - description: sample description - `), - "cm.yaml": strings.TrimSpace(` -apiVersion: v1 -kind: ConfigMap -metadata: - name: game-config - namespace: default -data: - foo: bar - `), - }, - output: ` -apiVersion: config.kubernetes.io/v1 -kind: ResourceList -items: -- apiVersion: porch.kpt.dev/v1alpha1 - kind: KptRevisionMetadata - metadata: - name: repo-fjdos9u2nfe2f32 - namespace: ns - creationTimestamp: null - resourceVersion: "999" - annotations: - config.kubernetes.io/index: '0' - internal.config.kubernetes.io/index: '0' - internal.config.kubernetes.io/path: '.KptRevisionMetadata' - config.kubernetes.io/path: '.KptRevisionMetadata' -- apiVersion: kpt.dev/v1 - kind: Kptfile - metadata: - name: bar - annotations: - config.kubernetes.io/local-config: "true" - config.kubernetes.io/index: '0' - internal.config.kubernetes.io/index: '0' - internal.config.kubernetes.io/path: 'Kptfile' - config.kubernetes.io/path: 'Kptfile' - info: - description: sample description -- apiVersion: v1 - kind: ConfigMap - metadata: - name: game-config - namespace: default - annotations: - config.kubernetes.io/index: '0' - internal.config.kubernetes.io/index: '0' - internal.config.kubernetes.io/path: 'cm.yaml' - config.kubernetes.io/path: 'cm.yaml' - data: - foo: bar - `, - }, - "package with subdirectory": { - resources: map[string]string{ - "Kptfile": strings.TrimSpace(` -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: bar - annotations: - config.kubernetes.io/local-config: "true" -info: - description: sample description - `), - "sub/cm.yaml": strings.TrimSpace(` -apiVersion: v1 -kind: ConfigMap -metadata: - name: game-config - namespace: default -data: - foo: bar - `), - }, - output: ` -apiVersion: config.kubernetes.io/v1 -kind: ResourceList -items: -- apiVersion: porch.kpt.dev/v1alpha1 - kind: KptRevisionMetadata - metadata: - name: repo-fjdos9u2nfe2f32 - namespace: ns - creationTimestamp: null - resourceVersion: "999" - annotations: - config.kubernetes.io/index: '0' - internal.config.kubernetes.io/index: '0' - internal.config.kubernetes.io/path: '.KptRevisionMetadata' - config.kubernetes.io/path: '.KptRevisionMetadata' -- apiVersion: kpt.dev/v1 - kind: Kptfile - metadata: - name: bar - annotations: - config.kubernetes.io/local-config: "true" - config.kubernetes.io/index: '0' - internal.config.kubernetes.io/index: '0' - internal.config.kubernetes.io/path: 'Kptfile' - config.kubernetes.io/path: 'Kptfile' - info: - description: sample description -- apiVersion: v1 - kind: ConfigMap - metadata: - name: game-config - namespace: default - annotations: - config.kubernetes.io/index: '0' - internal.config.kubernetes.io/index: '0' - internal.config.kubernetes.io/path: 'sub/cm.yaml' - config.kubernetes.io/path: 'sub/cm.yaml' - data: - foo: bar - `, - }, - } - - for tn := range testCases { - tc := testCases[tn] - t.Run(tn, func(t *testing.T) { - c := fake.NewClientBuilder(). - WithScheme(scheme). - WithObjects(&porchapi.PackageRevisionResources{ - ObjectMeta: metav1.ObjectMeta{ - Name: pkgRevName, - Namespace: "ns", - }, - Spec: porchapi.PackageRevisionResourcesSpec{ - PackageName: "foo", - Resources: tc.resources, - }, - }). - Build() - output := &bytes.Buffer{} - ctx := fakeprint.CtxWithPrinter(output, output) - r := &runner{ - ctx: ctx, - cfg: &genericclioptions.ConfigFlags{ - Namespace: &ns, - }, - client: c, - printer: printer.FromContextOrDie(ctx), - } - cmd := &cobra.Command{} - err = r.runE(cmd, []string{pkgRevName}) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - if diff := cmp.Diff(strings.TrimSpace(tc.output), strings.TrimSpace(output.String())); diff != "" { - t.Errorf("Unexpected result (-want, +got): %s", diff) - } - }) - } -} diff --git a/commands/alpha/rpkg/push/command.go b/commands/alpha/rpkg/push/command.go deleted file mode 100644 index 13b3223114..0000000000 --- a/commands/alpha/rpkg/push/command.go +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright 2022 The kpt 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. - -package push - -import ( - "bytes" - "context" - "fmt" - "io" - "io/fs" - "os" - "path" - "path/filepath" - "strings" - - "github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/util" - "github.com/GoogleContainerTools/kpt/internal/docs/generated/rpkgdocs" - "github.com/GoogleContainerTools/kpt/internal/errors" - "github.com/GoogleContainerTools/kpt/internal/fnruntime" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - "github.com/GoogleContainerTools/kpt/pkg/printer" - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/spf13/cobra" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/cli-runtime/pkg/genericclioptions" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/kio/kioutil" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -const ( - command = "cmdrpkgpush" -) - -func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner { - r := &runner{ - ctx: ctx, - cfg: rcg, - } - c := &cobra.Command{ - Use: "push PACKAGE [DIR]", - Aliases: []string{"sink", "write"}, - SuggestFor: []string{}, - Short: rpkgdocs.PushShort, - Long: rpkgdocs.PushShort + "\n" + rpkgdocs.PushLong, - Example: rpkgdocs.PushExamples, - PreRunE: r.preRunE, - RunE: r.runE, - Hidden: porch.HidePorchCommands, - } - r.Command = c - return r -} - -func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command { - return newRunner(ctx, rcg).Command -} - -type runner struct { - ctx context.Context - cfg *genericclioptions.ConfigFlags - client client.Client - Command *cobra.Command - printer printer.Printer -} - -func (r *runner) preRunE(_ *cobra.Command, _ []string) error { - const op errors.Op = command + ".preRunE" - config, err := r.cfg.ToRESTConfig() - if err != nil { - return errors.E(op, err) - } - - scheme, err := createScheme() - if err != nil { - return errors.E(op, err) - } - - c, err := client.New(config, client.Options{Scheme: scheme}) - if err != nil { - return errors.E(op, err) - } - - r.client = c - r.printer = printer.FromContextOrDie(r.ctx) - return nil -} - -func (r *runner) runE(cmd *cobra.Command, args []string) error { - const op errors.Op = command + ".runE" - - if len(args) == 0 { - return errors.E(op, "PACKAGE is a required positional argument") - } - - packageName := args[0] - var resources map[string]string - var err error - - if len(args) > 1 { - resources, err = readFromDir(args[1]) - } else { - resources, err = readFromReader(cmd.InOrStdin()) - } - if err != nil { - return errors.E(op, err) - } - - pkgResources := porchapi.PackageRevisionResources{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevisionResources", - APIVersion: porchapi.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: packageName, - Namespace: *r.cfg.Namespace, - }, - Spec: porchapi.PackageRevisionResourcesSpec{ - Resources: resources, - }, - } - - rv, err := util.GetResourceVersion(&pkgResources) - if err != nil { - return errors.E(op, err) - } - pkgResources.ResourceVersion = rv - if err = util.RemoveRevisionMetadata(&pkgResources); err != nil { - return errors.E(op, err) - } - - if err := r.client.Update(r.ctx, &pkgResources); err != nil { - return errors.E(op, err) - } - rs := pkgResources.Status.RenderStatus - if rs.Err != "" { - r.printer.Printf("Package is updated, but failed to render the package.\n") - r.printer.Printf("Error: %s\n", rs.Err) - } - if len(rs.Result.Items) > 0 { - for _, result := range rs.Result.Items { - r.printer.Printf("[RUNNING] %q \n", result.Image) - printOpt := printer.NewOpt() - if result.ExitCode != 0 { - r.printer.OptPrintf(printOpt, "[FAIL] %q\n", result.Image) - } else { - r.printer.OptPrintf(printOpt, "[PASS] %q\n", result.Image) - } - r.printFnResult(result, printOpt) - } - } - return nil -} - -// printFnResult prints given function result in a user friendly -// format on kpt CLI. -func (r *runner) printFnResult(fnResult *porchapi.Result, opt *printer.Options) { - if len(fnResult.Results) > 0 { - // function returned structured results - var lines []string - for _, item := range fnResult.Results { - lines = append(lines, str(item)) - } - ri := &fnruntime.MultiLineFormatter{ - Title: "Results", - Lines: lines, - TruncateOutput: printer.TruncateOutput, - } - r.printer.OptPrintf(opt, "%s", ri.String()) - } -} - -// String provides a human-readable message for the result item -func str(i porchapi.ResultItem) string { - identifier := i.ResourceRef - var idStringList []string - if identifier != nil { - if identifier.APIVersion != "" { - idStringList = append(idStringList, identifier.APIVersion) - } - if identifier.Kind != "" { - idStringList = append(idStringList, identifier.Kind) - } - if identifier.Namespace != "" { - idStringList = append(idStringList, identifier.Namespace) - } - if identifier.Name != "" { - idStringList = append(idStringList, identifier.Name) - } - } - formatString := "[%s]" - severity := i.Severity - // We default Severity to Info when converting a result to a message. - if i.Severity == "" { - severity = "info" - } - list := []interface{}{severity} - if len(idStringList) > 0 { - formatString += " %s" - list = append(list, strings.Join(idStringList, "/")) - } - if i.Field != nil { - formatString += " %s" - list = append(list, i.Field.Path) - } - formatString += ": %s" - list = append(list, i.Message) - return fmt.Sprintf(formatString, list...) -} - -func readFromDir(dir string) (map[string]string, error) { - resources := map[string]string{} - if err := filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { - if err != nil { - return err - } - if !info.Mode().IsRegular() { - return nil - } - rel, err := filepath.Rel(dir, path) - if err != nil { - return err - } - contents, err := os.ReadFile(path) - if err != nil { - return err - } - resources[rel] = string(contents) - return nil - }); err != nil { - return nil, err - } - return resources, nil -} - -func readFromReader(in io.Reader) (map[string]string, error) { - rw := &resourceWriter{ - resources: map[string]string{}, - } - - if err := (kio.Pipeline{ - Inputs: []kio.Reader{&kio.ByteReader{ - Reader: in, - PreserveSeqIndent: true, - WrapBareSeqNode: true, - }}, - Outputs: []kio.Writer{rw}, - }.Execute()); err != nil { - return nil, err - } - return rw.resources, nil -} - -func createScheme() (*runtime.Scheme, error) { - scheme := runtime.NewScheme() - - for _, api := range (runtime.SchemeBuilder{ - porchapi.AddToScheme, - }) { - if err := api(scheme); err != nil { - return nil, err - } - } - return scheme, nil -} - -type resourceWriter struct { - resources map[string]string -} - -var _ kio.Writer = &resourceWriter{} - -func (w *resourceWriter) Write(nodes []*yaml.RNode) error { - paths := map[string][]*yaml.RNode{} - for _, node := range nodes { - path := getPath(node) - paths[path] = append(paths[path], node) - } - - buf := &bytes.Buffer{} - for path, nodes := range paths { - bw := kio.ByteWriter{ - Writer: buf, - ClearAnnotations: []string{ - kioutil.PathAnnotation, - kioutil.IndexAnnotation, - }, - } - if err := bw.Write(nodes); err != nil { - return err - } - w.resources[path] = buf.String() - buf.Reset() - } - return nil -} - -func getPath(node *yaml.RNode) string { - ann := node.GetAnnotations() - if path, ok := ann[kioutil.PathAnnotation]; ok { - return path - } - ns := node.GetNamespace() - if ns == "" { - ns = "non-namespaced" - } - name := node.GetName() - if name == "" { - name = "unnamed" - } - // TODO: harden for escaping etc. - return path.Join(ns, fmt.Sprintf("%s.yaml", name)) -} diff --git a/commands/alpha/rpkg/reject/command.go b/commands/alpha/rpkg/reject/command.go deleted file mode 100644 index e9a035d822..0000000000 --- a/commands/alpha/rpkg/reject/command.go +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2022 The kpt 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. - -package reject - -import ( - "context" - "fmt" - "strings" - - "github.com/GoogleContainerTools/kpt/internal/docs/generated/rpkgdocs" - "github.com/GoogleContainerTools/kpt/internal/errors" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/client-go/rest" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - command = "cmdrpkgreject" -) - -func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command { - return newRunner(ctx, rcg).Command -} - -func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner { - r := &runner{ - ctx: ctx, - cfg: rcg, - client: nil, - } - - c := &cobra.Command{ - Use: "reject PACKAGE", - Short: rpkgdocs.RejectShort, - Long: rpkgdocs.RejectShort + "\n" + rpkgdocs.RejectLong, - Example: rpkgdocs.RejectExamples, - PreRunE: r.preRunE, - RunE: r.runE, - Hidden: porch.HidePorchCommands, - } - r.Command = c - - return r -} - -type runner struct { - ctx context.Context - cfg *genericclioptions.ConfigFlags - client rest.Interface - porchClient client.Client - Command *cobra.Command - - // Flags -} - -func (r *runner) preRunE(_ *cobra.Command, args []string) error { - const op errors.Op = command + ".preRunE" - - if len(args) < 1 { - return errors.E(op, "PACKAGE_REVISION is a required positional argument") - } - - client, err := porch.CreateRESTClient(r.cfg) - if err != nil { - return errors.E(op, err) - } - r.client = client - - porchClient, err := porch.CreateClientWithFlags(r.cfg) - if err != nil { - return errors.E(op, err) - } - r.porchClient = porchClient - return nil -} - -func (r *runner) runE(_ *cobra.Command, args []string) error { - const op errors.Op = command + ".runE" - var messages []string - - namespace := *r.cfg.Namespace - - for _, name := range args { - pr := &v1alpha1.PackageRevision{} - if err := r.porchClient.Get(r.ctx, client.ObjectKey{ - Namespace: namespace, - Name: name, - }, pr); err != nil { - return errors.E(op, err) - } - switch pr.Spec.Lifecycle { - case v1alpha1.PackageRevisionLifecycleProposed: - if err := porch.UpdatePackageRevisionApproval(r.ctx, r.client, client.ObjectKey{ - Namespace: namespace, - Name: name, - }, v1alpha1.PackageRevisionLifecycleDraft); err != nil { - messages = append(messages, err.Error()) - fmt.Fprintf(r.Command.ErrOrStderr(), "%s failed (%s)\n", name, err) - } else { - fmt.Fprintf(r.Command.OutOrStderr(), "%s rejected\n", name) - } - case v1alpha1.PackageRevisionLifecycleDeletionProposed: - pr.Spec.Lifecycle = v1alpha1.PackageRevisionLifecyclePublished - if err := r.porchClient.Update(r.ctx, pr); err != nil { - messages = append(messages, err.Error()) - fmt.Fprintf(r.Command.ErrOrStderr(), "%s failed (%s)\n", name, err) - } else { - fmt.Fprintf(r.Command.OutOrStderr(), "%s no longer proposed for deletion\n", name) - } - default: - msg := fmt.Sprintf("cannot reject %s with lifecycle '%s'", name, pr.Spec.Lifecycle) - messages = append(messages, msg) - fmt.Fprintln(r.Command.ErrOrStderr(), msg) - } - } - - if len(messages) > 0 { - return errors.E(op, fmt.Errorf("errors:\n %s", strings.Join(messages, "\n "))) - } - - return nil -} diff --git a/commands/alpha/rpkg/rpkgcmd.go b/commands/alpha/rpkg/rpkgcmd.go deleted file mode 100644 index 15d528be28..0000000000 --- a/commands/alpha/rpkg/rpkgcmd.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2022 The kpt 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. - -package rpkg - -import ( - "context" - "flag" - "fmt" - - "github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/approve" - "github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/clone" - "github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/copy" - "github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/del" - "github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/get" - initialization "github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/init" - "github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/propose" - "github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/proposedelete" - "github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/pull" - "github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/push" - "github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/reject" - "github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/update" - "github.com/GoogleContainerTools/kpt/internal/docs/generated/rpkgdocs" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/client-go/rest" -) - -func NewCommand(ctx context.Context, version string) *cobra.Command { - repo := &cobra.Command{ - Use: "rpkg", - Aliases: []string{"rpackage"}, - Short: "[Alpha] " + rpkgdocs.RpkgShort, - Long: "[Alpha] " + rpkgdocs.RpkgLong, - RunE: func(cmd *cobra.Command, args []string) error { - h, err := cmd.Flags().GetBool("help") - if err != nil { - return err - } - if h { - return cmd.Help() - } - return cmd.Usage() - }, - Hidden: porch.HidePorchCommands, - } - - pf := repo.PersistentFlags() - - kubeflags := genericclioptions.NewConfigFlags(true) - kubeflags.AddFlags(pf) - - kubeflags.WrapConfigFn = func(rc *rest.Config) *rest.Config { - rc.UserAgent = fmt.Sprintf("kpt/%s", version) - return rc - } - - pf.AddGoFlagSet(flag.CommandLine) - - repo.AddCommand( - get.NewCommand(ctx, kubeflags), - pull.NewCommand(ctx, kubeflags), - push.NewCommand(ctx, kubeflags), - clone.NewCommand(ctx, kubeflags), - initialization.NewCommand(ctx, kubeflags), - propose.NewCommand(ctx, kubeflags), - approve.NewCommand(ctx, kubeflags), - reject.NewCommand(ctx, kubeflags), - del.NewCommand(ctx, kubeflags), - copy.NewCommand(ctx, kubeflags), - update.NewCommand(ctx, kubeflags), - proposedelete.NewCommand(ctx, kubeflags), - ) - - return repo -} diff --git a/commands/alpha/rpkg/update/command.go b/commands/alpha/rpkg/update/command.go deleted file mode 100644 index 1cba69e944..0000000000 --- a/commands/alpha/rpkg/update/command.go +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright 2022 The kpt 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. - -package update - -import ( - "context" - "fmt" - - "github.com/GoogleContainerTools/kpt/internal/docs/generated/rpkgdocs" - "github.com/GoogleContainerTools/kpt/internal/errors" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericclioptions" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - command = "cmdrpkgupdate" - - upstream = "upstream" - downstream = "downstream" -) - -func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command { - return newRunner(ctx, rcg).Command -} - -func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner { - r := &runner{ - ctx: ctx, - cfg: rcg, - } - r.Command = &cobra.Command{ - Use: "update SOURCE_PACKAGE", - PreRunE: r.preRunE, - RunE: r.runE, - Short: rpkgdocs.UpdateShort, - Long: rpkgdocs.UpdateShort + "\n" + rpkgdocs.UpdateLong, - Example: rpkgdocs.UpdateExamples, - Hidden: porch.HidePorchCommands, - } - r.Command.Flags().StringVar(&r.revision, "revision", "", "Revision of the upstream package to update to.") - r.Command.Flags().StringVar(&r.discover, "discover", "", - `If set, search for available updates instead of performing an update. -Setting this to 'upstream' will discover upstream updates of downstream packages. -Setting this to 'downstream' will discover downstream package revisions of upstream packages that need to be updated.`) - return r -} - -type runner struct { - ctx context.Context - cfg *genericclioptions.ConfigFlags - client client.Client - Command *cobra.Command - - revision string // Target package revision - discover string // If set, discover updates rather than do updates - - // there are multiple places where we need access to all package revisions, so - // we store it in the runner - prs []porchapi.PackageRevision -} - -func (r *runner) preRunE(_ *cobra.Command, args []string) error { - const op errors.Op = command + ".preRunE" - c, err := porch.CreateClientWithFlags(r.cfg) - if err != nil { - return errors.E(op, err) - } - r.client = c - - if r.discover == "" { - if len(args) < 1 { - return errors.E(op, fmt.Errorf("SOURCE_PACKAGE is a required positional argument")) - } - if len(args) > 1 { - return errors.E(op, fmt.Errorf("too many arguments; SOURCE_PACKAGE is the only accepted positional arguments")) - } - // TODO: This should use the latest available revision if one isn't specified. - if r.revision == "" { - return errors.E(op, fmt.Errorf("revision is required")) - } - } else if r.discover != upstream && r.discover != downstream { - return errors.E(op, fmt.Errorf("argument for 'discover' must be one of 'upstream' or 'downstream'")) - } - - packageRevisionList := porchapi.PackageRevisionList{} - if err := r.client.List(r.ctx, &packageRevisionList, &client.ListOptions{}); err != nil { - return errors.E(op, err) - } - r.prs = packageRevisionList.Items - - return nil -} - -func (r *runner) runE(cmd *cobra.Command, args []string) error { - const op errors.Op = command + ".runE" - - if r.discover == "" { - pr := r.findPackageRevision(args[0]) - if pr == nil { - return errors.E(op, fmt.Errorf("could not find package revision %s", args[0])) - } - if err := r.doUpdate(pr); err != nil { - return errors.E(op, err) - } - if _, err := fmt.Fprintf(cmd.OutOrStdout(), "%s updated\n", pr.Name); err != nil { - return errors.E(op, err) - } - } else if err := r.discoverUpdates(cmd, args); err != nil { - return errors.E(op, err) - } - return nil -} - -func (r *runner) doUpdate(pr *porchapi.PackageRevision) error { - cloneTask := r.findCloneTask(pr) - if cloneTask == nil { - return fmt.Errorf("upstream source not found for package rev %q; only cloned packages can be updated", pr.Spec.PackageName) - } - - switch cloneTask.Clone.Upstream.Type { - case porchapi.RepositoryTypeGit: - cloneTask.Clone.Upstream.Git.Ref = r.revision - case porchapi.RepositoryTypeOCI: - return fmt.Errorf("update not implemented for oci packages") - default: - upstreamPr := r.findPackageRevision(cloneTask.Clone.Upstream.UpstreamRef.Name) - if upstreamPr == nil { - return fmt.Errorf("upstream package revision %s no longer exists", cloneTask.Clone.Upstream.UpstreamRef.Name) - } - newUpstreamPr := r.findPackageRevisionForRef(upstreamPr.Spec.PackageName) - if newUpstreamPr == nil { - return fmt.Errorf("revision %s does not exist for package %s", r.revision, pr.Spec.PackageName) - } - newTask := porchapi.Task{ - Type: porchapi.TaskTypeUpdate, - Update: &porchapi.PackageUpdateTaskSpec{ - Upstream: cloneTask.Clone.Upstream, - }, - } - newTask.Update.Upstream.UpstreamRef.Name = newUpstreamPr.Name - pr.Spec.Tasks = append(pr.Spec.Tasks, newTask) - } - - return r.client.Update(r.ctx, pr) -} - -func (r *runner) findPackageRevision(prName string) *porchapi.PackageRevision { - for i := range r.prs { - pr := r.prs[i] - if pr.Name == prName { - return &pr - } - } - return nil -} - -func (r *runner) findCloneTask(pr *porchapi.PackageRevision) *porchapi.Task { - if len(pr.Spec.Tasks) == 0 { - return nil - } - firstTask := pr.Spec.Tasks[0] - if firstTask.Type == porchapi.TaskTypeClone { - return &firstTask - } - return nil -} - -func (r *runner) findPackageRevisionForRef(name string) *porchapi.PackageRevision { - for i := range r.prs { - pr := r.prs[i] - if pr.Spec.PackageName == name && pr.Spec.Revision == r.revision { - return &pr - } - } - return nil -} diff --git a/commands/alpha/rpkg/update/discover.go b/commands/alpha/rpkg/update/discover.go deleted file mode 100644 index 3f25f87f31..0000000000 --- a/commands/alpha/rpkg/update/discover.go +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright 2022 The kpt 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. - -package update - -import ( - "fmt" - "io" - "strings" - - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/spf13/cobra" - "golang.org/x/mod/semver" - "k8s.io/cli-runtime/pkg/printers" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -func (r *runner) discoverUpdates(cmd *cobra.Command, args []string) error { - var prs []porchapi.PackageRevision - var errs []string - if len(args) == 0 || r.discover == downstream { - prs = r.prs - } else { - for i := range args { - pr := r.findPackageRevision(args[i]) - if pr == nil { - errs = append(errs, fmt.Sprintf("could not find package revision %s", args[i])) - continue - } - prs = append(prs, *pr) - } - } - if len(errs) > 0 { - return fmt.Errorf("errors:\n %s", strings.Join(errs, "\n ")) - } - - repositories, err := r.getRepositories() - if err != nil { - return err - } - - switch r.discover { - case upstream: - return r.findUpstreamUpdates(prs, repositories, cmd.OutOrStdout()) - case downstream: - return r.findDownstreamUpdates(prs, repositories, args, cmd.OutOrStdout()) - default: // this should never happen, because we validate in preRunE - return fmt.Errorf("invalid argument %q for --discover", r.discover) - } -} - -func (r *runner) findUpstreamUpdates(prs []porchapi.PackageRevision, repositories *configapi.RepositoryList, w io.Writer) error { - var upstreamUpdates [][]string - for _, pr := range prs { - availableUpdates, upstreamName, _, err := r.availableUpdates(pr.Status.UpstreamLock, repositories) - if err != nil { - return fmt.Errorf("could not parse upstreamLock in Kptfile of package %q: %s", pr.Name, err.Error()) - } - if len(availableUpdates) == 0 { - upstreamUpdates = append(upstreamUpdates, []string{pr.Name, upstreamName, "No update available"}) - } else { - var revisions []string - for i := range availableUpdates { - revisions = append(revisions, availableUpdates[i].Spec.Revision) - } - upstreamUpdates = append(upstreamUpdates, []string{pr.Name, upstreamName, strings.Join(revisions, ", ")}) - } - } - return printUpstreamUpdates(upstreamUpdates, w) -} - -func (r *runner) findDownstreamUpdates(prs []porchapi.PackageRevision, repositories *configapi.RepositoryList, - args []string, w io.Writer) error { - // map from the upstream package revision to a list of its downstream package revisions - downstreamUpdatesMap := make(map[string][]porchapi.PackageRevision) - - for _, pr := range prs { - availableUpdates, _, draftName, err := r.availableUpdates(pr.Status.UpstreamLock, repositories) - if err != nil { - return fmt.Errorf("could not parse upstreamLock in Kptfile of package %q: %s", pr.Name, err.Error()) - } - for _, update := range availableUpdates { - key := fmt.Sprintf("%s:%s:%s", update.Name, update.Spec.Revision, draftName) - downstreamUpdatesMap[key] = append(downstreamUpdatesMap[key], pr) - } - } - return printDownstreamUpdates(downstreamUpdatesMap, args, w) -} - -func (r *runner) availableUpdates(upstreamLock *porchapi.UpstreamLock, repositories *configapi.RepositoryList) ([]porchapi.PackageRevision, string, string, error) { - var availableUpdates []porchapi.PackageRevision - var upstream string - - if upstreamLock == nil || upstreamLock.Git == nil { - return nil, "", "", nil - } - var currentUpstreamRevision string - var draftName string - - // separate the revision number from the package name - lastIndex := strings.LastIndex(upstreamLock.Git.Ref, "/") - if lastIndex < 0 { - // "/" not found - upstreamLock.Git.Ref is not in the expected format - return nil, "", "", fmt.Errorf("malformed upstreamLock.Git.Ref %q", upstreamLock.Git.Ref) - } - - if strings.HasPrefix(upstreamLock.Git.Ref, "drafts") { - // The upstream is not a published package, so doesn't have a revision number. - // Use v0 as a placeholder, so that all published packages get returned as available - // updates. - currentUpstreamRevision = "v0" - draftName = upstreamLock.Git.Ref[lastIndex+1:] - } else { - currentUpstreamRevision = upstreamLock.Git.Ref[lastIndex+1:] - } - - // upstream.git.ref could look like drafts/pkgname/version or pkgname/version - upstreamPackageName := upstreamLock.Git.Ref[:lastIndex] - upstreamPackageName = strings.TrimPrefix(upstreamPackageName, "drafts") - upstreamPackageName = strings.TrimPrefix(upstreamPackageName, "/") - - if !strings.HasSuffix(upstreamLock.Git.Repo, ".git") { - upstreamLock.Git.Repo += ".git" - } - - // find a repo that matches the upstreamLock - var revisions []porchapi.PackageRevision - for _, repo := range repositories.Items { - if repo.Spec.Type != configapi.RepositoryTypeGit { - // we are not currently supporting non-git repos for updates - continue - } - if !strings.HasSuffix(repo.Spec.Git.Repo, ".git") { - repo.Spec.Git.Repo += ".git" - } - if upstreamLock.Git.Repo == repo.Spec.Git.Repo { - upstream = repo.Name - revisions = r.getUpstreamRevisions(repo, upstreamPackageName) - } - } - - for _, upstreamRevision := range revisions { - switch cmp := semver.Compare(upstreamRevision.Spec.Revision, currentUpstreamRevision); { - case cmp > 0: // upstreamRevision > currentUpstreamRevision - availableUpdates = append(availableUpdates, upstreamRevision) - case cmp == 0, cmp < 0: // upstreamRevision <= currentUpstreamRevision, do nothing - } - } - - return availableUpdates, upstream, draftName, nil -} - -// fetches all registered repositories -func (r *runner) getRepositories() (*configapi.RepositoryList, error) { - repoList := configapi.RepositoryList{} - err := r.client.List(r.ctx, &repoList, &client.ListOptions{}) - return &repoList, err -} - -// fetches all package revision numbers for packages with the name upstreamPackageName from the repo -func (r *runner) getUpstreamRevisions(repo configapi.Repository, upstreamPackageName string) []porchapi.PackageRevision { - var result []porchapi.PackageRevision - for _, pkgRev := range r.prs { - if !porchapi.LifecycleIsPublished(pkgRev.Spec.Lifecycle) { - // only consider published packages - continue - } - if pkgRev.Spec.RepositoryName == repo.Name && pkgRev.Spec.PackageName == upstreamPackageName { - result = append(result, pkgRev) - } - } - return result -} - -func printUpstreamUpdates(upstreamUpdates [][]string, w io.Writer) error { - printer := printers.GetNewTabWriter(w) - if _, err := fmt.Fprintln(printer, "PACKAGE REVISION\tUPSTREAM REPOSITORY\tUPSTREAM UPDATES"); err != nil { - return err - } - for _, pkgRev := range upstreamUpdates { - if _, err := fmt.Fprintln(printer, strings.Join(pkgRev, "\t")); err != nil { - return err - } - } - return printer.Flush() -} - -func printDownstreamUpdates(downstreamUpdatesMap map[string][]porchapi.PackageRevision, args []string, w io.Writer) error { - var downstreamUpdates [][]string - for upstreamPkgRev, downstreamPkgRevs := range downstreamUpdatesMap { - split := strings.Split(upstreamPkgRev, ":") - upstreamPkgRevName := split[0] - upstreamPkgRevNum := split[1] - draftName := split[2] - for _, downstreamPkgRev := range downstreamPkgRevs { - if draftName != "" { - // the upstream package revision is not published, so does not have a revision number - downstreamUpdates = append(downstreamUpdates, - []string{upstreamPkgRevName, downstreamPkgRev.Name, fmt.Sprintf("(draft %q)->%s", draftName, upstreamPkgRevNum)}) - continue - } - // figure out which upstream revision the downstream revision is based on - lastIndex := strings.LastIndex(downstreamPkgRev.Status.UpstreamLock.Git.Ref, "v") - if lastIndex < 0 { - // this ref isn't formatted the way that porch expects - continue - } - downstreamRev := downstreamPkgRev.Status.UpstreamLock.Git.Ref[lastIndex:] - downstreamUpdates = append(downstreamUpdates, - []string{upstreamPkgRevName, downstreamPkgRev.Name, fmt.Sprintf("%s->%s", downstreamRev, upstreamPkgRevNum)}) - } - } - - var pkgRevsToPrint [][]string - if len(args) != 0 { - for _, arg := range args { - for _, pkgRev := range downstreamUpdates { - // filter out irrelevant packages based on provided args - if arg == pkgRev[0] { - pkgRevsToPrint = append(pkgRevsToPrint, pkgRev) - } - } - } - } else { - pkgRevsToPrint = downstreamUpdates - } - - printer := printers.GetNewTabWriter(w) - if len(pkgRevsToPrint) == 0 { - if _, err := fmt.Fprintln(printer, "All downstream packages are up to date."); err != nil { - return err - } - } else { - if _, err := fmt.Fprintln(printer, "PACKAGE REVISION\tDOWNSTREAM PACKAGE\tDOWNSTREAM UPDATE"); err != nil { - return err - } - for _, pkgRev := range pkgRevsToPrint { - if _, err := fmt.Fprintln(printer, strings.Join(pkgRev, "\t")); err != nil { - return err - } - } - } - return printer.Flush() -} diff --git a/commands/alpha/rpkg/util/common.go b/commands/alpha/rpkg/util/common.go deleted file mode 100644 index 5a2048ff18..0000000000 --- a/commands/alpha/rpkg/util/common.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2023 The kpt 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. - -package util - -import ( - "context" - "fmt" - - fnsdk "github.com/GoogleContainerTools/kpt-functions-sdk/go/fn" - kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - ResourceVersionAnnotation = "internal.kpt.dev/resource-version" -) - -func PackageAlreadyExists(ctx context.Context, c client.Client, repository, packageName, namespace string) (bool, error) { - // only the first package revision can be created from init or clone, so - // we need to check that the package doesn't already exist. - packageRevisionList := api.PackageRevisionList{} - if err := c.List(ctx, &packageRevisionList, &client.ListOptions{ - Namespace: namespace, - }); err != nil { - return false, err - } - for _, pr := range packageRevisionList.Items { - if pr.Spec.RepositoryName == repository && pr.Spec.PackageName == packageName { - return true, nil - } - } - return false, nil -} - -func GetResourceFileKubeObject(prr *api.PackageRevisionResources, file, kind, name string) (*fnsdk.KubeObject, error) { - if prr.Spec.Resources == nil { - return nil, fmt.Errorf("nil resources found for PackageRevisionResources '%s/%s'", prr.Namespace, prr.Name) - } - - if _, ok := prr.Spec.Resources[file]; !ok { - return nil, fmt.Errorf("%q not found in PackageRevisionResources '%s/%s'", file, prr.Namespace, prr.Name) - } - - ko, err := fnsdk.ParseKubeObject([]byte(prr.Spec.Resources[file])) - if err != nil { - return nil, fmt.Errorf("failed to parse %q of PackageRevisionResources %s/%s: %w", file, prr.Namespace, prr.Name, err) - } - if kind != "" && ko.GetKind() != kind { - return nil, fmt.Errorf("%q does not contain kind %q in PackageRevisionResources '%s/%s'", file, kind, prr.Namespace, prr.Name) - } - if name != "" && ko.GetName() != name { - return nil, fmt.Errorf("%q does not contain resource named %q in PackageRevisionResources '%s/%s'", file, name, prr.Namespace, prr.Name) - } - - return ko, nil -} - -func GetResourceVersion(prr *api.PackageRevisionResources) (string, error) { - ko, err := GetResourceFileKubeObject(prr, kptfilev1.RevisionMetaDataFileName, kptfilev1.RevisionMetaDataKind, "") - if err != nil { - return "", err - } - rv, _, _ := ko.NestedString("metadata", "resourceVersion") - return rv, nil -} - -func AddRevisionMetadata(prr *api.PackageRevisionResources) error { - kptMetaDataKo := fnsdk.NewEmptyKubeObject() - kptMetaDataKo.SetAPIVersion(prr.APIVersion) - kptMetaDataKo.SetKind(kptfilev1.RevisionMetaDataKind) - if err := kptMetaDataKo.SetNestedField(prr.GetObjectMeta(), "metadata"); err != nil { - return fmt.Errorf("cannot set metadata: %v", err) - } - prr.Spec.Resources[kptfilev1.RevisionMetaDataFileName] = kptMetaDataKo.String() - - return nil -} - -func RemoveRevisionMetadata(prr *api.PackageRevisionResources) error { - delete(prr.Spec.Resources, kptfilev1.RevisionMetaDataFileName) - return nil -} diff --git a/commands/alpha/sync/create/command.go b/commands/alpha/sync/create/command.go deleted file mode 100644 index 31c8fb3046..0000000000 --- a/commands/alpha/sync/create/command.go +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2022 The kpt 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. - -package create - -import ( - "context" - "fmt" - - "github.com/GoogleContainerTools/kpt/commands/util" - "github.com/GoogleContainerTools/kpt/internal/docs/generated/syncdocs" - "github.com/GoogleContainerTools/kpt/internal/errors" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/spf13/cobra" - coreapi "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/cli-runtime/pkg/genericclioptions" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - command = "cmdsync.create" -) - -func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner { - r := &runner{ - ctx: ctx, - cfg: rcg, - } - c := &cobra.Command{ - Use: "create NAME", - Short: syncdocs.CreateShort, - Long: syncdocs.CreateShort + "\n" + syncdocs.CreateLong, - Example: syncdocs.CreateExamples, - PreRunE: r.preRunE, - RunE: r.runE, - Hidden: porch.HidePorchCommands, - } - r.Command = c - - c.Flags().StringVar(&r.syncPkg, "package", "", "Name of the package revision to sync. Required.") - - return r -} - -func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command { - return newRunner(ctx, rcg).Command -} - -type runner struct { - ctx context.Context - cfg *genericclioptions.ConfigFlags - client client.Client - Command *cobra.Command - - // Flags - syncPkg string -} - -func (r *runner) preRunE(_ *cobra.Command, args []string) error { - const op errors.Op = command + ".preRunE" - - if len(args) == 0 { - return errors.E(op, "NAME is required positional argument") - } - if r.syncPkg == "" { - return errors.E(op, "--package is a required flag") - } - - client, err := porch.CreateDynamicClient(r.cfg) - if err != nil { - return errors.E(op, err) - } - - r.client = client - return nil -} - -func (r *runner) runE(_ *cobra.Command, args []string) error { - const op errors.Op = command + ".runE" - - syncName := args[0] - - var pr porchapi.PackageRevision - if err := r.client.Get(r.ctx, client.ObjectKey{ - Namespace: *r.cfg.Namespace, - Name: r.syncPkg, - }, &pr); err != nil { - return errors.E(op, err) - } - - var repository configapi.Repository - if err := r.client.Get(r.ctx, client.ObjectKey{ - Namespace: *r.cfg.Namespace, - Name: pr.Spec.RepositoryName, - }, &repository); err != nil { - return errors.E(op, err) - } - - if repository.Spec.Type != configapi.RepositoryTypeGit { - return errors.E(op, fmt.Sprintf("repository %s/%s is not a git repository; %s is not supported", - repository.Namespace, repository.Name, repository.Spec.Type)) - } - if repository.Spec.Git == nil { - return errors.E(op, fmt.Sprintf("repository %s/%s is missing Git spec", repository.Namespace, repository.Name)) - } - - var secret coreapi.Secret - - if secretName := repository.Spec.Git.SecretRef.Name; secretName != "" { - var repositorySecret coreapi.Secret - key := client.ObjectKey{Namespace: *r.cfg.Namespace, Name: repository.Spec.Git.SecretRef.Name} - if err := r.client.Get(r.ctx, key, &repositorySecret); err != nil { - return errors.E(op, fmt.Sprintf("cannot retrieve repository credentials %s: %v", key, err)) - } - - secret = coreapi.Secret{ - TypeMeta: metav1.TypeMeta{ - Kind: "Secret", - APIVersion: coreapi.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("%s-auth", syncName), - Namespace: util.RootSyncNamespace, - }, - Data: map[string][]byte{ - "username": repositorySecret.Data["username"], - "token": repositorySecret.Data["password"], - }, - } - - if err := porch.Apply(r.ctx, r.client, &secret); err != nil { - return errors.E(op, err) - } - } - - git := map[string]interface{}{ - "repo": repository.Spec.Git.Repo, - "revision": fmt.Sprintf("%s/%s", pr.Spec.PackageName, pr.Spec.Revision), - "dir": pr.Spec.PackageName, - "branch": repository.Spec.Git.Branch, - } - - if secret.Name != "" { - git["auth"] = "token" - git["secretRef"] = map[string]interface{}{ - "name": secret.Name, - } - } - - rootsync := &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "configsync.gke.io/v1beta1", - "kind": "RootSync", - "metadata": map[string]interface{}{ - "name": syncName, - "namespace": util.RootSyncNamespace, - }, - "spec": map[string]interface{}{ - "sourceFormat": "unstructured", - "git": git, - }, - }, - } - - fmt.Println(rootsync.GetName()) - fmt.Println(rootsync.GetNamespace()) - - if err := porch.Apply(r.ctx, r.client, rootsync); err != nil { - return errors.E(op, err) - } - - fmt.Fprintf(r.Command.OutOrStderr(), "Created RootSync config-management-system/%s", syncName) - return nil -} diff --git a/commands/alpha/sync/delete/command.go b/commands/alpha/sync/delete/command.go deleted file mode 100644 index 5718234f41..0000000000 --- a/commands/alpha/sync/delete/command.go +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright 2022 The kpt 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. - -package delete - -import ( - "context" - "fmt" - "time" - - "github.com/GoogleContainerTools/kpt/commands/util" - "github.com/GoogleContainerTools/kpt/internal/docs/generated/syncdocs" - "github.com/GoogleContainerTools/kpt/internal/errors" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - "github.com/spf13/cobra" - coreapi "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/cli-runtime/pkg/genericclioptions" - "sigs.k8s.io/cli-utils/pkg/kstatus/status" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - command = "cmdsync.delete" - emptyRepo = "https://github.com/platkrm/empty" - emptyRepoBranch = "main" - defaultTimeout = 2 * time.Minute -) - -var ( - rootSyncGVK = schema.GroupVersionKind{ - Group: "configsync.gke.io", - Version: "v1beta1", - Kind: "RootSync", - } - resourceGroupGVK = schema.GroupVersionKind{ - Group: "kpt.dev", - Version: "v1alpha1", - Kind: "ResourceGroup", - } -) - -func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command { - return newRunner(ctx, rcg).Command -} - -func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner { - r := &runner{ - ctx: ctx, - cfg: rcg, - } - c := &cobra.Command{ - Use: "del REPOSITORY [flags]", - Aliases: []string{"delete"}, - Short: syncdocs.DeleteShort, - Long: syncdocs.DeleteShort + "\n" + syncdocs.DeleteLong, - Example: syncdocs.DeleteExamples, - PreRunE: r.preRunE, - RunE: r.runE, - Hidden: porch.HidePorchCommands, - } - r.Command = c - - c.Flags().BoolVar(&r.keepSecret, "keep-auth-secret", false, "Keep the auth secret associated with the RootSync resource, if any") - c.Flags().DurationVar(&r.timeout, "timeout", defaultTimeout, "How long to wait for Config Sync to delete package RootSync") - - return r -} - -type runner struct { - ctx context.Context - cfg *genericclioptions.ConfigFlags - client client.WithWatch - Command *cobra.Command - - // Flags - keepSecret bool - timeout time.Duration -} - -func (r *runner) preRunE(_ *cobra.Command, _ []string) error { - const op errors.Op = command + ".preRunE" - client, err := porch.CreateDynamicClient(r.cfg) - if err != nil { - return errors.E(op, err) - } - r.client = client - return nil -} - -func (r *runner) runE(_ *cobra.Command, args []string) error { - const op errors.Op = command + ".runE" - - if len(args) == 0 { - return errors.E(op, fmt.Errorf("NAME is a required positional argument")) - } - - name := args[0] - namespace := util.RootSyncNamespace - if *r.cfg.Namespace != "" { - namespace = *r.cfg.Namespace - } - key := client.ObjectKey{ - Namespace: namespace, - Name: name, - } - rs := unstructured.Unstructured{} - rs.SetGroupVersionKind(rootSyncGVK) - if err := r.client.Get(r.ctx, key, &rs); err != nil { - return errors.E(op, fmt.Errorf("cannot get %s: %v", key, err)) - } - - git, found, err := unstructured.NestedMap(rs.Object, "spec", "git") - if err != nil || !found { - return errors.E(op, fmt.Errorf("couldn't find `spec.git`: %v", err)) - } - - git["repo"] = emptyRepo - git["branch"] = emptyRepoBranch - git["dir"] = "" - git["revision"] = "" - - if err := unstructured.SetNestedMap(rs.Object, git, "spec", "git"); err != nil { - return errors.E(op, err) - } - - fmt.Println("Deleting synced resources..") - if err := r.client.Update(r.ctx, &rs); err != nil { - return errors.E(op, err) - } - - if err := func() error { - ctx, cancel := context.WithTimeout(r.ctx, r.timeout) - defer cancel() - - if err := r.waitForRootSync(ctx, name, namespace); err != nil { - return err - } - - fmt.Println("Waiting for deleted resources to be removed..") - return r.waitForResourceGroup(ctx, name, namespace) - }(); err != nil { - // TODO: See if we can expose more information here about what might have prevented a package - // from being deleted. - e := fmt.Errorf("package %s failed to be deleted after %f seconds: %v", name, r.timeout.Seconds(), err) - return errors.E(op, e) - } - - if err := r.client.Delete(r.ctx, &rs); err != nil { - return errors.E(op, fmt.Errorf("failed to clean up RootSync: %w", err)) - } - - rg := unstructured.Unstructured{} - rg.SetGroupVersionKind(resourceGroupGVK) - rg.SetName(rs.GetName()) - rg.SetNamespace(rs.GetNamespace()) - if err := r.client.Delete(r.ctx, &rg); err != nil { - return errors.E(op, fmt.Errorf("failed to clean up ResourceGroup: %w", err)) - } - - if r.keepSecret { - return nil - } - - secret := getSecretName(&rs) - if secret == "" { - return nil - } - - if err := r.client.Delete(r.ctx, &coreapi.Secret{ - TypeMeta: metav1.TypeMeta{ - Kind: "Secret", - APIVersion: coreapi.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: secret, - Namespace: namespace, - }, - }); err != nil { - return errors.E(op, fmt.Errorf("failed to delete Secret %s: %w", secret, err)) - } - - fmt.Printf("Sync %s successfully deleted\n", name) - return nil -} - -func (r *runner) waitForRootSync(ctx context.Context, name string, namespace string) error { - const op errors.Op = command + ".waitForRootSync" - - return r.waitForResource(ctx, resourceGroupGVK, name, namespace, func(u *unstructured.Unstructured) (bool, error) { - res, err := status.Compute(u) - if err != nil { - return false, errors.E(op, err) - } - if res.Status == status.CurrentStatus { - return true, nil - } - return false, nil - }) -} - -func (r *runner) waitForResourceGroup(ctx context.Context, name string, namespace string) error { - const op errors.Op = command + ".waitForResourceGroup" - - return r.waitForResource(ctx, resourceGroupGVK, name, namespace, func(u *unstructured.Unstructured) (bool, error) { - resources, found, err := unstructured.NestedSlice(u.Object, "spec", "resources") - if err != nil { - return false, errors.E(op, err) - } - if !found { - return true, nil - } - if len(resources) == 0 { - return true, nil - } - return false, nil - }) -} - -type ReconcileFunc func(*unstructured.Unstructured) (bool, error) - -func (r *runner) waitForResource(ctx context.Context, gvk schema.GroupVersionKind, name, namespace string, reconcileFunc ReconcileFunc) error { - const op errors.Op = command + ".waitForResource" - - u := unstructured.UnstructuredList{} - u.SetGroupVersionKind(gvk) - watch, err := r.client.Watch(r.ctx, &u) - if err != nil { - return errors.E(op, err) - } - defer watch.Stop() - - for { - select { - case ev, ok := <-watch.ResultChan(): - if !ok { - return errors.E(op, fmt.Errorf("watch closed unexpectedly")) - } - if ev.Object == nil { - continue - } - - u := ev.Object.(*unstructured.Unstructured) - - if u.GetName() != name || u.GetNamespace() != namespace { - continue - } - - reconciled, err := reconcileFunc(u) - if err != nil { - return err - } - if reconciled { - return nil - } - case <-ctx.Done(): - return ctx.Err() - } - } -} - -func getSecretName(repo *unstructured.Unstructured) string { - name, _, _ := unstructured.NestedString(repo.Object, "spec", "git", "secretRef", "name") - return name -} diff --git a/commands/alpha/sync/get/command.go b/commands/alpha/sync/get/command.go deleted file mode 100644 index 5ae7a26f30..0000000000 --- a/commands/alpha/sync/get/command.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2022 The kpt 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. - -package get - -import ( - "context" - "fmt" - - "github.com/GoogleContainerTools/kpt/commands/util" - "github.com/GoogleContainerTools/kpt/internal/docs/generated/syncdocs" - "github.com/GoogleContainerTools/kpt/internal/errors" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/cli-runtime/pkg/printers" - "k8s.io/kubectl/pkg/cmd/get" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - command = "cmdsync.get" -) - -func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner { - r := &runner{ - ctx: ctx, - cfg: rcg, - printFlags: get.NewGetPrintFlags(), - } - c := &cobra.Command{ - Use: "get NAME", - Short: syncdocs.GetShort, - Long: syncdocs.GetShort + "\n" + syncdocs.GetLong, - Example: syncdocs.GetExamples, - PreRunE: r.preRunE, - RunE: r.runE, - Hidden: porch.HidePorchCommands, - } - r.Command = c - - // Create flags - r.printFlags.AddFlags(c) - - return r -} - -func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command { - return newRunner(ctx, rcg).Command -} - -type runner struct { - ctx context.Context - cfg *genericclioptions.ConfigFlags - client client.Client - Command *cobra.Command - - // Flags - printFlags *get.PrintFlags -} - -func (r *runner) preRunE(_ *cobra.Command, _ []string) error { - const op errors.Op = command + ".preRunE" - client, err := porch.CreateDynamicClient(r.cfg) - if err != nil { - return errors.E(op, err) - } - r.client = client - return nil -} - -func (r *runner) runE(cmd *cobra.Command, args []string) error { - const op errors.Op = command + ".runE" - - if len(args) == 0 { - return errors.E(op, "NAME is required positional argument") - } - - name := args[0] - namespace := util.RootSyncNamespace - if *r.cfg.Namespace != "" { - namespace = *r.cfg.Namespace - } - key := client.ObjectKey{ - Namespace: namespace, - Name: name, - } - rs := unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "configsync.gke.io/v1beta1", - "kind": "RootSync", - }, - } - if err := r.client.Get(r.ctx, key, &rs); err != nil { - return errors.E(op, fmt.Errorf("cannot get %s: %v", key, err)) - } - - printer, err := r.printFlags.ToPrinter() - if err != nil { - return errors.E(op, err) - } - - w := printers.GetNewTabWriter(cmd.OutOrStdout()) - - if err := printer.PrintObj(&rs, w); err != nil { - return errors.E(op, err) - } - if err := w.Flush(); err != nil { - return errors.E(op, err) - } - - return nil -} diff --git a/commands/alpha/sync/synccmd.go b/commands/alpha/sync/synccmd.go deleted file mode 100644 index d7171e079b..0000000000 --- a/commands/alpha/sync/synccmd.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2022 The kpt 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. - -package sync - -import ( - "context" - "flag" - "fmt" - - "github.com/GoogleContainerTools/kpt/commands/alpha/sync/create" - "github.com/GoogleContainerTools/kpt/commands/alpha/sync/delete" - "github.com/GoogleContainerTools/kpt/commands/alpha/sync/get" - "github.com/GoogleContainerTools/kpt/internal/docs/generated/syncdocs" - "github.com/GoogleContainerTools/kpt/internal/util/porch" - "github.com/spf13/cobra" - "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/client-go/rest" -) - -func NewCommand(ctx context.Context, version string) *cobra.Command { - sync := &cobra.Command{ - Use: "sync", - Short: "[Alpha] " + syncdocs.SyncShort, - Long: "[Alpha] " + syncdocs.SyncLong, - RunE: func(cmd *cobra.Command, args []string) error { - h, err := cmd.Flags().GetBool("help") - if err != nil { - return err - } - if h { - return cmd.Help() - } - return cmd.Usage() - }, - Hidden: porch.HidePorchCommands, - } - - pf := sync.PersistentFlags() - - kubeflags := genericclioptions.NewConfigFlags(true) - kubeflags.AddFlags(pf) - - kubeflags.WrapConfigFn = func(rc *rest.Config) *rest.Config { - rc.UserAgent = fmt.Sprintf("kpt/%s", version) - return rc - } - - pf.AddGoFlagSet(flag.CommandLine) - - sync.AddCommand( - create.NewCommand(ctx, kubeflags), - get.NewCommand(ctx, kubeflags), - delete.NewCommand(ctx, kubeflags), - ) - - return sync -} diff --git a/go.mod b/go.mod index d505347846..b2a0e34c51 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module github.com/GoogleContainerTools/kpt go 1.21 require ( - github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220506190241-f85503febd54 github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20230121152246-dc44dbd18a33 github.com/GoogleContainerTools/kpt/rollouts v0.0.0-20230209223911-c6c49d0a0636 github.com/bytecodealliance/wasmtime-go v0.39.0 diff --git a/go.sum b/go.sum index d6e679e125..24fd7d70e0 100644 --- a/go.sum +++ b/go.sum @@ -39,8 +39,6 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOEl github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= 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/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220506190241-f85503febd54 h1:z5iYiugZJiTzQ6ggU0Cae/T+LkrDwcqZyebh8SbmQ0E= -github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220506190241-f85503febd54/go.mod h1:vl3iiwgrqdDgvGi5ckt3O9IoyaHUgFkfxE4RjQIqgwk= github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20230121152246-dc44dbd18a33 h1:9M1bvq7hU/JTY4VVcqhCQT0eAa5HznrFaLAm2ldfe70= github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20230121152246-dc44dbd18a33/go.mod h1:ASrhnLAL4ahTuiUJyepqcpVRXIoRMJyDs8/eSxwhgZM= github.com/GoogleContainerTools/kpt/rollouts v0.0.0-20230209223911-c6c49d0a0636 h1:9oUTINyozQvQ78QvKM3jTLI54oKMrq9V1VYpb4m8Asc= diff --git a/internal/gitutil/gitutil.go b/internal/gitutil/gitutil.go index 41a3e14976..454b942fab 100644 --- a/internal/gitutil/gitutil.go +++ b/internal/gitutil/gitutil.go @@ -330,7 +330,7 @@ func (gur *GitUpstreamRepo) ResolveRef(ref string) (string, bool) { func (gur *GitUpstreamRepo) getRepoDir(uri string) string { if runtime.GOOS == "windows" { var hash = md5.Sum([]byte(uri)) - return strings.ToLower(hex.EncodeToString(hash[:])) + return strings.ToLower(hex.EncodeToString(hash[:])) } return strings.ToLower(base32.StdEncoding.EncodeToString(md5.New().Sum([]byte(uri)))) } diff --git a/pkg/api/kptfile/v1/types.go b/pkg/api/kptfile/v1/types.go index 29aa28b20a..57563c256e 100644 --- a/pkg/api/kptfile/v1/types.go +++ b/pkg/api/kptfile/v1/types.go @@ -24,8 +24,6 @@ import ( "sigs.k8s.io/kustomize/kyaml/yaml" ) -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 object:headerFile="../../../../porch/scripts/boilerplate.go.txt" - const ( KptFileName = "Kptfile" diff --git a/porch/.dockerignore b/porch/.dockerignore deleted file mode 100644 index 12b36705b8..0000000000 --- a/porch/.dockerignore +++ /dev/null @@ -1,4 +0,0 @@ -.build/ -.cache/ -default.etcd/ -apiserver.local.config/ diff --git a/porch/.gitignore b/porch/.gitignore deleted file mode 100644 index 080778b336..0000000000 --- a/porch/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -vendor/ -apiserver.local.config/ -/apiserver/porch - -# Development artifact path -.build/ -default.etcd/ - -# Local cache files -.cache/ diff --git a/porch/.vscode/launch.json b/porch/.vscode/launch.json deleted file mode 100644 index 6ae3651e66..0000000000 --- a/porch/.vscode/launch.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Launch test function", - "type": "go", - "request": "launch", - "mode": "test", - "program": "${workspaceFolder}/apiserver/pkg/e2e", - "args": [ - "-test.run", - "TestE2E/PorchSuite/TestCloneIntoDeploymentRepository" - ] - }, - { - "name": "Launch Server", - "type": "go", - "request": "launch", - "mode": "auto", - "program": "${workspaceFolder}/cmd/porch/main.go", - "args": [ - "--secure-port=9443", - "--v=7", - "--standalone-debug-mode", - "--kubeconfig=${workspaceFolder}/deployments/local/kubeconfig", - "--cache-directory=${workspaceFolder}/.cache", - "--function-runner=192.168.8.202:9445" - ], - "cwd": "${workspaceFolder}" - }, - { - "name": "Launch Func Client", - "type": "go", - "request": "launch", - "mode": "auto", - "program": "${workspaceFolder}/func/client/main.go", - "args": [ - "--address=192.168.8.202:9445", - "--package=${workspaceFolder}/func/config/", - "--image=gcr.io/kpt-fn/set-namespace:v0.2.0", - "--", - "namespace=foo" - ] - }, - { - "name": "Launch kpt", - "type": "go", - "request": "launch", - "mode": "auto", - "program": "${workspaceFolder}/../main.go", - "args": [ - "alpha", "rpkg", "get" - ], - "cwd": "${workspaceFolder}/.." - }, - { - "name": "Launch kpt e2e test", - "type": "go", - "request": "launch", - "mode": "test", - "program": "${workspaceFolder}/../e2e", - "args": [ - "-v", - "-test.run", - "TestPorch" - ] - } - ] -} \ No newline at end of file diff --git a/porch/Makefile b/porch/Makefile deleted file mode 100644 index d4083608f2..0000000000 --- a/porch/Makefile +++ /dev/null @@ -1,277 +0,0 @@ -# Copyright 2022 The kpt 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. - -MYGOBIN := $(shell go env GOPATH)/bin -KUBECONFIG=$(CURDIR)/deployments/local/kubeconfig -BUILDDIR=$(CURDIR)/.build -CACHEDIR=$(CURDIR)/.cache -DEPLOYCONFIGDIR=$(BUILDDIR)/deploy -DEPLOYCONFIG_NO_SA_DIR=$(BUILDDIR)/deploy-no-sa -KPTDIR=$(abspath $(CURDIR)/..) - -# Modules are ordered in dependency order. A module precedes modules that depend on it. -MODULES = \ - examples/apps/hello-server \ - api \ - . \ - controllers \ - -# GCP project to use for development -export GCP_PROJECT_ID ?= $(shell gcloud config get-value project) -export IMAGE_REPO ?= gcr.io/$(GCP_PROJECT_ID) -export IMAGE_TAG -ifndef IMAGE_TAG - git_tag := $(shell git rev-parse --short HEAD || "latest" ) - $(shell git diff --quiet) - ifneq ($(.SHELLSTATUS), 0) - git_tag := $(git_tag)-dirty - endif - - IMAGE_TAG=$(git_tag) -endif - -PORCH_SERVER_IMAGE ?= porch-server -PORCH_FUNCTION_RUNNER_IMAGE ?= porch-function-runner -PORCH_CONTROLLERS_IMAGE ?= porch-controllers -PORCH_WRAPPER_SERVER_IMAGE ?= porch-wrapper-server -TEST_GIT_SERVER_IMAGE ?= test-git-server - -# Only enable a subset of reconcilers in porch controllers by default. Use the RECONCILERS -# env variable to specify a specific list of reconcilers or use -# RECONCILERS=* to enable all known reconcilers. -ALL_RECONCILERS="rootsyncsets,remoterootsyncsets,workloadidentitybindings,rootsyncdeployments,functiondiscovery,packagevariants,packagevariantsets,rootsyncrollouts,fleetsyncs" -ifndef RECONCILERS - ENABLED_RECONCILERS="rootsyncsets,remoterootsyncsets,workloadidentitybindings,functiondiscovery,packagevariants,packagevariantsets" -else - ifeq ($(RECONCILERS),*) - ENABLED_RECONCILERS=${ALL_RECONCILERS} - else - ENABLED_RECONCILERS=$(RECONCILERS) - endif -endif - -.DEFAULT_GOAL := all - -.PHONY: all -all: stop network start-etcd start-kube-apiserver start-function-runner run-local - -.PHONY: network -network: - docker network create --subnet 192.168.8.0/24 porch - -.PHONY: stop -stop: - docker stop kube-apiserver || true - docker rm kube-apiserver || true - docker stop etcd || true - docker rm etcd || true - docker stop function-runner || true - docker rm function-runner || true - docker network rm porch || true - -.PHONY: start-etcd -start-etcd: - docker buildx build -t etcd --output=type=docker -f ./build/Dockerfile.etcd ./build - mkdir -p $(BUILDDIR)/data/etcd - docker stop etcd || true - docker rm etcd || true - docker run --detach --user `id -u`:`id -g` \ - --network=porch \ - --ip 192.168.8.200 \ - --name etcd -v $(BUILDDIR)/data/etcd:/data \ - etcd --listen-client-urls http://0.0.0.0:2379 --advertise-client-urls http://127.0.0.1:2379 - -.PHONY: start-kube-apiserver -start-kube-apiserver: - docker buildx build -t kube-apiserver --output=type=docker -f ./build/Dockerfile.apiserver ./build - docker stop kube-apiserver || true - docker rm kube-apiserver || true - deployments/local/makekeys.sh - docker run --detach --user `id -u`:`id -g` \ - --network=porch \ - --ip 192.168.8.201 \ - --name kube-apiserver -v $(BUILDDIR)/pki:/pki \ - --add-host host.docker.internal:host-gateway \ - kube-apiserver \ - --etcd-servers http://etcd:2379 \ - --secure-port 9444 \ - --service-account-issuer=https://kubernetes.default.svc.cluster.local \ - --service-account-key-file=/pki/service-account.pub \ - --service-account-signing-key-file=/pki/service-account.key \ - --cert-dir=/pki \ - --authorization-mode=RBAC \ - --anonymous-auth=false \ - --client-ca-file=/pki/ca.crt - -.PHONY: start-function-runner -start-function-runner: - IMAGE_NAME="$(PORCH_FUNCTION_RUNNER_IMAGE)" $(MAKE) -C ./func build-image - docker stop function-runner || true - docker rm -f function-runner || true - docker run --detach \ - --network=porch \ - --ip 192.168.8.202 \ - --name function-runner \ - $(IMAGE_REPO)/$(PORCH_FUNCTION_RUNNER_IMAGE):$(IMAGE_TAG) \ - -disable-runtimes pod - -.PHONY: generate -generate: - @for f in $(MODULES); do (cd $$f; echo "Generating $$f"; go generate -v ./...) || exit 1; done - -.PHONY: tidy -tidy: - @for f in $(MODULES); do (cd $$f; echo "Tidying $$f"; go mod tidy) || exit 1; done - -.PHONY: test -test: - @for f in $(MODULES); do (cd $$f; echo "Testing $$f"; E2E=1 go test -race --count=1 ./...) || exit 1; done - -.PHONY: vet -vet: - @for f in $(MODULES); do (cd $$f; echo "Checking $$f"; go run honnef.co/go/tools/cmd/staticcheck@latest ./...); done - @for f in $(MODULES); do (cd $$f; echo "Vetting $$f"; go vet ./...) || exit 1; done - -.PHONY: fmt -fmt: - @for f in $(MODULES); do (cd $$f; echo "Formatting $$f"; gofmt -s -w .); done - -PORCH = $(BUILDDIR)/porch - -.PHONY: run-local -run-local: porch - KUBECONFIG=$(KUBECONFIG) kubectl apply -f deployments/local/localconfig.yaml - KUBECONFIG=$(KUBECONFIG) kubectl apply -f api/porchconfig/v1alpha1/ - KUBECONFIG=$(KUBECONFIG) kubectl apply -f internal/api/porchinternal/v1alpha1/ - $(PORCH) \ - --secure-port 9443 \ - --standalone-debug-mode \ - --kubeconfig="$(KUBECONFIG)" \ - --cache-directory="$(CACHEDIR)" \ - --function-runner 192.168.8.202:9445 \ - --repo-sync-frequency=60s - -.PHONY: run-jaeger -run-jaeger: - docker run --rm --name jaeger -d -p4317:55680 -p6831:6831/udp -p16686:16686 jaegertracing/opentelemetry-all-in-one:latest - -.PHONY: porch -porch: - go build -o $(PORCH) ./cmd/porch - -.PHONY: fix-headers -fix-headers: - ../scripts/update-license.sh - -.PHONY: fix-all -fix-all: fix-headers fmt tidy - -.PHONY: push-images -push-images: - docker buildx build --push --tag $(IMAGE_REPO)/$(PORCH_SERVER_IMAGE):$(IMAGE_TAG) -f ./build/Dockerfile.porch "$(KPTDIR)" - IMAGE_NAME="$(PORCH_CONTROLLERS_IMAGE)" make -C controllers/ push-image - IMAGE_NAME="$(PORCH_FUNCTION_RUNNER_IMAGE)" WRAPPER_SERVER_IMAGE_NAME="$(PORCH_WRAPPER_SERVER_IMAGE)" make -C func/ push-image - IMAGE_NAME="$(TEST_GIT_SERVER_IMAGE)" make -C test/ push-image - -.PHONY: build-images -build-images: - docker buildx build --load --tag $(IMAGE_REPO)/$(PORCH_SERVER_IMAGE):$(IMAGE_TAG) -f ./build/Dockerfile.porch "$(KPTDIR)" - IMAGE_NAME="$(PORCH_CONTROLLERS_IMAGE)" make -C controllers/ build-image - IMAGE_NAME="$(PORCH_FUNCTION_RUNNER_IMAGE)" WRAPPER_SERVER_IMAGE_NAME="$(PORCH_WRAPPER_SERVER_IMAGE)" make -C func/ build-image - IMAGE_NAME="$(TEST_GIT_SERVER_IMAGE)" make -C test/ build-image - -.PHONY: dev-server -dev-server: - docker buildx build --push --tag $(IMAGE_REPO)/$(PORCH_SERVER_IMAGE):$(IMAGE_TAG) -f ./build/Dockerfile.porch "$(KPTDIR)" - kubectl set image -n porch-system deployment/porch-server porch-server=$(IMAGE_REPO)/$(PORCH_SERVER_IMAGE):${IMAGE_TAG} - -.PHONY: apply-dev-config -apply-dev-config: - # TODO: Replace with KCC (or self-host a registry?) - gcloud services enable artifactregistry.googleapis.com - gcloud artifacts repositories describe --location=us-west1 packages --format="value(name)" || gcloud artifacts repositories create --location=us-west1 --repository-format=docker packages - - # TODO: Replace with kpt function - cat config/samples/oci-repository.yaml | sed -e s/example-google-project-id/${GCP_PROJECT_ID}/g | kubectl apply -f - - - # TODO: Replace with KCC (or self-host a registry?) - gcloud services enable artifactregistry.googleapis.com - gcloud artifacts repositories describe --location=us-west1 deployment --format="value(name)" || gcloud artifacts repositories create --location=us-west1 --repository-format=docker deployment - - # TODO: Replace with kpt function - cat config/samples/deployment-repository.yaml | sed -e s/example-google-project-id/${GCP_PROJECT_ID}/g | kubectl apply -f - - -.PHONY: deployment-config -deployment-config: - rm -rf $(DEPLOYCONFIGDIR) || true - mkdir -p $(DEPLOYCONFIGDIR) - ./scripts/create-deployment-blueprint.sh \ - --destination "$(DEPLOYCONFIGDIR)" \ - --server-image "$(IMAGE_REPO)/$(PORCH_SERVER_IMAGE):$(IMAGE_TAG)" \ - --controllers-image "$(IMAGE_REPO)/$(PORCH_CONTROLLERS_IMAGE):$(IMAGE_TAG)" \ - --function-image "$(IMAGE_REPO)/$(PORCH_FUNCTION_RUNNER_IMAGE):$(IMAGE_TAG)" \ - --wrapper-server-image "$(IMAGE_REPO)/$(PORCH_WRAPPER_SERVER_IMAGE):$(IMAGE_TAG)" \ - --enabled-reconcilers "$(ENABLED_RECONCILERS)" \ - --project "$(GCP_PROJECT_ID)" - -.PHONY: deploy -deploy: deployment-config - kubectl apply -R -f $(DEPLOYCONFIGDIR) - -.PHONY: push-and-deploy -push-and-deploy: push-images deploy - -# Builds deployment config without configuring GCP workload identity for -# Porch server. This is sufficient for working with GitHub repositories. -# Workload identity is currently required for Porch to integrate with GCP -# Container and Artifact Registries; for those use cases, use the make -# targets without the `-no-sa` suffix (i.e. `deployment-config`, -# `push-and-deploy` etc.) -.PHONY: deployment-config-no-sa -deployment-config-no-sa: - rm -rf $(DEPLOYCONFIG_NO_SA_DIR) || true - mkdir -p $(DEPLOYCONFIG_NO_SA_DIR) - ./scripts/create-deployment-blueprint.sh \ - --destination "$(DEPLOYCONFIG_NO_SA_DIR)" \ - --server-image "$(IMAGE_REPO)/$(PORCH_SERVER_IMAGE):$(IMAGE_TAG)" \ - --controllers-image "$(IMAGE_REPO)/$(PORCH_CONTROLLERS_IMAGE):$(IMAGE_TAG)" \ - --function-image "$(IMAGE_REPO)/$(PORCH_FUNCTION_RUNNER_IMAGE):$(IMAGE_TAG)" \ - --wrapper-server-image "$(IMAGE_REPO)/$(PORCH_WRAPPER_SERVER_IMAGE):$(IMAGE_TAG)" \ - --enabled-reconcilers "$(ENABLED_RECONCILERS)" - -.PHONY: deploy-no-sa -deploy-no-sa: deployment-config-no-sa - kubectl apply -R -f $(DEPLOYCONFIG_NO_SA_DIR) - -.PHONY: push-and-deploy-no-sa -push-and-deploy-no-sa: push-images deploy-no-sa - -.PHONY: run-in-kind -run-in-kind: - IMAGE_REPO=porch-kind make build-images - kind load docker-image porch-kind/porch-server:${IMAGE_TAG} - kind load docker-image porch-kind/porch-controllers:${IMAGE_TAG} - kind load docker-image porch-kind/porch-function-runner:${IMAGE_TAG} - kind load docker-image porch-kind/porch-wrapper-server:${IMAGE_TAG} - kind load docker-image porch-kind/test-git-server:${IMAGE_TAG} - IMAGE_REPO=porch-kind make deployment-config - kubectl apply --wait --recursive --filename ./.build/deploy - kubectl rollout status deployment function-runner --namespace porch-system - kubectl rollout status deployment porch-controllers --namespace porch-system - kubectl rollout status deployment porch-server --namespace porch-system - -.PHONY: vulncheck -vulncheck: build - # Scan the source - GOFLAGS= go run golang.org/x/vuln/cmd/govulncheck@latest ./... diff --git a/porch/README.md b/porch/README.md index ffa350ecac..7f6f31e3b3 100644 --- a/porch/README.md +++ b/porch/README.md @@ -1,12 +1,3 @@ # Package Orchestration Server -Package Orchestration Server (a.k.a. Porch) is a k8s extension apiserver -which manages the lifecycle of KRM configuration packages. - -You can run Porch: - -* [On GKE](../site/guides/porch-installation.md) -* [Locally](./docs/running-locally.md), intended primarily for [development](./docs/development.md) - -If you already have Porch installed, you can proceed to the -[user guide](../site/guides/porch-user-guide.md). +Porch is now part of the Nephio project: https://github.com/nephio-project/porch diff --git a/porch/api/doc.go b/porch/api/doc.go deleted file mode 100644 index 3e907afe2f..0000000000 --- a/porch/api/doc.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2022 The kpt 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. - -// +domain=kpt.dev - -package apis diff --git a/porch/api/generated/clientset/versioned/clientset.go b/porch/api/generated/clientset/versioned/clientset.go deleted file mode 100644 index cb6249ea74..0000000000 --- a/porch/api/generated/clientset/versioned/clientset.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -package versioned - -import ( - "fmt" - "net/http" - - porchv1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned/typed/porch/v1alpha1" - discovery "k8s.io/client-go/discovery" - rest "k8s.io/client-go/rest" - flowcontrol "k8s.io/client-go/util/flowcontrol" -) - -type Interface interface { - Discovery() discovery.DiscoveryInterface - PorchV1alpha1() porchv1alpha1.PorchV1alpha1Interface -} - -// Clientset contains the clients for groups. Each group has exactly one -// version included in a Clientset. -type Clientset struct { - *discovery.DiscoveryClient - porchV1alpha1 *porchv1alpha1.PorchV1alpha1Client -} - -// PorchV1alpha1 retrieves the PorchV1alpha1Client -func (c *Clientset) PorchV1alpha1() porchv1alpha1.PorchV1alpha1Interface { - return c.porchV1alpha1 -} - -// Discovery retrieves the DiscoveryClient -func (c *Clientset) Discovery() discovery.DiscoveryInterface { - if c == nil { - return nil - } - return c.DiscoveryClient -} - -// NewForConfig creates a new Clientset for the given config. -// If config's RateLimiter is not set and QPS and Burst are acceptable, -// NewForConfig will generate a rate-limiter in configShallowCopy. -// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), -// where httpClient was generated with rest.HTTPClientFor(c). -func NewForConfig(c *rest.Config) (*Clientset, error) { - configShallowCopy := *c - - // share the transport between all clients - httpClient, err := rest.HTTPClientFor(&configShallowCopy) - if err != nil { - return nil, err - } - - return NewForConfigAndClient(&configShallowCopy, httpClient) -} - -// NewForConfigAndClient creates a new Clientset for the given config and http client. -// Note the http client provided takes precedence over the configured transport values. -// If config's RateLimiter is not set and QPS and Burst are acceptable, -// NewForConfigAndClient will generate a rate-limiter in configShallowCopy. -func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) { - configShallowCopy := *c - if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { - if configShallowCopy.Burst <= 0 { - return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") - } - configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) - } - - var cs Clientset - var err error - cs.porchV1alpha1, err = porchv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) - if err != nil { - return nil, err - } - - cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) - if err != nil { - return nil, err - } - return &cs, nil -} - -// NewForConfigOrDie creates a new Clientset for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *Clientset { - cs, err := NewForConfig(c) - if err != nil { - panic(err) - } - return cs -} - -// New creates a new Clientset for the given RESTClient. -func New(c rest.Interface) *Clientset { - var cs Clientset - cs.porchV1alpha1 = porchv1alpha1.New(c) - - cs.DiscoveryClient = discovery.NewDiscoveryClient(c) - return &cs -} diff --git a/porch/api/generated/clientset/versioned/doc.go b/porch/api/generated/clientset/versioned/doc.go deleted file mode 100644 index b648bee577..0000000000 --- a/porch/api/generated/clientset/versioned/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -// This package has the automatically generated clientset. -package versioned diff --git a/porch/api/generated/clientset/versioned/fake/clientset_generated.go b/porch/api/generated/clientset/versioned/fake/clientset_generated.go deleted file mode 100644 index 059c81e91a..0000000000 --- a/porch/api/generated/clientset/versioned/fake/clientset_generated.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -package fake - -import ( - clientset "github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned" - porchv1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned/typed/porch/v1alpha1" - fakeporchv1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/discovery" - fakediscovery "k8s.io/client-go/discovery/fake" - "k8s.io/client-go/testing" -) - -// NewSimpleClientset returns a clientset that will respond with the provided objects. -// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, -// without applying any validations and/or defaults. It shouldn't be considered a replacement -// for a real clientset and is mostly useful in simple unit tests. -func NewSimpleClientset(objects ...runtime.Object) *Clientset { - o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) - for _, obj := range objects { - if err := o.Add(obj); err != nil { - panic(err) - } - } - - cs := &Clientset{tracker: o} - cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} - cs.AddReactor("*", "*", testing.ObjectReaction(o)) - cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { - gvr := action.GetResource() - ns := action.GetNamespace() - watch, err := o.Watch(gvr, ns) - if err != nil { - return false, nil, err - } - return true, watch, nil - }) - - return cs -} - -// Clientset implements clientset.Interface. Meant to be embedded into a -// struct to get a default implementation. This makes faking out just the method -// you want to test easier. -type Clientset struct { - testing.Fake - discovery *fakediscovery.FakeDiscovery - tracker testing.ObjectTracker -} - -func (c *Clientset) Discovery() discovery.DiscoveryInterface { - return c.discovery -} - -func (c *Clientset) Tracker() testing.ObjectTracker { - return c.tracker -} - -var ( - _ clientset.Interface = &Clientset{} - _ testing.FakeClient = &Clientset{} -) - -// PorchV1alpha1 retrieves the PorchV1alpha1Client -func (c *Clientset) PorchV1alpha1() porchv1alpha1.PorchV1alpha1Interface { - return &fakeporchv1alpha1.FakePorchV1alpha1{Fake: &c.Fake} -} diff --git a/porch/api/generated/clientset/versioned/fake/doc.go b/porch/api/generated/clientset/versioned/fake/doc.go deleted file mode 100644 index afc33208c1..0000000000 --- a/porch/api/generated/clientset/versioned/fake/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -// This package has the automatically generated fake clientset. -package fake diff --git a/porch/api/generated/clientset/versioned/fake/register.go b/porch/api/generated/clientset/versioned/fake/register.go deleted file mode 100644 index 84cbfaeb05..0000000000 --- a/porch/api/generated/clientset/versioned/fake/register.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -package fake - -import ( - porchv1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" -) - -var scheme = runtime.NewScheme() -var codecs = serializer.NewCodecFactory(scheme) - -var localSchemeBuilder = runtime.SchemeBuilder{ - porchv1alpha1.AddToScheme, -} - -// AddToScheme adds all types of this clientset into the given scheme. This allows composition -// of clientsets, like in: -// -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) -// -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) -// -// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types -// correctly. -var AddToScheme = localSchemeBuilder.AddToScheme - -func init() { - v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) - utilruntime.Must(AddToScheme(scheme)) -} diff --git a/porch/api/generated/clientset/versioned/scheme/doc.go b/porch/api/generated/clientset/versioned/scheme/doc.go deleted file mode 100644 index daf0944855..0000000000 --- a/porch/api/generated/clientset/versioned/scheme/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -// This package contains the scheme of the automatically generated clientset. -package scheme diff --git a/porch/api/generated/clientset/versioned/scheme/register.go b/porch/api/generated/clientset/versioned/scheme/register.go deleted file mode 100644 index 07fc5417fe..0000000000 --- a/porch/api/generated/clientset/versioned/scheme/register.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -package scheme - -import ( - porchv1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" -) - -var Scheme = runtime.NewScheme() -var Codecs = serializer.NewCodecFactory(Scheme) -var ParameterCodec = runtime.NewParameterCodec(Scheme) -var localSchemeBuilder = runtime.SchemeBuilder{ - porchv1alpha1.AddToScheme, -} - -// AddToScheme adds all types of this clientset into the given scheme. This allows composition -// of clientsets, like in: -// -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) -// -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) -// -// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types -// correctly. -var AddToScheme = localSchemeBuilder.AddToScheme - -func init() { - v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) - utilruntime.Must(AddToScheme(Scheme)) -} diff --git a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/doc.go b/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/doc.go deleted file mode 100644 index ad4120775e..0000000000 --- a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -// This package has the automatically generated typed clients. -package v1alpha1 diff --git a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake/doc.go b/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake/doc.go deleted file mode 100644 index c85034c321..0000000000 --- a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -// Package fake has the automatically generated clients. -package fake diff --git a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake/fake_function.go b/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake/fake_function.go deleted file mode 100644 index 995e803efb..0000000000 --- a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake/fake_function.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -package fake - -import ( - "context" - - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" -) - -// FakeFunctions implements FunctionInterface -type FakeFunctions struct { - Fake *FakePorchV1alpha1 - ns string -} - -var functionsResource = schema.GroupVersionResource{Group: "porch.kpt.dev", Version: "v1alpha1", Resource: "functions"} - -var functionsKind = schema.GroupVersionKind{Group: "porch.kpt.dev", Version: "v1alpha1", Kind: "Function"} - -// Get takes name of the function, and returns the corresponding function object, and an error if there is any. -func (c *FakeFunctions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.Function, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(functionsResource, c.ns, name), &v1alpha1.Function{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.Function), err -} - -// List takes label and field selectors, and returns the list of Functions that match those selectors. -func (c *FakeFunctions) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.FunctionList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(functionsResource, functionsKind, c.ns, opts), &v1alpha1.FunctionList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1alpha1.FunctionList{ListMeta: obj.(*v1alpha1.FunctionList).ListMeta} - for _, item := range obj.(*v1alpha1.FunctionList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested functions. -func (c *FakeFunctions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(functionsResource, c.ns, opts)) - -} - -// Create takes the representation of a function and creates it. Returns the server's representation of the function, and an error, if there is any. -func (c *FakeFunctions) Create(ctx context.Context, function *v1alpha1.Function, opts v1.CreateOptions) (result *v1alpha1.Function, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(functionsResource, c.ns, function), &v1alpha1.Function{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.Function), err -} - -// Update takes the representation of a function and updates it. Returns the server's representation of the function, and an error, if there is any. -func (c *FakeFunctions) Update(ctx context.Context, function *v1alpha1.Function, opts v1.UpdateOptions) (result *v1alpha1.Function, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(functionsResource, c.ns, function), &v1alpha1.Function{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.Function), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeFunctions) UpdateStatus(ctx context.Context, function *v1alpha1.Function, opts v1.UpdateOptions) (*v1alpha1.Function, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(functionsResource, "status", c.ns, function), &v1alpha1.Function{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.Function), err -} - -// Delete takes name of the function and deletes it. Returns an error if one occurs. -func (c *FakeFunctions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteActionWithOptions(functionsResource, c.ns, name, opts), &v1alpha1.Function{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeFunctions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(functionsResource, c.ns, listOpts) - - _, err := c.Fake.Invokes(action, &v1alpha1.FunctionList{}) - return err -} - -// Patch applies the patch and returns the patched function. -func (c *FakeFunctions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Function, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(functionsResource, c.ns, name, pt, data, subresources...), &v1alpha1.Function{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.Function), err -} diff --git a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake/fake_packagerevision.go b/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake/fake_packagerevision.go deleted file mode 100644 index b8ed56968f..0000000000 --- a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake/fake_packagerevision.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -package fake - -import ( - "context" - - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" -) - -// FakePackageRevisions implements PackageRevisionInterface -type FakePackageRevisions struct { - Fake *FakePorchV1alpha1 - ns string -} - -var packagerevisionsResource = schema.GroupVersionResource{Group: "porch.kpt.dev", Version: "v1alpha1", Resource: "packagerevisions"} - -var packagerevisionsKind = schema.GroupVersionKind{Group: "porch.kpt.dev", Version: "v1alpha1", Kind: "PackageRevision"} - -// Get takes name of the packageRevision, and returns the corresponding packageRevision object, and an error if there is any. -func (c *FakePackageRevisions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.PackageRevision, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(packagerevisionsResource, c.ns, name), &v1alpha1.PackageRevision{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.PackageRevision), err -} - -// List takes label and field selectors, and returns the list of PackageRevisions that match those selectors. -func (c *FakePackageRevisions) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.PackageRevisionList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(packagerevisionsResource, packagerevisionsKind, c.ns, opts), &v1alpha1.PackageRevisionList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1alpha1.PackageRevisionList{ListMeta: obj.(*v1alpha1.PackageRevisionList).ListMeta} - for _, item := range obj.(*v1alpha1.PackageRevisionList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested packageRevisions. -func (c *FakePackageRevisions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(packagerevisionsResource, c.ns, opts)) - -} - -// Create takes the representation of a packageRevision and creates it. Returns the server's representation of the packageRevision, and an error, if there is any. -func (c *FakePackageRevisions) Create(ctx context.Context, packageRevision *v1alpha1.PackageRevision, opts v1.CreateOptions) (result *v1alpha1.PackageRevision, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(packagerevisionsResource, c.ns, packageRevision), &v1alpha1.PackageRevision{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.PackageRevision), err -} - -// Update takes the representation of a packageRevision and updates it. Returns the server's representation of the packageRevision, and an error, if there is any. -func (c *FakePackageRevisions) Update(ctx context.Context, packageRevision *v1alpha1.PackageRevision, opts v1.UpdateOptions) (result *v1alpha1.PackageRevision, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(packagerevisionsResource, c.ns, packageRevision), &v1alpha1.PackageRevision{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.PackageRevision), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakePackageRevisions) UpdateStatus(ctx context.Context, packageRevision *v1alpha1.PackageRevision, opts v1.UpdateOptions) (*v1alpha1.PackageRevision, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(packagerevisionsResource, "status", c.ns, packageRevision), &v1alpha1.PackageRevision{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.PackageRevision), err -} - -// Delete takes name of the packageRevision and deletes it. Returns an error if one occurs. -func (c *FakePackageRevisions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteActionWithOptions(packagerevisionsResource, c.ns, name, opts), &v1alpha1.PackageRevision{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakePackageRevisions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(packagerevisionsResource, c.ns, listOpts) - - _, err := c.Fake.Invokes(action, &v1alpha1.PackageRevisionList{}) - return err -} - -// Patch applies the patch and returns the patched packageRevision. -func (c *FakePackageRevisions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.PackageRevision, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(packagerevisionsResource, c.ns, name, pt, data, subresources...), &v1alpha1.PackageRevision{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.PackageRevision), err -} - -// UpdateApproval takes the representation of a packageRevision and updates it. Returns the server's representation of the packageRevision, and an error, if there is any. -func (c *FakePackageRevisions) UpdateApproval(ctx context.Context, packageRevisionName string, packageRevision *v1alpha1.PackageRevision, opts v1.UpdateOptions) (result *v1alpha1.PackageRevision, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(packagerevisionsResource, "approval", c.ns, packageRevision), &v1alpha1.PackageRevision{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.PackageRevision), err -} diff --git a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake/fake_packagerevisionresources.go b/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake/fake_packagerevisionresources.go deleted file mode 100644 index 43fa800cca..0000000000 --- a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake/fake_packagerevisionresources.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -package fake - -import ( - "context" - - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" -) - -// FakePackageRevisionResources implements PackageRevisionResourcesInterface -type FakePackageRevisionResources struct { - Fake *FakePorchV1alpha1 - ns string -} - -var packagerevisionresourcesResource = schema.GroupVersionResource{Group: "porch.kpt.dev", Version: "v1alpha1", Resource: "packagerevisionresources"} - -var packagerevisionresourcesKind = schema.GroupVersionKind{Group: "porch.kpt.dev", Version: "v1alpha1", Kind: "PackageRevisionResources"} - -// Get takes name of the packageRevisionResources, and returns the corresponding packageRevisionResources object, and an error if there is any. -func (c *FakePackageRevisionResources) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.PackageRevisionResources, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(packagerevisionresourcesResource, c.ns, name), &v1alpha1.PackageRevisionResources{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.PackageRevisionResources), err -} - -// List takes label and field selectors, and returns the list of PackageRevisionResources that match those selectors. -func (c *FakePackageRevisionResources) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.PackageRevisionResourcesList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(packagerevisionresourcesResource, packagerevisionresourcesKind, c.ns, opts), &v1alpha1.PackageRevisionResourcesList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1alpha1.PackageRevisionResourcesList{ListMeta: obj.(*v1alpha1.PackageRevisionResourcesList).ListMeta} - for _, item := range obj.(*v1alpha1.PackageRevisionResourcesList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested packageRevisionResources. -func (c *FakePackageRevisionResources) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(packagerevisionresourcesResource, c.ns, opts)) - -} - -// Create takes the representation of a packageRevisionResources and creates it. Returns the server's representation of the packageRevisionResources, and an error, if there is any. -func (c *FakePackageRevisionResources) Create(ctx context.Context, packageRevisionResources *v1alpha1.PackageRevisionResources, opts v1.CreateOptions) (result *v1alpha1.PackageRevisionResources, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(packagerevisionresourcesResource, c.ns, packageRevisionResources), &v1alpha1.PackageRevisionResources{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.PackageRevisionResources), err -} - -// Update takes the representation of a packageRevisionResources and updates it. Returns the server's representation of the packageRevisionResources, and an error, if there is any. -func (c *FakePackageRevisionResources) Update(ctx context.Context, packageRevisionResources *v1alpha1.PackageRevisionResources, opts v1.UpdateOptions) (result *v1alpha1.PackageRevisionResources, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(packagerevisionresourcesResource, c.ns, packageRevisionResources), &v1alpha1.PackageRevisionResources{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.PackageRevisionResources), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakePackageRevisionResources) UpdateStatus(ctx context.Context, packageRevisionResources *v1alpha1.PackageRevisionResources, opts v1.UpdateOptions) (*v1alpha1.PackageRevisionResources, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(packagerevisionresourcesResource, "status", c.ns, packageRevisionResources), &v1alpha1.PackageRevisionResources{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.PackageRevisionResources), err -} - -// Delete takes name of the packageRevisionResources and deletes it. Returns an error if one occurs. -func (c *FakePackageRevisionResources) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteActionWithOptions(packagerevisionresourcesResource, c.ns, name, opts), &v1alpha1.PackageRevisionResources{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakePackageRevisionResources) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(packagerevisionresourcesResource, c.ns, listOpts) - - _, err := c.Fake.Invokes(action, &v1alpha1.PackageRevisionResourcesList{}) - return err -} - -// Patch applies the patch and returns the patched packageRevisionResources. -func (c *FakePackageRevisionResources) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.PackageRevisionResources, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(packagerevisionresourcesResource, c.ns, name, pt, data, subresources...), &v1alpha1.PackageRevisionResources{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.PackageRevisionResources), err -} diff --git a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake/fake_pkg.go b/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake/fake_pkg.go deleted file mode 100644 index 8581913ffa..0000000000 --- a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake/fake_pkg.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -package fake - -import ( - "context" - - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" -) - -// FakePackages implements PackageInterface -type FakePackages struct { - Fake *FakePorchV1alpha1 - ns string -} - -var packagesResource = schema.GroupVersionResource{Group: "porch.kpt.dev", Version: "v1alpha1", Resource: "packages"} - -var packagesKind = schema.GroupVersionKind{Group: "porch.kpt.dev", Version: "v1alpha1", Kind: "Package"} - -// Get takes name of the pkg, and returns the corresponding pkg object, and an error if there is any. -func (c *FakePackages) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.Package, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(packagesResource, c.ns, name), &v1alpha1.Package{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.Package), err -} - -// List takes label and field selectors, and returns the list of Packages that match those selectors. -func (c *FakePackages) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.PackageList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(packagesResource, packagesKind, c.ns, opts), &v1alpha1.PackageList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1alpha1.PackageList{ListMeta: obj.(*v1alpha1.PackageList).ListMeta} - for _, item := range obj.(*v1alpha1.PackageList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested packages. -func (c *FakePackages) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(packagesResource, c.ns, opts)) - -} - -// Create takes the representation of a pkg and creates it. Returns the server's representation of the pkg, and an error, if there is any. -func (c *FakePackages) Create(ctx context.Context, pkg *v1alpha1.Package, opts v1.CreateOptions) (result *v1alpha1.Package, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(packagesResource, c.ns, pkg), &v1alpha1.Package{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.Package), err -} - -// Update takes the representation of a pkg and updates it. Returns the server's representation of the pkg, and an error, if there is any. -func (c *FakePackages) Update(ctx context.Context, pkg *v1alpha1.Package, opts v1.UpdateOptions) (result *v1alpha1.Package, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(packagesResource, c.ns, pkg), &v1alpha1.Package{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.Package), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakePackages) UpdateStatus(ctx context.Context, pkg *v1alpha1.Package, opts v1.UpdateOptions) (*v1alpha1.Package, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(packagesResource, "status", c.ns, pkg), &v1alpha1.Package{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.Package), err -} - -// Delete takes name of the pkg and deletes it. Returns an error if one occurs. -func (c *FakePackages) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteActionWithOptions(packagesResource, c.ns, name, opts), &v1alpha1.Package{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakePackages) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(packagesResource, c.ns, listOpts) - - _, err := c.Fake.Invokes(action, &v1alpha1.PackageList{}) - return err -} - -// Patch applies the patch and returns the patched pkg. -func (c *FakePackages) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Package, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(packagesResource, c.ns, name, pt, data, subresources...), &v1alpha1.Package{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.Package), err -} diff --git a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake/fake_porch_client.go b/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake/fake_porch_client.go deleted file mode 100644 index f9df12e154..0000000000 --- a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/fake/fake_porch_client.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -package fake - -import ( - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned/typed/porch/v1alpha1" - rest "k8s.io/client-go/rest" - testing "k8s.io/client-go/testing" -) - -type FakePorchV1alpha1 struct { - *testing.Fake -} - -func (c *FakePorchV1alpha1) Functions(namespace string) v1alpha1.FunctionInterface { - return &FakeFunctions{c, namespace} -} - -func (c *FakePorchV1alpha1) Packages(namespace string) v1alpha1.PackageInterface { - return &FakePackages{c, namespace} -} - -func (c *FakePorchV1alpha1) PackageRevisions(namespace string) v1alpha1.PackageRevisionInterface { - return &FakePackageRevisions{c, namespace} -} - -func (c *FakePorchV1alpha1) PackageRevisionResources(namespace string) v1alpha1.PackageRevisionResourcesInterface { - return &FakePackageRevisionResources{c, namespace} -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *FakePorchV1alpha1) RESTClient() rest.Interface { - var ret *rest.RESTClient - return ret -} diff --git a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/function.go b/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/function.go deleted file mode 100644 index 86dbdf7911..0000000000 --- a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/function.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "context" - "time" - - scheme "github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned/scheme" - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" -) - -// FunctionsGetter has a method to return a FunctionInterface. -// A group's client should implement this interface. -type FunctionsGetter interface { - Functions(namespace string) FunctionInterface -} - -// FunctionInterface has methods to work with Function resources. -type FunctionInterface interface { - Create(ctx context.Context, function *v1alpha1.Function, opts v1.CreateOptions) (*v1alpha1.Function, error) - Update(ctx context.Context, function *v1alpha1.Function, opts v1.UpdateOptions) (*v1alpha1.Function, error) - UpdateStatus(ctx context.Context, function *v1alpha1.Function, opts v1.UpdateOptions) (*v1alpha1.Function, error) - Delete(ctx context.Context, name string, opts v1.DeleteOptions) error - DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.Function, error) - List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.FunctionList, error) - Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Function, err error) - FunctionExpansion -} - -// functions implements FunctionInterface -type functions struct { - client rest.Interface - ns string -} - -// newFunctions returns a Functions -func newFunctions(c *PorchV1alpha1Client, namespace string) *functions { - return &functions{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the function, and returns the corresponding function object, and an error if there is any. -func (c *functions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.Function, err error) { - result = &v1alpha1.Function{} - err = c.client.Get(). - Namespace(c.ns). - Resource("functions"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of Functions that match those selectors. -func (c *functions) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.FunctionList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.FunctionList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("functions"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested functions. -func (c *functions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("functions"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a function and creates it. Returns the server's representation of the function, and an error, if there is any. -func (c *functions) Create(ctx context.Context, function *v1alpha1.Function, opts v1.CreateOptions) (result *v1alpha1.Function, err error) { - result = &v1alpha1.Function{} - err = c.client.Post(). - Namespace(c.ns). - Resource("functions"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(function). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a function and updates it. Returns the server's representation of the function, and an error, if there is any. -func (c *functions) Update(ctx context.Context, function *v1alpha1.Function, opts v1.UpdateOptions) (result *v1alpha1.Function, err error) { - result = &v1alpha1.Function{} - err = c.client.Put(). - Namespace(c.ns). - Resource("functions"). - Name(function.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(function). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *functions) UpdateStatus(ctx context.Context, function *v1alpha1.Function, opts v1.UpdateOptions) (result *v1alpha1.Function, err error) { - result = &v1alpha1.Function{} - err = c.client.Put(). - Namespace(c.ns). - Resource("functions"). - Name(function.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(function). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the function and deletes it. Returns an error if one occurs. -func (c *functions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("functions"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *functions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("functions"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched function. -func (c *functions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Function, err error) { - result = &v1alpha1.Function{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("functions"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/generated_expansion.go b/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/generated_expansion.go deleted file mode 100644 index bb30f90eae..0000000000 --- a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/generated_expansion.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -package v1alpha1 - -type FunctionExpansion interface{} - -type PackageExpansion interface{} - -type PackageRevisionExpansion interface{} - -type PackageRevisionResourcesExpansion interface{} diff --git a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/packagerevision.go b/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/packagerevision.go deleted file mode 100644 index 775a5686a9..0000000000 --- a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/packagerevision.go +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "context" - "time" - - scheme "github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned/scheme" - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" -) - -// PackageRevisionsGetter has a method to return a PackageRevisionInterface. -// A group's client should implement this interface. -type PackageRevisionsGetter interface { - PackageRevisions(namespace string) PackageRevisionInterface -} - -// PackageRevisionInterface has methods to work with PackageRevision resources. -type PackageRevisionInterface interface { - Create(ctx context.Context, packageRevision *v1alpha1.PackageRevision, opts v1.CreateOptions) (*v1alpha1.PackageRevision, error) - Update(ctx context.Context, packageRevision *v1alpha1.PackageRevision, opts v1.UpdateOptions) (*v1alpha1.PackageRevision, error) - UpdateStatus(ctx context.Context, packageRevision *v1alpha1.PackageRevision, opts v1.UpdateOptions) (*v1alpha1.PackageRevision, error) - Delete(ctx context.Context, name string, opts v1.DeleteOptions) error - DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.PackageRevision, error) - List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.PackageRevisionList, error) - Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.PackageRevision, err error) - UpdateApproval(ctx context.Context, packageRevisionName string, packageRevision *v1alpha1.PackageRevision, opts v1.UpdateOptions) (*v1alpha1.PackageRevision, error) - - PackageRevisionExpansion -} - -// packageRevisions implements PackageRevisionInterface -type packageRevisions struct { - client rest.Interface - ns string -} - -// newPackageRevisions returns a PackageRevisions -func newPackageRevisions(c *PorchV1alpha1Client, namespace string) *packageRevisions { - return &packageRevisions{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the packageRevision, and returns the corresponding packageRevision object, and an error if there is any. -func (c *packageRevisions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.PackageRevision, err error) { - result = &v1alpha1.PackageRevision{} - err = c.client.Get(). - Namespace(c.ns). - Resource("packagerevisions"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of PackageRevisions that match those selectors. -func (c *packageRevisions) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.PackageRevisionList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.PackageRevisionList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("packagerevisions"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested packageRevisions. -func (c *packageRevisions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("packagerevisions"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a packageRevision and creates it. Returns the server's representation of the packageRevision, and an error, if there is any. -func (c *packageRevisions) Create(ctx context.Context, packageRevision *v1alpha1.PackageRevision, opts v1.CreateOptions) (result *v1alpha1.PackageRevision, err error) { - result = &v1alpha1.PackageRevision{} - err = c.client.Post(). - Namespace(c.ns). - Resource("packagerevisions"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(packageRevision). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a packageRevision and updates it. Returns the server's representation of the packageRevision, and an error, if there is any. -func (c *packageRevisions) Update(ctx context.Context, packageRevision *v1alpha1.PackageRevision, opts v1.UpdateOptions) (result *v1alpha1.PackageRevision, err error) { - result = &v1alpha1.PackageRevision{} - err = c.client.Put(). - Namespace(c.ns). - Resource("packagerevisions"). - Name(packageRevision.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(packageRevision). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *packageRevisions) UpdateStatus(ctx context.Context, packageRevision *v1alpha1.PackageRevision, opts v1.UpdateOptions) (result *v1alpha1.PackageRevision, err error) { - result = &v1alpha1.PackageRevision{} - err = c.client.Put(). - Namespace(c.ns). - Resource("packagerevisions"). - Name(packageRevision.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(packageRevision). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the packageRevision and deletes it. Returns an error if one occurs. -func (c *packageRevisions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("packagerevisions"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *packageRevisions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("packagerevisions"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched packageRevision. -func (c *packageRevisions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.PackageRevision, err error) { - result = &v1alpha1.PackageRevision{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("packagerevisions"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// UpdateApproval takes the top resource name and the representation of a packageRevision and updates it. Returns the server's representation of the packageRevision, and an error, if there is any. -func (c *packageRevisions) UpdateApproval(ctx context.Context, packageRevisionName string, packageRevision *v1alpha1.PackageRevision, opts v1.UpdateOptions) (result *v1alpha1.PackageRevision, err error) { - result = &v1alpha1.PackageRevision{} - err = c.client.Put(). - Namespace(c.ns). - Resource("packagerevisions"). - Name(packageRevisionName). - SubResource("approval"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(packageRevision). - Do(ctx). - Into(result) - return -} diff --git a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/packagerevisionresources.go b/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/packagerevisionresources.go deleted file mode 100644 index 6ad005f9ee..0000000000 --- a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/packagerevisionresources.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "context" - "time" - - scheme "github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned/scheme" - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" -) - -// PackageRevisionResourcesGetter has a method to return a PackageRevisionResourcesInterface. -// A group's client should implement this interface. -type PackageRevisionResourcesGetter interface { - PackageRevisionResources(namespace string) PackageRevisionResourcesInterface -} - -// PackageRevisionResourcesInterface has methods to work with PackageRevisionResources resources. -type PackageRevisionResourcesInterface interface { - Create(ctx context.Context, packageRevisionResources *v1alpha1.PackageRevisionResources, opts v1.CreateOptions) (*v1alpha1.PackageRevisionResources, error) - Update(ctx context.Context, packageRevisionResources *v1alpha1.PackageRevisionResources, opts v1.UpdateOptions) (*v1alpha1.PackageRevisionResources, error) - UpdateStatus(ctx context.Context, packageRevisionResources *v1alpha1.PackageRevisionResources, opts v1.UpdateOptions) (*v1alpha1.PackageRevisionResources, error) - Delete(ctx context.Context, name string, opts v1.DeleteOptions) error - DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.PackageRevisionResources, error) - List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.PackageRevisionResourcesList, error) - Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.PackageRevisionResources, err error) - PackageRevisionResourcesExpansion -} - -// packageRevisionResources implements PackageRevisionResourcesInterface -type packageRevisionResources struct { - client rest.Interface - ns string -} - -// newPackageRevisionResources returns a PackageRevisionResources -func newPackageRevisionResources(c *PorchV1alpha1Client, namespace string) *packageRevisionResources { - return &packageRevisionResources{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the packageRevisionResources, and returns the corresponding packageRevisionResources object, and an error if there is any. -func (c *packageRevisionResources) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.PackageRevisionResources, err error) { - result = &v1alpha1.PackageRevisionResources{} - err = c.client.Get(). - Namespace(c.ns). - Resource("packagerevisionresources"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of PackageRevisionResources that match those selectors. -func (c *packageRevisionResources) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.PackageRevisionResourcesList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.PackageRevisionResourcesList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("packagerevisionresources"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested packageRevisionResources. -func (c *packageRevisionResources) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("packagerevisionresources"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a packageRevisionResources and creates it. Returns the server's representation of the packageRevisionResources, and an error, if there is any. -func (c *packageRevisionResources) Create(ctx context.Context, packageRevisionResources *v1alpha1.PackageRevisionResources, opts v1.CreateOptions) (result *v1alpha1.PackageRevisionResources, err error) { - result = &v1alpha1.PackageRevisionResources{} - err = c.client.Post(). - Namespace(c.ns). - Resource("packagerevisionresources"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(packageRevisionResources). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a packageRevisionResources and updates it. Returns the server's representation of the packageRevisionResources, and an error, if there is any. -func (c *packageRevisionResources) Update(ctx context.Context, packageRevisionResources *v1alpha1.PackageRevisionResources, opts v1.UpdateOptions) (result *v1alpha1.PackageRevisionResources, err error) { - result = &v1alpha1.PackageRevisionResources{} - err = c.client.Put(). - Namespace(c.ns). - Resource("packagerevisionresources"). - Name(packageRevisionResources.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(packageRevisionResources). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *packageRevisionResources) UpdateStatus(ctx context.Context, packageRevisionResources *v1alpha1.PackageRevisionResources, opts v1.UpdateOptions) (result *v1alpha1.PackageRevisionResources, err error) { - result = &v1alpha1.PackageRevisionResources{} - err = c.client.Put(). - Namespace(c.ns). - Resource("packagerevisionresources"). - Name(packageRevisionResources.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(packageRevisionResources). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the packageRevisionResources and deletes it. Returns an error if one occurs. -func (c *packageRevisionResources) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("packagerevisionresources"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *packageRevisionResources) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("packagerevisionresources"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched packageRevisionResources. -func (c *packageRevisionResources) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.PackageRevisionResources, err error) { - result = &v1alpha1.PackageRevisionResources{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("packagerevisionresources"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/pkg.go b/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/pkg.go deleted file mode 100644 index 4033b6528a..0000000000 --- a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/pkg.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "context" - "time" - - scheme "github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned/scheme" - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" -) - -// PackagesGetter has a method to return a PackageInterface. -// A group's client should implement this interface. -type PackagesGetter interface { - Packages(namespace string) PackageInterface -} - -// PackageInterface has methods to work with Package resources. -type PackageInterface interface { - Create(ctx context.Context, pkg *v1alpha1.Package, opts v1.CreateOptions) (*v1alpha1.Package, error) - Update(ctx context.Context, pkg *v1alpha1.Package, opts v1.UpdateOptions) (*v1alpha1.Package, error) - UpdateStatus(ctx context.Context, pkg *v1alpha1.Package, opts v1.UpdateOptions) (*v1alpha1.Package, error) - Delete(ctx context.Context, name string, opts v1.DeleteOptions) error - DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.Package, error) - List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.PackageList, error) - Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Package, err error) - PackageExpansion -} - -// packages implements PackageInterface -type packages struct { - client rest.Interface - ns string -} - -// newPackages returns a Packages -func newPackages(c *PorchV1alpha1Client, namespace string) *packages { - return &packages{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the pkg, and returns the corresponding pkg object, and an error if there is any. -func (c *packages) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.Package, err error) { - result = &v1alpha1.Package{} - err = c.client.Get(). - Namespace(c.ns). - Resource("packages"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of Packages that match those selectors. -func (c *packages) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.PackageList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.PackageList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("packages"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested packages. -func (c *packages) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("packages"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a pkg and creates it. Returns the server's representation of the pkg, and an error, if there is any. -func (c *packages) Create(ctx context.Context, pkg *v1alpha1.Package, opts v1.CreateOptions) (result *v1alpha1.Package, err error) { - result = &v1alpha1.Package{} - err = c.client.Post(). - Namespace(c.ns). - Resource("packages"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(pkg). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a pkg and updates it. Returns the server's representation of the pkg, and an error, if there is any. -func (c *packages) Update(ctx context.Context, pkg *v1alpha1.Package, opts v1.UpdateOptions) (result *v1alpha1.Package, err error) { - result = &v1alpha1.Package{} - err = c.client.Put(). - Namespace(c.ns). - Resource("packages"). - Name(pkg.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(pkg). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *packages) UpdateStatus(ctx context.Context, pkg *v1alpha1.Package, opts v1.UpdateOptions) (result *v1alpha1.Package, err error) { - result = &v1alpha1.Package{} - err = c.client.Put(). - Namespace(c.ns). - Resource("packages"). - Name(pkg.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(pkg). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the pkg and deletes it. Returns an error if one occurs. -func (c *packages) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("packages"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *packages) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("packages"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched pkg. -func (c *packages) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Package, err error) { - result = &v1alpha1.Package{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("packages"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/porch_client.go b/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/porch_client.go deleted file mode 100644 index a81cf95f12..0000000000 --- a/porch/api/generated/clientset/versioned/typed/porch/v1alpha1/porch_client.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2023 The kpt 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 client-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "net/http" - - "github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned/scheme" - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - rest "k8s.io/client-go/rest" -) - -type PorchV1alpha1Interface interface { - RESTClient() rest.Interface - FunctionsGetter - PackagesGetter - PackageRevisionsGetter - PackageRevisionResourcesGetter -} - -// PorchV1alpha1Client is used to interact with features provided by the porch.kpt.dev group. -type PorchV1alpha1Client struct { - restClient rest.Interface -} - -func (c *PorchV1alpha1Client) Functions(namespace string) FunctionInterface { - return newFunctions(c, namespace) -} - -func (c *PorchV1alpha1Client) Packages(namespace string) PackageInterface { - return newPackages(c, namespace) -} - -func (c *PorchV1alpha1Client) PackageRevisions(namespace string) PackageRevisionInterface { - return newPackageRevisions(c, namespace) -} - -func (c *PorchV1alpha1Client) PackageRevisionResources(namespace string) PackageRevisionResourcesInterface { - return newPackageRevisionResources(c, namespace) -} - -// NewForConfig creates a new PorchV1alpha1Client for the given config. -// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), -// where httpClient was generated with rest.HTTPClientFor(c). -func NewForConfig(c *rest.Config) (*PorchV1alpha1Client, error) { - config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } - httpClient, err := rest.HTTPClientFor(&config) - if err != nil { - return nil, err - } - return NewForConfigAndClient(&config, httpClient) -} - -// NewForConfigAndClient creates a new PorchV1alpha1Client for the given config and http client. -// Note the http client provided takes precedence over the configured transport values. -func NewForConfigAndClient(c *rest.Config, h *http.Client) (*PorchV1alpha1Client, error) { - config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } - client, err := rest.RESTClientForConfigAndClient(&config, h) - if err != nil { - return nil, err - } - return &PorchV1alpha1Client{client}, nil -} - -// NewForConfigOrDie creates a new PorchV1alpha1Client for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *PorchV1alpha1Client { - client, err := NewForConfig(c) - if err != nil { - panic(err) - } - return client -} - -// New creates a new PorchV1alpha1Client for the given RESTClient. -func New(c rest.Interface) *PorchV1alpha1Client { - return &PorchV1alpha1Client{c} -} - -func setConfigDefaults(config *rest.Config) error { - gv := v1alpha1.SchemeGroupVersion - config.GroupVersion = &gv - config.APIPath = "/apis" - config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() - - if config.UserAgent == "" { - config.UserAgent = rest.DefaultKubernetesUserAgent() - } - - return nil -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *PorchV1alpha1Client) RESTClient() rest.Interface { - if c == nil { - return nil - } - return c.restClient -} diff --git a/porch/api/generated/informers/externalversions/factory.go b/porch/api/generated/informers/externalversions/factory.go deleted file mode 100644 index a3a70022a2..0000000000 --- a/porch/api/generated/informers/externalversions/factory.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2023 The kpt 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" - - versioned "github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned" - internalinterfaces "github.com/GoogleContainerTools/kpt/porch/api/generated/informers/externalversions/internalinterfaces" - porch "github.com/GoogleContainerTools/kpt/porch/api/generated/informers/externalversions/porch" - 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 versioned.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 -} - -// 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 versioned.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 versioned.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 versioned.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 -} - -// Start initializes all requested informers. -func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { - f.lock.Lock() - defer f.lock.Unlock() - - for informerType, informer := range f.informers { - if !f.startedInformers[informerType] { - go informer.Run(stopCh) - f.startedInformers[informerType] = true - } - } -} - -// WaitForCacheSync waits for all started informers' cache were synced. -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. -type SharedInformerFactory interface { - internalinterfaces.SharedInformerFactory - ForResource(resource schema.GroupVersionResource) (GenericInformer, error) - WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool - - Porch() porch.Interface -} - -func (f *sharedInformerFactory) Porch() porch.Interface { - return porch.New(f, f.namespace, f.tweakListOptions) -} diff --git a/porch/api/generated/informers/externalversions/generic.go b/porch/api/generated/informers/externalversions/generic.go deleted file mode 100644 index 70b5e89ec6..0000000000 --- a/porch/api/generated/informers/externalversions/generic.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2023 The kpt 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" - - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - 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=porch.kpt.dev, Version=v1alpha1 - case v1alpha1.SchemeGroupVersion.WithResource("functions"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Porch().V1alpha1().Functions().Informer()}, nil - case v1alpha1.SchemeGroupVersion.WithResource("packages"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Porch().V1alpha1().Packages().Informer()}, nil - case v1alpha1.SchemeGroupVersion.WithResource("packagerevisions"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Porch().V1alpha1().PackageRevisions().Informer()}, nil - case v1alpha1.SchemeGroupVersion.WithResource("packagerevisionresources"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Porch().V1alpha1().PackageRevisionResources().Informer()}, nil - - } - - return nil, fmt.Errorf("no informer found for %v", resource) -} diff --git a/porch/api/generated/informers/externalversions/internalinterfaces/factory_interfaces.go b/porch/api/generated/informers/externalversions/internalinterfaces/factory_interfaces.go deleted file mode 100644 index 4ae9f5fee8..0000000000 --- a/porch/api/generated/informers/externalversions/internalinterfaces/factory_interfaces.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2023 The kpt 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" - - versioned "github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - cache "k8s.io/client-go/tools/cache" -) - -// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. -type NewInformerFunc func(versioned.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/porch/api/generated/informers/externalversions/porch/interface.go b/porch/api/generated/informers/externalversions/porch/interface.go deleted file mode 100644 index 10d0bd9396..0000000000 --- a/porch/api/generated/informers/externalversions/porch/interface.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2023 The kpt 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 porch - -import ( - internalinterfaces "github.com/GoogleContainerTools/kpt/porch/api/generated/informers/externalversions/internalinterfaces" - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/generated/informers/externalversions/porch/v1alpha1" -) - -// Interface provides access to each of this group's versions. -type Interface interface { - // V1alpha1 provides access to shared informers for resources in V1alpha1. - V1alpha1() v1alpha1.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} -} - -// V1alpha1 returns a new v1alpha1.Interface. -func (g *group) V1alpha1() v1alpha1.Interface { - return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) -} diff --git a/porch/api/generated/informers/externalversions/porch/v1alpha1/function.go b/porch/api/generated/informers/externalversions/porch/v1alpha1/function.go deleted file mode 100644 index 54e492f1b4..0000000000 --- a/porch/api/generated/informers/externalversions/porch/v1alpha1/function.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2023 The kpt 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 v1alpha1 - -import ( - "context" - time "time" - - versioned "github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned" - internalinterfaces "github.com/GoogleContainerTools/kpt/porch/api/generated/informers/externalversions/internalinterfaces" - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/generated/listers/porch/v1alpha1" - porchv1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - 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" -) - -// FunctionInformer provides access to a shared informer and lister for -// Functions. -type FunctionInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1alpha1.FunctionLister -} - -type functionInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewFunctionInformer constructs a new informer for Function 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 NewFunctionInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredFunctionInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredFunctionInformer constructs a new informer for Function 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 NewFilteredFunctionInformer(client versioned.Interface, namespace string, 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.PorchV1alpha1().Functions(namespace).List(context.TODO(), options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.PorchV1alpha1().Functions(namespace).Watch(context.TODO(), options) - }, - }, - &porchv1alpha1.Function{}, - resyncPeriod, - indexers, - ) -} - -func (f *functionInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredFunctionInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *functionInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&porchv1alpha1.Function{}, f.defaultInformer) -} - -func (f *functionInformer) Lister() v1alpha1.FunctionLister { - return v1alpha1.NewFunctionLister(f.Informer().GetIndexer()) -} diff --git a/porch/api/generated/informers/externalversions/porch/v1alpha1/interface.go b/porch/api/generated/informers/externalversions/porch/v1alpha1/interface.go deleted file mode 100644 index 5e6ba484af..0000000000 --- a/porch/api/generated/informers/externalversions/porch/v1alpha1/interface.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2023 The kpt 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 v1alpha1 - -import ( - internalinterfaces "github.com/GoogleContainerTools/kpt/porch/api/generated/informers/externalversions/internalinterfaces" -) - -// Interface provides access to all the informers in this group version. -type Interface interface { - // Functions returns a FunctionInformer. - Functions() FunctionInformer - // Packages returns a PackageInformer. - Packages() PackageInformer - // PackageRevisions returns a PackageRevisionInformer. - PackageRevisions() PackageRevisionInformer - // PackageRevisionResources returns a PackageRevisionResourcesInformer. - PackageRevisionResources() PackageRevisionResourcesInformer -} - -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} -} - -// Functions returns a FunctionInformer. -func (v *version) Functions() FunctionInformer { - return &functionInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} - -// Packages returns a PackageInformer. -func (v *version) Packages() PackageInformer { - return &packageInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} - -// PackageRevisions returns a PackageRevisionInformer. -func (v *version) PackageRevisions() PackageRevisionInformer { - return &packageRevisionInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} - -// PackageRevisionResources returns a PackageRevisionResourcesInformer. -func (v *version) PackageRevisionResources() PackageRevisionResourcesInformer { - return &packageRevisionResourcesInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} diff --git a/porch/api/generated/informers/externalversions/porch/v1alpha1/package.go b/porch/api/generated/informers/externalversions/porch/v1alpha1/package.go deleted file mode 100644 index 3f6226e150..0000000000 --- a/porch/api/generated/informers/externalversions/porch/v1alpha1/package.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2023 The kpt 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 v1alpha1 - -import ( - "context" - time "time" - - versioned "github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned" - internalinterfaces "github.com/GoogleContainerTools/kpt/porch/api/generated/informers/externalversions/internalinterfaces" - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/generated/listers/porch/v1alpha1" - porchv1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - 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" -) - -// PackageInformer provides access to a shared informer and lister for -// Packages. -type PackageInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1alpha1.PackageLister -} - -type packageInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewPackageInformer constructs a new informer for Package 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 NewPackageInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredPackageInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredPackageInformer constructs a new informer for Package 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 NewFilteredPackageInformer(client versioned.Interface, namespace string, 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.PorchV1alpha1().Packages(namespace).List(context.TODO(), options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.PorchV1alpha1().Packages(namespace).Watch(context.TODO(), options) - }, - }, - &porchv1alpha1.Package{}, - resyncPeriod, - indexers, - ) -} - -func (f *packageInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredPackageInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *packageInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&porchv1alpha1.Package{}, f.defaultInformer) -} - -func (f *packageInformer) Lister() v1alpha1.PackageLister { - return v1alpha1.NewPackageLister(f.Informer().GetIndexer()) -} diff --git a/porch/api/generated/informers/externalversions/porch/v1alpha1/packagerevision.go b/porch/api/generated/informers/externalversions/porch/v1alpha1/packagerevision.go deleted file mode 100644 index 3bc1f0c538..0000000000 --- a/porch/api/generated/informers/externalversions/porch/v1alpha1/packagerevision.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2023 The kpt 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 v1alpha1 - -import ( - "context" - time "time" - - versioned "github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned" - internalinterfaces "github.com/GoogleContainerTools/kpt/porch/api/generated/informers/externalversions/internalinterfaces" - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/generated/listers/porch/v1alpha1" - porchv1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - 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" -) - -// PackageRevisionInformer provides access to a shared informer and lister for -// PackageRevisions. -type PackageRevisionInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1alpha1.PackageRevisionLister -} - -type packageRevisionInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewPackageRevisionInformer constructs a new informer for PackageRevision 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 NewPackageRevisionInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredPackageRevisionInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredPackageRevisionInformer constructs a new informer for PackageRevision 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 NewFilteredPackageRevisionInformer(client versioned.Interface, namespace string, 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.PorchV1alpha1().PackageRevisions(namespace).List(context.TODO(), options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.PorchV1alpha1().PackageRevisions(namespace).Watch(context.TODO(), options) - }, - }, - &porchv1alpha1.PackageRevision{}, - resyncPeriod, - indexers, - ) -} - -func (f *packageRevisionInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredPackageRevisionInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *packageRevisionInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&porchv1alpha1.PackageRevision{}, f.defaultInformer) -} - -func (f *packageRevisionInformer) Lister() v1alpha1.PackageRevisionLister { - return v1alpha1.NewPackageRevisionLister(f.Informer().GetIndexer()) -} diff --git a/porch/api/generated/informers/externalversions/porch/v1alpha1/packagerevisionresources.go b/porch/api/generated/informers/externalversions/porch/v1alpha1/packagerevisionresources.go deleted file mode 100644 index 1a99414c4f..0000000000 --- a/porch/api/generated/informers/externalversions/porch/v1alpha1/packagerevisionresources.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2023 The kpt 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 v1alpha1 - -import ( - "context" - time "time" - - versioned "github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned" - internalinterfaces "github.com/GoogleContainerTools/kpt/porch/api/generated/informers/externalversions/internalinterfaces" - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/generated/listers/porch/v1alpha1" - porchv1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - 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" -) - -// PackageRevisionResourcesInformer provides access to a shared informer and lister for -// PackageRevisionResources. -type PackageRevisionResourcesInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1alpha1.PackageRevisionResourcesLister -} - -type packageRevisionResourcesInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewPackageRevisionResourcesInformer constructs a new informer for PackageRevisionResources 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 NewPackageRevisionResourcesInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredPackageRevisionResourcesInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredPackageRevisionResourcesInformer constructs a new informer for PackageRevisionResources 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 NewFilteredPackageRevisionResourcesInformer(client versioned.Interface, namespace string, 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.PorchV1alpha1().PackageRevisionResources(namespace).List(context.TODO(), options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.PorchV1alpha1().PackageRevisionResources(namespace).Watch(context.TODO(), options) - }, - }, - &porchv1alpha1.PackageRevisionResources{}, - resyncPeriod, - indexers, - ) -} - -func (f *packageRevisionResourcesInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredPackageRevisionResourcesInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *packageRevisionResourcesInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&porchv1alpha1.PackageRevisionResources{}, f.defaultInformer) -} - -func (f *packageRevisionResourcesInformer) Lister() v1alpha1.PackageRevisionResourcesLister { - return v1alpha1.NewPackageRevisionResourcesLister(f.Informer().GetIndexer()) -} diff --git a/porch/api/generated/listers/porch/v1alpha1/expansion_generated.go b/porch/api/generated/listers/porch/v1alpha1/expansion_generated.go deleted file mode 100644 index df0d0a0bb6..0000000000 --- a/porch/api/generated/listers/porch/v1alpha1/expansion_generated.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2023 The kpt 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 v1alpha1 - -// FunctionListerExpansion allows custom methods to be added to -// FunctionLister. -type FunctionListerExpansion interface{} - -// FunctionNamespaceListerExpansion allows custom methods to be added to -// FunctionNamespaceLister. -type FunctionNamespaceListerExpansion interface{} - -// PackageListerExpansion allows custom methods to be added to -// PackageLister. -type PackageListerExpansion interface{} - -// PackageNamespaceListerExpansion allows custom methods to be added to -// PackageNamespaceLister. -type PackageNamespaceListerExpansion interface{} - -// PackageRevisionListerExpansion allows custom methods to be added to -// PackageRevisionLister. -type PackageRevisionListerExpansion interface{} - -// PackageRevisionNamespaceListerExpansion allows custom methods to be added to -// PackageRevisionNamespaceLister. -type PackageRevisionNamespaceListerExpansion interface{} - -// PackageRevisionResourcesListerExpansion allows custom methods to be added to -// PackageRevisionResourcesLister. -type PackageRevisionResourcesListerExpansion interface{} - -// PackageRevisionResourcesNamespaceListerExpansion allows custom methods to be added to -// PackageRevisionResourcesNamespaceLister. -type PackageRevisionResourcesNamespaceListerExpansion interface{} diff --git a/porch/api/generated/listers/porch/v1alpha1/function.go b/porch/api/generated/listers/porch/v1alpha1/function.go deleted file mode 100644 index 2f91172113..0000000000 --- a/porch/api/generated/listers/porch/v1alpha1/function.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2023 The kpt 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 v1alpha1 - -import ( - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" -) - -// FunctionLister helps list Functions. -// All objects returned here must be treated as read-only. -type FunctionLister interface { - // List lists all Functions in the indexer. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.Function, err error) - // Functions returns an object that can list and get Functions. - Functions(namespace string) FunctionNamespaceLister - FunctionListerExpansion -} - -// functionLister implements the FunctionLister interface. -type functionLister struct { - indexer cache.Indexer -} - -// NewFunctionLister returns a new FunctionLister. -func NewFunctionLister(indexer cache.Indexer) FunctionLister { - return &functionLister{indexer: indexer} -} - -// List lists all Functions in the indexer. -func (s *functionLister) List(selector labels.Selector) (ret []*v1alpha1.Function, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.Function)) - }) - return ret, err -} - -// Functions returns an object that can list and get Functions. -func (s *functionLister) Functions(namespace string) FunctionNamespaceLister { - return functionNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// FunctionNamespaceLister helps list and get Functions. -// All objects returned here must be treated as read-only. -type FunctionNamespaceLister interface { - // List lists all Functions in the indexer for a given namespace. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.Function, err error) - // Get retrieves the Function from the indexer for a given namespace and name. - // Objects returned here must be treated as read-only. - Get(name string) (*v1alpha1.Function, error) - FunctionNamespaceListerExpansion -} - -// functionNamespaceLister implements the FunctionNamespaceLister -// interface. -type functionNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all Functions in the indexer for a given namespace. -func (s functionNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Function, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.Function)) - }) - return ret, err -} - -// Get retrieves the Function from the indexer for a given namespace and name. -func (s functionNamespaceLister) Get(name string) (*v1alpha1.Function, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("function"), name) - } - return obj.(*v1alpha1.Function), nil -} diff --git a/porch/api/generated/listers/porch/v1alpha1/package.go b/porch/api/generated/listers/porch/v1alpha1/package.go deleted file mode 100644 index bc5510394d..0000000000 --- a/porch/api/generated/listers/porch/v1alpha1/package.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2023 The kpt 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 v1alpha1 - -import ( - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" -) - -// PackageLister helps list Packages. -// All objects returned here must be treated as read-only. -type PackageLister interface { - // List lists all Packages in the indexer. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.Package, err error) - // Packages returns an object that can list and get Packages. - Packages(namespace string) PackageNamespaceLister - PackageListerExpansion -} - -// packageLister implements the PackageLister interface. -type packageLister struct { - indexer cache.Indexer -} - -// NewPackageLister returns a new PackageLister. -func NewPackageLister(indexer cache.Indexer) PackageLister { - return &packageLister{indexer: indexer} -} - -// List lists all Packages in the indexer. -func (s *packageLister) List(selector labels.Selector) (ret []*v1alpha1.Package, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.Package)) - }) - return ret, err -} - -// Packages returns an object that can list and get Packages. -func (s *packageLister) Packages(namespace string) PackageNamespaceLister { - return packageNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// PackageNamespaceLister helps list and get Packages. -// All objects returned here must be treated as read-only. -type PackageNamespaceLister interface { - // List lists all Packages in the indexer for a given namespace. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.Package, err error) - // Get retrieves the Package from the indexer for a given namespace and name. - // Objects returned here must be treated as read-only. - Get(name string) (*v1alpha1.Package, error) - PackageNamespaceListerExpansion -} - -// packageNamespaceLister implements the PackageNamespaceLister -// interface. -type packageNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all Packages in the indexer for a given namespace. -func (s packageNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Package, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.Package)) - }) - return ret, err -} - -// Get retrieves the Package from the indexer for a given namespace and name. -func (s packageNamespaceLister) Get(name string) (*v1alpha1.Package, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("package"), name) - } - return obj.(*v1alpha1.Package), nil -} diff --git a/porch/api/generated/listers/porch/v1alpha1/packagerevision.go b/porch/api/generated/listers/porch/v1alpha1/packagerevision.go deleted file mode 100644 index 9a2c521110..0000000000 --- a/porch/api/generated/listers/porch/v1alpha1/packagerevision.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2023 The kpt 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 v1alpha1 - -import ( - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" -) - -// PackageRevisionLister helps list PackageRevisions. -// All objects returned here must be treated as read-only. -type PackageRevisionLister interface { - // List lists all PackageRevisions in the indexer. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.PackageRevision, err error) - // PackageRevisions returns an object that can list and get PackageRevisions. - PackageRevisions(namespace string) PackageRevisionNamespaceLister - PackageRevisionListerExpansion -} - -// packageRevisionLister implements the PackageRevisionLister interface. -type packageRevisionLister struct { - indexer cache.Indexer -} - -// NewPackageRevisionLister returns a new PackageRevisionLister. -func NewPackageRevisionLister(indexer cache.Indexer) PackageRevisionLister { - return &packageRevisionLister{indexer: indexer} -} - -// List lists all PackageRevisions in the indexer. -func (s *packageRevisionLister) List(selector labels.Selector) (ret []*v1alpha1.PackageRevision, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.PackageRevision)) - }) - return ret, err -} - -// PackageRevisions returns an object that can list and get PackageRevisions. -func (s *packageRevisionLister) PackageRevisions(namespace string) PackageRevisionNamespaceLister { - return packageRevisionNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// PackageRevisionNamespaceLister helps list and get PackageRevisions. -// All objects returned here must be treated as read-only. -type PackageRevisionNamespaceLister interface { - // List lists all PackageRevisions in the indexer for a given namespace. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.PackageRevision, err error) - // Get retrieves the PackageRevision from the indexer for a given namespace and name. - // Objects returned here must be treated as read-only. - Get(name string) (*v1alpha1.PackageRevision, error) - PackageRevisionNamespaceListerExpansion -} - -// packageRevisionNamespaceLister implements the PackageRevisionNamespaceLister -// interface. -type packageRevisionNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all PackageRevisions in the indexer for a given namespace. -func (s packageRevisionNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.PackageRevision, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.PackageRevision)) - }) - return ret, err -} - -// Get retrieves the PackageRevision from the indexer for a given namespace and name. -func (s packageRevisionNamespaceLister) Get(name string) (*v1alpha1.PackageRevision, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("packagerevision"), name) - } - return obj.(*v1alpha1.PackageRevision), nil -} diff --git a/porch/api/generated/listers/porch/v1alpha1/packagerevisionresources.go b/porch/api/generated/listers/porch/v1alpha1/packagerevisionresources.go deleted file mode 100644 index 236855a1e8..0000000000 --- a/porch/api/generated/listers/porch/v1alpha1/packagerevisionresources.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2023 The kpt 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 v1alpha1 - -import ( - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" -) - -// PackageRevisionResourcesLister helps list PackageRevisionResourceses. -// All objects returned here must be treated as read-only. -type PackageRevisionResourcesLister interface { - // List lists all PackageRevisionResourceses in the indexer. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.PackageRevisionResources, err error) - // PackageRevisionResourceses returns an object that can list and get PackageRevisionResourceses. - PackageRevisionResourceses(namespace string) PackageRevisionResourcesNamespaceLister - PackageRevisionResourcesListerExpansion -} - -// packageRevisionResourcesLister implements the PackageRevisionResourcesLister interface. -type packageRevisionResourcesLister struct { - indexer cache.Indexer -} - -// NewPackageRevisionResourcesLister returns a new PackageRevisionResourcesLister. -func NewPackageRevisionResourcesLister(indexer cache.Indexer) PackageRevisionResourcesLister { - return &packageRevisionResourcesLister{indexer: indexer} -} - -// List lists all PackageRevisionResourceses in the indexer. -func (s *packageRevisionResourcesLister) List(selector labels.Selector) (ret []*v1alpha1.PackageRevisionResources, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.PackageRevisionResources)) - }) - return ret, err -} - -// PackageRevisionResourceses returns an object that can list and get PackageRevisionResourceses. -func (s *packageRevisionResourcesLister) PackageRevisionResourceses(namespace string) PackageRevisionResourcesNamespaceLister { - return packageRevisionResourcesNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// PackageRevisionResourcesNamespaceLister helps list and get PackageRevisionResourceses. -// All objects returned here must be treated as read-only. -type PackageRevisionResourcesNamespaceLister interface { - // List lists all PackageRevisionResourceses in the indexer for a given namespace. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.PackageRevisionResources, err error) - // Get retrieves the PackageRevisionResources from the indexer for a given namespace and name. - // Objects returned here must be treated as read-only. - Get(name string) (*v1alpha1.PackageRevisionResources, error) - PackageRevisionResourcesNamespaceListerExpansion -} - -// packageRevisionResourcesNamespaceLister implements the PackageRevisionResourcesNamespaceLister -// interface. -type packageRevisionResourcesNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all PackageRevisionResourceses in the indexer for a given namespace. -func (s packageRevisionResourcesNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.PackageRevisionResources, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.PackageRevisionResources)) - }) - return ret, err -} - -// Get retrieves the PackageRevisionResources from the indexer for a given namespace and name. -func (s packageRevisionResourcesNamespaceLister) Get(name string) (*v1alpha1.PackageRevisionResources, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("packagerevisionresources"), name) - } - return obj.(*v1alpha1.PackageRevisionResources), nil -} diff --git a/porch/api/generated/openapi/zz_generated.openapi.go b/porch/api/generated/openapi/zz_generated.openapi.go deleted file mode 100644 index 2fab904171..0000000000 --- a/porch/api/generated/openapi/zz_generated.openapi.go +++ /dev/null @@ -1,4409 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// Copyright 2023 The kpt 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 openapi-gen. DO NOT EDIT. - -// This file was autogenerated by openapi-gen. Do not edit it manually! - -package openapi - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - common "k8s.io/kube-openapi/pkg/common" - spec "k8s.io/kube-openapi/pkg/validation/spec" -) - -func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { - return map[string]common.OpenAPIDefinition{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Condition": schema_porch_api_porch_v1alpha1_Condition(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Field": schema_porch_api_porch_v1alpha1_Field(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.File": schema_porch_api_porch_v1alpha1_File(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Function": schema_porch_api_porch_v1alpha1_Function(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.FunctionConfig": schema_porch_api_porch_v1alpha1_FunctionConfig(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.FunctionEvalTaskSpec": schema_porch_api_porch_v1alpha1_FunctionEvalTaskSpec(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.FunctionList": schema_porch_api_porch_v1alpha1_FunctionList(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.FunctionRef": schema_porch_api_porch_v1alpha1_FunctionRef(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.FunctionSpec": schema_porch_api_porch_v1alpha1_FunctionSpec(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.FunctionStatus": schema_porch_api_porch_v1alpha1_FunctionStatus(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.GitLock": schema_porch_api_porch_v1alpha1_GitLock(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.GitPackage": schema_porch_api_porch_v1alpha1_GitPackage(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.NameMeta": schema_porch_api_porch_v1alpha1_NameMeta(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.OciPackage": schema_porch_api_porch_v1alpha1_OciPackage(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Package": schema_porch_api_porch_v1alpha1_Package(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageCloneTaskSpec": schema_porch_api_porch_v1alpha1_PackageCloneTaskSpec(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageEditTaskSpec": schema_porch_api_porch_v1alpha1_PackageEditTaskSpec(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageInitTaskSpec": schema_porch_api_porch_v1alpha1_PackageInitTaskSpec(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageList": schema_porch_api_porch_v1alpha1_PackageList(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackagePatchTaskSpec": schema_porch_api_porch_v1alpha1_PackagePatchTaskSpec(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevision": schema_porch_api_porch_v1alpha1_PackageRevision(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionList": schema_porch_api_porch_v1alpha1_PackageRevisionList(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionRef": schema_porch_api_porch_v1alpha1_PackageRevisionRef(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionResources": schema_porch_api_porch_v1alpha1_PackageRevisionResources(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionResourcesList": schema_porch_api_porch_v1alpha1_PackageRevisionResourcesList(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionResourcesSpec": schema_porch_api_porch_v1alpha1_PackageRevisionResourcesSpec(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionResourcesStatus": schema_porch_api_porch_v1alpha1_PackageRevisionResourcesStatus(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionSpec": schema_porch_api_porch_v1alpha1_PackageRevisionSpec(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionStatus": schema_porch_api_porch_v1alpha1_PackageRevisionStatus(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageSpec": schema_porch_api_porch_v1alpha1_PackageSpec(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageStatus": schema_porch_api_porch_v1alpha1_PackageStatus(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageUpdateTaskSpec": schema_porch_api_porch_v1alpha1_PackageUpdateTaskSpec(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.ParentReference": schema_porch_api_porch_v1alpha1_ParentReference(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PatchSpec": schema_porch_api_porch_v1alpha1_PatchSpec(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.ReadinessGate": schema_porch_api_porch_v1alpha1_ReadinessGate(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.RenderStatus": schema_porch_api_porch_v1alpha1_RenderStatus(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.RepositoryRef": schema_porch_api_porch_v1alpha1_RepositoryRef(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.ResourceIdentifier": schema_porch_api_porch_v1alpha1_ResourceIdentifier(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Result": schema_porch_api_porch_v1alpha1_Result(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.ResultItem": schema_porch_api_porch_v1alpha1_ResultItem(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.ResultList": schema_porch_api_porch_v1alpha1_ResultList(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.SecretRef": schema_porch_api_porch_v1alpha1_SecretRef(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Selector": schema_porch_api_porch_v1alpha1_Selector(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Task": schema_porch_api_porch_v1alpha1_Task(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.TaskResult": schema_porch_api_porch_v1alpha1_TaskResult(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.UpstreamLock": schema_porch_api_porch_v1alpha1_UpstreamLock(ref), - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.UpstreamPackage": schema_porch_api_porch_v1alpha1_UpstreamPackage(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.APIGroup": schema_pkg_apis_meta_v1_APIGroup(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.APIGroupList": schema_pkg_apis_meta_v1_APIGroupList(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.APIResource": schema_pkg_apis_meta_v1_APIResource(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.APIResourceList": schema_pkg_apis_meta_v1_APIResourceList(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.APIVersions": schema_pkg_apis_meta_v1_APIVersions(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.ApplyOptions": schema_pkg_apis_meta_v1_ApplyOptions(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.Condition": schema_pkg_apis_meta_v1_Condition(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.CreateOptions": schema_pkg_apis_meta_v1_CreateOptions(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.DeleteOptions": schema_pkg_apis_meta_v1_DeleteOptions(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.Duration": schema_pkg_apis_meta_v1_Duration(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.FieldsV1": schema_pkg_apis_meta_v1_FieldsV1(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.GetOptions": schema_pkg_apis_meta_v1_GetOptions(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.GroupKind": schema_pkg_apis_meta_v1_GroupKind(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.GroupResource": schema_pkg_apis_meta_v1_GroupResource(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersion": schema_pkg_apis_meta_v1_GroupVersion(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionForDiscovery": schema_pkg_apis_meta_v1_GroupVersionForDiscovery(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionKind": schema_pkg_apis_meta_v1_GroupVersionKind(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionResource": schema_pkg_apis_meta_v1_GroupVersionResource(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.InternalEvent": schema_pkg_apis_meta_v1_InternalEvent(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector": schema_pkg_apis_meta_v1_LabelSelector(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelectorRequirement": schema_pkg_apis_meta_v1_LabelSelectorRequirement(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.List": schema_pkg_apis_meta_v1_List(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta": schema_pkg_apis_meta_v1_ListMeta(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.ListOptions": schema_pkg_apis_meta_v1_ListOptions(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.ManagedFieldsEntry": schema_pkg_apis_meta_v1_ManagedFieldsEntry(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.MicroTime": schema_pkg_apis_meta_v1_MicroTime(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta": schema_pkg_apis_meta_v1_ObjectMeta(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.OwnerReference": schema_pkg_apis_meta_v1_OwnerReference(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.PartialObjectMetadata": schema_pkg_apis_meta_v1_PartialObjectMetadata(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.PartialObjectMetadataList": schema_pkg_apis_meta_v1_PartialObjectMetadataList(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.Patch": schema_pkg_apis_meta_v1_Patch(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.PatchOptions": schema_pkg_apis_meta_v1_PatchOptions(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.Preconditions": schema_pkg_apis_meta_v1_Preconditions(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.RootPaths": schema_pkg_apis_meta_v1_RootPaths(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.ServerAddressByClientCIDR": schema_pkg_apis_meta_v1_ServerAddressByClientCIDR(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.Status": schema_pkg_apis_meta_v1_Status(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.StatusCause": schema_pkg_apis_meta_v1_StatusCause(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.StatusDetails": schema_pkg_apis_meta_v1_StatusDetails(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.Table": schema_pkg_apis_meta_v1_Table(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.TableColumnDefinition": schema_pkg_apis_meta_v1_TableColumnDefinition(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.TableOptions": schema_pkg_apis_meta_v1_TableOptions(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.TableRow": schema_pkg_apis_meta_v1_TableRow(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.TableRowCondition": schema_pkg_apis_meta_v1_TableRowCondition(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.Time": schema_pkg_apis_meta_v1_Time(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.Timestamp": schema_pkg_apis_meta_v1_Timestamp(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.TypeMeta": schema_pkg_apis_meta_v1_TypeMeta(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.UpdateOptions": schema_pkg_apis_meta_v1_UpdateOptions(ref), - "k8s.io/apimachinery/pkg/apis/meta/v1.WatchEvent": schema_pkg_apis_meta_v1_WatchEvent(ref), - "k8s.io/apimachinery/pkg/runtime.RawExtension": schema_k8sio_apimachinery_pkg_runtime_RawExtension(ref), - "k8s.io/apimachinery/pkg/runtime.TypeMeta": schema_k8sio_apimachinery_pkg_runtime_TypeMeta(ref), - "k8s.io/apimachinery/pkg/runtime.Unknown": schema_k8sio_apimachinery_pkg_runtime_Unknown(ref), - "k8s.io/apimachinery/pkg/version.Info": schema_k8sio_apimachinery_pkg_version_Info(ref), - } -} - -func schema_porch_api_porch_v1alpha1_Condition(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "type": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "status": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "reason": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "message": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"type", "status"}, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_Field(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Field references a field in a resource", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "path": { - SchemaProps: spec.SchemaProps{ - Description: "Path is the field path. This field is required.", - Type: []string{"string"}, - Format: "", - }, - }, - "currentValue": { - SchemaProps: spec.SchemaProps{ - Description: "CurrentValue is the current field value", - Type: []string{"string"}, - Format: "", - }, - }, - "proposedValue": { - SchemaProps: spec.SchemaProps{ - Description: "ProposedValue is the proposed value of the field to fix an issue.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_File(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "File references a file containing a resource", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "path": { - SchemaProps: spec.SchemaProps{ - Description: "Path is relative path to the file containing the resource. This field is required.", - Type: []string{"string"}, - Format: "", - }, - }, - "index": { - SchemaProps: spec.SchemaProps{ - Description: "Index is the index into the file containing the resource (i.e. if there are multiple resources in a single file)", - Type: []string{"integer"}, - Format: "int32", - }, - }, - }, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_Function(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Function represents a kpt function discovered in a repository Function resources are created automatically by discovery in a registered Repository. Function resource names will be computed as : to ensure uniqueness of names, and will follow formatting of [DNS Subdomain Names](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names).", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), - }, - }, - "spec": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.FunctionSpec"), - }, - }, - "status": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.FunctionStatus"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.FunctionSpec", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.FunctionStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, - } -} - -func schema_porch_api_porch_v1alpha1_FunctionConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "FunctionConfig specifies all the valid types of the function config for this function. If unspecified, defaults to v1/ConfigMap. For example, function `set-namespace` accepts both `ConfigMap` and `SetNamespace`", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "requiredFields": { - SchemaProps: spec.SchemaProps{ - Description: "Experimental: requiredFields tells necessary fields and is aimed to help users write the FunctionConfig. Otherwise, users can get the required fields info from the function evaluation error message.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - }, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_FunctionEvalTaskSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "subpackage": { - SchemaProps: spec.SchemaProps{ - Description: "`Subpackage` is a directory path to a subpackage in which to evaluate the function.", - Type: []string{"string"}, - Format: "", - }, - }, - "image": { - SchemaProps: spec.SchemaProps{ - Description: "`Image` specifies the function image, such as `gcr.io/kpt-fn/gatekeeper:v0.2`. Use of `Image` is mutually exclusive with `FunctionRef`.", - Type: []string{"string"}, - Format: "", - }, - }, - "functionRef": { - SchemaProps: spec.SchemaProps{ - Description: "`FunctionRef` specifies the function by reference to a Function resource. Mutually exclusive with `Image`.", - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.FunctionRef"), - }, - }, - "configMap": { - SchemaProps: spec.SchemaProps{ - Description: "`ConfigMap` specifies the function config (https://kpt.dev/reference/cli/fn/eval/). Mutually exclusive with Config.", - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "config": { - SchemaProps: spec.SchemaProps{ - Description: "`Config` specifies the function config, arbitrary KRM resource. Mutually exclusive with ConfigMap.", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/runtime.RawExtension"), - }, - }, - "includeMetaResources": { - SchemaProps: spec.SchemaProps{ - Description: "If enabled, meta resources (i.e. `Kptfile` and `functionConfig`) are included in the input to the function. By default it is disabled.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "enableNetwork": { - SchemaProps: spec.SchemaProps{ - Description: "`EnableNetwork` controls whether the function has access to network. Defaults to `false`.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "match": { - SchemaProps: spec.SchemaProps{ - Description: "Match specifies the selection criteria for the function evaluation. Corresponds to `kpt fn eval --match-???` flgs (https://kpt.dev/reference/cli/fn/eval/).", - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Selector"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.FunctionRef", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Selector", "k8s.io/apimachinery/pkg/runtime.RawExtension"}, - } -} - -func schema_porch_api_porch_v1alpha1_FunctionList(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "FunctionList", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), - }, - }, - "items": { - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Function"), - }, - }, - }, - }, - }, - }, - Required: []string{"items"}, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Function", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, - } -} - -func schema_porch_api_porch_v1alpha1_FunctionRef(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "FunctionRef is a reference to a Function resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { - SchemaProps: spec.SchemaProps{ - Description: "Name is the name of the Function resource referenced. The resource is expected to be within the same namespace.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"name"}, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_FunctionSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "FunctionSpec defines the desired state of a Function", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "image": { - SchemaProps: spec.SchemaProps{ - Description: "Image specifies the function image, such as 'gcr.io/kpt-fn/gatekeeper:v0.2'.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "repositoryRef": { - SchemaProps: spec.SchemaProps{ - Description: "RepositoryRef references the repository in which the function is located.", - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.RepositoryRef"), - }, - }, - "functionTypes": { - SchemaProps: spec.SchemaProps{ - Description: "FunctionType specifies the function types (mutator, validator or/and others).", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "functionConfigs": { - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.FunctionConfig"), - }, - }, - }, - }, - }, - "keywords": { - SchemaProps: spec.SchemaProps{ - Description: "Keywords are used as filters to provide correlation in function discovery.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "description": { - SchemaProps: spec.SchemaProps{ - Description: "Description is a short description of the function.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "documentationUrl": { - SchemaProps: spec.SchemaProps{ - Description: "`DocumentationUrl specifies the URL of comprehensive function documentation`", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"image", "repositoryRef", "description"}, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.FunctionConfig", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.RepositoryRef"}, - } -} - -func schema_porch_api_porch_v1alpha1_FunctionStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "FunctionStatus defines the observed state of Function", - Type: []string{"object"}, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_GitLock(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "GitLock is the resolved locator for a package on Git.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "repo": { - SchemaProps: spec.SchemaProps{ - Description: "Repo is the git repository that was fetched. e.g. 'https://github.com/kubernetes/examples.git'", - Type: []string{"string"}, - Format: "", - }, - }, - "directory": { - SchemaProps: spec.SchemaProps{ - Description: "Directory is the sub directory of the git repository that was fetched. e.g. 'staging/cockroachdb'", - Type: []string{"string"}, - Format: "", - }, - }, - "ref": { - SchemaProps: spec.SchemaProps{ - Description: "Ref can be a Git branch, tag, or a commit SHA-1 that was fetched. e.g. 'master'", - Type: []string{"string"}, - Format: "", - }, - }, - "commit": { - SchemaProps: spec.SchemaProps{ - Description: "Commit is the SHA-1 for the last fetch of the package. This is set by kpt for bookkeeping purposes.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_GitPackage(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "repo": { - SchemaProps: spec.SchemaProps{ - Description: "Address of the Git repository, for example:\n `https://github.com/GoogleCloudPlatform/blueprints.git`", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "ref": { - SchemaProps: spec.SchemaProps{ - Description: "`Ref` is the git ref containing the package. Ref can be a branch, tag, or commit SHA.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "directory": { - SchemaProps: spec.SchemaProps{ - Description: "Directory within the Git repository where the packages are stored. A subdirectory of this directory containing a Kptfile is considered a package.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "secretRef": { - SchemaProps: spec.SchemaProps{ - Description: "Reference to secret containing authentication credentials. Optional.", - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.SecretRef"), - }, - }, - }, - Required: []string{"repo", "ref", "directory"}, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.SecretRef"}, - } -} - -func schema_porch_api_porch_v1alpha1_NameMeta(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "NameMeta contains name information.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { - SchemaProps: spec.SchemaProps{ - Description: "Name is the metadata.name field of a Resource", - Type: []string{"string"}, - Format: "", - }, - }, - "namespace": { - SchemaProps: spec.SchemaProps{ - Description: "Namespace is the metadata.namespace field of a Resource", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_OciPackage(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "OciPackage describes a repository compatible with the Open Coutainer Registry standard.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "image": { - SchemaProps: spec.SchemaProps{ - Description: "Image is the address of an OCI image.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"image"}, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_Package(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Package", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), - }, - }, - "spec": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageSpec"), - }, - }, - "status": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageStatus"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageSpec", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, - } -} - -func schema_porch_api_porch_v1alpha1_PackageCloneTaskSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "upstreamRef": { - SchemaProps: spec.SchemaProps{ - Description: "`Upstream` is the reference to the upstream package to clone.", - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.UpstreamPackage"), - }, - }, - "strategy": { - SchemaProps: spec.SchemaProps{ - Description: "\n\tDefines which strategy should be used to update the package. It defaults to 'resource-merge'.\n * resource-merge: Perform a structural comparison of the original /\n updated resources, and merge the changes into the local package.\n * fast-forward: Fail without updating if the local package was modified\n since it was fetched.\n * force-delete-replace: Wipe all the local changes to the package and replace\n it with the remote version.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.UpstreamPackage"}, - } -} - -func schema_porch_api_porch_v1alpha1_PackageEditTaskSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "sourceRef": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionRef"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionRef"}, - } -} - -func schema_porch_api_porch_v1alpha1_PackageInitTaskSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PackageInitTaskSpec defines the package initialization task.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "subpackage": { - SchemaProps: spec.SchemaProps{ - Description: "`Subpackage` is a directory path to a subpackage to initialize. If unspecified, the main package will be initialized.", - Type: []string{"string"}, - Format: "", - }, - }, - "description": { - SchemaProps: spec.SchemaProps{ - Description: "`Description` is a short description of the package.", - Type: []string{"string"}, - Format: "", - }, - }, - "keywords": { - SchemaProps: spec.SchemaProps{ - Description: "`Keywords` is a list of keywords describing the package.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "site": { - SchemaProps: spec.SchemaProps{ - Description: "`Site is a link to page with information about the package.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_PackageList(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PackageList", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), - }, - }, - "items": { - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Package"), - }, - }, - }, - }, - }, - }, - Required: []string{"items"}, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Package", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, - } -} - -func schema_porch_api_porch_v1alpha1_PackagePatchTaskSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "patches": { - SchemaProps: spec.SchemaProps{ - Description: "Patches is a list of individual patch operations.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PatchSpec"), - }, - }, - }, - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PatchSpec"}, - } -} - -func schema_porch_api_porch_v1alpha1_PackageRevision(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PackageRevision", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), - }, - }, - "spec": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionSpec"), - }, - }, - "status": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionStatus"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionSpec", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, - } -} - -func schema_porch_api_porch_v1alpha1_PackageRevisionList(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PackageRevisionList", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), - }, - }, - "items": { - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevision"), - }, - }, - }, - }, - }, - }, - Required: []string{"items"}, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevision", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, - } -} - -func schema_porch_api_porch_v1alpha1_PackageRevisionRef(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PackageRevisionRef is a reference to a package revision.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { - SchemaProps: spec.SchemaProps{ - Description: "`Name` is the name of the referenced PackageRevision resource.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"name"}, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_PackageRevisionResources(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PackageRevisionResources", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), - }, - }, - "spec": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionResourcesSpec"), - }, - }, - "status": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionResourcesStatus"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionResourcesSpec", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionResourcesStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, - } -} - -func schema_porch_api_porch_v1alpha1_PackageRevisionResourcesList(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PackageRevisionResourcesList", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), - }, - }, - "items": { - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionResources"), - }, - }, - }, - }, - }, - }, - Required: []string{"items"}, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionResources", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, - } -} - -func schema_porch_api_porch_v1alpha1_PackageRevisionResourcesSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PackageRevisionResourcesSpec represents resources (as ResourceList serialized as yaml string) of the PackageRevision.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "packageName": { - SchemaProps: spec.SchemaProps{ - Description: "PackageName identifies the package in the repository.", - Type: []string{"string"}, - Format: "", - }, - }, - "workspaceName": { - SchemaProps: spec.SchemaProps{ - Description: "WorkspaceName identifies the workspace of the package.", - Type: []string{"string"}, - Format: "", - }, - }, - "revision": { - SchemaProps: spec.SchemaProps{ - Description: "Revision identifies the version of the package.", - Type: []string{"string"}, - Format: "", - }, - }, - "repository": { - SchemaProps: spec.SchemaProps{ - Description: "RepositoryName is the name of the Repository object containing this package.", - Type: []string{"string"}, - Format: "", - }, - }, - "resources": { - SchemaProps: spec.SchemaProps{ - Description: "Resources are the content of the package.", - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - }, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_PackageRevisionResourcesStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PackageRevisionResourcesStatus represents state of the rendered package resources.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "renderStatus": { - SchemaProps: spec.SchemaProps{ - Description: "RenderStatus contains the result of rendering the package resources.", - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.RenderStatus"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.RenderStatus"}, - } -} - -func schema_porch_api_porch_v1alpha1_PackageRevisionSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PackageRevisionSpec defines the desired state of PackageRevision", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "packageName": { - SchemaProps: spec.SchemaProps{ - Description: "PackageName identifies the package in the repository.", - Type: []string{"string"}, - Format: "", - }, - }, - "repository": { - SchemaProps: spec.SchemaProps{ - Description: "RepositoryName is the name of the Repository object containing this package.", - Type: []string{"string"}, - Format: "", - }, - }, - "workspaceName": { - SchemaProps: spec.SchemaProps{ - Description: "WorkspaceName is a short, unique description of the changes contained in this package revision.", - Type: []string{"string"}, - Format: "", - }, - }, - "revision": { - SchemaProps: spec.SchemaProps{ - Description: "Revision identifies the version of the package.", - Type: []string{"string"}, - Format: "", - }, - }, - "parent": { - SchemaProps: spec.SchemaProps{ - Description: "Parent references a package that provides resources to us", - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.ParentReference"), - }, - }, - "lifecycle": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "tasks": { - SchemaProps: spec.SchemaProps{ - Description: "The task slice holds zero or more tasks that describe the operations performed on the packagerevision. The are essentially a replayable history of the packagerevision,\n\nPackagerevisions that were not created in Porch may have an empty task list.\n\nPackagerevisions created and managed through Porch will always have either an Init, Edit, or a Clone task as the first entry in their task list. This represent packagerevisions created from scratch, based a copy of a different revision in the same package, or a packagerevision cloned from another package. Each change to the packagerevision will result in a correspondig task being added to the list of tasks. It will describe the operation performed and will have a corresponding entry (commit or layer) in git or oci. The task slice describes the history of the packagerevision, so it is an append only list (We might introduce some kind of compaction in the future to keep the number of tasks at a reasonable number).", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Task"), - }, - }, - }, - }, - }, - "readinessGates": { - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.ReadinessGate"), - }, - }, - }, - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.ParentReference", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.ReadinessGate", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Task"}, - } -} - -func schema_porch_api_porch_v1alpha1_PackageRevisionStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PackageRevisionStatus defines the observed state of PackageRevision", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "upstreamLock": { - SchemaProps: spec.SchemaProps{ - Description: "UpstreamLock identifies the upstream data for this package.", - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.UpstreamLock"), - }, - }, - "publishedBy": { - SchemaProps: spec.SchemaProps{ - Description: "PublishedBy is the identity of the user who approved the packagerevision.", - Type: []string{"string"}, - Format: "", - }, - }, - "publishTimestamp": { - SchemaProps: spec.SchemaProps{ - Description: "PublishedAt is the time when the packagerevision were approved.", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), - }, - }, - "deployment": { - SchemaProps: spec.SchemaProps{ - Description: "Deployment is true if this is a deployment package (in a deployment repository).", - Type: []string{"boolean"}, - Format: "", - }, - }, - "conditions": { - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Condition"), - }, - }, - }, - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Condition", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.UpstreamLock", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, - } -} - -func schema_porch_api_porch_v1alpha1_PackageSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PackageSpec defines the desired state of Package", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "packageName": { - SchemaProps: spec.SchemaProps{ - Description: "PackageName identifies the package in the repository.", - Type: []string{"string"}, - Format: "", - }, - }, - "repository": { - SchemaProps: spec.SchemaProps{ - Description: "RepositoryName is the name of the Repository object containing this package.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_PackageStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PackageStatus defines the observed state of Package", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "latestRevision": { - SchemaProps: spec.SchemaProps{ - Description: "LatestRevision identifies the package revision that is the latest published package revision belonging to this package", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_PackageUpdateTaskSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "upstreamRef": { - SchemaProps: spec.SchemaProps{ - Description: "`Upstream` is the reference to the upstream package.", - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.UpstreamPackage"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.UpstreamPackage"}, - } -} - -func schema_porch_api_porch_v1alpha1_ParentReference(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ParentReference is a reference to a parent package", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { - SchemaProps: spec.SchemaProps{ - Description: "Name is the name of the parent PackageRevision", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"name"}, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_PatchSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "file": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "contents": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "patchType": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_ReadinessGate(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "conditionType": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_RenderStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "RenderStatus represents the result of performing render operation on a package resources.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "result": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.ResultList"), - }, - }, - "error": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"error"}, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.ResultList"}, - } -} - -func schema_porch_api_porch_v1alpha1_RepositoryRef(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "RepositoryRef identifies a reference to a Repository resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { - SchemaProps: spec.SchemaProps{ - Description: "Name of the Repository resource referenced.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"name"}, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_ResourceIdentifier(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ResourceIdentifier contains the information needed to uniquely identify a resource in a cluster.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "name": { - SchemaProps: spec.SchemaProps{ - Description: "Name is the metadata.name field of a Resource", - Type: []string{"string"}, - Format: "", - }, - }, - "namespace": { - SchemaProps: spec.SchemaProps{ - Description: "Namespace is the metadata.namespace field of a Resource", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_Result(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Result contains the structured result from an individual function", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "image": { - SchemaProps: spec.SchemaProps{ - Description: "Image is the full name of the image that generates this result Image and Exec are mutually exclusive", - Type: []string{"string"}, - Format: "", - }, - }, - "exec": { - SchemaProps: spec.SchemaProps{ - Description: "ExecPath is the the absolute os-specific path to the executable file If user provides an executable file with commands, ExecPath should contain the entire input string.", - Type: []string{"string"}, - Format: "", - }, - }, - "stderr": { - SchemaProps: spec.SchemaProps{ - Description: "Enable this once test harness supports filepath based assertions. Pkg is OS specific Absolute path to the package. Pkg string `yaml:\"pkg,omitempty\"` Stderr is the content in function stderr", - Type: []string{"string"}, - Format: "", - }, - }, - "exitCode": { - SchemaProps: spec.SchemaProps{ - Description: "ExitCode is the exit code from running the function", - Default: 0, - Type: []string{"integer"}, - Format: "int32", - }, - }, - "results": { - SchemaProps: spec.SchemaProps{ - Description: "Results is the list of results for the function", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.ResultItem"), - }, - }, - }, - }, - }, - }, - Required: []string{"exitCode"}, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.ResultItem"}, - } -} - -func schema_porch_api_porch_v1alpha1_ResultItem(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ResultItem defines a validation result", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "message": { - SchemaProps: spec.SchemaProps{ - Description: "Message is a human readable message. This field is required.", - Type: []string{"string"}, - Format: "", - }, - }, - "severity": { - SchemaProps: spec.SchemaProps{ - Description: "Severity is the severity of this result", - Type: []string{"string"}, - Format: "", - }, - }, - "resourceRef": { - SchemaProps: spec.SchemaProps{ - Description: "ResourceRef is a reference to a resource. Required fields: apiVersion, kind, name.", - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.ResourceIdentifier"), - }, - }, - "field": { - SchemaProps: spec.SchemaProps{ - Description: "Field is a reference to the field in a resource this result refers to", - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Field"), - }, - }, - "file": { - SchemaProps: spec.SchemaProps{ - Description: "File references a file containing the resource this result refers to", - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.File"), - }, - }, - "tags": { - SchemaProps: spec.SchemaProps{ - Description: "Tags is an unstructured key value map stored with a result that may be set by external tools to store and retrieve arbitrary metadata", - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Field", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.File", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.ResourceIdentifier"}, - } -} - -func schema_porch_api_porch_v1alpha1_ResultList(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ResultList contains aggregated results from multiple functions", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), - }, - }, - "exitCode": { - SchemaProps: spec.SchemaProps{ - Description: "ExitCode is the exit code of kpt command", - Default: 0, - Type: []string{"integer"}, - Format: "int32", - }, - }, - "items": { - SchemaProps: spec.SchemaProps{ - Description: "Items contain a list of function result", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Result"), - }, - }, - }, - }, - }, - }, - Required: []string{"exitCode"}, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Result", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, - } -} - -func schema_porch_api_porch_v1alpha1_SecretRef(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { - SchemaProps: spec.SchemaProps{ - Description: "Name of the secret. The secret is expected to be located in the same namespace as the resource containing the reference.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"name"}, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_Selector(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Selector corresponds to the `--match-???` set of flags of the `kpt fn eval` command: See https://kpt.dev/reference/cli/fn/eval/ for additional information.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion of the target resources", - Type: []string{"string"}, - Format: "", - }, - }, - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind of the target resources", - Type: []string{"string"}, - Format: "", - }, - }, - "name": { - SchemaProps: spec.SchemaProps{ - Description: "Name of the target resources", - Type: []string{"string"}, - Format: "", - }, - }, - "namespace": { - SchemaProps: spec.SchemaProps{ - Description: "Namespace of the target resources", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_porch_api_porch_v1alpha1_Task(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "type": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "init": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageInitTaskSpec"), - }, - }, - "clone": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageCloneTaskSpec"), - }, - }, - "patch": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackagePatchTaskSpec"), - }, - }, - "edit": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageEditTaskSpec"), - }, - }, - "eval": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.FunctionEvalTaskSpec"), - }, - }, - "update": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageUpdateTaskSpec"), - }, - }, - }, - Required: []string{"type"}, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.FunctionEvalTaskSpec", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageCloneTaskSpec", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageEditTaskSpec", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageInitTaskSpec", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackagePatchTaskSpec", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageUpdateTaskSpec"}, - } -} - -func schema_porch_api_porch_v1alpha1_TaskResult(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "task": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Task"), - }, - }, - "renderStatus": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.RenderStatus"), - }, - }, - }, - Required: []string{"task"}, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.RenderStatus", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.Task"}, - } -} - -func schema_porch_api_porch_v1alpha1_UpstreamLock(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "UpstreamLock is a resolved locator for the last fetch of the package.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "type": { - SchemaProps: spec.SchemaProps{ - Description: "Type is the type of origin.", - Type: []string{"string"}, - Format: "", - }, - }, - "git": { - SchemaProps: spec.SchemaProps{ - Description: "Git is the resolved locator for a package on Git.", - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.GitLock"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.GitLock"}, - } -} - -func schema_porch_api_porch_v1alpha1_UpstreamPackage(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "UpstreamRepository repository may be specified directly or by referencing another Repository resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "type": { - SchemaProps: spec.SchemaProps{ - Description: "Type of the repository (i.e. git, OCI). If empty, `upstreamRef` will be used.", - Type: []string{"string"}, - Format: "", - }, - }, - "git": { - SchemaProps: spec.SchemaProps{ - Description: "Git upstream package specification. Required if `type` is `git`. Must be unspecified if `type` is not `git`.", - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.GitPackage"), - }, - }, - "oci": { - SchemaProps: spec.SchemaProps{ - Description: "OCI upstream package specification. Required if `type` is `oci`. Must be unspecified if `type` is not `oci`.", - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.OciPackage"), - }, - }, - "upstreamRef": { - SchemaProps: spec.SchemaProps{ - Description: "UpstreamRef is the reference to the package from a registered repository rather than external package.", - Ref: ref("github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionRef"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.GitPackage", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.OciPackage", "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevisionRef"}, - } -} - -func schema_pkg_apis_meta_v1_APIGroup(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "APIGroup contains the name, the supported versions, and the preferred version of a group.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "name": { - SchemaProps: spec.SchemaProps{ - Description: "name is the name of the group.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "versions": { - SchemaProps: spec.SchemaProps{ - Description: "versions are the versions supported in this group.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionForDiscovery"), - }, - }, - }, - }, - }, - "preferredVersion": { - SchemaProps: spec.SchemaProps{ - Description: "preferredVersion is the version preferred by the API server, which probably is the storage version.", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionForDiscovery"), - }, - }, - "serverAddressByClientCIDRs": { - SchemaProps: spec.SchemaProps{ - Description: "a map of client CIDR to server address that is serving this group. This is to help clients reach servers in the most network-efficient way possible. Clients can use the appropriate server address as per the CIDR that they match. In case of multiple matches, clients should use the longest matching CIDR. The server returns only those CIDRs that it thinks that the client can match. For example: the master will return an internal IP CIDR only, if the client reaches the server using an internal IP. Server looks at X-Forwarded-For header or X-Real-Ip header or request.RemoteAddr (in that order) to get the client IP.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ServerAddressByClientCIDR"), - }, - }, - }, - }, - }, - }, - Required: []string{"name", "versions"}, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionForDiscovery", "k8s.io/apimachinery/pkg/apis/meta/v1.ServerAddressByClientCIDR"}, - } -} - -func schema_pkg_apis_meta_v1_APIGroupList(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "APIGroupList is a list of APIGroup, to allow clients to discover the API at /apis.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "groups": { - SchemaProps: spec.SchemaProps{ - Description: "groups is a list of APIGroup.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.APIGroup"), - }, - }, - }, - }, - }, - }, - Required: []string{"groups"}, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.APIGroup"}, - } -} - -func schema_pkg_apis_meta_v1_APIResource(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "APIResource specifies the name of a resource and whether it is namespaced.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { - SchemaProps: spec.SchemaProps{ - Description: "name is the plural name of the resource.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "singularName": { - SchemaProps: spec.SchemaProps{ - Description: "singularName is the singular name of the resource. This allows clients to handle plural and singular opaquely. The singularName is more correct for reporting status on a single item and both singular and plural are allowed from the kubectl CLI interface.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "namespaced": { - SchemaProps: spec.SchemaProps{ - Description: "namespaced indicates if a resource is namespaced or not.", - Default: false, - Type: []string{"boolean"}, - Format: "", - }, - }, - "group": { - SchemaProps: spec.SchemaProps{ - Description: "group is the preferred group of the resource. Empty implies the group of the containing resource list. For subresources, this may have a different value, for example: Scale\".", - Type: []string{"string"}, - Format: "", - }, - }, - "version": { - SchemaProps: spec.SchemaProps{ - Description: "version is the preferred version of the resource. Empty implies the version of the containing resource list For subresources, this may have a different value, for example: v1 (while inside a v1beta1 version of the core resource's group)\".", - Type: []string{"string"}, - Format: "", - }, - }, - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "kind is the kind for the resource (e.g. 'Foo' is the kind for a resource 'foo')", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "verbs": { - SchemaProps: spec.SchemaProps{ - Description: "verbs is a list of supported kube verbs (this includes get, list, watch, create, update, patch, delete, deletecollection, and proxy)", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "shortNames": { - SchemaProps: spec.SchemaProps{ - Description: "shortNames is a list of suggested short names of the resource.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "categories": { - SchemaProps: spec.SchemaProps{ - Description: "categories is a list of the grouped resources this resource belongs to (e.g. 'all')", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "storageVersionHash": { - SchemaProps: spec.SchemaProps{ - Description: "The hash value of the storage version, the version this resource is converted to when written to the data store. Value must be treated as opaque by clients. Only equality comparison on the value is valid. This is an alpha feature and may change or be removed in the future. The field is populated by the apiserver only if the StorageVersionHash feature gate is enabled. This field will remain optional even if it graduates.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"name", "singularName", "namespaced", "kind", "verbs"}, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_APIResourceList(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "APIResourceList is a list of APIResource, it is used to expose the name of the resources supported in a specific group and version, and if the resource is namespaced.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "groupVersion": { - SchemaProps: spec.SchemaProps{ - Description: "groupVersion is the group and version this APIResourceList is for.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "resources": { - SchemaProps: spec.SchemaProps{ - Description: "resources contains the name of the resources and if they are namespaced.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.APIResource"), - }, - }, - }, - }, - }, - }, - Required: []string{"groupVersion", "resources"}, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.APIResource"}, - } -} - -func schema_pkg_apis_meta_v1_APIVersions(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "APIVersions lists the versions that are available, to allow clients to discover the API at /api, which is the root path of the legacy v1 API.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "versions": { - SchemaProps: spec.SchemaProps{ - Description: "versions are the api versions that are available.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "serverAddressByClientCIDRs": { - SchemaProps: spec.SchemaProps{ - Description: "a map of client CIDR to server address that is serving this group. This is to help clients reach servers in the most network-efficient way possible. Clients can use the appropriate server address as per the CIDR that they match. In case of multiple matches, clients should use the longest matching CIDR. The server returns only those CIDRs that it thinks that the client can match. For example: the master will return an internal IP CIDR only, if the client reaches the server using an internal IP. Server looks at X-Forwarded-For header or X-Real-Ip header or request.RemoteAddr (in that order) to get the client IP.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ServerAddressByClientCIDR"), - }, - }, - }, - }, - }, - }, - Required: []string{"versions", "serverAddressByClientCIDRs"}, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.ServerAddressByClientCIDR"}, - } -} - -func schema_pkg_apis_meta_v1_ApplyOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ApplyOptions may be provided when applying an API object. FieldManager is required for apply requests. ApplyOptions is equivalent to PatchOptions. It is provided as a convenience with documentation that speaks specifically to how the options fields relate to apply.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "dryRun": { - SchemaProps: spec.SchemaProps{ - Description: "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "force": { - SchemaProps: spec.SchemaProps{ - Description: "Force is going to \"force\" Apply requests. It means user will re-acquire conflicting fields owned by other people.", - Default: false, - Type: []string{"boolean"}, - Format: "", - }, - }, - "fieldManager": { - SchemaProps: spec.SchemaProps{ - Description: "fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"force", "fieldManager"}, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_Condition(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Condition contains details for one aspect of the current state of this API Resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "type": { - SchemaProps: spec.SchemaProps{ - Description: "type of condition in CamelCase or in foo.example.com/CamelCase.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "status": { - SchemaProps: spec.SchemaProps{ - Description: "status of the condition, one of True, False, Unknown.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "observedGeneration": { - SchemaProps: spec.SchemaProps{ - Description: "observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.", - Type: []string{"integer"}, - Format: "int64", - }, - }, - "lastTransitionTime": { - SchemaProps: spec.SchemaProps{ - Description: "lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), - }, - }, - "reason": { - SchemaProps: spec.SchemaProps{ - Description: "reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "message": { - SchemaProps: spec.SchemaProps{ - Description: "message is a human readable message indicating details about the transition. This may be an empty string.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"type", "status", "lastTransitionTime", "reason", "message"}, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, - } -} - -func schema_pkg_apis_meta_v1_CreateOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "CreateOptions may be provided when creating an API object.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "dryRun": { - SchemaProps: spec.SchemaProps{ - Description: "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "fieldManager": { - SchemaProps: spec.SchemaProps{ - Description: "fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint.", - Type: []string{"string"}, - Format: "", - }, - }, - "fieldValidation": { - SchemaProps: spec.SchemaProps{ - Description: "fieldValidation determines how the server should respond to unknown/duplicate fields in the object in the request. Introduced as alpha in 1.23, older servers or servers with the `ServerSideFieldValidation` feature disabled will discard valid values specified in this param and not perform any server side field validation. Valid values are: - Ignore: ignores unknown/duplicate fields. - Warn: responds with a warning for each unknown/duplicate field, but successfully serves the request. - Strict: fails the request on unknown/duplicate fields.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_DeleteOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "DeleteOptions may be provided when deleting an API object.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "gracePeriodSeconds": { - SchemaProps: spec.SchemaProps{ - Description: "The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately.", - Type: []string{"integer"}, - Format: "int64", - }, - }, - "preconditions": { - SchemaProps: spec.SchemaProps{ - Description: "Must be fulfilled before a deletion is carried out. If not possible, a 409 Conflict status will be returned.", - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Preconditions"), - }, - }, - "orphanDependents": { - SchemaProps: spec.SchemaProps{ - Description: "Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the \"orphan\" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "propagationPolicy": { - SchemaProps: spec.SchemaProps{ - Description: "Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground.", - Type: []string{"string"}, - Format: "", - }, - }, - "dryRun": { - SchemaProps: spec.SchemaProps{ - Description: "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - }, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.Preconditions"}, - } -} - -func schema_pkg_apis_meta_v1_Duration(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Duration is a wrapper around time.Duration which supports correct marshaling to YAML and JSON. In particular, it marshals into strings, which can be used as map keys in json.", - Type: v1.Duration{}.OpenAPISchemaType(), - Format: v1.Duration{}.OpenAPISchemaFormat(), - }, - }, - } -} - -func schema_pkg_apis_meta_v1_FieldsV1(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "FieldsV1 stores a set of fields in a data structure like a Trie, in JSON format.\n\nEach key is either a '.' representing the field itself, and will always map to an empty set, or a string representing a sub-field or item. The string will follow one of these four formats: 'f:', where is the name of a field in a struct, or key in a map 'v:', where is the exact json formatted value of a list item 'i:', where is position of a item in a list 'k:', where is a map of a list item's key fields to their unique values If a key maps to an empty Fields value, the field that key represents is part of the set.\n\nThe exact format is defined in sigs.k8s.io/structured-merge-diff", - Type: []string{"object"}, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_GetOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "GetOptions is the standard query options to the standard REST get call.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "resourceVersion": { - SchemaProps: spec.SchemaProps{ - Description: "resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details.\n\nDefaults to unset", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_GroupKind(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "GroupKind specifies a Group and a Kind, but does not force a version. This is useful for identifying concepts during lookup stages without having partially valid types", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "group": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "kind": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"group", "kind"}, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_GroupResource(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "GroupResource specifies a Group and a Resource, but does not force a version. This is useful for identifying concepts during lookup stages without having partially valid types", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "group": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "resource": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"group", "resource"}, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_GroupVersion(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "GroupVersion contains the \"group\" and the \"version\", which uniquely identifies the API.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "group": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "version": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"group", "version"}, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_GroupVersionForDiscovery(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "GroupVersion contains the \"group/version\" and \"version\" string of a version. It is made a struct to keep extensibility.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "groupVersion": { - SchemaProps: spec.SchemaProps{ - Description: "groupVersion specifies the API group and version in the form \"group/version\"", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "version": { - SchemaProps: spec.SchemaProps{ - Description: "version specifies the version in the form of \"version\". This is to save the clients the trouble of splitting the GroupVersion.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"groupVersion", "version"}, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_GroupVersionKind(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "GroupVersionKind unambiguously identifies a kind. It doesn't anonymously include GroupVersion to avoid automatic coercion. It doesn't use a GroupVersion to avoid custom marshalling", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "group": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "version": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "kind": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"group", "version", "kind"}, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_GroupVersionResource(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "GroupVersionResource unambiguously identifies a resource. It doesn't anonymously include GroupVersion to avoid automatic coercion. It doesn't use a GroupVersion to avoid custom marshalling", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "group": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "version": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "resource": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"group", "version", "resource"}, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_InternalEvent(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "InternalEvent makes watch.Event versioned", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "Type": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "Object": { - SchemaProps: spec.SchemaProps{ - Description: "Object is:\n * If Type is Added or Modified: the new state of the object.\n * If Type is Deleted: the state of the object immediately before deletion.\n * If Type is Bookmark: the object (instance of a type being watched) where\n only ResourceVersion field is set. On successful restart of watch from a\n bookmark resourceVersion, client is guaranteed to not get repeat event\n nor miss any events.\n * If Type is Error: *api.Status is recommended; other types may make sense\n depending on context.", - Ref: ref("k8s.io/apimachinery/pkg/runtime.Object"), - }, - }, - }, - Required: []string{"Type", "Object"}, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/runtime.Object"}, - } -} - -func schema_pkg_apis_meta_v1_LabelSelector(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "A label selector is a label query over a set of resources. The result of matchLabels and matchExpressions are ANDed. An empty label selector matches all objects. A null label selector matches no objects.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "matchLabels": { - SchemaProps: spec.SchemaProps{ - Description: "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.", - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "matchExpressions": { - SchemaProps: spec.SchemaProps{ - Description: "matchExpressions is a list of label selector requirements. The requirements are ANDed.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelectorRequirement"), - }, - }, - }, - }, - }, - }, - }, - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-map-type": "atomic", - }, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelectorRequirement"}, - } -} - -func schema_pkg_apis_meta_v1_LabelSelectorRequirement(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "key": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-patch-merge-key": "key", - "x-kubernetes-patch-strategy": "merge", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "key is the label key that the selector applies to.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "operator": { - SchemaProps: spec.SchemaProps{ - Description: "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "values": { - SchemaProps: spec.SchemaProps{ - Description: "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - }, - Required: []string{"key", "operator"}, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_List(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "List holds a list of objects, which may not be known by the server.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Description: "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), - }, - }, - "items": { - SchemaProps: spec.SchemaProps{ - Description: "List of objects", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/runtime.RawExtension"), - }, - }, - }, - }, - }, - }, - Required: []string{"items"}, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "k8s.io/apimachinery/pkg/runtime.RawExtension"}, - } -} - -func schema_pkg_apis_meta_v1_ListMeta(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ListMeta describes metadata that synthetic resources must have, including lists and various status objects. A resource may have only one of {ObjectMeta, ListMeta}.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "selfLink": { - SchemaProps: spec.SchemaProps{ - Description: "selfLink is a URL representing this object. Populated by the system. Read-only.\n\nDEPRECATED Kubernetes will stop propagating this field in 1.20 release and the field is planned to be removed in 1.21 release.", - Type: []string{"string"}, - Format: "", - }, - }, - "resourceVersion": { - SchemaProps: spec.SchemaProps{ - Description: "String that identifies the server's internal version of this object that can be used by clients to determine when objects have changed. Value must be treated as opaque by clients and passed unmodified back to the server. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency", - Type: []string{"string"}, - Format: "", - }, - }, - "continue": { - SchemaProps: spec.SchemaProps{ - Description: "continue may be set if the user set a limit on the number of items returned, and indicates that the server has more data available. The value is opaque and may be used to issue another request to the endpoint that served this list to retrieve the next set of available objects. Continuing a consistent list may not be possible if the server configuration has changed or more than a few minutes have passed. The resourceVersion field returned when using this continue value will be identical to the value in the first response, unless you have received this token from an error message.", - Type: []string{"string"}, - Format: "", - }, - }, - "remainingItemCount": { - SchemaProps: spec.SchemaProps{ - Description: "remainingItemCount is the number of subsequent items in the list which are not included in this list response. If the list request contained label or field selectors, then the number of remaining items is unknown and the field will be left unset and omitted during serialization. If the list is complete (either because it is not chunking or because this is the last chunk), then there are no more remaining items and this field will be left unset and omitted during serialization. Servers older than v1.15 do not set this field. The intended use of the remainingItemCount is *estimating* the size of a collection. Clients should not rely on the remainingItemCount to be set or to be exact.", - Type: []string{"integer"}, - Format: "int64", - }, - }, - }, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_ListOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ListOptions is the query options to a standard REST list call.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "labelSelector": { - SchemaProps: spec.SchemaProps{ - Description: "A selector to restrict the list of returned objects by their labels. Defaults to everything.", - Type: []string{"string"}, - Format: "", - }, - }, - "fieldSelector": { - SchemaProps: spec.SchemaProps{ - Description: "A selector to restrict the list of returned objects by their fields. Defaults to everything.", - Type: []string{"string"}, - Format: "", - }, - }, - "watch": { - SchemaProps: spec.SchemaProps{ - Description: "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "allowWatchBookmarks": { - SchemaProps: spec.SchemaProps{ - Description: "allowWatchBookmarks requests watch events with type \"BOOKMARK\". Servers that do not implement bookmarks may ignore this flag and bookmarks are sent at the server's discretion. Clients should not assume bookmarks are returned at any specific interval, nor may they assume the server will send any BOOKMARK event during a session. If this is not a watch, this field is ignored.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "resourceVersion": { - SchemaProps: spec.SchemaProps{ - Description: "resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details.\n\nDefaults to unset", - Type: []string{"string"}, - Format: "", - }, - }, - "resourceVersionMatch": { - SchemaProps: spec.SchemaProps{ - Description: "resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details.\n\nDefaults to unset", - Type: []string{"string"}, - Format: "", - }, - }, - "timeoutSeconds": { - SchemaProps: spec.SchemaProps{ - Description: "Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity.", - Type: []string{"integer"}, - Format: "int64", - }, - }, - "limit": { - SchemaProps: spec.SchemaProps{ - Description: "limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true.\n\nThe server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned.", - Type: []string{"integer"}, - Format: "int64", - }, - }, - "continue": { - SchemaProps: spec.SchemaProps{ - Description: "The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the \"next key\".\n\nThis field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_ManagedFieldsEntry(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ManagedFieldsEntry is a workflow-id, a FieldSet and the group version of the resource that the fieldset applies to.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "manager": { - SchemaProps: spec.SchemaProps{ - Description: "Manager is an identifier of the workflow managing these fields.", - Type: []string{"string"}, - Format: "", - }, - }, - "operation": { - SchemaProps: spec.SchemaProps{ - Description: "Operation is the type of operation which lead to this ManagedFieldsEntry being created. The only valid values for this field are 'Apply' and 'Update'.", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the version of this resource that this field set applies to. The format is \"group/version\" just like the top-level APIVersion field. It is necessary to track the version of a field set because it cannot be automatically converted.", - Type: []string{"string"}, - Format: "", - }, - }, - "time": { - SchemaProps: spec.SchemaProps{ - Description: "Time is timestamp of when these fields were set. It should always be empty if Operation is 'Apply'", - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), - }, - }, - "fieldsType": { - SchemaProps: spec.SchemaProps{ - Description: "FieldsType is the discriminator for the different fields format and version. There is currently only one possible value: \"FieldsV1\"", - Type: []string{"string"}, - Format: "", - }, - }, - "fieldsV1": { - SchemaProps: spec.SchemaProps{ - Description: "FieldsV1 holds the first JSON version format as described in the \"FieldsV1\" type.", - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.FieldsV1"), - }, - }, - "subresource": { - SchemaProps: spec.SchemaProps{ - Description: "Subresource is the name of the subresource used to update that object, or empty string if the object was updated through the main resource. The value of this field is used to distinguish between managers, even if they share the same name. For example, a status update will be distinct from a regular update using the same manager name. Note that the APIVersion field is not related to the Subresource field and it always corresponds to the version of the main resource.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.FieldsV1", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, - } -} - -func schema_pkg_apis_meta_v1_MicroTime(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "MicroTime is version of Time with microsecond level precision.", - Type: v1.MicroTime{}.OpenAPISchemaType(), - Format: v1.MicroTime{}.OpenAPISchemaFormat(), - }, - }, - } -} - -func schema_pkg_apis_meta_v1_ObjectMeta(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ObjectMeta is metadata that all persisted resources must have, which includes all objects users must create.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { - SchemaProps: spec.SchemaProps{ - Description: "Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names", - Type: []string{"string"}, - Format: "", - }, - }, - "generateName": { - SchemaProps: spec.SchemaProps{ - Description: "GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server.\n\nIf this field is specified and the generated name exists, the server will NOT return a 409 - instead, it will either return 201 Created or 500 with Reason ServerTimeout indicating a unique name could not be found in the time allotted, and the client should retry (optionally after the time indicated in the Retry-After header).\n\nApplied only if Name is not specified. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency", - Type: []string{"string"}, - Format: "", - }, - }, - "namespace": { - SchemaProps: spec.SchemaProps{ - Description: "Namespace defines the space within which each name must be unique. An empty namespace is equivalent to the \"default\" namespace, but \"default\" is the canonical representation. Not all objects are required to be scoped to a namespace - the value of this field for those objects will be empty.\n\nMust be a DNS_LABEL. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/namespaces", - Type: []string{"string"}, - Format: "", - }, - }, - "selfLink": { - SchemaProps: spec.SchemaProps{ - Description: "SelfLink is a URL representing this object. Populated by the system. Read-only.\n\nDEPRECATED Kubernetes will stop propagating this field in 1.20 release and the field is planned to be removed in 1.21 release.", - Type: []string{"string"}, - Format: "", - }, - }, - "uid": { - SchemaProps: spec.SchemaProps{ - Description: "UID is the unique in time and space value for this object. It is typically generated by the server on successful creation of a resource and is not allowed to change on PUT operations.\n\nPopulated by the system. Read-only. More info: http://kubernetes.io/docs/user-guide/identifiers#uids", - Type: []string{"string"}, - Format: "", - }, - }, - "resourceVersion": { - SchemaProps: spec.SchemaProps{ - Description: "An opaque value that represents the internal version of this object that can be used by clients to determine when objects have changed. May be used for optimistic concurrency, change detection, and the watch operation on a resource or set of resources. Clients must treat these values as opaque and passed unmodified back to the server. They may only be valid for a particular resource or set of resources.\n\nPopulated by the system. Read-only. Value must be treated as opaque by clients and . More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency", - Type: []string{"string"}, - Format: "", - }, - }, - "generation": { - SchemaProps: spec.SchemaProps{ - Description: "A sequence number representing a specific generation of the desired state. Populated by the system. Read-only.", - Type: []string{"integer"}, - Format: "int64", - }, - }, - "creationTimestamp": { - SchemaProps: spec.SchemaProps{ - Description: "CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC.\n\nPopulated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), - }, - }, - "deletionTimestamp": { - SchemaProps: spec.SchemaProps{ - Description: "DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This field is set by the server when a graceful deletion is requested by the user, and is not directly settable by a client. The resource is expected to be deleted (no longer visible from resource lists, and not reachable by name) after the time in this field, once the finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. Once the deletionTimestamp is set, this value may not be unset or be set further into the future, although it may be shortened or the resource may be deleted prior to this time. For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination signal to the containers in the pod. After that 30 seconds, the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, remove the pod from the API. In the presence of network partitions, this object may still exist after this timestamp, until an administrator or automated process can determine the resource is fully terminated. If not set, graceful deletion of the object has not been requested.\n\nPopulated by the system when a graceful deletion is requested. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), - }, - }, - "deletionGracePeriodSeconds": { - SchemaProps: spec.SchemaProps{ - Description: "Number of seconds allowed for this object to gracefully terminate before it will be removed from the system. Only set when deletionTimestamp is also set. May only be shortened. Read-only.", - Type: []string{"integer"}, - Format: "int64", - }, - }, - "labels": { - SchemaProps: spec.SchemaProps{ - Description: "Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: http://kubernetes.io/docs/user-guide/labels", - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "annotations": { - SchemaProps: spec.SchemaProps{ - Description: "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: http://kubernetes.io/docs/user-guide/annotations", - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "ownerReferences": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-patch-merge-key": "uid", - "x-kubernetes-patch-strategy": "merge", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "List of objects depended by this object. If ALL objects in the list have been deleted, this object will be garbage collected. If this object is managed by a controller, then an entry in this list will point to this controller, with the controller field set to true. There cannot be more than one managing controller.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.OwnerReference"), - }, - }, - }, - }, - }, - "finalizers": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-patch-strategy": "merge", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "Must be empty before the object is deleted from the registry. Each entry is an identifier for the responsible component that will remove the entry from the list. If the deletionTimestamp of the object is non-nil, entries in this list can only be removed. Finalizers may be processed and removed in any order. Order is NOT enforced because it introduces significant risk of stuck finalizers. finalizers is a shared field, any actor with permission can reorder it. If the finalizer list is processed in order, then this can lead to a situation in which the component responsible for the first finalizer in the list is waiting for a signal (field value, external system, or other) produced by a component responsible for a finalizer later in the list, resulting in a deadlock. Without enforced ordering finalizers are free to order amongst themselves and are not vulnerable to ordering changes in the list.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "clusterName": { - SchemaProps: spec.SchemaProps{ - Description: "The name of the cluster which the object belongs to. This is used to distinguish resources with same name and namespace in different clusters. This field is not set anywhere right now and apiserver is going to ignore it if set in create or update request.", - Type: []string{"string"}, - Format: "", - }, - }, - "managedFields": { - SchemaProps: spec.SchemaProps{ - Description: "ManagedFields maps workflow-id and version to the set of fields that are managed by that workflow. This is mostly for internal housekeeping, and users typically shouldn't need to set or understand this field. A workflow can be the user's name, a controller's name, or the name of a specific apply path like \"ci-cd\". The set of fields is always in the version that the workflow used when modifying the object.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ManagedFieldsEntry"), - }, - }, - }, - }, - }, - }, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.ManagedFieldsEntry", "k8s.io/apimachinery/pkg/apis/meta/v1.OwnerReference", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, - } -} - -func schema_pkg_apis_meta_v1_OwnerReference(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "OwnerReference contains enough information to let you identify an owning object. An owning object must be in the same namespace as the dependent, or be cluster-scoped, so there is no namespace field.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "API version of the referent.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "name": { - SchemaProps: spec.SchemaProps{ - Description: "Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "uid": { - SchemaProps: spec.SchemaProps{ - Description: "UID of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#uids", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "controller": { - SchemaProps: spec.SchemaProps{ - Description: "If true, this reference points to the managing controller.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "blockOwnerDeletion": { - SchemaProps: spec.SchemaProps{ - Description: "If true, AND if the owner has the \"foregroundDeletion\" finalizer, then the owner cannot be deleted from the key-value store until this reference is removed. Defaults to false. To set this field, a user needs \"delete\" permission of the owner, otherwise 422 (Unprocessable Entity) will be returned.", - Type: []string{"boolean"}, - Format: "", - }, - }, - }, - Required: []string{"apiVersion", "kind", "name", "uid"}, - }, - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-map-type": "atomic", - }, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_PartialObjectMetadata(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PartialObjectMetadata is a generic representation of any object with ObjectMeta. It allows clients to get access to a particular ObjectMeta schema without knowing the details of the version.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Description: "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, - } -} - -func schema_pkg_apis_meta_v1_PartialObjectMetadataList(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PartialObjectMetadataList contains a list of objects containing only their metadata", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Description: "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), - }, - }, - "items": { - SchemaProps: spec.SchemaProps{ - Description: "items contains each of the included items.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.PartialObjectMetadata"), - }, - }, - }, - }, - }, - }, - Required: []string{"items"}, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "k8s.io/apimachinery/pkg/apis/meta/v1.PartialObjectMetadata"}, - } -} - -func schema_pkg_apis_meta_v1_Patch(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Patch is provided to give a concrete name and type to the Kubernetes PATCH request body.", - Type: []string{"object"}, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_PatchOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PatchOptions may be provided when patching an API object. PatchOptions is meant to be a superset of UpdateOptions.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "dryRun": { - SchemaProps: spec.SchemaProps{ - Description: "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "force": { - SchemaProps: spec.SchemaProps{ - Description: "Force is going to \"force\" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "fieldManager": { - SchemaProps: spec.SchemaProps{ - Description: "fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch).", - Type: []string{"string"}, - Format: "", - }, - }, - "fieldValidation": { - SchemaProps: spec.SchemaProps{ - Description: "fieldValidation determines how the server should respond to unknown/duplicate fields in the object in the request. Introduced as alpha in 1.23, older servers or servers with the `ServerSideFieldValidation` feature disabled will discard valid values specified in this param and not perform any server side field validation. Valid values are: - Ignore: ignores unknown/duplicate fields. - Warn: responds with a warning for each unknown/duplicate field, but successfully serves the request. - Strict: fails the request on unknown/duplicate fields.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_Preconditions(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Preconditions must be fulfilled before an operation (update, delete, etc.) is carried out.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "uid": { - SchemaProps: spec.SchemaProps{ - Description: "Specifies the target UID.", - Type: []string{"string"}, - Format: "", - }, - }, - "resourceVersion": { - SchemaProps: spec.SchemaProps{ - Description: "Specifies the target ResourceVersion", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_RootPaths(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "RootPaths lists the paths available at root. For example: \"/healthz\", \"/apis\".", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "paths": { - SchemaProps: spec.SchemaProps{ - Description: "paths are the paths available at root.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - }, - Required: []string{"paths"}, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_ServerAddressByClientCIDR(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ServerAddressByClientCIDR helps the client to determine the server address that they should use, depending on the clientCIDR that they match.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "clientCIDR": { - SchemaProps: spec.SchemaProps{ - Description: "The CIDR with which clients can match their IP to figure out the server address that they should use.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "serverAddress": { - SchemaProps: spec.SchemaProps{ - Description: "Address of this server, suitable for a client that matches the above CIDR. This can be a hostname, hostname:port, IP or IP:port.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"clientCIDR", "serverAddress"}, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_Status(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Status is a return value for calls that don't return other objects.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Description: "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), - }, - }, - "status": { - SchemaProps: spec.SchemaProps{ - Description: "Status of the operation. One of: \"Success\" or \"Failure\". More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status", - Type: []string{"string"}, - Format: "", - }, - }, - "message": { - SchemaProps: spec.SchemaProps{ - Description: "A human-readable description of the status of this operation.", - Type: []string{"string"}, - Format: "", - }, - }, - "reason": { - SchemaProps: spec.SchemaProps{ - Description: "A machine-readable description of why this operation is in the \"Failure\" status. If this value is empty there is no information available. A Reason clarifies an HTTP status code but does not override it.", - Type: []string{"string"}, - Format: "", - }, - }, - "details": { - SchemaProps: spec.SchemaProps{ - Description: "Extended data associated with the reason. Each reason may define its own extended details. This field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type.", - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.StatusDetails"), - }, - }, - "code": { - SchemaProps: spec.SchemaProps{ - Description: "Suggested HTTP return code for this status, 0 if not set.", - Type: []string{"integer"}, - Format: "int32", - }, - }, - }, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "k8s.io/apimachinery/pkg/apis/meta/v1.StatusDetails"}, - } -} - -func schema_pkg_apis_meta_v1_StatusCause(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "StatusCause provides more information about an api.Status failure, including cases when multiple errors are encountered.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "reason": { - SchemaProps: spec.SchemaProps{ - Description: "A machine-readable description of the cause of the error. If this value is empty there is no information available.", - Type: []string{"string"}, - Format: "", - }, - }, - "message": { - SchemaProps: spec.SchemaProps{ - Description: "A human-readable description of the cause of the error. This field may be presented as-is to a reader.", - Type: []string{"string"}, - Format: "", - }, - }, - "field": { - SchemaProps: spec.SchemaProps{ - Description: "The field of the resource that has caused this error, as named by its JSON serialization. May include dot and postfix notation for nested attributes. Arrays are zero-indexed. Fields may appear more than once in an array of causes due to fields having multiple errors. Optional.\n\nExamples:\n \"name\" - the field \"name\" on the current resource\n \"items[0].name\" - the field \"name\" on the first array entry in \"items\"", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_StatusDetails(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "StatusDetails is a set of additional properties that MAY be set by the server to provide additional information about a response. The Reason field of a Status object defines what attributes will be set. Clients must ignore fields that do not match the defined type of each attribute, and should assume that any attribute may be empty, invalid, or under defined.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { - SchemaProps: spec.SchemaProps{ - Description: "The name attribute of the resource associated with the status StatusReason (when there is a single name which can be described).", - Type: []string{"string"}, - Format: "", - }, - }, - "group": { - SchemaProps: spec.SchemaProps{ - Description: "The group attribute of the resource associated with the status StatusReason.", - Type: []string{"string"}, - Format: "", - }, - }, - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "The kind attribute of the resource associated with the status StatusReason. On some operations may differ from the requested resource Kind. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "uid": { - SchemaProps: spec.SchemaProps{ - Description: "UID of the resource. (when there is a single resource which can be described). More info: http://kubernetes.io/docs/user-guide/identifiers#uids", - Type: []string{"string"}, - Format: "", - }, - }, - "causes": { - SchemaProps: spec.SchemaProps{ - Description: "The Causes array includes more details associated with the StatusReason failure. Not all StatusReasons may provide detailed causes.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.StatusCause"), - }, - }, - }, - }, - }, - "retryAfterSeconds": { - SchemaProps: spec.SchemaProps{ - Description: "If specified, the time in seconds before the operation should be retried. Some errors may indicate the client must take an alternate action - for those errors this field may indicate how long to wait before taking the alternate action.", - Type: []string{"integer"}, - Format: "int32", - }, - }, - }, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.StatusCause"}, - } -} - -func schema_pkg_apis_meta_v1_Table(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Table is a tabular representation of a set of API resources. The server transforms the object into a set of preferred columns for quickly reviewing the objects.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Description: "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), - }, - }, - "columnDefinitions": { - SchemaProps: spec.SchemaProps{ - Description: "columnDefinitions describes each column in the returned items array. The number of cells per row will always match the number of column definitions.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.TableColumnDefinition"), - }, - }, - }, - }, - }, - "rows": { - SchemaProps: spec.SchemaProps{ - Description: "rows is the list of items in the table.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.TableRow"), - }, - }, - }, - }, - }, - }, - Required: []string{"columnDefinitions", "rows"}, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "k8s.io/apimachinery/pkg/apis/meta/v1.TableColumnDefinition", "k8s.io/apimachinery/pkg/apis/meta/v1.TableRow"}, - } -} - -func schema_pkg_apis_meta_v1_TableColumnDefinition(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "TableColumnDefinition contains information about a column returned in the Table.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { - SchemaProps: spec.SchemaProps{ - Description: "name is a human readable name for the column.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "type": { - SchemaProps: spec.SchemaProps{ - Description: "type is an OpenAPI type definition for this column, such as number, integer, string, or array. See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for more.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "format": { - SchemaProps: spec.SchemaProps{ - Description: "format is an optional OpenAPI type modifier for this column. A format modifies the type and imposes additional rules, like date or time formatting for a string. The 'name' format is applied to the primary identifier column which has type 'string' to assist in clients identifying column is the resource name. See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for more.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "description": { - SchemaProps: spec.SchemaProps{ - Description: "description is a human readable description of this column.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "priority": { - SchemaProps: spec.SchemaProps{ - Description: "priority is an integer defining the relative importance of this column compared to others. Lower numbers are considered higher priority. Columns that may be omitted in limited space scenarios should be given a higher priority.", - Default: 0, - Type: []string{"integer"}, - Format: "int32", - }, - }, - }, - Required: []string{"name", "type", "format", "description", "priority"}, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_TableOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "TableOptions are used when a Table is requested by the caller.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "includeObject": { - SchemaProps: spec.SchemaProps{ - Description: "includeObject decides whether to include each object along with its columnar information. Specifying \"None\" will return no object, specifying \"Object\" will return the full object contents, and specifying \"Metadata\" (the default) will return the object's metadata in the PartialObjectMetadata kind in version v1beta1 of the meta.k8s.io API group.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_TableRow(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "TableRow is an individual row in a table.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "cells": { - SchemaProps: spec.SchemaProps{ - Description: "cells will be as wide as the column definitions array and may contain strings, numbers (float64 or int64), booleans, simple maps, lists, or null. See the type field of the column definition for a more detailed description.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Format: "", - }, - }, - }, - }, - }, - "conditions": { - SchemaProps: spec.SchemaProps{ - Description: "conditions describe additional status of a row that are relevant for a human user. These conditions apply to the row, not to the object, and will be specific to table output. The only defined condition type is 'Completed', for a row that indicates a resource that has run to completion and can be given less visual priority.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.TableRowCondition"), - }, - }, - }, - }, - }, - "object": { - SchemaProps: spec.SchemaProps{ - Description: "This field contains the requested additional information about each object based on the includeObject policy when requesting the Table. If \"None\", this field is empty, if \"Object\" this will be the default serialization of the object for the current API version, and if \"Metadata\" (the default) will contain the object metadata. Check the returned kind and apiVersion of the object before parsing. The media type of the object will always match the enclosing list - if this as a JSON table, these will be JSON encoded objects.", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/runtime.RawExtension"), - }, - }, - }, - Required: []string{"cells"}, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.TableRowCondition", "k8s.io/apimachinery/pkg/runtime.RawExtension"}, - } -} - -func schema_pkg_apis_meta_v1_TableRowCondition(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "TableRowCondition allows a row to be marked with additional information.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "type": { - SchemaProps: spec.SchemaProps{ - Description: "Type of row condition. The only defined value is 'Completed' indicating that the object this row represents has reached a completed state and may be given less visual priority than other rows. Clients are not required to honor any conditions but should be consistent where possible about handling the conditions.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "status": { - SchemaProps: spec.SchemaProps{ - Description: "Status of the condition, one of True, False, Unknown.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "reason": { - SchemaProps: spec.SchemaProps{ - Description: "(brief) machine readable reason for the condition's last transition.", - Type: []string{"string"}, - Format: "", - }, - }, - "message": { - SchemaProps: spec.SchemaProps{ - Description: "Human readable message indicating details about last transition.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"type", "status"}, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_Time(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Time is a wrapper around time.Time which supports correct marshaling to YAML and JSON. Wrappers are provided for many of the factory methods that the time package offers.", - Type: v1.Time{}.OpenAPISchemaType(), - Format: v1.Time{}.OpenAPISchemaFormat(), - }, - }, - } -} - -func schema_pkg_apis_meta_v1_Timestamp(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Timestamp is a struct that is equivalent to Time, but intended for protobuf marshalling/unmarshalling. It is generated into a serialization that matches Time. Do not use in Go structs.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "seconds": { - SchemaProps: spec.SchemaProps{ - Description: "Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.", - Default: 0, - Type: []string{"integer"}, - Format: "int64", - }, - }, - "nanos": { - SchemaProps: spec.SchemaProps{ - Description: "Non-negative fractions of a second at nanosecond resolution. Negative second values with fractions must still have non-negative nanos values that count forward in time. Must be from 0 to 999,999,999 inclusive. This field may be limited in precision depending on context.", - Default: 0, - Type: []string{"integer"}, - Format: "int32", - }, - }, - }, - Required: []string{"seconds", "nanos"}, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_TypeMeta(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "TypeMeta describes an individual object in an API response or request with strings representing the type of the object and its API schema version. Structures that are versioned or persisted should inline TypeMeta.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_UpdateOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "UpdateOptions may be provided when updating an API object. All fields in UpdateOptions should also be present in PatchOptions.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "dryRun": { - SchemaProps: spec.SchemaProps{ - Description: "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "fieldManager": { - SchemaProps: spec.SchemaProps{ - Description: "fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint.", - Type: []string{"string"}, - Format: "", - }, - }, - "fieldValidation": { - SchemaProps: spec.SchemaProps{ - Description: "fieldValidation determines how the server should respond to unknown/duplicate fields in the object in the request. Introduced as alpha in 1.23, older servers or servers with the `ServerSideFieldValidation` feature disabled will discard valid values specified in this param and not perform any server side field validation. Valid values are: - Ignore: ignores unknown/duplicate fields. - Warn: responds with a warning for each unknown/duplicate field, but successfully serves the request. - Strict: fails the request on unknown/duplicate fields.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_pkg_apis_meta_v1_WatchEvent(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Event represents a single event to a watched resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "type": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "object": { - SchemaProps: spec.SchemaProps{ - Description: "Object is:\n * If Type is Added or Modified: the new state of the object.\n * If Type is Deleted: the state of the object immediately before deletion.\n * If Type is Error: *Status is recommended; other types may make sense\n depending on context.", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/runtime.RawExtension"), - }, - }, - }, - Required: []string{"type", "object"}, - }, - }, - Dependencies: []string{ - "k8s.io/apimachinery/pkg/runtime.RawExtension"}, - } -} - -func schema_k8sio_apimachinery_pkg_runtime_RawExtension(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "RawExtension is used to hold extensions in external versions.\n\nTo use this, make a field which has RawExtension as its type in your external, versioned struct, and Object in your internal struct. You also need to register your various plugin types.\n\n// Internal package: type MyAPIObject struct {\n\truntime.TypeMeta `json:\",inline\"`\n\tMyPlugin runtime.Object `json:\"myPlugin\"`\n} type PluginA struct {\n\tAOption string `json:\"aOption\"`\n}\n\n// External package: type MyAPIObject struct {\n\truntime.TypeMeta `json:\",inline\"`\n\tMyPlugin runtime.RawExtension `json:\"myPlugin\"`\n} type PluginA struct {\n\tAOption string `json:\"aOption\"`\n}\n\n// On the wire, the JSON will look something like this: {\n\t\"kind\":\"MyAPIObject\",\n\t\"apiVersion\":\"v1\",\n\t\"myPlugin\": {\n\t\t\"kind\":\"PluginA\",\n\t\t\"aOption\":\"foo\",\n\t},\n}\n\nSo what happens? Decode first uses json or yaml to unmarshal the serialized data into your external MyAPIObject. That causes the raw JSON to be stored, but not unpacked. The next step is to copy (using pkg/conversion) into the internal struct. The runtime package's DefaultScheme has conversion functions installed which will unpack the JSON stored in RawExtension, turning it into the correct object type, and storing it in the Object. (TODO: In the case where the object is of an unknown type, a runtime.Unknown object will be created and stored.)", - Type: []string{"object"}, - }, - }, - } -} - -func schema_k8sio_apimachinery_pkg_runtime_TypeMeta(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "TypeMeta is shared by all top level objects. The proper way to use it is to inline it in your type, like this: type MyAwesomeAPIObject struct {\n runtime.TypeMeta `json:\",inline\"`\n ... // other fields\n} func (obj *MyAwesomeAPIObject) SetGroupVersionKind(gvk *metav1.GroupVersionKind) { metav1.UpdateTypeMeta(obj,gvk) }; GroupVersionKind() *GroupVersionKind\n\nTypeMeta is provided here for convenience. You may use it directly from this package or define your own with the same fields.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "kind": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_k8sio_apimachinery_pkg_runtime_Unknown(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Unknown allows api objects with unknown types to be passed-through. This can be used to deal with the API objects from a plug-in. Unknown objects still have functioning TypeMeta features-- kind, version, etc. metadata and field mutatation.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "kind": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "Raw": { - SchemaProps: spec.SchemaProps{ - Description: "Raw will hold the complete serialized object which couldn't be matched with a registered type. Most likely, nothing should be done with this except for passing it through the system.", - Type: []string{"string"}, - Format: "byte", - }, - }, - "ContentEncoding": { - SchemaProps: spec.SchemaProps{ - Description: "ContentEncoding is encoding used to encode 'Raw' data. Unspecified means no encoding.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "ContentType": { - SchemaProps: spec.SchemaProps{ - Description: "ContentType is serialization method used to serialize 'Raw'. Unspecified means ContentTypeJSON.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"Raw", "ContentEncoding", "ContentType"}, - }, - }, - } -} - -func schema_k8sio_apimachinery_pkg_version_Info(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Info contains versioning information. how we'll want to distribute that information.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "major": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "minor": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "gitVersion": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "gitCommit": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "gitTreeState": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "buildDate": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "goVersion": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "compiler": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "platform": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"major", "minor", "gitVersion", "gitCommit", "gitTreeState", "buildDate", "goVersion", "compiler", "platform"}, - }, - }, - } -} diff --git a/porch/api/go.mod b/porch/api/go.mod deleted file mode 100644 index 546697b3ca..0000000000 --- a/porch/api/go.mod +++ /dev/null @@ -1,62 +0,0 @@ -module github.com/GoogleContainerTools/kpt/porch/api - -go 1.21 - -require ( - golang.org/x/tools v0.6.0 - k8s.io/apimachinery v0.23.5 - k8s.io/client-go v0.23.5 - k8s.io/code-generator v0.23.5 - k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 -) - -require ( - github.com/PuerkitoBio/purell v1.1.1 // indirect - github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/emicklei/go-restful v2.16.0+incompatible // indirect - github.com/evanphx/json-patch v4.12.0+incompatible // indirect - github.com/fsnotify/fsnotify v1.5.1 // indirect - github.com/go-logr/logr v1.2.0 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.19.6 // indirect - github.com/go-openapi/swag v0.21.1 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/google/go-cmp v0.5.7 // indirect - github.com/google/gofuzz v1.1.0 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/googleapis/gnostic v0.5.5 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/onsi/ginkgo v1.16.5 // indirect - github.com/onsi/gomega v1.17.0 // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/testify v1.7.1 // indirect - golang.org/x/mod v0.8.0 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/term v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.33.0 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0 // indirect - k8s.io/api v0.23.5 // indirect - k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c // indirect - k8s.io/klog/v2 v2.40.1 // indirect - k8s.io/utils v0.0.0-20211208161948-7d6a63dca704 // indirect - sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect -) - -replace k8s.io/code-generator => github.com/platkrm/code-generator v0.23.5-porch.1 diff --git a/porch/api/go.sum b/porch/api/go.sum deleted file mode 100644 index 47164c2788..0000000000 --- a/porch/api/go.sum +++ /dev/null @@ -1,679 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -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= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -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/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= -github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= -github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/logger v0.2.1/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/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -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/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-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -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/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -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 v2.16.0+incompatible h1:rgqiKNjTnFQA6kkhFe16D8epTksy9HQ1MyrbDXSdYhM= -github.com/emicklei/go-restful v2.16.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -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= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= -github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -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.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= -github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= -github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= -github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= -github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU= -github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -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= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -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/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -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= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -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= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -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/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/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2/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= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= -github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= -github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -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/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -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/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -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/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -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/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.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -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= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -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/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -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.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/platkrm/code-generator v0.23.5-porch.1 h1:SMWdEx8urgCWrQzm2SbJyp/64oNw4wHheW3rVH2CbnQ= -github.com/platkrm/code-generator v0.23.5-porch.1/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk= -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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -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= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -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-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-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -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/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-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= -golang.org/x/mod v0.8.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-20190108225652-1e06a53dbb7e/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-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-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -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-20190827160401-ba9fcec4b297/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= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/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-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/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-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= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-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-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= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/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-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-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/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-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= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -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-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/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-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -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.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -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-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/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= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/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= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -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-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-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -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= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -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= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -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-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-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= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -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-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= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/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-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-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/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-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -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.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= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -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.4/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= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -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= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -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.23.5 h1:zno3LUiMubxD/V1Zw3ijyKO3wxrhbUF1Ck+VjBvfaoA= -k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8= -k8s.io/apimachinery v0.23.5 h1:Va7dwhp8wgkUPWsEXk6XglXWU4IKYLKNlv8VkX7SDM0= -k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= -k8s.io/client-go v0.23.5 h1:zUXHmEuqx0RY4+CsnkOn5l0GU+skkRXKGJrhmE2SLd8= -k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4= -k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c h1:GohjlNKauSai7gN4wsJkeZ3WAJx4Sh+oT/b5IYn5suA= -k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/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.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/klog/v2 v2.40.1 h1:P4RRucWk/lFOlDdkAr3mc7iWFkgKrZY9qZMAgek06S4= -k8s.io/klog/v2 v2.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4= -k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= -k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20211208161948-7d6a63dca704 h1:ZKMMxTvduyf5WUtREOqg5LiXaN1KO/+0oOQPRFrClpo= -k8s.io/utils v0.0.0-20211208161948-7d6a63dca704/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -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/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= -sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 h1:kDi4JBNAsJWfz1aEXhO8Jg87JJaPNLh5tIzYHgStQ9Y= -sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= -sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= -sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/porch/api/internal/tools/tools.go b/porch/api/internal/tools/tools.go deleted file mode 100644 index 88371475a9..0000000000 --- a/porch/api/internal/tools/tools.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2022 The kpt 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. - -//go:build tools -// +build tools - -package tools - -import ( - _ "golang.org/x/tools/cmd/stringer" - _ "k8s.io/code-generator" -) diff --git a/porch/api/porch/doc.go b/porch/api/porch/doc.go deleted file mode 100644 index c2c8bbfa12..0000000000 --- a/porch/api/porch/doc.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2022 The kpt 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. - -//go:generate go run k8s.io/code-generator/cmd/deepcopy-gen --input-dirs ./... -O zz_generated.deepcopy --go-header-file ../../scripts/boilerplate.go.txt -//go:generate go run k8s.io/code-generator/cmd/openapi-gen --input-dirs github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1 --input-dirs k8s.io/apimachinery/pkg/apis/meta/v1,k8s.io/apimachinery/pkg/runtime,k8s.io/apimachinery/pkg/version --output-package github.com/GoogleContainerTools/kpt/porch/api/generated/openapi -O zz_generated.openapi --go-header-file ../../scripts/boilerplate.go.txt - -// +k8s:deepcopy-gen=package,register -// +groupName=porch.kpt.dev - -// Package api is the internal version of the API. -package porch diff --git a/porch/api/porch/fuzzer/fuzzer.go b/porch/api/porch/fuzzer/fuzzer.go deleted file mode 100644 index 0e69fdbc92..0000000000 --- a/porch/api/porch/fuzzer/fuzzer.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2022 The kpt 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. - -package fuzzer - -import ( - runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" -) - -var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} { - return []interface{}{} -} diff --git a/porch/api/porch/install/install.go b/porch/api/porch/install/install.go deleted file mode 100644 index 20a928c414..0000000000 --- a/porch/api/porch/install/install.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2022 The kpt 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. - -package install - -import ( - "github.com/GoogleContainerTools/kpt/porch/api/porch" - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "k8s.io/apimachinery/pkg/runtime" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" -) - -// Install registers the API group and adds types to a scheme -func Install(scheme *runtime.Scheme) { - utilruntime.Must(porch.AddToScheme(scheme)) - utilruntime.Must(v1alpha1.AddToScheme(scheme)) -} diff --git a/porch/api/porch/install/roundtrip_test.go b/porch/api/porch/install/roundtrip_test.go deleted file mode 100644 index 2372f9ac4a..0000000000 --- a/porch/api/porch/install/roundtrip_test.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2022 The kpt 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. - -package install - -import ( - "testing" - - "github.com/GoogleContainerTools/kpt/porch/api/porch/fuzzer" - "k8s.io/apimachinery/pkg/api/apitesting/roundtrip" -) - -func TestRoundTripTypes(t *testing.T) { - roundtrip.RoundTripTestForAPIGroup(t, Install, fuzzer.Funcs) -} diff --git a/porch/api/porch/register.go b/porch/api/porch/register.go deleted file mode 100644 index 4b40f3d103..0000000000 --- a/porch/api/porch/register.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -const GroupName = "porch.kpt.dev" - -var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} - -func Kind(kind string) schema.GroupKind { - return SchemeGroupVersion.WithKind(kind).GroupKind() -} - -func Resource(resource string) schema.GroupResource { - return SchemeGroupVersion.WithResource(resource).GroupResource() -} - -var ( - SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) - AddToScheme = SchemeBuilder.AddToScheme -) - -func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(SchemeGroupVersion, - &Package{}, - &PackageList{}, - &PackageRevision{}, - &PackageRevisionList{}, - &PackageRevisionResources{}, - &PackageRevisionResourcesList{}, - &Function{}, - &FunctionList{}, - ) - return nil -} diff --git a/porch/api/porch/types_functions.go b/porch/api/porch/types_functions.go deleted file mode 100644 index 306f7dc40f..0000000000 --- a/porch/api/porch/types_functions.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// Function represents a kpt function discovered in a repository -// Function resources are created automatically by discovery in a registered Repository. -// Function resource names will be computed as : -// to ensure uniqueness of names, and will follow formatting of -// [DNS Subdomain Names](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names). -// +k8s:openapi-gen=true -type Function struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec FunctionSpec `json:"spec,omitempty"` - Status FunctionStatus `json:"status,omitempty"` -} - -// FunctionList -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -type FunctionList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - - Items []Function `json:"items"` -} - -type FunctionType string - -const ( - FunctionTypeValidator FunctionType = "validator" - FunctionTypeMutator FunctionType = "mutator" -) - -// FunctionSpec defines the desired state of a Function -type FunctionSpec struct { - // Image specifies the function image, such as 'gcr.io/kpt-fn/gatekeeper:v0.2'. - Image string `json:"image"` - - // RepositoryRef references the repository in which the function is located. - RepositoryRef RepositoryRef `json:"repositoryRef"` - - // FunctionType specifies the function types (mutator, validator or/and others). - FunctionTypes []FunctionType `json:"functionTypes,omitempty"` - - FunctionConfigs []FunctionConfig `json:"functionConfigs,omitempty"` - - // Keywords are used as filters to provide correlation in function discovery. - Keywords []string `json:"keywords,omitempty"` - - // Description is a short description of the function. - Description string `json:"description"` - - // `DocumentationUrl specifies the URL of comprehensive function documentation` - DocumentationUrl string `json:"documentationUrl,omitempty"` - - // InputTypes specifies to which input KRM types the function applies. Specified as Group Version Kind. - // For example: - // - // inputTypes: - // - kind: RoleBinding - // # If version is unspecified, applies to all versions - // apiVersion: rbac.authorization.k8s.io - // - kind: ClusterRoleBinding - // apiVersion: rbac.authorization.k8s.io/v1 - // InputTypes []metav1.TypeMeta - - // OutputTypes specifies types of any KRM resources the function creates - // For example: - // - // outputTypes: - // - kind: ConfigMap - // apiVersion: v1 - // OutputTypes []metav1.TypeMeta - -} - -// FunctionConfig specifies all the valid types of the function config for this function. -// If unspecified, defaults to v1/ConfigMap. For example, function `set-namespace` accepts both `ConfigMap` and `SetNamespace` -type FunctionConfig struct { - metav1.TypeMeta `json:",inline"` - // Experimental: requiredFields tells necessary fields and is aimed to help users write the FunctionConfig. - // Otherwise, users can get the required fields info from the function evaluation error message. - RequiredFields []string `json:"requiredFields,omitempty"` -} - -// FunctionRef is a reference to a Function resource. -type FunctionRef struct { - // Name is the name of the Function resource referenced. The resource is expected to be within the same namespace. - Name string `json:"name"` -} - -// FunctionStatus defines the observed state of Function -type FunctionStatus struct { -} diff --git a/porch/api/porch/types_package.go b/porch/api/porch/types_package.go deleted file mode 100644 index db3a559442..0000000000 --- a/porch/api/porch/types_package.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// Package -// +k8s:openapi-gen=true -type Package struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec PackageSpec `json:"spec,omitempty"` - Status PackageStatus `json:"status,omitempty"` -} - -// PackageList -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -type PackageList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - - Items []Package `json:"items"` -} - -// PackageSpec defines the desired state of Package -type PackageSpec struct { - // PackageName identifies the package in the repository. - PackageName string `json:"packageName,omitempty"` - - // RepositoryName is the name of the Repository object containing this package. - RepositoryName string `json:"repository,omitempty"` -} - -// PackageStatus defines the observed state of Package -type PackageStatus struct { - // LatestRevision identifies the package revision that is the latest - // published package revision belonging to this package - LatestRevision string `json:"latestRevision,omitempty"` -} diff --git a/porch/api/porch/types_packagerevisionresources.go b/porch/api/porch/types_packagerevisionresources.go deleted file mode 100644 index e8de507576..0000000000 --- a/porch/api/porch/types_packagerevisionresources.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// PackageRevisionResources -// +k8s:openapi-gen=true -type PackageRevisionResources struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec PackageRevisionResourcesSpec `json:"spec,omitempty"` - Status PackageRevisionResourcesStatus `json:"status,omitempty"` -} - -// PackageRevisionResourcesList -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -type PackageRevisionResourcesList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - - Items []PackageRevisionResources `json:"items"` -} - -// PackageRevisionResourcesSpec represents resources (as ResourceList serialized as yaml string) of the PackageRevision. -type PackageRevisionResourcesSpec struct { - // PackageName identifies the package in the repository. - PackageName string `json:"packageName,omitempty"` - - // WorkspaceName identifies the workspace of the package. - WorkspaceName WorkspaceName `json:"workspaceName,omitempty"` - - // Revision identifies the version of the package. - Revision string `json:"revision,omitempty"` - - // RepositoryName is the name of the Repository object containing this package. - RepositoryName string `json:"repository,omitempty"` - - // Resources are the content of the package. - Resources map[string]string `json:"resources,omitempty"` -} - -// PackageRevisionResourcesStatus represents state of the rendered package resources. -type PackageRevisionResourcesStatus struct { - // RenderStatus contains the result of rendering the package resources. - RenderStatus RenderStatus `json:"renderStatus,omitempty"` -} diff --git a/porch/api/porch/types_packagerevisions.go b/porch/api/porch/types_packagerevisions.go deleted file mode 100644 index 848c7a2578..0000000000 --- a/porch/api/porch/types_packagerevisions.go +++ /dev/null @@ -1,452 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" -) - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// PackageRevision -// +k8s:openapi-gen=true -type PackageRevision struct { - metav1.TypeMeta - metav1.ObjectMeta - - Spec PackageRevisionSpec - Status PackageRevisionStatus -} - -// PackageRevisionList -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -type PackageRevisionList struct { - metav1.TypeMeta - metav1.ListMeta - - Items []PackageRevision -} - -type PackageRevisionLifecycle string - -const ( - PackageRevisionLifecycleDraft PackageRevisionLifecycle = "Draft" - PackageRevisionLifecycleProposed PackageRevisionLifecycle = "Proposed" - PackageRevisionLifecyclePublished PackageRevisionLifecycle = "Published" - PackageRevisionLifecycleDeletionProposed PackageRevisionLifecycle = "DeletionProposed" -) - -type WorkspaceName string - -// PackageRevisionSpec defines the desired state of PackageRevision -type PackageRevisionSpec struct { - // PackageName identifies the package in the repository. - PackageName string `json:"packageName,omitempty"` - - // RepositoryName is the name of the Repository object containing this package. - RepositoryName string `json:"repository,omitempty"` - - // WorkspaceName is a short, unique description of the changes contained in this package revision. - WorkspaceName WorkspaceName `json:"workspaceName,omitempty"` - - // Revision identifies the version of the package. - Revision string `json:"revision,omitempty"` - - // Parent references a package that provides resources to us - Parent *ParentReference `json:"parent,omitempty"` - - Lifecycle PackageRevisionLifecycle `json:"lifecycle,omitempty"` - - Tasks []Task `json:"tasks,omitempty"` - - ReadinessGates []ReadinessGate `json:"readinessGates,omitempty"` -} - -type ReadinessGate struct { - ConditionType string `json:"conditionType,omitempty"` -} - -// ParentReference is a reference to a parent package -type ParentReference struct { - // TODO: Should this be a revision or a package? - - // Name is the name of the parent PackageRevision - Name string `json:"name"` -} - -// PackageRevisionStatus defines the observed state of PackageRevision -type PackageRevisionStatus struct { - // UpstreamLock identifies the upstream data for this package. - UpstreamLock *UpstreamLock `json:"upstreamLock,omitempty"` - - // PublishedBy is the identity of the user who approved the packagerevision. - PublishedBy string `json:"publishedBy,omitempty"` - - // PublishedAt is the time when the packagerevision were approved. - PublishedAt metav1.Time `json:"publishTimestamp,omitempty"` - - // Deployment is true if this is a deployment package (in a deployment repository). - Deployment bool `json:"deployment,omitempty"` - - Conditions []Condition `json:"conditions,omitempty"` -} - -type TaskType string - -const ( - TaskTypeInit TaskType = "init" - TaskTypeClone TaskType = "clone" - TaskTypePatch TaskType = "patch" - TaskTypeEdit TaskType = "edit" - TaskTypeEval TaskType = "eval" - TaskTypeUpdate TaskType = "update" -) - -type Task struct { - Type TaskType `json:"type"` - Init *PackageInitTaskSpec `json:"init,omitempty"` - Clone *PackageCloneTaskSpec `json:"clone,omitempty"` - Patch *PackagePatchTaskSpec `json:"patch,omitempty"` - Edit *PackageEditTaskSpec `json:"edit,omitempty"` - Eval *FunctionEvalTaskSpec `json:"eval,omitempty"` - Update *PackageUpdateTaskSpec `json:"update,omitempty"` -} - -type TaskResult struct { - Task *Task `json:"task"` - RenderStatus *RenderStatus `json:"renderStatus,omitempty"` -} - -// RenderStatus represents the result of performing render operation -// on a package resources. -type RenderStatus struct { - Result ResultList `json:"result,omitempty"` - Err string `json:"error"` -} - -// PackageInitTaskSpec defines the package initialization task. -type PackageInitTaskSpec struct { - // `Subpackage` is a directory path to a subpackage to initialize. If unspecified, the main package will be initialized. - Subpackage string `json:"subpackage,omitempty"` - // `Description` is a short description of the package. - Description string `json:"description,omitempty"` - // `Keywords` is a list of keywords describing the package. - Keywords []string `json:"keywords,omitempty"` - // `Site is a link to page with information about the package. - Site string `json:"site,omitempty"` -} - -type PackageCloneTaskSpec struct { - // // `Subpackage` is a path to a directory where to clone the upstream package. - // Subpackage string `json:"subpackage,omitempty"` - - // `Upstream` is the reference to the upstream package to clone. - Upstream UpstreamPackage `json:"upstreamRef,omitempty"` - - // Defines which strategy should be used to update the package. It defaults to 'resource-merge'. - // * resource-merge: Perform a structural comparison of the original / - // updated resources, and merge the changes into the local package. - // * fast-forward: Fail without updating if the local package was modified - // since it was fetched. - // * force-delete-replace: Wipe all the local changes to the package and replace - // it with the remote version. - Strategy PackageMergeStrategy `json:"strategy,omitempty"` -} - -type PackageMergeStrategy string - -type PackageUpdateTaskSpec struct { - // `Upstream` is the reference to the upstream package. - Upstream UpstreamPackage `json:"upstreamRef,omitempty"` -} - -const ( - ResourceMerge PackageMergeStrategy = "resource-merge" - FastForward PackageMergeStrategy = "fast-forward" - ForceDeleteReplace PackageMergeStrategy = "force-delete-replace" -) - -type PackagePatchTaskSpec struct { - // Patches is a list of individual patch operations. - Patches []PatchSpec `json:"patches,omitempty"` -} - -type PatchType string - -const ( - PatchTypeCreateFile PatchType = "CreateFile" - PatchTypeDeleteFile PatchType = "DeleteFile" - PatchTypePatchFile PatchType = "PatchFile" -) - -type PatchSpec struct { - File string `json:"file,omitempty"` - Contents string `json:"contents,omitempty"` - PatchType PatchType `json:"patchType,omitempty"` -} - -type PackageEditTaskSpec struct { - Source *PackageRevisionRef `json:"sourceRef,omitempty"` -} - -type RepositoryType string - -const ( - RepositoryTypeGit RepositoryType = "git" - RepositoryTypeOCI RepositoryType = "oci" -) - -// UpstreamRepository repository may be specified directly or by referencing another Repository resource. -type UpstreamPackage struct { - // Type of the repository (i.e. git, OCI). If empty, `upstreamRef` will be used. - Type RepositoryType `json:"type,omitempty"` - - // Git upstream package specification. Required if `type` is `git`. Must be unspecified if `type` is not `git`. - Git *GitPackage `json:"git,omitempty"` - - // OCI upstream package specification. Required if `type` is `oci`. Must be unspecified if `type` is not `oci`. - Oci *OciPackage `json:"oci,omitempty"` - - // UpstreamRef is the reference to the package from a registered repository rather than external package. - UpstreamRef *PackageRevisionRef `json:"upstreamRef,omitempty"` -} - -type GitPackage struct { - // Address of the Git repository, for example: - // `https://github.com/GoogleCloudPlatform/blueprints.git` - Repo string `json:"repo"` - - // `Ref` is the git ref containing the package. Ref can be a branch, tag, or commit SHA. - Ref string `json:"ref"` - - // Directory within the Git repository where the packages are stored. A subdirectory of this directory containing a Kptfile is considered a package. - Directory string `json:"directory"` - - // Reference to secret containing authentication credentials. Optional. - SecretRef SecretRef `json:"secretRef,omitempty"` -} - -type SecretRef struct { - // Name of the secret. The secret is expected to be located in the same namespace as the resource containing the reference. - Name string `json:"name"` -} - -// OciPackage describes a repository compatible with the Open Container Registry standard. -type OciPackage struct { - // Image is the address of an OCI image. - Image string `json:"image"` -} - -// PackageRevisionRef is a reference to a package revision. -type PackageRevisionRef struct { - // `Name` is the name of the referenced PackageRevision resource. - Name string `json:"name"` -} - -// RepositoryRef identifies a reference to a Repository resource. -type RepositoryRef struct { - // Name of the Repository resource referenced. - Name string `json:"name"` -} - -type FunctionEvalTaskSpec struct { - // `Subpackage` is a directory path to a subpackage in which to evaluate the function. - Subpackage string `json:"subpackage,omitempty"` - // `Image` specifies the function image, such as `gcr.io/kpt-fn/gatekeeper:v0.2`. Use of `Image` is mutually exclusive with `FunctionRef`. - Image string `json:"image,omitempty"` - // `FunctionRef` specifies the function by reference to a Function resource. Mutually exclusive with `Image`. - FunctionRef *FunctionRef `json:"functionRef,omitempty"` - // `ConfigMap` specifies the function config (https://kpt.dev/reference/cli/fn/eval/). Mutually exclusive with Config. - ConfigMap map[string]string `json:"configMap,omitempty"` - - // `Config` specifies the function config, arbitrary KRM resource. Mutually exclusive with ConfigMap. - Config runtime.RawExtension `json:"config,omitempty"` - - // If enabled, meta resources (i.e. `Kptfile` and `functionConfig`) are included - // in the input to the function. By default it is disabled. - IncludeMetaResources bool `json:"includeMetaResources,omitempty"` - // `EnableNetwork` controls whether the function has access to network. Defaults to `false`. - EnableNetwork bool `json:"enableNetwork,omitempty"` - // Match specifies the selection criteria for the function evaluation. - Match Selector `json:"match,omitempty"` -} - -type Selector struct { - // APIVersion of the target resources - APIVersion string `json:"apiVersion,omitempty"` - // Kind of the target resources - Kind string `json:"kind,omitempty"` - // Name of the target resources - Name string `json:"name,omitempty"` - // Namespace of the target resources - Namespace string `json:"namespace,omitempty"` -} - -// The following types (UpstreamLock, OriginType, and GitLock) are duplicates from the kpt library. -// We are repeating them here to avoid cyclic dependencies, but these duplicate type should be removed when -// https://github.com/GoogleContainerTools/kpt/issues/3297 is resolved. - -type OriginType string - -// UpstreamLock is a resolved locator for the last fetch of the package. -type UpstreamLock struct { - // Type is the type of origin. - Type OriginType `json:"type,omitempty"` - - // Git is the resolved locator for a package on Git. - Git *GitLock `json:"git,omitempty"` -} - -// GitLock is the resolved locator for a package on Git. -type GitLock struct { - // Repo is the git repository that was fetched. - // e.g. 'https://github.com/kubernetes/examples.git' - Repo string `json:"repo,omitempty"` - - // Directory is the sub directory of the git repository that was fetched. - // e.g. 'staging/cockroachdb' - Directory string `json:"directory,omitempty"` - - // Ref can be a Git branch, tag, or a commit SHA-1 that was fetched. - // e.g. 'master' - Ref string `json:"ref,omitempty"` - - // Commit is the SHA-1 for the last fetch of the package. - // This is set by kpt for bookkeeping purposes. - Commit string `json:"commit,omitempty"` -} - -type Condition struct { - Type string `json:"type"` - - Status ConditionStatus `json:"status"` - - Reason string `json:"reason,omitempty"` - - Message string `json:"message,omitempty"` -} - -type ConditionStatus string - -const ( - ConditionTrue ConditionStatus = "True" - ConditionFalse ConditionStatus = "False" - ConditionUnknown ConditionStatus = "Unknown" -) - -const ( - // Deprecated: prefer ResultListGVK - ResultListKind = "FunctionResultList" - // Deprecated: prefer ResultListGVK - ResultListGroup = "kpt.dev" - // Deprecated: prefer ResultListGVK - ResultListVersion = "v1" - // Deprecated: prefer ResultListGVK - ResultListAPIVersion = ResultListGroup + "/" + ResultListVersion -) - -// ResultList contains aggregated results from multiple functions -type ResultList struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - // ExitCode is the exit code of kpt command - ExitCode int `json:"exitCode"` - // Items contain a list of function result - Items []*Result `json:"items,omitempty"` -} - -// Result contains the structured result from an individual function -type Result struct { - // Image is the full name of the image that generates this result - // Image and Exec are mutually exclusive - Image string `json:"image,omitempty"` - // ExecPath is the the absolute os-specific path to the executable file - // If user provides an executable file with commands, ExecPath should - // contain the entire input string. - ExecPath string `json:"exec,omitempty"` - // TODO(droot): This is required for making structured results subpackage aware. - // Enable this once test harness supports filepath based assertions. - // Pkg is OS specific Absolute path to the package. - // Pkg string `yaml:"pkg,omitempty"` - // Stderr is the content in function stderr - Stderr string `json:"stderr,omitempty"` - // ExitCode is the exit code from running the function - ExitCode int `json:"exitCode"` - // Results is the list of results for the function - Results []ResultItem `json:"results,omitempty"` -} - -// ResultItem defines a validation result -type ResultItem struct { - // Message is a human readable message. This field is required. - Message string `json:"message,omitempty"` - - // Severity is the severity of this result - Severity string `json:"severity,omitempty"` - - // ResourceRef is a reference to a resource. - // Required fields: apiVersion, kind, name. - ResourceRef *ResourceIdentifier `json:"resourceRef,omitempty"` - - // Field is a reference to the field in a resource this result refers to - Field *Field `json:"field,omitempty"` - - // File references a file containing the resource this result refers to - File *File `json:"file,omitempty"` - - // Tags is an unstructured key value map stored with a result that may be set - // by external tools to store and retrieve arbitrary metadata - Tags map[string]string `json:"tags,omitempty"` -} - -// File references a file containing a resource -type File struct { - // Path is relative path to the file containing the resource. - // This field is required. - Path string `json:"path,omitempty"` - - // Index is the index into the file containing the resource - // (i.e. if there are multiple resources in a single file) - Index int `json:"index,omitempty"` -} - -// Field references a field in a resource -type Field struct { - // Path is the field path. This field is required. - Path string `json:"path,omitempty"` - - // CurrentValue is the current field value - CurrentValue string `json:"currentValue,omitempty"` - - // ProposedValue is the proposed value of the field to fix an issue. - ProposedValue string `json:"proposedValue,omitempty"` -} - -// ResourceIdentifier contains the information needed to uniquely -// identify a resource in a cluster. -type ResourceIdentifier struct { - metav1.TypeMeta `json:",inline"` - NameMeta `json:",inline"` -} - -// NameMeta contains name information. -type NameMeta struct { - // Name is the metadata.name field of a Resource - Name string `json:"name,omitempty"` - // Namespace is the metadata.namespace field of a Resource - Namespace string `json:"namespace,omitempty"` -} diff --git a/porch/api/porch/v1alpha1/doc.go b/porch/api/porch/v1alpha1/doc.go deleted file mode 100644 index 48a7be01e6..0000000000 --- a/porch/api/porch/v1alpha1/doc.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2022 The kpt 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. - -//go:generate go run k8s.io/code-generator/cmd/deepcopy-gen@v0.25.3 --input-dirs ../v1alpha1 -O zz_generated.deepcopy --go-header-file ../../../scripts/boilerplate.go.txt -//go:generate go run k8s.io/code-generator/cmd/defaulter-gen --input-dirs ./ -O zz_generated.defaults --go-header-file ../../../scripts/boilerplate.go.txt -//go:generate go run k8s.io/code-generator/cmd/client-gen --clientset-name versioned --input-base "" --input github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1 --output-package github.com/GoogleContainerTools/kpt/porch/api/generated/clientset --plural-exceptions PackageRevisionResources:PackageRevisionResources --go-header-file ../../../scripts/boilerplate.go.txt -//go:generate go run k8s.io/code-generator/cmd/lister-gen --input-dirs github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1 --output-package github.com/GoogleContainerTools/kpt/porch/api/generated/listers --go-header-file ../../../scripts/boilerplate.go.txt -//go:generate go run k8s.io/code-generator/cmd/informer-gen --input-dirs github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1 --versioned-clientset-package github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned --listers-package github.com/GoogleContainerTools/kpt/porch/api/generated/listers --output-package github.com/GoogleContainerTools/kpt/porch/api/generated/informers --plural-exceptions PackageRevisionResources:PackageRevisionResources --go-header-file ../../../scripts/boilerplate.go.txt -//go:generate go run k8s.io/code-generator/cmd/conversion-gen --input-dirs github.com/GoogleContainerTools/kpt/porch/api/porch,github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1 -O zz_generated.conversion --go-header-file ../../../scripts/boilerplate.go.txt - -// Api versions allow the api contract for a resource to be changed while keeping -// backward compatibility by support multiple concurrent versions -// of the same resource - -// +k8s:openapi-gen=true -// +k8s:deepcopy-gen=package,register -// +k8s:conversion-gen=github.com/GoogleContainerTools/kpt/porch/api/porch -// +k8s:defaulter-gen=TypeMeta -// +groupName=porch.kpt.dev -package v1alpha1 // import "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" diff --git a/porch/api/porch/v1alpha1/register.go b/porch/api/porch/v1alpha1/register.go deleted file mode 100644 index 1cba07fe9c..0000000000 --- a/porch/api/porch/v1alpha1/register.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2022 The kpt 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. - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -const GroupName = "porch.kpt.dev" - -var ( - SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"} - SchemeBuilder runtime.SchemeBuilder - localSchemeBuilder = &SchemeBuilder - AddToScheme = localSchemeBuilder.AddToScheme - - PackageGVR = SchemeGroupVersion.WithResource("packages") - PackageRevisionGVR = SchemeGroupVersion.WithResource("packagerevisions") - PackageRevisionResourcesGVR = SchemeGroupVersion.WithResource("packagerevisionresources") - FunctionGVR = SchemeGroupVersion.WithResource("functions") -) - -func init() { - localSchemeBuilder.Register(addKnownTypes) -} - -// Adds the list of known types to the given scheme. -func addKnownTypes(scheme *runtime.Scheme) error { - // +kubebuilder:scaffold:install - - scheme.AddKnownTypes(SchemeGroupVersion, - &Package{}, - &PackageList{}, - &PackageRevision{}, - &PackageRevisionList{}, - &PackageRevisionResources{}, - &PackageRevisionResourcesList{}, - &Function{}, - &FunctionList{}, - ) - - metav1.AddToGroupVersion(scheme, SchemeGroupVersion) - return nil -} - -// Resource takes an unqualified resource and returns a Group qualified GroupResource -func Resource(resource string) schema.GroupResource { - return SchemeGroupVersion.WithResource(resource).GroupResource() -} diff --git a/porch/api/porch/v1alpha1/types_functions.go b/porch/api/porch/v1alpha1/types_functions.go deleted file mode 100644 index c1e4356ad2..0000000000 --- a/porch/api/porch/v1alpha1/types_functions.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2022 The kpt 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. - -package v1alpha1 - -import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// Function represents a kpt function discovered in a repository -// Function resources are created automatically by discovery in a registered Repository. -// Function resource names will be computed as : -// to ensure uniqueness of names, and will follow formatting of -// [DNS Subdomain Names](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names). -// +k8s:openapi-gen=true -type Function struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec FunctionSpec `json:"spec,omitempty"` - Status FunctionStatus `json:"status,omitempty"` -} - -// FunctionList -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -type FunctionList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - - Items []Function `json:"items"` -} - -type FunctionType string - -const ( - FunctionTypeValidator FunctionType = "validator" - FunctionTypeMutator FunctionType = "mutator" -) - -// FunctionSpec defines the desired state of a Function -type FunctionSpec struct { - // Image specifies the function image, such as 'gcr.io/kpt-fn/gatekeeper:v0.2'. - Image string `json:"image"` - - // RepositoryRef references the repository in which the function is located. - RepositoryRef RepositoryRef `json:"repositoryRef"` - - // FunctionType specifies the function types (mutator, validator or/and others). - FunctionTypes []FunctionType `json:"functionTypes,omitempty"` - - FunctionConfigs []FunctionConfig `json:"functionConfigs,omitempty"` - - // Keywords are used as filters to provide correlation in function discovery. - Keywords []string `json:"keywords,omitempty"` - - // Description is a short description of the function. - Description string `json:"description"` - - // `DocumentationUrl specifies the URL of comprehensive function documentation` - DocumentationUrl string `json:"documentationUrl,omitempty"` - - // InputTypes specifies to which input KRM types the function applies. Specified as Group Version Kind. - // For example: - // - // inputTypes: - // - kind: RoleBinding - // # If version is unspecified, applies to all versions - // apiVersion: rbac.authorization.k8s.io - // - kind: ClusterRoleBinding - // apiVersion: rbac.authorization.k8s.io/v1 - // InputTypes []metav1.TypeMeta - - // OutputTypes specifies types of any KRM resources the function creates - // For example: - // - // outputTypes: - // - kind: ConfigMap - // apiVersion: v1 - // OutputTypes []metav1.TypeMeta - -} - -// FunctionConfig specifies all the valid types of the function config for this function. -// If unspecified, defaults to v1/ConfigMap. For example, function `set-namespace` accepts both `ConfigMap` and `SetNamespace` -type FunctionConfig struct { - metav1.TypeMeta `json:",inline"` - // Experimental: requiredFields tells necessary fields and is aimed to help users write the FunctionConfig. - // Otherwise, users can get the required fields info from the function evaluation error message. - RequiredFields []string `json:"requiredFields,omitempty"` -} - -// FunctionRef is a reference to a Function resource. -type FunctionRef struct { - // Name is the name of the Function resource referenced. The resource is expected to be within the same namespace. - Name string `json:"name"` -} - -// FunctionStatus defines the observed state of Function -type FunctionStatus struct { -} diff --git a/porch/api/porch/v1alpha1/types_package.go b/porch/api/porch/v1alpha1/types_package.go deleted file mode 100644 index 54006ac9b8..0000000000 --- a/porch/api/porch/v1alpha1/types_package.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2022 The kpt 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. - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// Package -// +k8s:openapi-gen=true -type Package struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec PackageSpec `json:"spec,omitempty"` - Status PackageStatus `json:"status,omitempty"` -} - -// PackageList -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -type PackageList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - - Items []Package `json:"items"` -} - -// PackageSpec defines the desired state of Package -type PackageSpec struct { - // PackageName identifies the package in the repository. - PackageName string `json:"packageName,omitempty"` - - // RepositoryName is the name of the Repository object containing this package. - RepositoryName string `json:"repository,omitempty"` -} - -// PackageStatus defines the observed state of Package -type PackageStatus struct { - // LatestRevision identifies the package revision that is the latest - // published package revision belonging to this package - LatestRevision string `json:"latestRevision,omitempty"` -} diff --git a/porch/api/porch/v1alpha1/types_packagerevisionresources.go b/porch/api/porch/v1alpha1/types_packagerevisionresources.go deleted file mode 100644 index c7b3fb3d11..0000000000 --- a/porch/api/porch/v1alpha1/types_packagerevisionresources.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2022 The kpt 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. - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// PackageRevisionResources -// +k8s:openapi-gen=true -type PackageRevisionResources struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec PackageRevisionResourcesSpec `json:"spec,omitempty"` - Status PackageRevisionResourcesStatus `json:"status,omitempty"` -} - -// PackageRevisionResourcesList -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -type PackageRevisionResourcesList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - - Items []PackageRevisionResources `json:"items"` -} - -// PackageRevisionResourcesSpec represents resources (as ResourceList serialized as yaml string) of the PackageRevision. -type PackageRevisionResourcesSpec struct { - // PackageName identifies the package in the repository. - PackageName string `json:"packageName,omitempty"` - - // WorkspaceName identifies the workspace of the package. - WorkspaceName WorkspaceName `json:"workspaceName,omitempty"` - - // Revision identifies the version of the package. - Revision string `json:"revision,omitempty"` - - // RepositoryName is the name of the Repository object containing this package. - RepositoryName string `json:"repository,omitempty"` - - // Resources are the content of the package. - Resources map[string]string `json:"resources,omitempty"` -} - -// PackageRevisionResourcesStatus represents state of the rendered package resources. -type PackageRevisionResourcesStatus struct { - // RenderStatus contains the result of rendering the package resources. - RenderStatus RenderStatus `json:"renderStatus,omitempty"` -} diff --git a/porch/api/porch/v1alpha1/types_packagerevisions.go b/porch/api/porch/v1alpha1/types_packagerevisions.go deleted file mode 100644 index 1c70cfd10d..0000000000 --- a/porch/api/porch/v1alpha1/types_packagerevisions.go +++ /dev/null @@ -1,482 +0,0 @@ -// Copyright 2022 The kpt 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. - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" -) - -// +genclient -// +genclient:method=UpdateApproval,verb=update,subresource=approval,input=github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevision,result=github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1.PackageRevision -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// PackageRevision -// +k8s:openapi-gen=true -type PackageRevision struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec PackageRevisionSpec `json:"spec,omitempty"` - Status PackageRevisionStatus `json:"status,omitempty"` -} - -// Key and value of the latest package revision label: - -const ( - LatestPackageRevisionKey = "kpt.dev/latest-revision" - LatestPackageRevisionValue = "true" -) - -// PackageRevisionList -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -type PackageRevisionList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - - Items []PackageRevision `json:"items"` -} - -type PackageRevisionLifecycle string - -const ( - PackageRevisionLifecycleDraft PackageRevisionLifecycle = "Draft" - PackageRevisionLifecycleProposed PackageRevisionLifecycle = "Proposed" - PackageRevisionLifecyclePublished PackageRevisionLifecycle = "Published" - PackageRevisionLifecycleDeletionProposed PackageRevisionLifecycle = "DeletionProposed" -) - -type WorkspaceName string - -// PackageRevisionSpec defines the desired state of PackageRevision -type PackageRevisionSpec struct { - // PackageName identifies the package in the repository. - PackageName string `json:"packageName,omitempty"` - - // RepositoryName is the name of the Repository object containing this package. - RepositoryName string `json:"repository,omitempty"` - - // WorkspaceName is a short, unique description of the changes contained in this package revision. - WorkspaceName WorkspaceName `json:"workspaceName,omitempty"` - - // Revision identifies the version of the package. - Revision string `json:"revision,omitempty"` - - // Parent references a package that provides resources to us - Parent *ParentReference `json:"parent,omitempty"` - - Lifecycle PackageRevisionLifecycle `json:"lifecycle,omitempty"` - - // The task slice holds zero or more tasks that describe the operations - // performed on the packagerevision. The are essentially a replayable history - // of the packagerevision, - // - // Packagerevisions that were not created in Porch may have an - // empty task list. - // - // Packagerevisions created and managed through Porch will always - // have either an Init, Edit, or a Clone task as the first entry in their - // task list. This represent packagerevisions created from scratch, based - // a copy of a different revision in the same package, or a packagerevision - // cloned from another package. - // Each change to the packagerevision will result in a correspondig - // task being added to the list of tasks. It will describe the operation - // performed and will have a corresponding entry (commit or layer) in git - // or oci. - // The task slice describes the history of the packagerevision, so it - // is an append only list (We might introduce some kind of compaction in the - // future to keep the number of tasks at a reasonable number). - Tasks []Task `json:"tasks,omitempty"` - - ReadinessGates []ReadinessGate `json:"readinessGates,omitempty"` -} - -type ReadinessGate struct { - ConditionType string `json:"conditionType,omitempty"` -} - -// ParentReference is a reference to a parent package -type ParentReference struct { - // TODO: Should this be a revision or a package? - - // Name is the name of the parent PackageRevision - Name string `json:"name"` -} - -// PackageRevisionStatus defines the observed state of PackageRevision -type PackageRevisionStatus struct { - // UpstreamLock identifies the upstream data for this package. - UpstreamLock *UpstreamLock `json:"upstreamLock,omitempty"` - - // PublishedBy is the identity of the user who approved the packagerevision. - PublishedBy string `json:"publishedBy,omitempty"` - - // PublishedAt is the time when the packagerevision were approved. - PublishedAt metav1.Time `json:"publishTimestamp,omitempty"` - - // Deployment is true if this is a deployment package (in a deployment repository). - Deployment bool `json:"deployment,omitempty"` - - Conditions []Condition `json:"conditions,omitempty"` -} - -type TaskType string - -const ( - TaskTypeInit TaskType = "init" - TaskTypeClone TaskType = "clone" - TaskTypePatch TaskType = "patch" - TaskTypeEdit TaskType = "edit" - TaskTypeEval TaskType = "eval" - TaskTypeUpdate TaskType = "update" -) - -type Task struct { - Type TaskType `json:"type"` - Init *PackageInitTaskSpec `json:"init,omitempty"` - Clone *PackageCloneTaskSpec `json:"clone,omitempty"` - Patch *PackagePatchTaskSpec `json:"patch,omitempty"` - Edit *PackageEditTaskSpec `json:"edit,omitempty"` - Eval *FunctionEvalTaskSpec `json:"eval,omitempty"` - Update *PackageUpdateTaskSpec `json:"update,omitempty"` -} - -type TaskResult struct { - Task *Task `json:"task"` - RenderStatus *RenderStatus `json:"renderStatus,omitempty"` -} - -// RenderStatus represents the result of performing render operation -// on a package resources. -type RenderStatus struct { - Result ResultList `json:"result,omitempty"` - Err string `json:"error"` -} - -// PackageInitTaskSpec defines the package initialization task. -type PackageInitTaskSpec struct { - // `Subpackage` is a directory path to a subpackage to initialize. If unspecified, the main package will be initialized. - Subpackage string `json:"subpackage,omitempty"` - // `Description` is a short description of the package. - Description string `json:"description,omitempty"` - // `Keywords` is a list of keywords describing the package. - Keywords []string `json:"keywords,omitempty"` - // `Site is a link to page with information about the package. - Site string `json:"site,omitempty"` -} - -type PackageCloneTaskSpec struct { - // // `Subpackage` is a path to a directory where to clone the upstream package. - // Subpackage string `json:"subpackage,omitempty"` - - // `Upstream` is the reference to the upstream package to clone. - Upstream UpstreamPackage `json:"upstreamRef,omitempty"` - - // Defines which strategy should be used to update the package. It defaults to 'resource-merge'. - // * resource-merge: Perform a structural comparison of the original / - // updated resources, and merge the changes into the local package. - // * fast-forward: Fail without updating if the local package was modified - // since it was fetched. - // * force-delete-replace: Wipe all the local changes to the package and replace - // it with the remote version. - Strategy PackageMergeStrategy `json:"strategy,omitempty"` -} - -type PackageMergeStrategy string - -type PackageUpdateTaskSpec struct { - // `Upstream` is the reference to the upstream package. - Upstream UpstreamPackage `json:"upstreamRef,omitempty"` -} - -const ( - ResourceMerge PackageMergeStrategy = "resource-merge" - FastForward PackageMergeStrategy = "fast-forward" - ForceDeleteReplace PackageMergeStrategy = "force-delete-replace" -) - -type PackagePatchTaskSpec struct { - // Patches is a list of individual patch operations. - Patches []PatchSpec `json:"patches,omitempty"` -} - -type PatchType string - -const ( - PatchTypeCreateFile PatchType = "CreateFile" - PatchTypeDeleteFile PatchType = "DeleteFile" - PatchTypePatchFile PatchType = "PatchFile" -) - -type PatchSpec struct { - File string `json:"file,omitempty"` - Contents string `json:"contents,omitempty"` - PatchType PatchType `json:"patchType,omitempty"` -} - -type PackageEditTaskSpec struct { - Source *PackageRevisionRef `json:"sourceRef,omitempty"` -} - -type RepositoryType string - -const ( - RepositoryTypeGit RepositoryType = "git" - RepositoryTypeOCI RepositoryType = "oci" -) - -// UpstreamRepository repository may be specified directly or by referencing another Repository resource. -type UpstreamPackage struct { - // Type of the repository (i.e. git, OCI). If empty, `upstreamRef` will be used. - Type RepositoryType `json:"type,omitempty"` - - // Git upstream package specification. Required if `type` is `git`. Must be unspecified if `type` is not `git`. - Git *GitPackage `json:"git,omitempty"` - - // OCI upstream package specification. Required if `type` is `oci`. Must be unspecified if `type` is not `oci`. - Oci *OciPackage `json:"oci,omitempty"` - - // UpstreamRef is the reference to the package from a registered repository rather than external package. - UpstreamRef *PackageRevisionRef `json:"upstreamRef,omitempty"` -} - -type GitPackage struct { - // Address of the Git repository, for example: - // `https://github.com/GoogleCloudPlatform/blueprints.git` - Repo string `json:"repo"` - - // `Ref` is the git ref containing the package. Ref can be a branch, tag, or commit SHA. - Ref string `json:"ref"` - - // Directory within the Git repository where the packages are stored. A subdirectory of this directory containing a Kptfile is considered a package. - Directory string `json:"directory"` - - // Reference to secret containing authentication credentials. Optional. - SecretRef SecretRef `json:"secretRef,omitempty"` -} - -type SecretRef struct { - // Name of the secret. The secret is expected to be located in the same namespace as the resource containing the reference. - Name string `json:"name"` -} - -// OciPackage describes a repository compatible with the Open Coutainer Registry standard. -type OciPackage struct { - // Image is the address of an OCI image. - Image string `json:"image"` -} - -// PackageRevisionRef is a reference to a package revision. -type PackageRevisionRef struct { - // `Name` is the name of the referenced PackageRevision resource. - Name string `json:"name"` -} - -// RepositoryRef identifies a reference to a Repository resource. -type RepositoryRef struct { - // Name of the Repository resource referenced. - Name string `json:"name"` -} - -type FunctionEvalTaskSpec struct { - // `Subpackage` is a directory path to a subpackage in which to evaluate the function. - Subpackage string `json:"subpackage,omitempty"` - // `Image` specifies the function image, such as `gcr.io/kpt-fn/gatekeeper:v0.2`. Use of `Image` is mutually exclusive with `FunctionRef`. - Image string `json:"image,omitempty"` - // `FunctionRef` specifies the function by reference to a Function resource. Mutually exclusive with `Image`. - FunctionRef *FunctionRef `json:"functionRef,omitempty"` - // `ConfigMap` specifies the function config (https://kpt.dev/reference/cli/fn/eval/). Mutually exclusive with Config. - ConfigMap map[string]string `json:"configMap,omitempty"` - - // `Config` specifies the function config, arbitrary KRM resource. Mutually exclusive with ConfigMap. - Config runtime.RawExtension `json:"config,omitempty"` - - // If enabled, meta resources (i.e. `Kptfile` and `functionConfig`) are included - // in the input to the function. By default it is disabled. - IncludeMetaResources bool `json:"includeMetaResources,omitempty"` - // `EnableNetwork` controls whether the function has access to network. Defaults to `false`. - EnableNetwork bool `json:"enableNetwork,omitempty"` - // Match specifies the selection criteria for the function evaluation. - // Corresponds to `kpt fn eval --match-???` flgs (https://kpt.dev/reference/cli/fn/eval/). - Match Selector `json:"match,omitempty"` -} - -// Selector corresponds to the `--match-???` set of flags of the `kpt fn eval` command: -// See https://kpt.dev/reference/cli/fn/eval/ for additional information. -type Selector struct { - // APIVersion of the target resources - APIVersion string `json:"apiVersion,omitempty"` - // Kind of the target resources - Kind string `json:"kind,omitempty"` - // Name of the target resources - Name string `json:"name,omitempty"` - // Namespace of the target resources - Namespace string `json:"namespace,omitempty"` -} - -// The following types (UpstreamLock, OriginType, and GitLock) are duplicates from the kpt library. -// We are repeating them here to avoid cyclic dependencies, but these duplicate type should be removed when -// https://github.com/GoogleContainerTools/kpt/issues/3297 is resolved. - -type OriginType string - -// UpstreamLock is a resolved locator for the last fetch of the package. -type UpstreamLock struct { - // Type is the type of origin. - Type OriginType `json:"type,omitempty"` - - // Git is the resolved locator for a package on Git. - Git *GitLock `json:"git,omitempty"` -} - -// GitLock is the resolved locator for a package on Git. -type GitLock struct { - // Repo is the git repository that was fetched. - // e.g. 'https://github.com/kubernetes/examples.git' - Repo string `json:"repo,omitempty"` - - // Directory is the sub directory of the git repository that was fetched. - // e.g. 'staging/cockroachdb' - Directory string `json:"directory,omitempty"` - - // Ref can be a Git branch, tag, or a commit SHA-1 that was fetched. - // e.g. 'master' - Ref string `json:"ref,omitempty"` - - // Commit is the SHA-1 for the last fetch of the package. - // This is set by kpt for bookkeeping purposes. - Commit string `json:"commit,omitempty"` -} - -type Condition struct { - Type string `json:"type"` - - Status ConditionStatus `json:"status"` - - Reason string `json:"reason,omitempty"` - - Message string `json:"message,omitempty"` -} - -type ConditionStatus string - -const ( - ConditionTrue ConditionStatus = "True" - ConditionFalse ConditionStatus = "False" - ConditionUnknown ConditionStatus = "Unknown" -) - -const ( - // Deprecated: prefer ResultListGVK - ResultListKind = "FunctionResultList" - // Deprecated: prefer ResultListGVK - ResultListGroup = "kpt.dev" - // Deprecated: prefer ResultListGVK - ResultListVersion = "v1" - // Deprecated: prefer ResultListGVK - ResultListAPIVersion = ResultListGroup + "/" + ResultListVersion -) - -// ResultList contains aggregated results from multiple functions -type ResultList struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - // ExitCode is the exit code of kpt command - ExitCode int `json:"exitCode"` - // Items contain a list of function result - Items []*Result `json:"items,omitempty"` -} - -// Result contains the structured result from an individual function -type Result struct { - // Image is the full name of the image that generates this result - // Image and Exec are mutually exclusive - Image string `json:"image,omitempty"` - // ExecPath is the the absolute os-specific path to the executable file - // If user provides an executable file with commands, ExecPath should - // contain the entire input string. - ExecPath string `json:"exec,omitempty"` - // TODO(droot): This is required for making structured results subpackage aware. - // Enable this once test harness supports filepath based assertions. - // Pkg is OS specific Absolute path to the package. - // Pkg string `yaml:"pkg,omitempty"` - // Stderr is the content in function stderr - Stderr string `json:"stderr,omitempty"` - // ExitCode is the exit code from running the function - ExitCode int `json:"exitCode"` - // Results is the list of results for the function - Results []ResultItem `json:"results,omitempty"` -} - -// ResultItem defines a validation result -type ResultItem struct { - // Message is a human readable message. This field is required. - Message string `json:"message,omitempty"` - - // Severity is the severity of this result - Severity string `json:"severity,omitempty"` - - // ResourceRef is a reference to a resource. - // Required fields: apiVersion, kind, name. - ResourceRef *ResourceIdentifier `json:"resourceRef,omitempty"` - - // Field is a reference to the field in a resource this result refers to - Field *Field `json:"field,omitempty"` - - // File references a file containing the resource this result refers to - File *File `json:"file,omitempty"` - - // Tags is an unstructured key value map stored with a result that may be set - // by external tools to store and retrieve arbitrary metadata - Tags map[string]string `json:"tags,omitempty"` -} - -// File references a file containing a resource -type File struct { - // Path is relative path to the file containing the resource. - // This field is required. - Path string `json:"path,omitempty"` - - // Index is the index into the file containing the resource - // (i.e. if there are multiple resources in a single file) - Index int `json:"index,omitempty"` -} - -// Field references a field in a resource -type Field struct { - // Path is the field path. This field is required. - Path string `json:"path,omitempty"` - - // CurrentValue is the current field value - CurrentValue string `json:"currentValue,omitempty"` - - // ProposedValue is the proposed value of the field to fix an issue. - ProposedValue string `json:"proposedValue,omitempty"` -} - -// ResourceIdentifier contains the information needed to uniquely -// identify a resource in a cluster. -type ResourceIdentifier struct { - metav1.TypeMeta `json:",inline"` - NameMeta `json:",inline"` -} - -// NameMeta contains name information. -type NameMeta struct { - // Name is the metadata.name field of a Resource - Name string `json:"name,omitempty"` - // Namespace is the metadata.namespace field of a Resource - Namespace string `json:"namespace,omitempty"` -} diff --git a/porch/api/porch/v1alpha1/util.go b/porch/api/porch/v1alpha1/util.go deleted file mode 100644 index a58a912b97..0000000000 --- a/porch/api/porch/v1alpha1/util.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2022 The kpt 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 - -package v1alpha1 - -func LifecycleIsPublished(lifecycle PackageRevisionLifecycle) bool { - return lifecycle == PackageRevisionLifecyclePublished || lifecycle == PackageRevisionLifecycleDeletionProposed -} diff --git a/porch/api/porch/v1alpha1/zz_generated.conversion.go b/porch/api/porch/v1alpha1/zz_generated.conversion.go deleted file mode 100644 index ff4b6ab353..0000000000 --- a/porch/api/porch/v1alpha1/zz_generated.conversion.go +++ /dev/null @@ -1,1682 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// Copyright 2023 The kpt 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 conversion-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - unsafe "unsafe" - - porch "github.com/GoogleContainerTools/kpt/porch/api/porch" - conversion "k8s.io/apimachinery/pkg/conversion" - runtime "k8s.io/apimachinery/pkg/runtime" -) - -func init() { - localSchemeBuilder.Register(RegisterConversions) -} - -// RegisterConversions adds conversion functions to the given scheme. -// Public to allow building arbitrary schemes. -func RegisterConversions(s *runtime.Scheme) error { - if err := s.AddGeneratedConversionFunc((*Condition)(nil), (*porch.Condition)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_Condition_To_porch_Condition(a.(*Condition), b.(*porch.Condition), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.Condition)(nil), (*Condition)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_Condition_To_v1alpha1_Condition(a.(*porch.Condition), b.(*Condition), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*Field)(nil), (*porch.Field)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_Field_To_porch_Field(a.(*Field), b.(*porch.Field), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.Field)(nil), (*Field)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_Field_To_v1alpha1_Field(a.(*porch.Field), b.(*Field), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*File)(nil), (*porch.File)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_File_To_porch_File(a.(*File), b.(*porch.File), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.File)(nil), (*File)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_File_To_v1alpha1_File(a.(*porch.File), b.(*File), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*Function)(nil), (*porch.Function)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_Function_To_porch_Function(a.(*Function), b.(*porch.Function), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.Function)(nil), (*Function)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_Function_To_v1alpha1_Function(a.(*porch.Function), b.(*Function), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*FunctionConfig)(nil), (*porch.FunctionConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_FunctionConfig_To_porch_FunctionConfig(a.(*FunctionConfig), b.(*porch.FunctionConfig), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.FunctionConfig)(nil), (*FunctionConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_FunctionConfig_To_v1alpha1_FunctionConfig(a.(*porch.FunctionConfig), b.(*FunctionConfig), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*FunctionEvalTaskSpec)(nil), (*porch.FunctionEvalTaskSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_FunctionEvalTaskSpec_To_porch_FunctionEvalTaskSpec(a.(*FunctionEvalTaskSpec), b.(*porch.FunctionEvalTaskSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.FunctionEvalTaskSpec)(nil), (*FunctionEvalTaskSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_FunctionEvalTaskSpec_To_v1alpha1_FunctionEvalTaskSpec(a.(*porch.FunctionEvalTaskSpec), b.(*FunctionEvalTaskSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*FunctionList)(nil), (*porch.FunctionList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_FunctionList_To_porch_FunctionList(a.(*FunctionList), b.(*porch.FunctionList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.FunctionList)(nil), (*FunctionList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_FunctionList_To_v1alpha1_FunctionList(a.(*porch.FunctionList), b.(*FunctionList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*FunctionRef)(nil), (*porch.FunctionRef)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_FunctionRef_To_porch_FunctionRef(a.(*FunctionRef), b.(*porch.FunctionRef), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.FunctionRef)(nil), (*FunctionRef)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_FunctionRef_To_v1alpha1_FunctionRef(a.(*porch.FunctionRef), b.(*FunctionRef), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*FunctionSpec)(nil), (*porch.FunctionSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_FunctionSpec_To_porch_FunctionSpec(a.(*FunctionSpec), b.(*porch.FunctionSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.FunctionSpec)(nil), (*FunctionSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_FunctionSpec_To_v1alpha1_FunctionSpec(a.(*porch.FunctionSpec), b.(*FunctionSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*FunctionStatus)(nil), (*porch.FunctionStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_FunctionStatus_To_porch_FunctionStatus(a.(*FunctionStatus), b.(*porch.FunctionStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.FunctionStatus)(nil), (*FunctionStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_FunctionStatus_To_v1alpha1_FunctionStatus(a.(*porch.FunctionStatus), b.(*FunctionStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*GitLock)(nil), (*porch.GitLock)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_GitLock_To_porch_GitLock(a.(*GitLock), b.(*porch.GitLock), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.GitLock)(nil), (*GitLock)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_GitLock_To_v1alpha1_GitLock(a.(*porch.GitLock), b.(*GitLock), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*GitPackage)(nil), (*porch.GitPackage)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_GitPackage_To_porch_GitPackage(a.(*GitPackage), b.(*porch.GitPackage), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.GitPackage)(nil), (*GitPackage)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_GitPackage_To_v1alpha1_GitPackage(a.(*porch.GitPackage), b.(*GitPackage), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*NameMeta)(nil), (*porch.NameMeta)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_NameMeta_To_porch_NameMeta(a.(*NameMeta), b.(*porch.NameMeta), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.NameMeta)(nil), (*NameMeta)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_NameMeta_To_v1alpha1_NameMeta(a.(*porch.NameMeta), b.(*NameMeta), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*OciPackage)(nil), (*porch.OciPackage)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_OciPackage_To_porch_OciPackage(a.(*OciPackage), b.(*porch.OciPackage), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.OciPackage)(nil), (*OciPackage)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_OciPackage_To_v1alpha1_OciPackage(a.(*porch.OciPackage), b.(*OciPackage), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*Package)(nil), (*porch.Package)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_Package_To_porch_Package(a.(*Package), b.(*porch.Package), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.Package)(nil), (*Package)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_Package_To_v1alpha1_Package(a.(*porch.Package), b.(*Package), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*PackageCloneTaskSpec)(nil), (*porch.PackageCloneTaskSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_PackageCloneTaskSpec_To_porch_PackageCloneTaskSpec(a.(*PackageCloneTaskSpec), b.(*porch.PackageCloneTaskSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.PackageCloneTaskSpec)(nil), (*PackageCloneTaskSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_PackageCloneTaskSpec_To_v1alpha1_PackageCloneTaskSpec(a.(*porch.PackageCloneTaskSpec), b.(*PackageCloneTaskSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*PackageEditTaskSpec)(nil), (*porch.PackageEditTaskSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_PackageEditTaskSpec_To_porch_PackageEditTaskSpec(a.(*PackageEditTaskSpec), b.(*porch.PackageEditTaskSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.PackageEditTaskSpec)(nil), (*PackageEditTaskSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_PackageEditTaskSpec_To_v1alpha1_PackageEditTaskSpec(a.(*porch.PackageEditTaskSpec), b.(*PackageEditTaskSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*PackageInitTaskSpec)(nil), (*porch.PackageInitTaskSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_PackageInitTaskSpec_To_porch_PackageInitTaskSpec(a.(*PackageInitTaskSpec), b.(*porch.PackageInitTaskSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.PackageInitTaskSpec)(nil), (*PackageInitTaskSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_PackageInitTaskSpec_To_v1alpha1_PackageInitTaskSpec(a.(*porch.PackageInitTaskSpec), b.(*PackageInitTaskSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*PackageList)(nil), (*porch.PackageList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_PackageList_To_porch_PackageList(a.(*PackageList), b.(*porch.PackageList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.PackageList)(nil), (*PackageList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_PackageList_To_v1alpha1_PackageList(a.(*porch.PackageList), b.(*PackageList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*PackagePatchTaskSpec)(nil), (*porch.PackagePatchTaskSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_PackagePatchTaskSpec_To_porch_PackagePatchTaskSpec(a.(*PackagePatchTaskSpec), b.(*porch.PackagePatchTaskSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.PackagePatchTaskSpec)(nil), (*PackagePatchTaskSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_PackagePatchTaskSpec_To_v1alpha1_PackagePatchTaskSpec(a.(*porch.PackagePatchTaskSpec), b.(*PackagePatchTaskSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*PackageRevision)(nil), (*porch.PackageRevision)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_PackageRevision_To_porch_PackageRevision(a.(*PackageRevision), b.(*porch.PackageRevision), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.PackageRevision)(nil), (*PackageRevision)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_PackageRevision_To_v1alpha1_PackageRevision(a.(*porch.PackageRevision), b.(*PackageRevision), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*PackageRevisionList)(nil), (*porch.PackageRevisionList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_PackageRevisionList_To_porch_PackageRevisionList(a.(*PackageRevisionList), b.(*porch.PackageRevisionList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.PackageRevisionList)(nil), (*PackageRevisionList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_PackageRevisionList_To_v1alpha1_PackageRevisionList(a.(*porch.PackageRevisionList), b.(*PackageRevisionList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*PackageRevisionRef)(nil), (*porch.PackageRevisionRef)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_PackageRevisionRef_To_porch_PackageRevisionRef(a.(*PackageRevisionRef), b.(*porch.PackageRevisionRef), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.PackageRevisionRef)(nil), (*PackageRevisionRef)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_PackageRevisionRef_To_v1alpha1_PackageRevisionRef(a.(*porch.PackageRevisionRef), b.(*PackageRevisionRef), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*PackageRevisionResources)(nil), (*porch.PackageRevisionResources)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_PackageRevisionResources_To_porch_PackageRevisionResources(a.(*PackageRevisionResources), b.(*porch.PackageRevisionResources), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.PackageRevisionResources)(nil), (*PackageRevisionResources)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_PackageRevisionResources_To_v1alpha1_PackageRevisionResources(a.(*porch.PackageRevisionResources), b.(*PackageRevisionResources), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*PackageRevisionResourcesList)(nil), (*porch.PackageRevisionResourcesList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_PackageRevisionResourcesList_To_porch_PackageRevisionResourcesList(a.(*PackageRevisionResourcesList), b.(*porch.PackageRevisionResourcesList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.PackageRevisionResourcesList)(nil), (*PackageRevisionResourcesList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_PackageRevisionResourcesList_To_v1alpha1_PackageRevisionResourcesList(a.(*porch.PackageRevisionResourcesList), b.(*PackageRevisionResourcesList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*PackageRevisionResourcesSpec)(nil), (*porch.PackageRevisionResourcesSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_PackageRevisionResourcesSpec_To_porch_PackageRevisionResourcesSpec(a.(*PackageRevisionResourcesSpec), b.(*porch.PackageRevisionResourcesSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.PackageRevisionResourcesSpec)(nil), (*PackageRevisionResourcesSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_PackageRevisionResourcesSpec_To_v1alpha1_PackageRevisionResourcesSpec(a.(*porch.PackageRevisionResourcesSpec), b.(*PackageRevisionResourcesSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*PackageRevisionResourcesStatus)(nil), (*porch.PackageRevisionResourcesStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_PackageRevisionResourcesStatus_To_porch_PackageRevisionResourcesStatus(a.(*PackageRevisionResourcesStatus), b.(*porch.PackageRevisionResourcesStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.PackageRevisionResourcesStatus)(nil), (*PackageRevisionResourcesStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_PackageRevisionResourcesStatus_To_v1alpha1_PackageRevisionResourcesStatus(a.(*porch.PackageRevisionResourcesStatus), b.(*PackageRevisionResourcesStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*PackageRevisionSpec)(nil), (*porch.PackageRevisionSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_PackageRevisionSpec_To_porch_PackageRevisionSpec(a.(*PackageRevisionSpec), b.(*porch.PackageRevisionSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.PackageRevisionSpec)(nil), (*PackageRevisionSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_PackageRevisionSpec_To_v1alpha1_PackageRevisionSpec(a.(*porch.PackageRevisionSpec), b.(*PackageRevisionSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*PackageRevisionStatus)(nil), (*porch.PackageRevisionStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_PackageRevisionStatus_To_porch_PackageRevisionStatus(a.(*PackageRevisionStatus), b.(*porch.PackageRevisionStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.PackageRevisionStatus)(nil), (*PackageRevisionStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_PackageRevisionStatus_To_v1alpha1_PackageRevisionStatus(a.(*porch.PackageRevisionStatus), b.(*PackageRevisionStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*PackageSpec)(nil), (*porch.PackageSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_PackageSpec_To_porch_PackageSpec(a.(*PackageSpec), b.(*porch.PackageSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.PackageSpec)(nil), (*PackageSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_PackageSpec_To_v1alpha1_PackageSpec(a.(*porch.PackageSpec), b.(*PackageSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*PackageStatus)(nil), (*porch.PackageStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_PackageStatus_To_porch_PackageStatus(a.(*PackageStatus), b.(*porch.PackageStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.PackageStatus)(nil), (*PackageStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_PackageStatus_To_v1alpha1_PackageStatus(a.(*porch.PackageStatus), b.(*PackageStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*PackageUpdateTaskSpec)(nil), (*porch.PackageUpdateTaskSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_PackageUpdateTaskSpec_To_porch_PackageUpdateTaskSpec(a.(*PackageUpdateTaskSpec), b.(*porch.PackageUpdateTaskSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.PackageUpdateTaskSpec)(nil), (*PackageUpdateTaskSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_PackageUpdateTaskSpec_To_v1alpha1_PackageUpdateTaskSpec(a.(*porch.PackageUpdateTaskSpec), b.(*PackageUpdateTaskSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*ParentReference)(nil), (*porch.ParentReference)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_ParentReference_To_porch_ParentReference(a.(*ParentReference), b.(*porch.ParentReference), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.ParentReference)(nil), (*ParentReference)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_ParentReference_To_v1alpha1_ParentReference(a.(*porch.ParentReference), b.(*ParentReference), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*PatchSpec)(nil), (*porch.PatchSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_PatchSpec_To_porch_PatchSpec(a.(*PatchSpec), b.(*porch.PatchSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.PatchSpec)(nil), (*PatchSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_PatchSpec_To_v1alpha1_PatchSpec(a.(*porch.PatchSpec), b.(*PatchSpec), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*ReadinessGate)(nil), (*porch.ReadinessGate)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_ReadinessGate_To_porch_ReadinessGate(a.(*ReadinessGate), b.(*porch.ReadinessGate), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.ReadinessGate)(nil), (*ReadinessGate)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_ReadinessGate_To_v1alpha1_ReadinessGate(a.(*porch.ReadinessGate), b.(*ReadinessGate), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*RenderStatus)(nil), (*porch.RenderStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_RenderStatus_To_porch_RenderStatus(a.(*RenderStatus), b.(*porch.RenderStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.RenderStatus)(nil), (*RenderStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_RenderStatus_To_v1alpha1_RenderStatus(a.(*porch.RenderStatus), b.(*RenderStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*RepositoryRef)(nil), (*porch.RepositoryRef)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_RepositoryRef_To_porch_RepositoryRef(a.(*RepositoryRef), b.(*porch.RepositoryRef), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.RepositoryRef)(nil), (*RepositoryRef)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_RepositoryRef_To_v1alpha1_RepositoryRef(a.(*porch.RepositoryRef), b.(*RepositoryRef), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*ResourceIdentifier)(nil), (*porch.ResourceIdentifier)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_ResourceIdentifier_To_porch_ResourceIdentifier(a.(*ResourceIdentifier), b.(*porch.ResourceIdentifier), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.ResourceIdentifier)(nil), (*ResourceIdentifier)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_ResourceIdentifier_To_v1alpha1_ResourceIdentifier(a.(*porch.ResourceIdentifier), b.(*ResourceIdentifier), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*Result)(nil), (*porch.Result)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_Result_To_porch_Result(a.(*Result), b.(*porch.Result), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.Result)(nil), (*Result)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_Result_To_v1alpha1_Result(a.(*porch.Result), b.(*Result), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*ResultItem)(nil), (*porch.ResultItem)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_ResultItem_To_porch_ResultItem(a.(*ResultItem), b.(*porch.ResultItem), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.ResultItem)(nil), (*ResultItem)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_ResultItem_To_v1alpha1_ResultItem(a.(*porch.ResultItem), b.(*ResultItem), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*ResultList)(nil), (*porch.ResultList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_ResultList_To_porch_ResultList(a.(*ResultList), b.(*porch.ResultList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.ResultList)(nil), (*ResultList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_ResultList_To_v1alpha1_ResultList(a.(*porch.ResultList), b.(*ResultList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*SecretRef)(nil), (*porch.SecretRef)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_SecretRef_To_porch_SecretRef(a.(*SecretRef), b.(*porch.SecretRef), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.SecretRef)(nil), (*SecretRef)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_SecretRef_To_v1alpha1_SecretRef(a.(*porch.SecretRef), b.(*SecretRef), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*Selector)(nil), (*porch.Selector)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_Selector_To_porch_Selector(a.(*Selector), b.(*porch.Selector), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.Selector)(nil), (*Selector)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_Selector_To_v1alpha1_Selector(a.(*porch.Selector), b.(*Selector), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*Task)(nil), (*porch.Task)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_Task_To_porch_Task(a.(*Task), b.(*porch.Task), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.Task)(nil), (*Task)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_Task_To_v1alpha1_Task(a.(*porch.Task), b.(*Task), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*TaskResult)(nil), (*porch.TaskResult)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_TaskResult_To_porch_TaskResult(a.(*TaskResult), b.(*porch.TaskResult), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.TaskResult)(nil), (*TaskResult)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_TaskResult_To_v1alpha1_TaskResult(a.(*porch.TaskResult), b.(*TaskResult), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*UpstreamLock)(nil), (*porch.UpstreamLock)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_UpstreamLock_To_porch_UpstreamLock(a.(*UpstreamLock), b.(*porch.UpstreamLock), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.UpstreamLock)(nil), (*UpstreamLock)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_UpstreamLock_To_v1alpha1_UpstreamLock(a.(*porch.UpstreamLock), b.(*UpstreamLock), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*UpstreamPackage)(nil), (*porch.UpstreamPackage)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_UpstreamPackage_To_porch_UpstreamPackage(a.(*UpstreamPackage), b.(*porch.UpstreamPackage), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*porch.UpstreamPackage)(nil), (*UpstreamPackage)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_porch_UpstreamPackage_To_v1alpha1_UpstreamPackage(a.(*porch.UpstreamPackage), b.(*UpstreamPackage), scope) - }); err != nil { - return err - } - return nil -} - -func autoConvert_v1alpha1_Condition_To_porch_Condition(in *Condition, out *porch.Condition, s conversion.Scope) error { - out.Type = in.Type - out.Status = porch.ConditionStatus(in.Status) - out.Reason = in.Reason - out.Message = in.Message - return nil -} - -// Convert_v1alpha1_Condition_To_porch_Condition is an autogenerated conversion function. -func Convert_v1alpha1_Condition_To_porch_Condition(in *Condition, out *porch.Condition, s conversion.Scope) error { - return autoConvert_v1alpha1_Condition_To_porch_Condition(in, out, s) -} - -func autoConvert_porch_Condition_To_v1alpha1_Condition(in *porch.Condition, out *Condition, s conversion.Scope) error { - out.Type = in.Type - out.Status = ConditionStatus(in.Status) - out.Reason = in.Reason - out.Message = in.Message - return nil -} - -// Convert_porch_Condition_To_v1alpha1_Condition is an autogenerated conversion function. -func Convert_porch_Condition_To_v1alpha1_Condition(in *porch.Condition, out *Condition, s conversion.Scope) error { - return autoConvert_porch_Condition_To_v1alpha1_Condition(in, out, s) -} - -func autoConvert_v1alpha1_Field_To_porch_Field(in *Field, out *porch.Field, s conversion.Scope) error { - out.Path = in.Path - out.CurrentValue = in.CurrentValue - out.ProposedValue = in.ProposedValue - return nil -} - -// Convert_v1alpha1_Field_To_porch_Field is an autogenerated conversion function. -func Convert_v1alpha1_Field_To_porch_Field(in *Field, out *porch.Field, s conversion.Scope) error { - return autoConvert_v1alpha1_Field_To_porch_Field(in, out, s) -} - -func autoConvert_porch_Field_To_v1alpha1_Field(in *porch.Field, out *Field, s conversion.Scope) error { - out.Path = in.Path - out.CurrentValue = in.CurrentValue - out.ProposedValue = in.ProposedValue - return nil -} - -// Convert_porch_Field_To_v1alpha1_Field is an autogenerated conversion function. -func Convert_porch_Field_To_v1alpha1_Field(in *porch.Field, out *Field, s conversion.Scope) error { - return autoConvert_porch_Field_To_v1alpha1_Field(in, out, s) -} - -func autoConvert_v1alpha1_File_To_porch_File(in *File, out *porch.File, s conversion.Scope) error { - out.Path = in.Path - out.Index = in.Index - return nil -} - -// Convert_v1alpha1_File_To_porch_File is an autogenerated conversion function. -func Convert_v1alpha1_File_To_porch_File(in *File, out *porch.File, s conversion.Scope) error { - return autoConvert_v1alpha1_File_To_porch_File(in, out, s) -} - -func autoConvert_porch_File_To_v1alpha1_File(in *porch.File, out *File, s conversion.Scope) error { - out.Path = in.Path - out.Index = in.Index - return nil -} - -// Convert_porch_File_To_v1alpha1_File is an autogenerated conversion function. -func Convert_porch_File_To_v1alpha1_File(in *porch.File, out *File, s conversion.Scope) error { - return autoConvert_porch_File_To_v1alpha1_File(in, out, s) -} - -func autoConvert_v1alpha1_Function_To_porch_Function(in *Function, out *porch.Function, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_v1alpha1_FunctionSpec_To_porch_FunctionSpec(&in.Spec, &out.Spec, s); err != nil { - return err - } - if err := Convert_v1alpha1_FunctionStatus_To_porch_FunctionStatus(&in.Status, &out.Status, s); err != nil { - return err - } - return nil -} - -// Convert_v1alpha1_Function_To_porch_Function is an autogenerated conversion function. -func Convert_v1alpha1_Function_To_porch_Function(in *Function, out *porch.Function, s conversion.Scope) error { - return autoConvert_v1alpha1_Function_To_porch_Function(in, out, s) -} - -func autoConvert_porch_Function_To_v1alpha1_Function(in *porch.Function, out *Function, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_porch_FunctionSpec_To_v1alpha1_FunctionSpec(&in.Spec, &out.Spec, s); err != nil { - return err - } - if err := Convert_porch_FunctionStatus_To_v1alpha1_FunctionStatus(&in.Status, &out.Status, s); err != nil { - return err - } - return nil -} - -// Convert_porch_Function_To_v1alpha1_Function is an autogenerated conversion function. -func Convert_porch_Function_To_v1alpha1_Function(in *porch.Function, out *Function, s conversion.Scope) error { - return autoConvert_porch_Function_To_v1alpha1_Function(in, out, s) -} - -func autoConvert_v1alpha1_FunctionConfig_To_porch_FunctionConfig(in *FunctionConfig, out *porch.FunctionConfig, s conversion.Scope) error { - out.RequiredFields = *(*[]string)(unsafe.Pointer(&in.RequiredFields)) - return nil -} - -// Convert_v1alpha1_FunctionConfig_To_porch_FunctionConfig is an autogenerated conversion function. -func Convert_v1alpha1_FunctionConfig_To_porch_FunctionConfig(in *FunctionConfig, out *porch.FunctionConfig, s conversion.Scope) error { - return autoConvert_v1alpha1_FunctionConfig_To_porch_FunctionConfig(in, out, s) -} - -func autoConvert_porch_FunctionConfig_To_v1alpha1_FunctionConfig(in *porch.FunctionConfig, out *FunctionConfig, s conversion.Scope) error { - out.RequiredFields = *(*[]string)(unsafe.Pointer(&in.RequiredFields)) - return nil -} - -// Convert_porch_FunctionConfig_To_v1alpha1_FunctionConfig is an autogenerated conversion function. -func Convert_porch_FunctionConfig_To_v1alpha1_FunctionConfig(in *porch.FunctionConfig, out *FunctionConfig, s conversion.Scope) error { - return autoConvert_porch_FunctionConfig_To_v1alpha1_FunctionConfig(in, out, s) -} - -func autoConvert_v1alpha1_FunctionEvalTaskSpec_To_porch_FunctionEvalTaskSpec(in *FunctionEvalTaskSpec, out *porch.FunctionEvalTaskSpec, s conversion.Scope) error { - out.Subpackage = in.Subpackage - out.Image = in.Image - out.FunctionRef = (*porch.FunctionRef)(unsafe.Pointer(in.FunctionRef)) - out.ConfigMap = *(*map[string]string)(unsafe.Pointer(&in.ConfigMap)) - out.Config = in.Config - out.IncludeMetaResources = in.IncludeMetaResources - out.EnableNetwork = in.EnableNetwork - if err := Convert_v1alpha1_Selector_To_porch_Selector(&in.Match, &out.Match, s); err != nil { - return err - } - return nil -} - -// Convert_v1alpha1_FunctionEvalTaskSpec_To_porch_FunctionEvalTaskSpec is an autogenerated conversion function. -func Convert_v1alpha1_FunctionEvalTaskSpec_To_porch_FunctionEvalTaskSpec(in *FunctionEvalTaskSpec, out *porch.FunctionEvalTaskSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_FunctionEvalTaskSpec_To_porch_FunctionEvalTaskSpec(in, out, s) -} - -func autoConvert_porch_FunctionEvalTaskSpec_To_v1alpha1_FunctionEvalTaskSpec(in *porch.FunctionEvalTaskSpec, out *FunctionEvalTaskSpec, s conversion.Scope) error { - out.Subpackage = in.Subpackage - out.Image = in.Image - out.FunctionRef = (*FunctionRef)(unsafe.Pointer(in.FunctionRef)) - out.ConfigMap = *(*map[string]string)(unsafe.Pointer(&in.ConfigMap)) - out.Config = in.Config - out.IncludeMetaResources = in.IncludeMetaResources - out.EnableNetwork = in.EnableNetwork - if err := Convert_porch_Selector_To_v1alpha1_Selector(&in.Match, &out.Match, s); err != nil { - return err - } - return nil -} - -// Convert_porch_FunctionEvalTaskSpec_To_v1alpha1_FunctionEvalTaskSpec is an autogenerated conversion function. -func Convert_porch_FunctionEvalTaskSpec_To_v1alpha1_FunctionEvalTaskSpec(in *porch.FunctionEvalTaskSpec, out *FunctionEvalTaskSpec, s conversion.Scope) error { - return autoConvert_porch_FunctionEvalTaskSpec_To_v1alpha1_FunctionEvalTaskSpec(in, out, s) -} - -func autoConvert_v1alpha1_FunctionList_To_porch_FunctionList(in *FunctionList, out *porch.FunctionList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - out.Items = *(*[]porch.Function)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_v1alpha1_FunctionList_To_porch_FunctionList is an autogenerated conversion function. -func Convert_v1alpha1_FunctionList_To_porch_FunctionList(in *FunctionList, out *porch.FunctionList, s conversion.Scope) error { - return autoConvert_v1alpha1_FunctionList_To_porch_FunctionList(in, out, s) -} - -func autoConvert_porch_FunctionList_To_v1alpha1_FunctionList(in *porch.FunctionList, out *FunctionList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - out.Items = *(*[]Function)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_porch_FunctionList_To_v1alpha1_FunctionList is an autogenerated conversion function. -func Convert_porch_FunctionList_To_v1alpha1_FunctionList(in *porch.FunctionList, out *FunctionList, s conversion.Scope) error { - return autoConvert_porch_FunctionList_To_v1alpha1_FunctionList(in, out, s) -} - -func autoConvert_v1alpha1_FunctionRef_To_porch_FunctionRef(in *FunctionRef, out *porch.FunctionRef, s conversion.Scope) error { - out.Name = in.Name - return nil -} - -// Convert_v1alpha1_FunctionRef_To_porch_FunctionRef is an autogenerated conversion function. -func Convert_v1alpha1_FunctionRef_To_porch_FunctionRef(in *FunctionRef, out *porch.FunctionRef, s conversion.Scope) error { - return autoConvert_v1alpha1_FunctionRef_To_porch_FunctionRef(in, out, s) -} - -func autoConvert_porch_FunctionRef_To_v1alpha1_FunctionRef(in *porch.FunctionRef, out *FunctionRef, s conversion.Scope) error { - out.Name = in.Name - return nil -} - -// Convert_porch_FunctionRef_To_v1alpha1_FunctionRef is an autogenerated conversion function. -func Convert_porch_FunctionRef_To_v1alpha1_FunctionRef(in *porch.FunctionRef, out *FunctionRef, s conversion.Scope) error { - return autoConvert_porch_FunctionRef_To_v1alpha1_FunctionRef(in, out, s) -} - -func autoConvert_v1alpha1_FunctionSpec_To_porch_FunctionSpec(in *FunctionSpec, out *porch.FunctionSpec, s conversion.Scope) error { - out.Image = in.Image - if err := Convert_v1alpha1_RepositoryRef_To_porch_RepositoryRef(&in.RepositoryRef, &out.RepositoryRef, s); err != nil { - return err - } - out.FunctionTypes = *(*[]porch.FunctionType)(unsafe.Pointer(&in.FunctionTypes)) - out.FunctionConfigs = *(*[]porch.FunctionConfig)(unsafe.Pointer(&in.FunctionConfigs)) - out.Keywords = *(*[]string)(unsafe.Pointer(&in.Keywords)) - out.Description = in.Description - out.DocumentationUrl = in.DocumentationUrl - return nil -} - -// Convert_v1alpha1_FunctionSpec_To_porch_FunctionSpec is an autogenerated conversion function. -func Convert_v1alpha1_FunctionSpec_To_porch_FunctionSpec(in *FunctionSpec, out *porch.FunctionSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_FunctionSpec_To_porch_FunctionSpec(in, out, s) -} - -func autoConvert_porch_FunctionSpec_To_v1alpha1_FunctionSpec(in *porch.FunctionSpec, out *FunctionSpec, s conversion.Scope) error { - out.Image = in.Image - if err := Convert_porch_RepositoryRef_To_v1alpha1_RepositoryRef(&in.RepositoryRef, &out.RepositoryRef, s); err != nil { - return err - } - out.FunctionTypes = *(*[]FunctionType)(unsafe.Pointer(&in.FunctionTypes)) - out.FunctionConfigs = *(*[]FunctionConfig)(unsafe.Pointer(&in.FunctionConfigs)) - out.Keywords = *(*[]string)(unsafe.Pointer(&in.Keywords)) - out.Description = in.Description - out.DocumentationUrl = in.DocumentationUrl - return nil -} - -// Convert_porch_FunctionSpec_To_v1alpha1_FunctionSpec is an autogenerated conversion function. -func Convert_porch_FunctionSpec_To_v1alpha1_FunctionSpec(in *porch.FunctionSpec, out *FunctionSpec, s conversion.Scope) error { - return autoConvert_porch_FunctionSpec_To_v1alpha1_FunctionSpec(in, out, s) -} - -func autoConvert_v1alpha1_FunctionStatus_To_porch_FunctionStatus(in *FunctionStatus, out *porch.FunctionStatus, s conversion.Scope) error { - return nil -} - -// Convert_v1alpha1_FunctionStatus_To_porch_FunctionStatus is an autogenerated conversion function. -func Convert_v1alpha1_FunctionStatus_To_porch_FunctionStatus(in *FunctionStatus, out *porch.FunctionStatus, s conversion.Scope) error { - return autoConvert_v1alpha1_FunctionStatus_To_porch_FunctionStatus(in, out, s) -} - -func autoConvert_porch_FunctionStatus_To_v1alpha1_FunctionStatus(in *porch.FunctionStatus, out *FunctionStatus, s conversion.Scope) error { - return nil -} - -// Convert_porch_FunctionStatus_To_v1alpha1_FunctionStatus is an autogenerated conversion function. -func Convert_porch_FunctionStatus_To_v1alpha1_FunctionStatus(in *porch.FunctionStatus, out *FunctionStatus, s conversion.Scope) error { - return autoConvert_porch_FunctionStatus_To_v1alpha1_FunctionStatus(in, out, s) -} - -func autoConvert_v1alpha1_GitLock_To_porch_GitLock(in *GitLock, out *porch.GitLock, s conversion.Scope) error { - out.Repo = in.Repo - out.Directory = in.Directory - out.Ref = in.Ref - out.Commit = in.Commit - return nil -} - -// Convert_v1alpha1_GitLock_To_porch_GitLock is an autogenerated conversion function. -func Convert_v1alpha1_GitLock_To_porch_GitLock(in *GitLock, out *porch.GitLock, s conversion.Scope) error { - return autoConvert_v1alpha1_GitLock_To_porch_GitLock(in, out, s) -} - -func autoConvert_porch_GitLock_To_v1alpha1_GitLock(in *porch.GitLock, out *GitLock, s conversion.Scope) error { - out.Repo = in.Repo - out.Directory = in.Directory - out.Ref = in.Ref - out.Commit = in.Commit - return nil -} - -// Convert_porch_GitLock_To_v1alpha1_GitLock is an autogenerated conversion function. -func Convert_porch_GitLock_To_v1alpha1_GitLock(in *porch.GitLock, out *GitLock, s conversion.Scope) error { - return autoConvert_porch_GitLock_To_v1alpha1_GitLock(in, out, s) -} - -func autoConvert_v1alpha1_GitPackage_To_porch_GitPackage(in *GitPackage, out *porch.GitPackage, s conversion.Scope) error { - out.Repo = in.Repo - out.Ref = in.Ref - out.Directory = in.Directory - if err := Convert_v1alpha1_SecretRef_To_porch_SecretRef(&in.SecretRef, &out.SecretRef, s); err != nil { - return err - } - return nil -} - -// Convert_v1alpha1_GitPackage_To_porch_GitPackage is an autogenerated conversion function. -func Convert_v1alpha1_GitPackage_To_porch_GitPackage(in *GitPackage, out *porch.GitPackage, s conversion.Scope) error { - return autoConvert_v1alpha1_GitPackage_To_porch_GitPackage(in, out, s) -} - -func autoConvert_porch_GitPackage_To_v1alpha1_GitPackage(in *porch.GitPackage, out *GitPackage, s conversion.Scope) error { - out.Repo = in.Repo - out.Ref = in.Ref - out.Directory = in.Directory - if err := Convert_porch_SecretRef_To_v1alpha1_SecretRef(&in.SecretRef, &out.SecretRef, s); err != nil { - return err - } - return nil -} - -// Convert_porch_GitPackage_To_v1alpha1_GitPackage is an autogenerated conversion function. -func Convert_porch_GitPackage_To_v1alpha1_GitPackage(in *porch.GitPackage, out *GitPackage, s conversion.Scope) error { - return autoConvert_porch_GitPackage_To_v1alpha1_GitPackage(in, out, s) -} - -func autoConvert_v1alpha1_NameMeta_To_porch_NameMeta(in *NameMeta, out *porch.NameMeta, s conversion.Scope) error { - out.Name = in.Name - out.Namespace = in.Namespace - return nil -} - -// Convert_v1alpha1_NameMeta_To_porch_NameMeta is an autogenerated conversion function. -func Convert_v1alpha1_NameMeta_To_porch_NameMeta(in *NameMeta, out *porch.NameMeta, s conversion.Scope) error { - return autoConvert_v1alpha1_NameMeta_To_porch_NameMeta(in, out, s) -} - -func autoConvert_porch_NameMeta_To_v1alpha1_NameMeta(in *porch.NameMeta, out *NameMeta, s conversion.Scope) error { - out.Name = in.Name - out.Namespace = in.Namespace - return nil -} - -// Convert_porch_NameMeta_To_v1alpha1_NameMeta is an autogenerated conversion function. -func Convert_porch_NameMeta_To_v1alpha1_NameMeta(in *porch.NameMeta, out *NameMeta, s conversion.Scope) error { - return autoConvert_porch_NameMeta_To_v1alpha1_NameMeta(in, out, s) -} - -func autoConvert_v1alpha1_OciPackage_To_porch_OciPackage(in *OciPackage, out *porch.OciPackage, s conversion.Scope) error { - out.Image = in.Image - return nil -} - -// Convert_v1alpha1_OciPackage_To_porch_OciPackage is an autogenerated conversion function. -func Convert_v1alpha1_OciPackage_To_porch_OciPackage(in *OciPackage, out *porch.OciPackage, s conversion.Scope) error { - return autoConvert_v1alpha1_OciPackage_To_porch_OciPackage(in, out, s) -} - -func autoConvert_porch_OciPackage_To_v1alpha1_OciPackage(in *porch.OciPackage, out *OciPackage, s conversion.Scope) error { - out.Image = in.Image - return nil -} - -// Convert_porch_OciPackage_To_v1alpha1_OciPackage is an autogenerated conversion function. -func Convert_porch_OciPackage_To_v1alpha1_OciPackage(in *porch.OciPackage, out *OciPackage, s conversion.Scope) error { - return autoConvert_porch_OciPackage_To_v1alpha1_OciPackage(in, out, s) -} - -func autoConvert_v1alpha1_Package_To_porch_Package(in *Package, out *porch.Package, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_v1alpha1_PackageSpec_To_porch_PackageSpec(&in.Spec, &out.Spec, s); err != nil { - return err - } - if err := Convert_v1alpha1_PackageStatus_To_porch_PackageStatus(&in.Status, &out.Status, s); err != nil { - return err - } - return nil -} - -// Convert_v1alpha1_Package_To_porch_Package is an autogenerated conversion function. -func Convert_v1alpha1_Package_To_porch_Package(in *Package, out *porch.Package, s conversion.Scope) error { - return autoConvert_v1alpha1_Package_To_porch_Package(in, out, s) -} - -func autoConvert_porch_Package_To_v1alpha1_Package(in *porch.Package, out *Package, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_porch_PackageSpec_To_v1alpha1_PackageSpec(&in.Spec, &out.Spec, s); err != nil { - return err - } - if err := Convert_porch_PackageStatus_To_v1alpha1_PackageStatus(&in.Status, &out.Status, s); err != nil { - return err - } - return nil -} - -// Convert_porch_Package_To_v1alpha1_Package is an autogenerated conversion function. -func Convert_porch_Package_To_v1alpha1_Package(in *porch.Package, out *Package, s conversion.Scope) error { - return autoConvert_porch_Package_To_v1alpha1_Package(in, out, s) -} - -func autoConvert_v1alpha1_PackageCloneTaskSpec_To_porch_PackageCloneTaskSpec(in *PackageCloneTaskSpec, out *porch.PackageCloneTaskSpec, s conversion.Scope) error { - if err := Convert_v1alpha1_UpstreamPackage_To_porch_UpstreamPackage(&in.Upstream, &out.Upstream, s); err != nil { - return err - } - out.Strategy = porch.PackageMergeStrategy(in.Strategy) - return nil -} - -// Convert_v1alpha1_PackageCloneTaskSpec_To_porch_PackageCloneTaskSpec is an autogenerated conversion function. -func Convert_v1alpha1_PackageCloneTaskSpec_To_porch_PackageCloneTaskSpec(in *PackageCloneTaskSpec, out *porch.PackageCloneTaskSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_PackageCloneTaskSpec_To_porch_PackageCloneTaskSpec(in, out, s) -} - -func autoConvert_porch_PackageCloneTaskSpec_To_v1alpha1_PackageCloneTaskSpec(in *porch.PackageCloneTaskSpec, out *PackageCloneTaskSpec, s conversion.Scope) error { - if err := Convert_porch_UpstreamPackage_To_v1alpha1_UpstreamPackage(&in.Upstream, &out.Upstream, s); err != nil { - return err - } - out.Strategy = PackageMergeStrategy(in.Strategy) - return nil -} - -// Convert_porch_PackageCloneTaskSpec_To_v1alpha1_PackageCloneTaskSpec is an autogenerated conversion function. -func Convert_porch_PackageCloneTaskSpec_To_v1alpha1_PackageCloneTaskSpec(in *porch.PackageCloneTaskSpec, out *PackageCloneTaskSpec, s conversion.Scope) error { - return autoConvert_porch_PackageCloneTaskSpec_To_v1alpha1_PackageCloneTaskSpec(in, out, s) -} - -func autoConvert_v1alpha1_PackageEditTaskSpec_To_porch_PackageEditTaskSpec(in *PackageEditTaskSpec, out *porch.PackageEditTaskSpec, s conversion.Scope) error { - out.Source = (*porch.PackageRevisionRef)(unsafe.Pointer(in.Source)) - return nil -} - -// Convert_v1alpha1_PackageEditTaskSpec_To_porch_PackageEditTaskSpec is an autogenerated conversion function. -func Convert_v1alpha1_PackageEditTaskSpec_To_porch_PackageEditTaskSpec(in *PackageEditTaskSpec, out *porch.PackageEditTaskSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_PackageEditTaskSpec_To_porch_PackageEditTaskSpec(in, out, s) -} - -func autoConvert_porch_PackageEditTaskSpec_To_v1alpha1_PackageEditTaskSpec(in *porch.PackageEditTaskSpec, out *PackageEditTaskSpec, s conversion.Scope) error { - out.Source = (*PackageRevisionRef)(unsafe.Pointer(in.Source)) - return nil -} - -// Convert_porch_PackageEditTaskSpec_To_v1alpha1_PackageEditTaskSpec is an autogenerated conversion function. -func Convert_porch_PackageEditTaskSpec_To_v1alpha1_PackageEditTaskSpec(in *porch.PackageEditTaskSpec, out *PackageEditTaskSpec, s conversion.Scope) error { - return autoConvert_porch_PackageEditTaskSpec_To_v1alpha1_PackageEditTaskSpec(in, out, s) -} - -func autoConvert_v1alpha1_PackageInitTaskSpec_To_porch_PackageInitTaskSpec(in *PackageInitTaskSpec, out *porch.PackageInitTaskSpec, s conversion.Scope) error { - out.Subpackage = in.Subpackage - out.Description = in.Description - out.Keywords = *(*[]string)(unsafe.Pointer(&in.Keywords)) - out.Site = in.Site - return nil -} - -// Convert_v1alpha1_PackageInitTaskSpec_To_porch_PackageInitTaskSpec is an autogenerated conversion function. -func Convert_v1alpha1_PackageInitTaskSpec_To_porch_PackageInitTaskSpec(in *PackageInitTaskSpec, out *porch.PackageInitTaskSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_PackageInitTaskSpec_To_porch_PackageInitTaskSpec(in, out, s) -} - -func autoConvert_porch_PackageInitTaskSpec_To_v1alpha1_PackageInitTaskSpec(in *porch.PackageInitTaskSpec, out *PackageInitTaskSpec, s conversion.Scope) error { - out.Subpackage = in.Subpackage - out.Description = in.Description - out.Keywords = *(*[]string)(unsafe.Pointer(&in.Keywords)) - out.Site = in.Site - return nil -} - -// Convert_porch_PackageInitTaskSpec_To_v1alpha1_PackageInitTaskSpec is an autogenerated conversion function. -func Convert_porch_PackageInitTaskSpec_To_v1alpha1_PackageInitTaskSpec(in *porch.PackageInitTaskSpec, out *PackageInitTaskSpec, s conversion.Scope) error { - return autoConvert_porch_PackageInitTaskSpec_To_v1alpha1_PackageInitTaskSpec(in, out, s) -} - -func autoConvert_v1alpha1_PackageList_To_porch_PackageList(in *PackageList, out *porch.PackageList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - out.Items = *(*[]porch.Package)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_v1alpha1_PackageList_To_porch_PackageList is an autogenerated conversion function. -func Convert_v1alpha1_PackageList_To_porch_PackageList(in *PackageList, out *porch.PackageList, s conversion.Scope) error { - return autoConvert_v1alpha1_PackageList_To_porch_PackageList(in, out, s) -} - -func autoConvert_porch_PackageList_To_v1alpha1_PackageList(in *porch.PackageList, out *PackageList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - out.Items = *(*[]Package)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_porch_PackageList_To_v1alpha1_PackageList is an autogenerated conversion function. -func Convert_porch_PackageList_To_v1alpha1_PackageList(in *porch.PackageList, out *PackageList, s conversion.Scope) error { - return autoConvert_porch_PackageList_To_v1alpha1_PackageList(in, out, s) -} - -func autoConvert_v1alpha1_PackagePatchTaskSpec_To_porch_PackagePatchTaskSpec(in *PackagePatchTaskSpec, out *porch.PackagePatchTaskSpec, s conversion.Scope) error { - out.Patches = *(*[]porch.PatchSpec)(unsafe.Pointer(&in.Patches)) - return nil -} - -// Convert_v1alpha1_PackagePatchTaskSpec_To_porch_PackagePatchTaskSpec is an autogenerated conversion function. -func Convert_v1alpha1_PackagePatchTaskSpec_To_porch_PackagePatchTaskSpec(in *PackagePatchTaskSpec, out *porch.PackagePatchTaskSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_PackagePatchTaskSpec_To_porch_PackagePatchTaskSpec(in, out, s) -} - -func autoConvert_porch_PackagePatchTaskSpec_To_v1alpha1_PackagePatchTaskSpec(in *porch.PackagePatchTaskSpec, out *PackagePatchTaskSpec, s conversion.Scope) error { - out.Patches = *(*[]PatchSpec)(unsafe.Pointer(&in.Patches)) - return nil -} - -// Convert_porch_PackagePatchTaskSpec_To_v1alpha1_PackagePatchTaskSpec is an autogenerated conversion function. -func Convert_porch_PackagePatchTaskSpec_To_v1alpha1_PackagePatchTaskSpec(in *porch.PackagePatchTaskSpec, out *PackagePatchTaskSpec, s conversion.Scope) error { - return autoConvert_porch_PackagePatchTaskSpec_To_v1alpha1_PackagePatchTaskSpec(in, out, s) -} - -func autoConvert_v1alpha1_PackageRevision_To_porch_PackageRevision(in *PackageRevision, out *porch.PackageRevision, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_v1alpha1_PackageRevisionSpec_To_porch_PackageRevisionSpec(&in.Spec, &out.Spec, s); err != nil { - return err - } - if err := Convert_v1alpha1_PackageRevisionStatus_To_porch_PackageRevisionStatus(&in.Status, &out.Status, s); err != nil { - return err - } - return nil -} - -// Convert_v1alpha1_PackageRevision_To_porch_PackageRevision is an autogenerated conversion function. -func Convert_v1alpha1_PackageRevision_To_porch_PackageRevision(in *PackageRevision, out *porch.PackageRevision, s conversion.Scope) error { - return autoConvert_v1alpha1_PackageRevision_To_porch_PackageRevision(in, out, s) -} - -func autoConvert_porch_PackageRevision_To_v1alpha1_PackageRevision(in *porch.PackageRevision, out *PackageRevision, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_porch_PackageRevisionSpec_To_v1alpha1_PackageRevisionSpec(&in.Spec, &out.Spec, s); err != nil { - return err - } - if err := Convert_porch_PackageRevisionStatus_To_v1alpha1_PackageRevisionStatus(&in.Status, &out.Status, s); err != nil { - return err - } - return nil -} - -// Convert_porch_PackageRevision_To_v1alpha1_PackageRevision is an autogenerated conversion function. -func Convert_porch_PackageRevision_To_v1alpha1_PackageRevision(in *porch.PackageRevision, out *PackageRevision, s conversion.Scope) error { - return autoConvert_porch_PackageRevision_To_v1alpha1_PackageRevision(in, out, s) -} - -func autoConvert_v1alpha1_PackageRevisionList_To_porch_PackageRevisionList(in *PackageRevisionList, out *porch.PackageRevisionList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - out.Items = *(*[]porch.PackageRevision)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_v1alpha1_PackageRevisionList_To_porch_PackageRevisionList is an autogenerated conversion function. -func Convert_v1alpha1_PackageRevisionList_To_porch_PackageRevisionList(in *PackageRevisionList, out *porch.PackageRevisionList, s conversion.Scope) error { - return autoConvert_v1alpha1_PackageRevisionList_To_porch_PackageRevisionList(in, out, s) -} - -func autoConvert_porch_PackageRevisionList_To_v1alpha1_PackageRevisionList(in *porch.PackageRevisionList, out *PackageRevisionList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - out.Items = *(*[]PackageRevision)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_porch_PackageRevisionList_To_v1alpha1_PackageRevisionList is an autogenerated conversion function. -func Convert_porch_PackageRevisionList_To_v1alpha1_PackageRevisionList(in *porch.PackageRevisionList, out *PackageRevisionList, s conversion.Scope) error { - return autoConvert_porch_PackageRevisionList_To_v1alpha1_PackageRevisionList(in, out, s) -} - -func autoConvert_v1alpha1_PackageRevisionRef_To_porch_PackageRevisionRef(in *PackageRevisionRef, out *porch.PackageRevisionRef, s conversion.Scope) error { - out.Name = in.Name - return nil -} - -// Convert_v1alpha1_PackageRevisionRef_To_porch_PackageRevisionRef is an autogenerated conversion function. -func Convert_v1alpha1_PackageRevisionRef_To_porch_PackageRevisionRef(in *PackageRevisionRef, out *porch.PackageRevisionRef, s conversion.Scope) error { - return autoConvert_v1alpha1_PackageRevisionRef_To_porch_PackageRevisionRef(in, out, s) -} - -func autoConvert_porch_PackageRevisionRef_To_v1alpha1_PackageRevisionRef(in *porch.PackageRevisionRef, out *PackageRevisionRef, s conversion.Scope) error { - out.Name = in.Name - return nil -} - -// Convert_porch_PackageRevisionRef_To_v1alpha1_PackageRevisionRef is an autogenerated conversion function. -func Convert_porch_PackageRevisionRef_To_v1alpha1_PackageRevisionRef(in *porch.PackageRevisionRef, out *PackageRevisionRef, s conversion.Scope) error { - return autoConvert_porch_PackageRevisionRef_To_v1alpha1_PackageRevisionRef(in, out, s) -} - -func autoConvert_v1alpha1_PackageRevisionResources_To_porch_PackageRevisionResources(in *PackageRevisionResources, out *porch.PackageRevisionResources, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_v1alpha1_PackageRevisionResourcesSpec_To_porch_PackageRevisionResourcesSpec(&in.Spec, &out.Spec, s); err != nil { - return err - } - if err := Convert_v1alpha1_PackageRevisionResourcesStatus_To_porch_PackageRevisionResourcesStatus(&in.Status, &out.Status, s); err != nil { - return err - } - return nil -} - -// Convert_v1alpha1_PackageRevisionResources_To_porch_PackageRevisionResources is an autogenerated conversion function. -func Convert_v1alpha1_PackageRevisionResources_To_porch_PackageRevisionResources(in *PackageRevisionResources, out *porch.PackageRevisionResources, s conversion.Scope) error { - return autoConvert_v1alpha1_PackageRevisionResources_To_porch_PackageRevisionResources(in, out, s) -} - -func autoConvert_porch_PackageRevisionResources_To_v1alpha1_PackageRevisionResources(in *porch.PackageRevisionResources, out *PackageRevisionResources, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_porch_PackageRevisionResourcesSpec_To_v1alpha1_PackageRevisionResourcesSpec(&in.Spec, &out.Spec, s); err != nil { - return err - } - if err := Convert_porch_PackageRevisionResourcesStatus_To_v1alpha1_PackageRevisionResourcesStatus(&in.Status, &out.Status, s); err != nil { - return err - } - return nil -} - -// Convert_porch_PackageRevisionResources_To_v1alpha1_PackageRevisionResources is an autogenerated conversion function. -func Convert_porch_PackageRevisionResources_To_v1alpha1_PackageRevisionResources(in *porch.PackageRevisionResources, out *PackageRevisionResources, s conversion.Scope) error { - return autoConvert_porch_PackageRevisionResources_To_v1alpha1_PackageRevisionResources(in, out, s) -} - -func autoConvert_v1alpha1_PackageRevisionResourcesList_To_porch_PackageRevisionResourcesList(in *PackageRevisionResourcesList, out *porch.PackageRevisionResourcesList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - out.Items = *(*[]porch.PackageRevisionResources)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_v1alpha1_PackageRevisionResourcesList_To_porch_PackageRevisionResourcesList is an autogenerated conversion function. -func Convert_v1alpha1_PackageRevisionResourcesList_To_porch_PackageRevisionResourcesList(in *PackageRevisionResourcesList, out *porch.PackageRevisionResourcesList, s conversion.Scope) error { - return autoConvert_v1alpha1_PackageRevisionResourcesList_To_porch_PackageRevisionResourcesList(in, out, s) -} - -func autoConvert_porch_PackageRevisionResourcesList_To_v1alpha1_PackageRevisionResourcesList(in *porch.PackageRevisionResourcesList, out *PackageRevisionResourcesList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - out.Items = *(*[]PackageRevisionResources)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_porch_PackageRevisionResourcesList_To_v1alpha1_PackageRevisionResourcesList is an autogenerated conversion function. -func Convert_porch_PackageRevisionResourcesList_To_v1alpha1_PackageRevisionResourcesList(in *porch.PackageRevisionResourcesList, out *PackageRevisionResourcesList, s conversion.Scope) error { - return autoConvert_porch_PackageRevisionResourcesList_To_v1alpha1_PackageRevisionResourcesList(in, out, s) -} - -func autoConvert_v1alpha1_PackageRevisionResourcesSpec_To_porch_PackageRevisionResourcesSpec(in *PackageRevisionResourcesSpec, out *porch.PackageRevisionResourcesSpec, s conversion.Scope) error { - out.PackageName = in.PackageName - out.WorkspaceName = porch.WorkspaceName(in.WorkspaceName) - out.Revision = in.Revision - out.RepositoryName = in.RepositoryName - out.Resources = *(*map[string]string)(unsafe.Pointer(&in.Resources)) - return nil -} - -// Convert_v1alpha1_PackageRevisionResourcesSpec_To_porch_PackageRevisionResourcesSpec is an autogenerated conversion function. -func Convert_v1alpha1_PackageRevisionResourcesSpec_To_porch_PackageRevisionResourcesSpec(in *PackageRevisionResourcesSpec, out *porch.PackageRevisionResourcesSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_PackageRevisionResourcesSpec_To_porch_PackageRevisionResourcesSpec(in, out, s) -} - -func autoConvert_porch_PackageRevisionResourcesSpec_To_v1alpha1_PackageRevisionResourcesSpec(in *porch.PackageRevisionResourcesSpec, out *PackageRevisionResourcesSpec, s conversion.Scope) error { - out.PackageName = in.PackageName - out.WorkspaceName = WorkspaceName(in.WorkspaceName) - out.Revision = in.Revision - out.RepositoryName = in.RepositoryName - out.Resources = *(*map[string]string)(unsafe.Pointer(&in.Resources)) - return nil -} - -// Convert_porch_PackageRevisionResourcesSpec_To_v1alpha1_PackageRevisionResourcesSpec is an autogenerated conversion function. -func Convert_porch_PackageRevisionResourcesSpec_To_v1alpha1_PackageRevisionResourcesSpec(in *porch.PackageRevisionResourcesSpec, out *PackageRevisionResourcesSpec, s conversion.Scope) error { - return autoConvert_porch_PackageRevisionResourcesSpec_To_v1alpha1_PackageRevisionResourcesSpec(in, out, s) -} - -func autoConvert_v1alpha1_PackageRevisionResourcesStatus_To_porch_PackageRevisionResourcesStatus(in *PackageRevisionResourcesStatus, out *porch.PackageRevisionResourcesStatus, s conversion.Scope) error { - if err := Convert_v1alpha1_RenderStatus_To_porch_RenderStatus(&in.RenderStatus, &out.RenderStatus, s); err != nil { - return err - } - return nil -} - -// Convert_v1alpha1_PackageRevisionResourcesStatus_To_porch_PackageRevisionResourcesStatus is an autogenerated conversion function. -func Convert_v1alpha1_PackageRevisionResourcesStatus_To_porch_PackageRevisionResourcesStatus(in *PackageRevisionResourcesStatus, out *porch.PackageRevisionResourcesStatus, s conversion.Scope) error { - return autoConvert_v1alpha1_PackageRevisionResourcesStatus_To_porch_PackageRevisionResourcesStatus(in, out, s) -} - -func autoConvert_porch_PackageRevisionResourcesStatus_To_v1alpha1_PackageRevisionResourcesStatus(in *porch.PackageRevisionResourcesStatus, out *PackageRevisionResourcesStatus, s conversion.Scope) error { - if err := Convert_porch_RenderStatus_To_v1alpha1_RenderStatus(&in.RenderStatus, &out.RenderStatus, s); err != nil { - return err - } - return nil -} - -// Convert_porch_PackageRevisionResourcesStatus_To_v1alpha1_PackageRevisionResourcesStatus is an autogenerated conversion function. -func Convert_porch_PackageRevisionResourcesStatus_To_v1alpha1_PackageRevisionResourcesStatus(in *porch.PackageRevisionResourcesStatus, out *PackageRevisionResourcesStatus, s conversion.Scope) error { - return autoConvert_porch_PackageRevisionResourcesStatus_To_v1alpha1_PackageRevisionResourcesStatus(in, out, s) -} - -func autoConvert_v1alpha1_PackageRevisionSpec_To_porch_PackageRevisionSpec(in *PackageRevisionSpec, out *porch.PackageRevisionSpec, s conversion.Scope) error { - out.PackageName = in.PackageName - out.RepositoryName = in.RepositoryName - out.WorkspaceName = porch.WorkspaceName(in.WorkspaceName) - out.Revision = in.Revision - out.Parent = (*porch.ParentReference)(unsafe.Pointer(in.Parent)) - out.Lifecycle = porch.PackageRevisionLifecycle(in.Lifecycle) - out.Tasks = *(*[]porch.Task)(unsafe.Pointer(&in.Tasks)) - out.ReadinessGates = *(*[]porch.ReadinessGate)(unsafe.Pointer(&in.ReadinessGates)) - return nil -} - -// Convert_v1alpha1_PackageRevisionSpec_To_porch_PackageRevisionSpec is an autogenerated conversion function. -func Convert_v1alpha1_PackageRevisionSpec_To_porch_PackageRevisionSpec(in *PackageRevisionSpec, out *porch.PackageRevisionSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_PackageRevisionSpec_To_porch_PackageRevisionSpec(in, out, s) -} - -func autoConvert_porch_PackageRevisionSpec_To_v1alpha1_PackageRevisionSpec(in *porch.PackageRevisionSpec, out *PackageRevisionSpec, s conversion.Scope) error { - out.PackageName = in.PackageName - out.RepositoryName = in.RepositoryName - out.WorkspaceName = WorkspaceName(in.WorkspaceName) - out.Revision = in.Revision - out.Parent = (*ParentReference)(unsafe.Pointer(in.Parent)) - out.Lifecycle = PackageRevisionLifecycle(in.Lifecycle) - out.Tasks = *(*[]Task)(unsafe.Pointer(&in.Tasks)) - out.ReadinessGates = *(*[]ReadinessGate)(unsafe.Pointer(&in.ReadinessGates)) - return nil -} - -// Convert_porch_PackageRevisionSpec_To_v1alpha1_PackageRevisionSpec is an autogenerated conversion function. -func Convert_porch_PackageRevisionSpec_To_v1alpha1_PackageRevisionSpec(in *porch.PackageRevisionSpec, out *PackageRevisionSpec, s conversion.Scope) error { - return autoConvert_porch_PackageRevisionSpec_To_v1alpha1_PackageRevisionSpec(in, out, s) -} - -func autoConvert_v1alpha1_PackageRevisionStatus_To_porch_PackageRevisionStatus(in *PackageRevisionStatus, out *porch.PackageRevisionStatus, s conversion.Scope) error { - out.UpstreamLock = (*porch.UpstreamLock)(unsafe.Pointer(in.UpstreamLock)) - out.PublishedBy = in.PublishedBy - out.PublishedAt = in.PublishedAt - out.Deployment = in.Deployment - out.Conditions = *(*[]porch.Condition)(unsafe.Pointer(&in.Conditions)) - return nil -} - -// Convert_v1alpha1_PackageRevisionStatus_To_porch_PackageRevisionStatus is an autogenerated conversion function. -func Convert_v1alpha1_PackageRevisionStatus_To_porch_PackageRevisionStatus(in *PackageRevisionStatus, out *porch.PackageRevisionStatus, s conversion.Scope) error { - return autoConvert_v1alpha1_PackageRevisionStatus_To_porch_PackageRevisionStatus(in, out, s) -} - -func autoConvert_porch_PackageRevisionStatus_To_v1alpha1_PackageRevisionStatus(in *porch.PackageRevisionStatus, out *PackageRevisionStatus, s conversion.Scope) error { - out.UpstreamLock = (*UpstreamLock)(unsafe.Pointer(in.UpstreamLock)) - out.PublishedBy = in.PublishedBy - out.PublishedAt = in.PublishedAt - out.Deployment = in.Deployment - out.Conditions = *(*[]Condition)(unsafe.Pointer(&in.Conditions)) - return nil -} - -// Convert_porch_PackageRevisionStatus_To_v1alpha1_PackageRevisionStatus is an autogenerated conversion function. -func Convert_porch_PackageRevisionStatus_To_v1alpha1_PackageRevisionStatus(in *porch.PackageRevisionStatus, out *PackageRevisionStatus, s conversion.Scope) error { - return autoConvert_porch_PackageRevisionStatus_To_v1alpha1_PackageRevisionStatus(in, out, s) -} - -func autoConvert_v1alpha1_PackageSpec_To_porch_PackageSpec(in *PackageSpec, out *porch.PackageSpec, s conversion.Scope) error { - out.PackageName = in.PackageName - out.RepositoryName = in.RepositoryName - return nil -} - -// Convert_v1alpha1_PackageSpec_To_porch_PackageSpec is an autogenerated conversion function. -func Convert_v1alpha1_PackageSpec_To_porch_PackageSpec(in *PackageSpec, out *porch.PackageSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_PackageSpec_To_porch_PackageSpec(in, out, s) -} - -func autoConvert_porch_PackageSpec_To_v1alpha1_PackageSpec(in *porch.PackageSpec, out *PackageSpec, s conversion.Scope) error { - out.PackageName = in.PackageName - out.RepositoryName = in.RepositoryName - return nil -} - -// Convert_porch_PackageSpec_To_v1alpha1_PackageSpec is an autogenerated conversion function. -func Convert_porch_PackageSpec_To_v1alpha1_PackageSpec(in *porch.PackageSpec, out *PackageSpec, s conversion.Scope) error { - return autoConvert_porch_PackageSpec_To_v1alpha1_PackageSpec(in, out, s) -} - -func autoConvert_v1alpha1_PackageStatus_To_porch_PackageStatus(in *PackageStatus, out *porch.PackageStatus, s conversion.Scope) error { - out.LatestRevision = in.LatestRevision - return nil -} - -// Convert_v1alpha1_PackageStatus_To_porch_PackageStatus is an autogenerated conversion function. -func Convert_v1alpha1_PackageStatus_To_porch_PackageStatus(in *PackageStatus, out *porch.PackageStatus, s conversion.Scope) error { - return autoConvert_v1alpha1_PackageStatus_To_porch_PackageStatus(in, out, s) -} - -func autoConvert_porch_PackageStatus_To_v1alpha1_PackageStatus(in *porch.PackageStatus, out *PackageStatus, s conversion.Scope) error { - out.LatestRevision = in.LatestRevision - return nil -} - -// Convert_porch_PackageStatus_To_v1alpha1_PackageStatus is an autogenerated conversion function. -func Convert_porch_PackageStatus_To_v1alpha1_PackageStatus(in *porch.PackageStatus, out *PackageStatus, s conversion.Scope) error { - return autoConvert_porch_PackageStatus_To_v1alpha1_PackageStatus(in, out, s) -} - -func autoConvert_v1alpha1_PackageUpdateTaskSpec_To_porch_PackageUpdateTaskSpec(in *PackageUpdateTaskSpec, out *porch.PackageUpdateTaskSpec, s conversion.Scope) error { - if err := Convert_v1alpha1_UpstreamPackage_To_porch_UpstreamPackage(&in.Upstream, &out.Upstream, s); err != nil { - return err - } - return nil -} - -// Convert_v1alpha1_PackageUpdateTaskSpec_To_porch_PackageUpdateTaskSpec is an autogenerated conversion function. -func Convert_v1alpha1_PackageUpdateTaskSpec_To_porch_PackageUpdateTaskSpec(in *PackageUpdateTaskSpec, out *porch.PackageUpdateTaskSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_PackageUpdateTaskSpec_To_porch_PackageUpdateTaskSpec(in, out, s) -} - -func autoConvert_porch_PackageUpdateTaskSpec_To_v1alpha1_PackageUpdateTaskSpec(in *porch.PackageUpdateTaskSpec, out *PackageUpdateTaskSpec, s conversion.Scope) error { - if err := Convert_porch_UpstreamPackage_To_v1alpha1_UpstreamPackage(&in.Upstream, &out.Upstream, s); err != nil { - return err - } - return nil -} - -// Convert_porch_PackageUpdateTaskSpec_To_v1alpha1_PackageUpdateTaskSpec is an autogenerated conversion function. -func Convert_porch_PackageUpdateTaskSpec_To_v1alpha1_PackageUpdateTaskSpec(in *porch.PackageUpdateTaskSpec, out *PackageUpdateTaskSpec, s conversion.Scope) error { - return autoConvert_porch_PackageUpdateTaskSpec_To_v1alpha1_PackageUpdateTaskSpec(in, out, s) -} - -func autoConvert_v1alpha1_ParentReference_To_porch_ParentReference(in *ParentReference, out *porch.ParentReference, s conversion.Scope) error { - out.Name = in.Name - return nil -} - -// Convert_v1alpha1_ParentReference_To_porch_ParentReference is an autogenerated conversion function. -func Convert_v1alpha1_ParentReference_To_porch_ParentReference(in *ParentReference, out *porch.ParentReference, s conversion.Scope) error { - return autoConvert_v1alpha1_ParentReference_To_porch_ParentReference(in, out, s) -} - -func autoConvert_porch_ParentReference_To_v1alpha1_ParentReference(in *porch.ParentReference, out *ParentReference, s conversion.Scope) error { - out.Name = in.Name - return nil -} - -// Convert_porch_ParentReference_To_v1alpha1_ParentReference is an autogenerated conversion function. -func Convert_porch_ParentReference_To_v1alpha1_ParentReference(in *porch.ParentReference, out *ParentReference, s conversion.Scope) error { - return autoConvert_porch_ParentReference_To_v1alpha1_ParentReference(in, out, s) -} - -func autoConvert_v1alpha1_PatchSpec_To_porch_PatchSpec(in *PatchSpec, out *porch.PatchSpec, s conversion.Scope) error { - out.File = in.File - out.Contents = in.Contents - out.PatchType = porch.PatchType(in.PatchType) - return nil -} - -// Convert_v1alpha1_PatchSpec_To_porch_PatchSpec is an autogenerated conversion function. -func Convert_v1alpha1_PatchSpec_To_porch_PatchSpec(in *PatchSpec, out *porch.PatchSpec, s conversion.Scope) error { - return autoConvert_v1alpha1_PatchSpec_To_porch_PatchSpec(in, out, s) -} - -func autoConvert_porch_PatchSpec_To_v1alpha1_PatchSpec(in *porch.PatchSpec, out *PatchSpec, s conversion.Scope) error { - out.File = in.File - out.Contents = in.Contents - out.PatchType = PatchType(in.PatchType) - return nil -} - -// Convert_porch_PatchSpec_To_v1alpha1_PatchSpec is an autogenerated conversion function. -func Convert_porch_PatchSpec_To_v1alpha1_PatchSpec(in *porch.PatchSpec, out *PatchSpec, s conversion.Scope) error { - return autoConvert_porch_PatchSpec_To_v1alpha1_PatchSpec(in, out, s) -} - -func autoConvert_v1alpha1_ReadinessGate_To_porch_ReadinessGate(in *ReadinessGate, out *porch.ReadinessGate, s conversion.Scope) error { - out.ConditionType = in.ConditionType - return nil -} - -// Convert_v1alpha1_ReadinessGate_To_porch_ReadinessGate is an autogenerated conversion function. -func Convert_v1alpha1_ReadinessGate_To_porch_ReadinessGate(in *ReadinessGate, out *porch.ReadinessGate, s conversion.Scope) error { - return autoConvert_v1alpha1_ReadinessGate_To_porch_ReadinessGate(in, out, s) -} - -func autoConvert_porch_ReadinessGate_To_v1alpha1_ReadinessGate(in *porch.ReadinessGate, out *ReadinessGate, s conversion.Scope) error { - out.ConditionType = in.ConditionType - return nil -} - -// Convert_porch_ReadinessGate_To_v1alpha1_ReadinessGate is an autogenerated conversion function. -func Convert_porch_ReadinessGate_To_v1alpha1_ReadinessGate(in *porch.ReadinessGate, out *ReadinessGate, s conversion.Scope) error { - return autoConvert_porch_ReadinessGate_To_v1alpha1_ReadinessGate(in, out, s) -} - -func autoConvert_v1alpha1_RenderStatus_To_porch_RenderStatus(in *RenderStatus, out *porch.RenderStatus, s conversion.Scope) error { - if err := Convert_v1alpha1_ResultList_To_porch_ResultList(&in.Result, &out.Result, s); err != nil { - return err - } - out.Err = in.Err - return nil -} - -// Convert_v1alpha1_RenderStatus_To_porch_RenderStatus is an autogenerated conversion function. -func Convert_v1alpha1_RenderStatus_To_porch_RenderStatus(in *RenderStatus, out *porch.RenderStatus, s conversion.Scope) error { - return autoConvert_v1alpha1_RenderStatus_To_porch_RenderStatus(in, out, s) -} - -func autoConvert_porch_RenderStatus_To_v1alpha1_RenderStatus(in *porch.RenderStatus, out *RenderStatus, s conversion.Scope) error { - if err := Convert_porch_ResultList_To_v1alpha1_ResultList(&in.Result, &out.Result, s); err != nil { - return err - } - out.Err = in.Err - return nil -} - -// Convert_porch_RenderStatus_To_v1alpha1_RenderStatus is an autogenerated conversion function. -func Convert_porch_RenderStatus_To_v1alpha1_RenderStatus(in *porch.RenderStatus, out *RenderStatus, s conversion.Scope) error { - return autoConvert_porch_RenderStatus_To_v1alpha1_RenderStatus(in, out, s) -} - -func autoConvert_v1alpha1_RepositoryRef_To_porch_RepositoryRef(in *RepositoryRef, out *porch.RepositoryRef, s conversion.Scope) error { - out.Name = in.Name - return nil -} - -// Convert_v1alpha1_RepositoryRef_To_porch_RepositoryRef is an autogenerated conversion function. -func Convert_v1alpha1_RepositoryRef_To_porch_RepositoryRef(in *RepositoryRef, out *porch.RepositoryRef, s conversion.Scope) error { - return autoConvert_v1alpha1_RepositoryRef_To_porch_RepositoryRef(in, out, s) -} - -func autoConvert_porch_RepositoryRef_To_v1alpha1_RepositoryRef(in *porch.RepositoryRef, out *RepositoryRef, s conversion.Scope) error { - out.Name = in.Name - return nil -} - -// Convert_porch_RepositoryRef_To_v1alpha1_RepositoryRef is an autogenerated conversion function. -func Convert_porch_RepositoryRef_To_v1alpha1_RepositoryRef(in *porch.RepositoryRef, out *RepositoryRef, s conversion.Scope) error { - return autoConvert_porch_RepositoryRef_To_v1alpha1_RepositoryRef(in, out, s) -} - -func autoConvert_v1alpha1_ResourceIdentifier_To_porch_ResourceIdentifier(in *ResourceIdentifier, out *porch.ResourceIdentifier, s conversion.Scope) error { - if err := Convert_v1alpha1_NameMeta_To_porch_NameMeta(&in.NameMeta, &out.NameMeta, s); err != nil { - return err - } - return nil -} - -// Convert_v1alpha1_ResourceIdentifier_To_porch_ResourceIdentifier is an autogenerated conversion function. -func Convert_v1alpha1_ResourceIdentifier_To_porch_ResourceIdentifier(in *ResourceIdentifier, out *porch.ResourceIdentifier, s conversion.Scope) error { - return autoConvert_v1alpha1_ResourceIdentifier_To_porch_ResourceIdentifier(in, out, s) -} - -func autoConvert_porch_ResourceIdentifier_To_v1alpha1_ResourceIdentifier(in *porch.ResourceIdentifier, out *ResourceIdentifier, s conversion.Scope) error { - if err := Convert_porch_NameMeta_To_v1alpha1_NameMeta(&in.NameMeta, &out.NameMeta, s); err != nil { - return err - } - return nil -} - -// Convert_porch_ResourceIdentifier_To_v1alpha1_ResourceIdentifier is an autogenerated conversion function. -func Convert_porch_ResourceIdentifier_To_v1alpha1_ResourceIdentifier(in *porch.ResourceIdentifier, out *ResourceIdentifier, s conversion.Scope) error { - return autoConvert_porch_ResourceIdentifier_To_v1alpha1_ResourceIdentifier(in, out, s) -} - -func autoConvert_v1alpha1_Result_To_porch_Result(in *Result, out *porch.Result, s conversion.Scope) error { - out.Image = in.Image - out.ExecPath = in.ExecPath - out.Stderr = in.Stderr - out.ExitCode = in.ExitCode - out.Results = *(*[]porch.ResultItem)(unsafe.Pointer(&in.Results)) - return nil -} - -// Convert_v1alpha1_Result_To_porch_Result is an autogenerated conversion function. -func Convert_v1alpha1_Result_To_porch_Result(in *Result, out *porch.Result, s conversion.Scope) error { - return autoConvert_v1alpha1_Result_To_porch_Result(in, out, s) -} - -func autoConvert_porch_Result_To_v1alpha1_Result(in *porch.Result, out *Result, s conversion.Scope) error { - out.Image = in.Image - out.ExecPath = in.ExecPath - out.Stderr = in.Stderr - out.ExitCode = in.ExitCode - out.Results = *(*[]ResultItem)(unsafe.Pointer(&in.Results)) - return nil -} - -// Convert_porch_Result_To_v1alpha1_Result is an autogenerated conversion function. -func Convert_porch_Result_To_v1alpha1_Result(in *porch.Result, out *Result, s conversion.Scope) error { - return autoConvert_porch_Result_To_v1alpha1_Result(in, out, s) -} - -func autoConvert_v1alpha1_ResultItem_To_porch_ResultItem(in *ResultItem, out *porch.ResultItem, s conversion.Scope) error { - out.Message = in.Message - out.Severity = in.Severity - out.ResourceRef = (*porch.ResourceIdentifier)(unsafe.Pointer(in.ResourceRef)) - out.Field = (*porch.Field)(unsafe.Pointer(in.Field)) - out.File = (*porch.File)(unsafe.Pointer(in.File)) - out.Tags = *(*map[string]string)(unsafe.Pointer(&in.Tags)) - return nil -} - -// Convert_v1alpha1_ResultItem_To_porch_ResultItem is an autogenerated conversion function. -func Convert_v1alpha1_ResultItem_To_porch_ResultItem(in *ResultItem, out *porch.ResultItem, s conversion.Scope) error { - return autoConvert_v1alpha1_ResultItem_To_porch_ResultItem(in, out, s) -} - -func autoConvert_porch_ResultItem_To_v1alpha1_ResultItem(in *porch.ResultItem, out *ResultItem, s conversion.Scope) error { - out.Message = in.Message - out.Severity = in.Severity - out.ResourceRef = (*ResourceIdentifier)(unsafe.Pointer(in.ResourceRef)) - out.Field = (*Field)(unsafe.Pointer(in.Field)) - out.File = (*File)(unsafe.Pointer(in.File)) - out.Tags = *(*map[string]string)(unsafe.Pointer(&in.Tags)) - return nil -} - -// Convert_porch_ResultItem_To_v1alpha1_ResultItem is an autogenerated conversion function. -func Convert_porch_ResultItem_To_v1alpha1_ResultItem(in *porch.ResultItem, out *ResultItem, s conversion.Scope) error { - return autoConvert_porch_ResultItem_To_v1alpha1_ResultItem(in, out, s) -} - -func autoConvert_v1alpha1_ResultList_To_porch_ResultList(in *ResultList, out *porch.ResultList, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - out.ExitCode = in.ExitCode - out.Items = *(*[]*porch.Result)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_v1alpha1_ResultList_To_porch_ResultList is an autogenerated conversion function. -func Convert_v1alpha1_ResultList_To_porch_ResultList(in *ResultList, out *porch.ResultList, s conversion.Scope) error { - return autoConvert_v1alpha1_ResultList_To_porch_ResultList(in, out, s) -} - -func autoConvert_porch_ResultList_To_v1alpha1_ResultList(in *porch.ResultList, out *ResultList, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - out.ExitCode = in.ExitCode - out.Items = *(*[]*Result)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_porch_ResultList_To_v1alpha1_ResultList is an autogenerated conversion function. -func Convert_porch_ResultList_To_v1alpha1_ResultList(in *porch.ResultList, out *ResultList, s conversion.Scope) error { - return autoConvert_porch_ResultList_To_v1alpha1_ResultList(in, out, s) -} - -func autoConvert_v1alpha1_SecretRef_To_porch_SecretRef(in *SecretRef, out *porch.SecretRef, s conversion.Scope) error { - out.Name = in.Name - return nil -} - -// Convert_v1alpha1_SecretRef_To_porch_SecretRef is an autogenerated conversion function. -func Convert_v1alpha1_SecretRef_To_porch_SecretRef(in *SecretRef, out *porch.SecretRef, s conversion.Scope) error { - return autoConvert_v1alpha1_SecretRef_To_porch_SecretRef(in, out, s) -} - -func autoConvert_porch_SecretRef_To_v1alpha1_SecretRef(in *porch.SecretRef, out *SecretRef, s conversion.Scope) error { - out.Name = in.Name - return nil -} - -// Convert_porch_SecretRef_To_v1alpha1_SecretRef is an autogenerated conversion function. -func Convert_porch_SecretRef_To_v1alpha1_SecretRef(in *porch.SecretRef, out *SecretRef, s conversion.Scope) error { - return autoConvert_porch_SecretRef_To_v1alpha1_SecretRef(in, out, s) -} - -func autoConvert_v1alpha1_Selector_To_porch_Selector(in *Selector, out *porch.Selector, s conversion.Scope) error { - out.APIVersion = in.APIVersion - out.Kind = in.Kind - out.Name = in.Name - out.Namespace = in.Namespace - return nil -} - -// Convert_v1alpha1_Selector_To_porch_Selector is an autogenerated conversion function. -func Convert_v1alpha1_Selector_To_porch_Selector(in *Selector, out *porch.Selector, s conversion.Scope) error { - return autoConvert_v1alpha1_Selector_To_porch_Selector(in, out, s) -} - -func autoConvert_porch_Selector_To_v1alpha1_Selector(in *porch.Selector, out *Selector, s conversion.Scope) error { - out.APIVersion = in.APIVersion - out.Kind = in.Kind - out.Name = in.Name - out.Namespace = in.Namespace - return nil -} - -// Convert_porch_Selector_To_v1alpha1_Selector is an autogenerated conversion function. -func Convert_porch_Selector_To_v1alpha1_Selector(in *porch.Selector, out *Selector, s conversion.Scope) error { - return autoConvert_porch_Selector_To_v1alpha1_Selector(in, out, s) -} - -func autoConvert_v1alpha1_Task_To_porch_Task(in *Task, out *porch.Task, s conversion.Scope) error { - out.Type = porch.TaskType(in.Type) - out.Init = (*porch.PackageInitTaskSpec)(unsafe.Pointer(in.Init)) - out.Clone = (*porch.PackageCloneTaskSpec)(unsafe.Pointer(in.Clone)) - out.Patch = (*porch.PackagePatchTaskSpec)(unsafe.Pointer(in.Patch)) - out.Edit = (*porch.PackageEditTaskSpec)(unsafe.Pointer(in.Edit)) - out.Eval = (*porch.FunctionEvalTaskSpec)(unsafe.Pointer(in.Eval)) - out.Update = (*porch.PackageUpdateTaskSpec)(unsafe.Pointer(in.Update)) - return nil -} - -// Convert_v1alpha1_Task_To_porch_Task is an autogenerated conversion function. -func Convert_v1alpha1_Task_To_porch_Task(in *Task, out *porch.Task, s conversion.Scope) error { - return autoConvert_v1alpha1_Task_To_porch_Task(in, out, s) -} - -func autoConvert_porch_Task_To_v1alpha1_Task(in *porch.Task, out *Task, s conversion.Scope) error { - out.Type = TaskType(in.Type) - out.Init = (*PackageInitTaskSpec)(unsafe.Pointer(in.Init)) - out.Clone = (*PackageCloneTaskSpec)(unsafe.Pointer(in.Clone)) - out.Patch = (*PackagePatchTaskSpec)(unsafe.Pointer(in.Patch)) - out.Edit = (*PackageEditTaskSpec)(unsafe.Pointer(in.Edit)) - out.Eval = (*FunctionEvalTaskSpec)(unsafe.Pointer(in.Eval)) - out.Update = (*PackageUpdateTaskSpec)(unsafe.Pointer(in.Update)) - return nil -} - -// Convert_porch_Task_To_v1alpha1_Task is an autogenerated conversion function. -func Convert_porch_Task_To_v1alpha1_Task(in *porch.Task, out *Task, s conversion.Scope) error { - return autoConvert_porch_Task_To_v1alpha1_Task(in, out, s) -} - -func autoConvert_v1alpha1_TaskResult_To_porch_TaskResult(in *TaskResult, out *porch.TaskResult, s conversion.Scope) error { - out.Task = (*porch.Task)(unsafe.Pointer(in.Task)) - out.RenderStatus = (*porch.RenderStatus)(unsafe.Pointer(in.RenderStatus)) - return nil -} - -// Convert_v1alpha1_TaskResult_To_porch_TaskResult is an autogenerated conversion function. -func Convert_v1alpha1_TaskResult_To_porch_TaskResult(in *TaskResult, out *porch.TaskResult, s conversion.Scope) error { - return autoConvert_v1alpha1_TaskResult_To_porch_TaskResult(in, out, s) -} - -func autoConvert_porch_TaskResult_To_v1alpha1_TaskResult(in *porch.TaskResult, out *TaskResult, s conversion.Scope) error { - out.Task = (*Task)(unsafe.Pointer(in.Task)) - out.RenderStatus = (*RenderStatus)(unsafe.Pointer(in.RenderStatus)) - return nil -} - -// Convert_porch_TaskResult_To_v1alpha1_TaskResult is an autogenerated conversion function. -func Convert_porch_TaskResult_To_v1alpha1_TaskResult(in *porch.TaskResult, out *TaskResult, s conversion.Scope) error { - return autoConvert_porch_TaskResult_To_v1alpha1_TaskResult(in, out, s) -} - -func autoConvert_v1alpha1_UpstreamLock_To_porch_UpstreamLock(in *UpstreamLock, out *porch.UpstreamLock, s conversion.Scope) error { - out.Type = porch.OriginType(in.Type) - out.Git = (*porch.GitLock)(unsafe.Pointer(in.Git)) - return nil -} - -// Convert_v1alpha1_UpstreamLock_To_porch_UpstreamLock is an autogenerated conversion function. -func Convert_v1alpha1_UpstreamLock_To_porch_UpstreamLock(in *UpstreamLock, out *porch.UpstreamLock, s conversion.Scope) error { - return autoConvert_v1alpha1_UpstreamLock_To_porch_UpstreamLock(in, out, s) -} - -func autoConvert_porch_UpstreamLock_To_v1alpha1_UpstreamLock(in *porch.UpstreamLock, out *UpstreamLock, s conversion.Scope) error { - out.Type = OriginType(in.Type) - out.Git = (*GitLock)(unsafe.Pointer(in.Git)) - return nil -} - -// Convert_porch_UpstreamLock_To_v1alpha1_UpstreamLock is an autogenerated conversion function. -func Convert_porch_UpstreamLock_To_v1alpha1_UpstreamLock(in *porch.UpstreamLock, out *UpstreamLock, s conversion.Scope) error { - return autoConvert_porch_UpstreamLock_To_v1alpha1_UpstreamLock(in, out, s) -} - -func autoConvert_v1alpha1_UpstreamPackage_To_porch_UpstreamPackage(in *UpstreamPackage, out *porch.UpstreamPackage, s conversion.Scope) error { - out.Type = porch.RepositoryType(in.Type) - out.Git = (*porch.GitPackage)(unsafe.Pointer(in.Git)) - out.Oci = (*porch.OciPackage)(unsafe.Pointer(in.Oci)) - out.UpstreamRef = (*porch.PackageRevisionRef)(unsafe.Pointer(in.UpstreamRef)) - return nil -} - -// Convert_v1alpha1_UpstreamPackage_To_porch_UpstreamPackage is an autogenerated conversion function. -func Convert_v1alpha1_UpstreamPackage_To_porch_UpstreamPackage(in *UpstreamPackage, out *porch.UpstreamPackage, s conversion.Scope) error { - return autoConvert_v1alpha1_UpstreamPackage_To_porch_UpstreamPackage(in, out, s) -} - -func autoConvert_porch_UpstreamPackage_To_v1alpha1_UpstreamPackage(in *porch.UpstreamPackage, out *UpstreamPackage, s conversion.Scope) error { - out.Type = RepositoryType(in.Type) - out.Git = (*GitPackage)(unsafe.Pointer(in.Git)) - out.Oci = (*OciPackage)(unsafe.Pointer(in.Oci)) - out.UpstreamRef = (*PackageRevisionRef)(unsafe.Pointer(in.UpstreamRef)) - return nil -} - -// Convert_porch_UpstreamPackage_To_v1alpha1_UpstreamPackage is an autogenerated conversion function. -func Convert_porch_UpstreamPackage_To_v1alpha1_UpstreamPackage(in *porch.UpstreamPackage, out *UpstreamPackage, s conversion.Scope) error { - return autoConvert_porch_UpstreamPackage_To_v1alpha1_UpstreamPackage(in, out, s) -} diff --git a/porch/api/porch/v1alpha1/zz_generated.deepcopy.go b/porch/api/porch/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index 3b79fb0c74..0000000000 --- a/porch/api/porch/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,1089 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// Copyright 2023 The kpt 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 deepcopy-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Condition) DeepCopyInto(out *Condition) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition. -func (in *Condition) DeepCopy() *Condition { - if in == nil { - return nil - } - out := new(Condition) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Field) DeepCopyInto(out *Field) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Field. -func (in *Field) DeepCopy() *Field { - if in == nil { - return nil - } - out := new(Field) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *File) DeepCopyInto(out *File) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new File. -func (in *File) DeepCopy() *File { - if in == nil { - return nil - } - out := new(File) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Function) DeepCopyInto(out *Function) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - out.Status = in.Status - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Function. -func (in *Function) DeepCopy() *Function { - if in == nil { - return nil - } - out := new(Function) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Function) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionConfig) DeepCopyInto(out *FunctionConfig) { - *out = *in - out.TypeMeta = in.TypeMeta - if in.RequiredFields != nil { - in, out := &in.RequiredFields, &out.RequiredFields - *out = make([]string, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionConfig. -func (in *FunctionConfig) DeepCopy() *FunctionConfig { - if in == nil { - return nil - } - out := new(FunctionConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionEvalTaskSpec) DeepCopyInto(out *FunctionEvalTaskSpec) { - *out = *in - if in.FunctionRef != nil { - in, out := &in.FunctionRef, &out.FunctionRef - *out = new(FunctionRef) - **out = **in - } - if in.ConfigMap != nil { - in, out := &in.ConfigMap, &out.ConfigMap - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - in.Config.DeepCopyInto(&out.Config) - out.Match = in.Match - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionEvalTaskSpec. -func (in *FunctionEvalTaskSpec) DeepCopy() *FunctionEvalTaskSpec { - if in == nil { - return nil - } - out := new(FunctionEvalTaskSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionList) DeepCopyInto(out *FunctionList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Function, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionList. -func (in *FunctionList) DeepCopy() *FunctionList { - if in == nil { - return nil - } - out := new(FunctionList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FunctionList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionRef) DeepCopyInto(out *FunctionRef) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionRef. -func (in *FunctionRef) DeepCopy() *FunctionRef { - if in == nil { - return nil - } - out := new(FunctionRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionSpec) DeepCopyInto(out *FunctionSpec) { - *out = *in - out.RepositoryRef = in.RepositoryRef - if in.FunctionTypes != nil { - in, out := &in.FunctionTypes, &out.FunctionTypes - *out = make([]FunctionType, len(*in)) - copy(*out, *in) - } - if in.FunctionConfigs != nil { - in, out := &in.FunctionConfigs, &out.FunctionConfigs - *out = make([]FunctionConfig, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Keywords != nil { - in, out := &in.Keywords, &out.Keywords - *out = make([]string, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionSpec. -func (in *FunctionSpec) DeepCopy() *FunctionSpec { - if in == nil { - return nil - } - out := new(FunctionSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionStatus) DeepCopyInto(out *FunctionStatus) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionStatus. -func (in *FunctionStatus) DeepCopy() *FunctionStatus { - if in == nil { - return nil - } - out := new(FunctionStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GitLock) DeepCopyInto(out *GitLock) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitLock. -func (in *GitLock) DeepCopy() *GitLock { - if in == nil { - return nil - } - out := new(GitLock) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GitPackage) DeepCopyInto(out *GitPackage) { - *out = *in - out.SecretRef = in.SecretRef - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitPackage. -func (in *GitPackage) DeepCopy() *GitPackage { - if in == nil { - return nil - } - out := new(GitPackage) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NameMeta) DeepCopyInto(out *NameMeta) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NameMeta. -func (in *NameMeta) DeepCopy() *NameMeta { - if in == nil { - return nil - } - out := new(NameMeta) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OciPackage) DeepCopyInto(out *OciPackage) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OciPackage. -func (in *OciPackage) DeepCopy() *OciPackage { - if in == nil { - return nil - } - out := new(OciPackage) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Package) DeepCopyInto(out *Package) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - out.Status = in.Status - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Package. -func (in *Package) DeepCopy() *Package { - if in == nil { - return nil - } - out := new(Package) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Package) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageCloneTaskSpec) DeepCopyInto(out *PackageCloneTaskSpec) { - *out = *in - in.Upstream.DeepCopyInto(&out.Upstream) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageCloneTaskSpec. -func (in *PackageCloneTaskSpec) DeepCopy() *PackageCloneTaskSpec { - if in == nil { - return nil - } - out := new(PackageCloneTaskSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageEditTaskSpec) DeepCopyInto(out *PackageEditTaskSpec) { - *out = *in - if in.Source != nil { - in, out := &in.Source, &out.Source - *out = new(PackageRevisionRef) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageEditTaskSpec. -func (in *PackageEditTaskSpec) DeepCopy() *PackageEditTaskSpec { - if in == nil { - return nil - } - out := new(PackageEditTaskSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageInitTaskSpec) DeepCopyInto(out *PackageInitTaskSpec) { - *out = *in - if in.Keywords != nil { - in, out := &in.Keywords, &out.Keywords - *out = make([]string, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageInitTaskSpec. -func (in *PackageInitTaskSpec) DeepCopy() *PackageInitTaskSpec { - if in == nil { - return nil - } - out := new(PackageInitTaskSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageList) DeepCopyInto(out *PackageList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Package, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageList. -func (in *PackageList) DeepCopy() *PackageList { - if in == nil { - return nil - } - out := new(PackageList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackageList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackagePatchTaskSpec) DeepCopyInto(out *PackagePatchTaskSpec) { - *out = *in - if in.Patches != nil { - in, out := &in.Patches, &out.Patches - *out = make([]PatchSpec, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackagePatchTaskSpec. -func (in *PackagePatchTaskSpec) DeepCopy() *PackagePatchTaskSpec { - if in == nil { - return nil - } - out := new(PackagePatchTaskSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevision) DeepCopyInto(out *PackageRevision) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevision. -func (in *PackageRevision) DeepCopy() *PackageRevision { - if in == nil { - return nil - } - out := new(PackageRevision) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackageRevision) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevisionList) DeepCopyInto(out *PackageRevisionList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]PackageRevision, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevisionList. -func (in *PackageRevisionList) DeepCopy() *PackageRevisionList { - if in == nil { - return nil - } - out := new(PackageRevisionList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackageRevisionList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevisionRef) DeepCopyInto(out *PackageRevisionRef) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevisionRef. -func (in *PackageRevisionRef) DeepCopy() *PackageRevisionRef { - if in == nil { - return nil - } - out := new(PackageRevisionRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevisionResources) DeepCopyInto(out *PackageRevisionResources) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevisionResources. -func (in *PackageRevisionResources) DeepCopy() *PackageRevisionResources { - if in == nil { - return nil - } - out := new(PackageRevisionResources) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackageRevisionResources) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevisionResourcesList) DeepCopyInto(out *PackageRevisionResourcesList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]PackageRevisionResources, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevisionResourcesList. -func (in *PackageRevisionResourcesList) DeepCopy() *PackageRevisionResourcesList { - if in == nil { - return nil - } - out := new(PackageRevisionResourcesList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackageRevisionResourcesList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevisionResourcesSpec) DeepCopyInto(out *PackageRevisionResourcesSpec) { - *out = *in - if in.Resources != nil { - in, out := &in.Resources, &out.Resources - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevisionResourcesSpec. -func (in *PackageRevisionResourcesSpec) DeepCopy() *PackageRevisionResourcesSpec { - if in == nil { - return nil - } - out := new(PackageRevisionResourcesSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevisionResourcesStatus) DeepCopyInto(out *PackageRevisionResourcesStatus) { - *out = *in - in.RenderStatus.DeepCopyInto(&out.RenderStatus) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevisionResourcesStatus. -func (in *PackageRevisionResourcesStatus) DeepCopy() *PackageRevisionResourcesStatus { - if in == nil { - return nil - } - out := new(PackageRevisionResourcesStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevisionSpec) DeepCopyInto(out *PackageRevisionSpec) { - *out = *in - if in.Parent != nil { - in, out := &in.Parent, &out.Parent - *out = new(ParentReference) - **out = **in - } - if in.Tasks != nil { - in, out := &in.Tasks, &out.Tasks - *out = make([]Task, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.ReadinessGates != nil { - in, out := &in.ReadinessGates, &out.ReadinessGates - *out = make([]ReadinessGate, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevisionSpec. -func (in *PackageRevisionSpec) DeepCopy() *PackageRevisionSpec { - if in == nil { - return nil - } - out := new(PackageRevisionSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevisionStatus) DeepCopyInto(out *PackageRevisionStatus) { - *out = *in - if in.UpstreamLock != nil { - in, out := &in.UpstreamLock, &out.UpstreamLock - *out = new(UpstreamLock) - (*in).DeepCopyInto(*out) - } - in.PublishedAt.DeepCopyInto(&out.PublishedAt) - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]Condition, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevisionStatus. -func (in *PackageRevisionStatus) DeepCopy() *PackageRevisionStatus { - if in == nil { - return nil - } - out := new(PackageRevisionStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageSpec) DeepCopyInto(out *PackageSpec) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageSpec. -func (in *PackageSpec) DeepCopy() *PackageSpec { - if in == nil { - return nil - } - out := new(PackageSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageStatus) DeepCopyInto(out *PackageStatus) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageStatus. -func (in *PackageStatus) DeepCopy() *PackageStatus { - if in == nil { - return nil - } - out := new(PackageStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageUpdateTaskSpec) DeepCopyInto(out *PackageUpdateTaskSpec) { - *out = *in - in.Upstream.DeepCopyInto(&out.Upstream) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageUpdateTaskSpec. -func (in *PackageUpdateTaskSpec) DeepCopy() *PackageUpdateTaskSpec { - if in == nil { - return nil - } - out := new(PackageUpdateTaskSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ParentReference) DeepCopyInto(out *ParentReference) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParentReference. -func (in *ParentReference) DeepCopy() *ParentReference { - if in == nil { - return nil - } - out := new(ParentReference) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PatchSpec) DeepCopyInto(out *PatchSpec) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PatchSpec. -func (in *PatchSpec) DeepCopy() *PatchSpec { - if in == nil { - return nil - } - out := new(PatchSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ReadinessGate) DeepCopyInto(out *ReadinessGate) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReadinessGate. -func (in *ReadinessGate) DeepCopy() *ReadinessGate { - if in == nil { - return nil - } - out := new(ReadinessGate) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RenderStatus) DeepCopyInto(out *RenderStatus) { - *out = *in - in.Result.DeepCopyInto(&out.Result) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RenderStatus. -func (in *RenderStatus) DeepCopy() *RenderStatus { - if in == nil { - return nil - } - out := new(RenderStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RepositoryRef) DeepCopyInto(out *RepositoryRef) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RepositoryRef. -func (in *RepositoryRef) DeepCopy() *RepositoryRef { - if in == nil { - return nil - } - out := new(RepositoryRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ResourceIdentifier) DeepCopyInto(out *ResourceIdentifier) { - *out = *in - out.TypeMeta = in.TypeMeta - out.NameMeta = in.NameMeta - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceIdentifier. -func (in *ResourceIdentifier) DeepCopy() *ResourceIdentifier { - if in == nil { - return nil - } - out := new(ResourceIdentifier) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Result) DeepCopyInto(out *Result) { - *out = *in - if in.Results != nil { - in, out := &in.Results, &out.Results - *out = make([]ResultItem, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Result. -func (in *Result) DeepCopy() *Result { - if in == nil { - return nil - } - out := new(Result) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ResultItem) DeepCopyInto(out *ResultItem) { - *out = *in - if in.ResourceRef != nil { - in, out := &in.ResourceRef, &out.ResourceRef - *out = new(ResourceIdentifier) - **out = **in - } - if in.Field != nil { - in, out := &in.Field, &out.Field - *out = new(Field) - **out = **in - } - if in.File != nil { - in, out := &in.File, &out.File - *out = new(File) - **out = **in - } - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResultItem. -func (in *ResultItem) DeepCopy() *ResultItem { - if in == nil { - return nil - } - out := new(ResultItem) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ResultList) DeepCopyInto(out *ResultList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]*Result, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(Result) - (*in).DeepCopyInto(*out) - } - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResultList. -func (in *ResultList) DeepCopy() *ResultList { - if in == nil { - return nil - } - out := new(ResultList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecretRef) DeepCopyInto(out *SecretRef) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretRef. -func (in *SecretRef) DeepCopy() *SecretRef { - if in == nil { - return nil - } - out := new(SecretRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Selector) DeepCopyInto(out *Selector) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Selector. -func (in *Selector) DeepCopy() *Selector { - if in == nil { - return nil - } - out := new(Selector) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Task) DeepCopyInto(out *Task) { - *out = *in - if in.Init != nil { - in, out := &in.Init, &out.Init - *out = new(PackageInitTaskSpec) - (*in).DeepCopyInto(*out) - } - if in.Clone != nil { - in, out := &in.Clone, &out.Clone - *out = new(PackageCloneTaskSpec) - (*in).DeepCopyInto(*out) - } - if in.Patch != nil { - in, out := &in.Patch, &out.Patch - *out = new(PackagePatchTaskSpec) - (*in).DeepCopyInto(*out) - } - if in.Edit != nil { - in, out := &in.Edit, &out.Edit - *out = new(PackageEditTaskSpec) - (*in).DeepCopyInto(*out) - } - if in.Eval != nil { - in, out := &in.Eval, &out.Eval - *out = new(FunctionEvalTaskSpec) - (*in).DeepCopyInto(*out) - } - if in.Update != nil { - in, out := &in.Update, &out.Update - *out = new(PackageUpdateTaskSpec) - (*in).DeepCopyInto(*out) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Task. -func (in *Task) DeepCopy() *Task { - if in == nil { - return nil - } - out := new(Task) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TaskResult) DeepCopyInto(out *TaskResult) { - *out = *in - if in.Task != nil { - in, out := &in.Task, &out.Task - *out = new(Task) - (*in).DeepCopyInto(*out) - } - if in.RenderStatus != nil { - in, out := &in.RenderStatus, &out.RenderStatus - *out = new(RenderStatus) - (*in).DeepCopyInto(*out) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TaskResult. -func (in *TaskResult) DeepCopy() *TaskResult { - if in == nil { - return nil - } - out := new(TaskResult) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *UpstreamLock) DeepCopyInto(out *UpstreamLock) { - *out = *in - if in.Git != nil { - in, out := &in.Git, &out.Git - *out = new(GitLock) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpstreamLock. -func (in *UpstreamLock) DeepCopy() *UpstreamLock { - if in == nil { - return nil - } - out := new(UpstreamLock) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *UpstreamPackage) DeepCopyInto(out *UpstreamPackage) { - *out = *in - if in.Git != nil { - in, out := &in.Git, &out.Git - *out = new(GitPackage) - **out = **in - } - if in.Oci != nil { - in, out := &in.Oci, &out.Oci - *out = new(OciPackage) - **out = **in - } - if in.UpstreamRef != nil { - in, out := &in.UpstreamRef, &out.UpstreamRef - *out = new(PackageRevisionRef) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpstreamPackage. -func (in *UpstreamPackage) DeepCopy() *UpstreamPackage { - if in == nil { - return nil - } - out := new(UpstreamPackage) - in.DeepCopyInto(out) - return out -} diff --git a/porch/api/porch/v1alpha1/zz_generated.defaults.go b/porch/api/porch/v1alpha1/zz_generated.defaults.go deleted file mode 100644 index 964227b279..0000000000 --- a/porch/api/porch/v1alpha1/zz_generated.defaults.go +++ /dev/null @@ -1,31 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// Copyright 2023 The kpt 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 defaulter-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// RegisterDefaults adds defaulters functions to the given scheme. -// Public to allow building arbitrary schemes. -// All generated defaulters are covering - they call all nested defaulters. -func RegisterDefaults(scheme *runtime.Scheme) error { - return nil -} diff --git a/porch/api/porch/zz_generated.deepcopy.go b/porch/api/porch/zz_generated.deepcopy.go deleted file mode 100644 index 275ab6c955..0000000000 --- a/porch/api/porch/zz_generated.deepcopy.go +++ /dev/null @@ -1,1089 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// Copyright 2023 The kpt 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 deepcopy-gen. DO NOT EDIT. - -package porch - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Condition) DeepCopyInto(out *Condition) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition. -func (in *Condition) DeepCopy() *Condition { - if in == nil { - return nil - } - out := new(Condition) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Field) DeepCopyInto(out *Field) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Field. -func (in *Field) DeepCopy() *Field { - if in == nil { - return nil - } - out := new(Field) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *File) DeepCopyInto(out *File) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new File. -func (in *File) DeepCopy() *File { - if in == nil { - return nil - } - out := new(File) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Function) DeepCopyInto(out *Function) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - out.Status = in.Status - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Function. -func (in *Function) DeepCopy() *Function { - if in == nil { - return nil - } - out := new(Function) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Function) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionConfig) DeepCopyInto(out *FunctionConfig) { - *out = *in - out.TypeMeta = in.TypeMeta - if in.RequiredFields != nil { - in, out := &in.RequiredFields, &out.RequiredFields - *out = make([]string, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionConfig. -func (in *FunctionConfig) DeepCopy() *FunctionConfig { - if in == nil { - return nil - } - out := new(FunctionConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionEvalTaskSpec) DeepCopyInto(out *FunctionEvalTaskSpec) { - *out = *in - if in.FunctionRef != nil { - in, out := &in.FunctionRef, &out.FunctionRef - *out = new(FunctionRef) - **out = **in - } - if in.ConfigMap != nil { - in, out := &in.ConfigMap, &out.ConfigMap - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - in.Config.DeepCopyInto(&out.Config) - out.Match = in.Match - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionEvalTaskSpec. -func (in *FunctionEvalTaskSpec) DeepCopy() *FunctionEvalTaskSpec { - if in == nil { - return nil - } - out := new(FunctionEvalTaskSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionList) DeepCopyInto(out *FunctionList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Function, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionList. -func (in *FunctionList) DeepCopy() *FunctionList { - if in == nil { - return nil - } - out := new(FunctionList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FunctionList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionRef) DeepCopyInto(out *FunctionRef) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionRef. -func (in *FunctionRef) DeepCopy() *FunctionRef { - if in == nil { - return nil - } - out := new(FunctionRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionSpec) DeepCopyInto(out *FunctionSpec) { - *out = *in - out.RepositoryRef = in.RepositoryRef - if in.FunctionTypes != nil { - in, out := &in.FunctionTypes, &out.FunctionTypes - *out = make([]FunctionType, len(*in)) - copy(*out, *in) - } - if in.FunctionConfigs != nil { - in, out := &in.FunctionConfigs, &out.FunctionConfigs - *out = make([]FunctionConfig, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Keywords != nil { - in, out := &in.Keywords, &out.Keywords - *out = make([]string, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionSpec. -func (in *FunctionSpec) DeepCopy() *FunctionSpec { - if in == nil { - return nil - } - out := new(FunctionSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionStatus) DeepCopyInto(out *FunctionStatus) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionStatus. -func (in *FunctionStatus) DeepCopy() *FunctionStatus { - if in == nil { - return nil - } - out := new(FunctionStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GitLock) DeepCopyInto(out *GitLock) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitLock. -func (in *GitLock) DeepCopy() *GitLock { - if in == nil { - return nil - } - out := new(GitLock) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GitPackage) DeepCopyInto(out *GitPackage) { - *out = *in - out.SecretRef = in.SecretRef - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitPackage. -func (in *GitPackage) DeepCopy() *GitPackage { - if in == nil { - return nil - } - out := new(GitPackage) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NameMeta) DeepCopyInto(out *NameMeta) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NameMeta. -func (in *NameMeta) DeepCopy() *NameMeta { - if in == nil { - return nil - } - out := new(NameMeta) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OciPackage) DeepCopyInto(out *OciPackage) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OciPackage. -func (in *OciPackage) DeepCopy() *OciPackage { - if in == nil { - return nil - } - out := new(OciPackage) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Package) DeepCopyInto(out *Package) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - out.Status = in.Status - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Package. -func (in *Package) DeepCopy() *Package { - if in == nil { - return nil - } - out := new(Package) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Package) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageCloneTaskSpec) DeepCopyInto(out *PackageCloneTaskSpec) { - *out = *in - in.Upstream.DeepCopyInto(&out.Upstream) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageCloneTaskSpec. -func (in *PackageCloneTaskSpec) DeepCopy() *PackageCloneTaskSpec { - if in == nil { - return nil - } - out := new(PackageCloneTaskSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageEditTaskSpec) DeepCopyInto(out *PackageEditTaskSpec) { - *out = *in - if in.Source != nil { - in, out := &in.Source, &out.Source - *out = new(PackageRevisionRef) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageEditTaskSpec. -func (in *PackageEditTaskSpec) DeepCopy() *PackageEditTaskSpec { - if in == nil { - return nil - } - out := new(PackageEditTaskSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageInitTaskSpec) DeepCopyInto(out *PackageInitTaskSpec) { - *out = *in - if in.Keywords != nil { - in, out := &in.Keywords, &out.Keywords - *out = make([]string, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageInitTaskSpec. -func (in *PackageInitTaskSpec) DeepCopy() *PackageInitTaskSpec { - if in == nil { - return nil - } - out := new(PackageInitTaskSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageList) DeepCopyInto(out *PackageList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Package, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageList. -func (in *PackageList) DeepCopy() *PackageList { - if in == nil { - return nil - } - out := new(PackageList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackageList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackagePatchTaskSpec) DeepCopyInto(out *PackagePatchTaskSpec) { - *out = *in - if in.Patches != nil { - in, out := &in.Patches, &out.Patches - *out = make([]PatchSpec, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackagePatchTaskSpec. -func (in *PackagePatchTaskSpec) DeepCopy() *PackagePatchTaskSpec { - if in == nil { - return nil - } - out := new(PackagePatchTaskSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevision) DeepCopyInto(out *PackageRevision) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevision. -func (in *PackageRevision) DeepCopy() *PackageRevision { - if in == nil { - return nil - } - out := new(PackageRevision) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackageRevision) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevisionList) DeepCopyInto(out *PackageRevisionList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]PackageRevision, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevisionList. -func (in *PackageRevisionList) DeepCopy() *PackageRevisionList { - if in == nil { - return nil - } - out := new(PackageRevisionList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackageRevisionList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevisionRef) DeepCopyInto(out *PackageRevisionRef) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevisionRef. -func (in *PackageRevisionRef) DeepCopy() *PackageRevisionRef { - if in == nil { - return nil - } - out := new(PackageRevisionRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevisionResources) DeepCopyInto(out *PackageRevisionResources) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevisionResources. -func (in *PackageRevisionResources) DeepCopy() *PackageRevisionResources { - if in == nil { - return nil - } - out := new(PackageRevisionResources) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackageRevisionResources) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevisionResourcesList) DeepCopyInto(out *PackageRevisionResourcesList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]PackageRevisionResources, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevisionResourcesList. -func (in *PackageRevisionResourcesList) DeepCopy() *PackageRevisionResourcesList { - if in == nil { - return nil - } - out := new(PackageRevisionResourcesList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackageRevisionResourcesList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevisionResourcesSpec) DeepCopyInto(out *PackageRevisionResourcesSpec) { - *out = *in - if in.Resources != nil { - in, out := &in.Resources, &out.Resources - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevisionResourcesSpec. -func (in *PackageRevisionResourcesSpec) DeepCopy() *PackageRevisionResourcesSpec { - if in == nil { - return nil - } - out := new(PackageRevisionResourcesSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevisionResourcesStatus) DeepCopyInto(out *PackageRevisionResourcesStatus) { - *out = *in - in.RenderStatus.DeepCopyInto(&out.RenderStatus) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevisionResourcesStatus. -func (in *PackageRevisionResourcesStatus) DeepCopy() *PackageRevisionResourcesStatus { - if in == nil { - return nil - } - out := new(PackageRevisionResourcesStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevisionSpec) DeepCopyInto(out *PackageRevisionSpec) { - *out = *in - if in.Parent != nil { - in, out := &in.Parent, &out.Parent - *out = new(ParentReference) - **out = **in - } - if in.Tasks != nil { - in, out := &in.Tasks, &out.Tasks - *out = make([]Task, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.ReadinessGates != nil { - in, out := &in.ReadinessGates, &out.ReadinessGates - *out = make([]ReadinessGate, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevisionSpec. -func (in *PackageRevisionSpec) DeepCopy() *PackageRevisionSpec { - if in == nil { - return nil - } - out := new(PackageRevisionSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevisionStatus) DeepCopyInto(out *PackageRevisionStatus) { - *out = *in - if in.UpstreamLock != nil { - in, out := &in.UpstreamLock, &out.UpstreamLock - *out = new(UpstreamLock) - (*in).DeepCopyInto(*out) - } - in.PublishedAt.DeepCopyInto(&out.PublishedAt) - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]Condition, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevisionStatus. -func (in *PackageRevisionStatus) DeepCopy() *PackageRevisionStatus { - if in == nil { - return nil - } - out := new(PackageRevisionStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageSpec) DeepCopyInto(out *PackageSpec) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageSpec. -func (in *PackageSpec) DeepCopy() *PackageSpec { - if in == nil { - return nil - } - out := new(PackageSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageStatus) DeepCopyInto(out *PackageStatus) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageStatus. -func (in *PackageStatus) DeepCopy() *PackageStatus { - if in == nil { - return nil - } - out := new(PackageStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageUpdateTaskSpec) DeepCopyInto(out *PackageUpdateTaskSpec) { - *out = *in - in.Upstream.DeepCopyInto(&out.Upstream) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageUpdateTaskSpec. -func (in *PackageUpdateTaskSpec) DeepCopy() *PackageUpdateTaskSpec { - if in == nil { - return nil - } - out := new(PackageUpdateTaskSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ParentReference) DeepCopyInto(out *ParentReference) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParentReference. -func (in *ParentReference) DeepCopy() *ParentReference { - if in == nil { - return nil - } - out := new(ParentReference) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PatchSpec) DeepCopyInto(out *PatchSpec) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PatchSpec. -func (in *PatchSpec) DeepCopy() *PatchSpec { - if in == nil { - return nil - } - out := new(PatchSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ReadinessGate) DeepCopyInto(out *ReadinessGate) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReadinessGate. -func (in *ReadinessGate) DeepCopy() *ReadinessGate { - if in == nil { - return nil - } - out := new(ReadinessGate) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RenderStatus) DeepCopyInto(out *RenderStatus) { - *out = *in - in.Result.DeepCopyInto(&out.Result) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RenderStatus. -func (in *RenderStatus) DeepCopy() *RenderStatus { - if in == nil { - return nil - } - out := new(RenderStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RepositoryRef) DeepCopyInto(out *RepositoryRef) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RepositoryRef. -func (in *RepositoryRef) DeepCopy() *RepositoryRef { - if in == nil { - return nil - } - out := new(RepositoryRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ResourceIdentifier) DeepCopyInto(out *ResourceIdentifier) { - *out = *in - out.TypeMeta = in.TypeMeta - out.NameMeta = in.NameMeta - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceIdentifier. -func (in *ResourceIdentifier) DeepCopy() *ResourceIdentifier { - if in == nil { - return nil - } - out := new(ResourceIdentifier) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Result) DeepCopyInto(out *Result) { - *out = *in - if in.Results != nil { - in, out := &in.Results, &out.Results - *out = make([]ResultItem, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Result. -func (in *Result) DeepCopy() *Result { - if in == nil { - return nil - } - out := new(Result) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ResultItem) DeepCopyInto(out *ResultItem) { - *out = *in - if in.ResourceRef != nil { - in, out := &in.ResourceRef, &out.ResourceRef - *out = new(ResourceIdentifier) - **out = **in - } - if in.Field != nil { - in, out := &in.Field, &out.Field - *out = new(Field) - **out = **in - } - if in.File != nil { - in, out := &in.File, &out.File - *out = new(File) - **out = **in - } - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResultItem. -func (in *ResultItem) DeepCopy() *ResultItem { - if in == nil { - return nil - } - out := new(ResultItem) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ResultList) DeepCopyInto(out *ResultList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]*Result, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(Result) - (*in).DeepCopyInto(*out) - } - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResultList. -func (in *ResultList) DeepCopy() *ResultList { - if in == nil { - return nil - } - out := new(ResultList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecretRef) DeepCopyInto(out *SecretRef) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretRef. -func (in *SecretRef) DeepCopy() *SecretRef { - if in == nil { - return nil - } - out := new(SecretRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Selector) DeepCopyInto(out *Selector) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Selector. -func (in *Selector) DeepCopy() *Selector { - if in == nil { - return nil - } - out := new(Selector) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Task) DeepCopyInto(out *Task) { - *out = *in - if in.Init != nil { - in, out := &in.Init, &out.Init - *out = new(PackageInitTaskSpec) - (*in).DeepCopyInto(*out) - } - if in.Clone != nil { - in, out := &in.Clone, &out.Clone - *out = new(PackageCloneTaskSpec) - (*in).DeepCopyInto(*out) - } - if in.Patch != nil { - in, out := &in.Patch, &out.Patch - *out = new(PackagePatchTaskSpec) - (*in).DeepCopyInto(*out) - } - if in.Edit != nil { - in, out := &in.Edit, &out.Edit - *out = new(PackageEditTaskSpec) - (*in).DeepCopyInto(*out) - } - if in.Eval != nil { - in, out := &in.Eval, &out.Eval - *out = new(FunctionEvalTaskSpec) - (*in).DeepCopyInto(*out) - } - if in.Update != nil { - in, out := &in.Update, &out.Update - *out = new(PackageUpdateTaskSpec) - (*in).DeepCopyInto(*out) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Task. -func (in *Task) DeepCopy() *Task { - if in == nil { - return nil - } - out := new(Task) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TaskResult) DeepCopyInto(out *TaskResult) { - *out = *in - if in.Task != nil { - in, out := &in.Task, &out.Task - *out = new(Task) - (*in).DeepCopyInto(*out) - } - if in.RenderStatus != nil { - in, out := &in.RenderStatus, &out.RenderStatus - *out = new(RenderStatus) - (*in).DeepCopyInto(*out) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TaskResult. -func (in *TaskResult) DeepCopy() *TaskResult { - if in == nil { - return nil - } - out := new(TaskResult) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *UpstreamLock) DeepCopyInto(out *UpstreamLock) { - *out = *in - if in.Git != nil { - in, out := &in.Git, &out.Git - *out = new(GitLock) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpstreamLock. -func (in *UpstreamLock) DeepCopy() *UpstreamLock { - if in == nil { - return nil - } - out := new(UpstreamLock) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *UpstreamPackage) DeepCopyInto(out *UpstreamPackage) { - *out = *in - if in.Git != nil { - in, out := &in.Git, &out.Git - *out = new(GitPackage) - **out = **in - } - if in.Oci != nil { - in, out := &in.Oci, &out.Oci - *out = new(OciPackage) - **out = **in - } - if in.UpstreamRef != nil { - in, out := &in.UpstreamRef, &out.UpstreamRef - *out = new(PackageRevisionRef) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpstreamPackage. -func (in *UpstreamPackage) DeepCopy() *UpstreamPackage { - if in == nil { - return nil - } - out := new(UpstreamPackage) - in.DeepCopyInto(out) - return out -} diff --git a/porch/api/porchconfig/v1alpha1/config.porch.kpt.dev_functions.yaml b/porch/api/porchconfig/v1alpha1/config.porch.kpt.dev_functions.yaml deleted file mode 100644 index 7a21f080e6..0000000000 --- a/porch/api/porchconfig/v1alpha1/config.porch.kpt.dev_functions.yaml +++ /dev/null @@ -1,135 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: functions.config.porch.kpt.dev -spec: - group: config.porch.kpt.dev - names: - kind: Function - listKind: FunctionList - plural: functions - singular: function - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: Function represents a kpt function discovered in a repository - Function resources are created automatically by discovery in a registered - Repository. Function resource names will be computed as : to ensure uniqueness of names, and will follow formatting of [DNS - Subdomain Names](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names). - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: FunctionSpec defines the desired state of a Function - properties: - description: - description: Description is a short description of the function. - type: string - documentationUrl: - description: '`DocumentationUrl specifies the URL of comprehensive - function documentation`' - type: string - functionConfigs: - items: - description: FunctionConfig specifies all the valid types of the - function config for this function. If unspecified, defaults to - v1/ConfigMap. For example, function `set-namespace` accepts both - `ConfigMap` and `SetNamespace` - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this - representation of an object. Servers should convert recognized - schemas to the latest internal value, and may reject unrecognized - values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource - this object represents. Servers may infer this from the endpoint - the client submits requests to. Cannot be updated. In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - requiredFields: - description: 'Experimental: requiredFields tells necessary fields - and is aimed to help users write the FunctionConfig. Otherwise, - users can get the required fields info from the function evaluation - error message.' - items: - type: string - type: array - type: object - type: array - functionTypes: - description: FunctionType specifies the function types (mutator, validator - or/and others). - items: - type: string - type: array - image: - description: Image specifies the function image, such as 'gcr.io/kpt-fn/gatekeeper:v0.2'. - type: string - keywords: - description: Keywords are used as filters to provide correlation in - function discovery. - items: - type: string - type: array - repositoryRef: - description: RepositoryRef references the repository in which the - function is located. - properties: - name: - description: Name of the Repository resource referenced. - type: string - required: - - name - type: object - required: - - description - - image - - repositoryRef - type: object - status: - description: FunctionStatus defines the observed state of Function - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/porch/api/porchconfig/v1alpha1/config.porch.kpt.dev_repositories.yaml b/porch/api/porchconfig/v1alpha1/config.porch.kpt.dev_repositories.yaml deleted file mode 100644 index f3c7c3ba8e..0000000000 --- a/porch/api/porchconfig/v1alpha1/config.porch.kpt.dev_repositories.yaml +++ /dev/null @@ -1,372 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: repositories.config.porch.kpt.dev -spec: - group: config.porch.kpt.dev - names: - kind: Repository - listKind: RepositoryList - plural: repositories - singular: repository - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.type - name: Type - type: string - - jsonPath: .spec.content - name: Content - type: string - - jsonPath: .spec.deployment - name: Deployment - type: boolean - - jsonPath: .status.conditions[?(@.type=='Ready')].status - name: Ready - type: string - - jsonPath: .spec['git','oci']['repo','registry'] - name: Address - type: string - name: v1alpha1 - schema: - openAPIV3Schema: - description: Repository - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: "RepositorySpec defines the desired state of Repository \n - Notes: - deployment repository - in KRM API ConfigSync would be configured - directly? (or via this API)" - properties: - content: - description: 'Content stored in the repository (i.e. Function, Package - - the literal values correspond to the API resource names). TODO: - support repository with mixed content?' - type: string - deployment: - description: The repository is a deployment repository; final packages - in this repository are deployment ready. - type: boolean - description: - description: User-friendly description of the repository - type: string - git: - description: Git repository details. Required if `type` is `git`. - Ignored if `type` is not `git`. - properties: - branch: - description: Name of the branch containing the packages. Finalized - packages will be committed to this branch (if the repository - allows write access). If unspecified, defaults to "main". - type: string - createBranch: - description: CreateBranch specifies if Porch should create the - package branch if it doesn't exist. - type: boolean - directory: - description: Directory within the Git repository where the packages - are stored. A subdirectory of this directory containing a Kptfile - is considered a package. If unspecified, defaults to root directory. - type: string - repo: - description: 'Address of the Git repository, for example: `https://github.com/GoogleCloudPlatform/blueprints.git`' - type: string - secretRef: - description: Reference to secret containing authentication credentials. - properties: - name: - description: Name of the secret. The secret is expected to - be located in the same namespace as the resource containing - the reference. - type: string - required: - - name - type: object - required: - - repo - type: object - mutators: - description: '`Mutators` specifies list of functions to be added to - the list of package''s mutators on changes to the packages in the - repository to ensure the packages meet constraints enforced by the - mutators associated with the repository. Based on the Kubernetest - Admission Controllers (https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/). - The functions will be evaluated in the order specified in the list.' - items: - properties: - configMap: - additionalProperties: - type: string - description: '`ConfigMap` specifies the function config (https://kpt.dev/reference/cli/fn/eval/).' - type: object - functionRef: - description: '`FunctionRef` specifies the function by reference - to a Function resource. Mutually exclusive with `Image`.' - properties: - name: - description: '`Name` is the name of the `Function` resource - referenced. The resource is expected to be within the - same namespace.' - type: string - required: - - name - type: object - image: - description: '`Image` specifies the function image, such as - `gcr.io/kpt-fn/gatekeeper:v0.2`. Use of `Image` is mutually - exclusive with `FunctionRef`.' - type: string - type: object - type: array - oci: - description: OCI repository details. Required if `type` is `oci`. - Ignored if `type` is not `oci`. - properties: - registry: - description: Registry is the address of the OCI registry - type: string - secretRef: - description: Reference to secret containing authentication credentials. - properties: - name: - description: Name of the secret. The secret is expected to - be located in the same namespace as the resource containing - the reference. - type: string - required: - - name - type: object - required: - - registry - type: object - type: - description: Type of the repository (i.e. git, OCI) - type: string - upstream: - description: Upstream is the default upstream repository for packages - in this repository. Specifying it per repository allows simpler - UX when creating packages. - properties: - git: - description: Git repository details. Required if `type` is `git`. - Must be unspecified if `type` is not `git`. - properties: - branch: - description: Name of the branch containing the packages. Finalized - packages will be committed to this branch (if the repository - allows write access). If unspecified, defaults to "main". - type: string - createBranch: - description: CreateBranch specifies if Porch should create - the package branch if it doesn't exist. - type: boolean - directory: - description: Directory within the Git repository where the - packages are stored. A subdirectory of this directory containing - a Kptfile is considered a package. If unspecified, defaults - to root directory. - type: string - repo: - description: 'Address of the Git repository, for example: - `https://github.com/GoogleCloudPlatform/blueprints.git`' - type: string - secretRef: - description: Reference to secret containing authentication - credentials. - properties: - name: - description: Name of the secret. The secret is expected - to be located in the same namespace as the resource - containing the reference. - type: string - required: - - name - type: object - required: - - repo - type: object - oci: - description: OCI repository details. Required if `type` is `oci`. - Must be unspecified if `type` is not `oci`. - properties: - registry: - description: Registry is the address of the OCI registry - type: string - secretRef: - description: Reference to secret containing authentication - credentials. - properties: - name: - description: Name of the secret. The secret is expected - to be located in the same namespace as the resource - containing the reference. - type: string - required: - - name - type: object - required: - - registry - type: object - repositoryRef: - description: RepositoryRef contains a reference to an existing - Repository resource to be used as the default upstream repository. - properties: - name: - description: Name of the Repository resource referenced. - type: string - required: - - name - type: object - type: - description: Type of the repository (i.e. git, OCI). If empty, - repositoryRef will be used. - type: string - type: object - validators: - description: '`Validators` specifies list of functions to be added - to the list of package''s validators on changes to the packages - in the repository to ensure the packages meet constraints enforced - by the validators associated with the repository. Based on the Kubernetest - Admission Controllers (https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/). - The functions will be evaluated in the order specified in the list.' - items: - properties: - configMap: - additionalProperties: - type: string - description: '`ConfigMap` specifies the function config (https://kpt.dev/reference/cli/fn/eval/).' - type: object - functionRef: - description: '`FunctionRef` specifies the function by reference - to a Function resource. Mutually exclusive with `Image`.' - properties: - name: - description: '`Name` is the name of the `Function` resource - referenced. The resource is expected to be within the - same namespace.' - type: string - required: - - name - type: object - image: - description: '`Image` specifies the function image, such as - `gcr.io/kpt-fn/gatekeeper:v0.2`. Use of `Image` is mutually - exclusive with `FunctionRef`.' - type: string - type: object - type: array - type: object - status: - description: RepositoryStatus defines the observed state of Repository - properties: - conditions: - description: Conditions describes the reconciliation state of the - object. - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - type FooStatus struct{ // Represents the observations of a foo's - current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/porch/api/porchconfig/v1alpha1/groupversion_info.go b/porch/api/porchconfig/v1alpha1/groupversion_info.go deleted file mode 100644 index 09fc68acd9..0000000000 --- a/porch/api/porchconfig/v1alpha1/groupversion_info.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2022 The kpt 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. - -// Package v1alpha1 contains API Schema definitions for the v1alpha1 API group -// +kubebuilder:object:generate=true -// +groupName=config.porch.kpt.dev -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 object:headerFile="../../../scripts/boilerplate.go.txt" crd:crdVersions=v1 output:crd:artifacts:config=. paths=./... - -var ( - // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "config.porch.kpt.dev", Version: "v1alpha1"} - - // We removed SchemeBuilder to keep our dependencies small - - TypeRepository = TypeInfo{ - Kind: "Repository", - Resource: GroupVersion.WithResource("repositories"), - objects: []runtime.Object{&Repository{}, &RepositoryList{}}, - } - - TypeFunction = TypeInfo{ - Kind: "Function", - Resource: GroupVersion.WithResource("functions"), - objects: []runtime.Object{&Function{}, &FunctionList{}}, - } - - AllKinds = []TypeInfo{TypeRepository, TypeFunction} -) - -//+kubebuilder:object:generate=false - -// TypeInfo holds type meta-information -type TypeInfo struct { - Kind string - Resource schema.GroupVersionResource - objects []runtime.Object -} - -// GVK returns the schema.GroupVersionKind for the type -func (t *TypeInfo) GVK() schema.GroupVersionKind { - return t.Resource.GroupVersion().WithKind(t.Kind) -} - -// APIVersion returns the apiVersion for the type -func (t *TypeInfo) APIVersion() string { - return t.Resource.GroupVersion().Identifier() -} - -// GroupResource returns the GroupResource for the kind -func (t *TypeInfo) GroupResource() schema.GroupResource { - return t.Resource.GroupResource() -} - -func AddToScheme(scheme *runtime.Scheme) error { - for _, kind := range AllKinds { - scheme.AddKnownTypes(GroupVersion, kind.objects...) - } - metav1.AddToGroupVersion(scheme, GroupVersion) - return nil -} diff --git a/porch/api/porchconfig/v1alpha1/types.go b/porch/api/porchconfig/v1alpha1/types.go deleted file mode 100644 index e9a09eb4f0..0000000000 --- a/porch/api/porchconfig/v1alpha1/types.go +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2022 The kpt 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. - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:resource:path=repositories,singular=repository -//+kubebuilder:printcolumn:name="Type",type=string,JSONPath=`.spec.type` -//+kubebuilder:printcolumn:name="Content",type=string,JSONPath=`.spec.content` -//+kubebuilder:printcolumn:name="Deployment",type=boolean,JSONPath=`.spec.deployment` -//+kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=='Ready')].status` -//+kubebuilder:printcolumn:name="Address",type=string,JSONPath=`.spec['git','oci']['repo','registry']` - -// Repository -type Repository struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec RepositorySpec `json:"spec,omitempty"` - Status RepositoryStatus `json:"status,omitempty"` -} - -type RepositoryType string - -const ( - RepositoryTypeGit RepositoryType = "git" - RepositoryTypeOCI RepositoryType = "oci" -) - -type RepositoryContent string - -const ( - RepositoryContentFunction RepositoryContent = "Function" - RepositoryContentPackage RepositoryContent = "Package" -) - -// RepositorySpec defines the desired state of Repository -// -// Notes: -// - deployment repository - in KRM API ConfigSync would be configured directly? (or via this API) -type RepositorySpec struct { - // User-friendly description of the repository - Description string `json:"description,omitempty"` - // The repository is a deployment repository; final packages in this repository are deployment ready. - Deployment bool `json:"deployment,omitempty"` - // Type of the repository (i.e. git, OCI) - Type RepositoryType `json:"type,omitempty"` - // Content stored in the repository (i.e. Function, Package - the literal values correspond to the API resource names). - // TODO: support repository with mixed content? - Content RepositoryContent `json:"content,omitempty"` - // Git repository details. Required if `type` is `git`. Ignored if `type` is not `git`. - Git *GitRepository `json:"git,omitempty"` - // OCI repository details. Required if `type` is `oci`. Ignored if `type` is not `oci`. - Oci *OciRepository `json:"oci,omitempty"` - // Upstream is the default upstream repository for packages in this - // repository. Specifying it per repository allows simpler UX when - // creating packages. - Upstream *UpstreamRepository `json:"upstream,omitempty"` - - // `Mutators` specifies list of functions to be added to the list of package's mutators on changes to the packages in the repository to ensure the packages meet constraints - // enforced by the mutators associated with the repository. - // Based on the Kubernetest Admission Controllers (https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/). The functions will be evaluated - // in the order specified in the list. - Mutators []FunctionEval `json:"mutators,omitempty"` - - // `Validators` specifies list of functions to be added to the list of package's validators on changes to the packages in the repository to ensure the packages meet constraints - // enforced by the validators associated with the repository. - // Based on the Kubernetest Admission Controllers (https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/). The functions will be evaluated - // in the order specified in the list. - Validators []FunctionEval `json:"validators,omitempty"` -} - -// GitRepository describes a Git repository. -// TODO: authentication methods -type GitRepository struct { - // Address of the Git repository, for example: - // `https://github.com/GoogleCloudPlatform/blueprints.git` - Repo string `json:"repo"` - // Name of the branch containing the packages. Finalized packages will be committed to this branch (if the repository allows write access). If unspecified, defaults to "main". - Branch string `json:"branch,omitempty"` - // CreateBranch specifies if Porch should create the package branch if it doesn't exist. - CreateBranch bool `json:"createBranch,omitempty"` - // Directory within the Git repository where the packages are stored. A subdirectory of this directory containing a Kptfile is considered a package. If unspecified, defaults to root directory. - Directory string `json:"directory,omitempty"` - // Reference to secret containing authentication credentials. - SecretRef SecretRef `json:"secretRef,omitempty"` -} - -// OciRepository describes a repository compatible with the Open Container Registry standard. -// TODO: allow sub-selection of the registry, i.e. filter by tags, ...? -// TODO: authentication types? -type OciRepository struct { - // Registry is the address of the OCI registry - Registry string `json:"registry"` - // Reference to secret containing authentication credentials. - SecretRef SecretRef `json:"secretRef,omitempty"` -} - -// UpstreamRepository repository may be specified directly or by referencing another Repository resource. -type UpstreamRepository struct { - // Type of the repository (i.e. git, OCI). If empty, repositoryRef will be used. - Type RepositoryType `json:"type,omitempty"` - // Git repository details. Required if `type` is `git`. Must be unspecified if `type` is not `git`. - Git *GitRepository `json:"git,omitempty"` - // OCI repository details. Required if `type` is `oci`. Must be unspecified if `type` is not `oci`. - Oci *OciRepository `json:"oci,omitempty"` - // RepositoryRef contains a reference to an existing Repository resource to be used as the default upstream repository. - RepositoryRef *RepositoryRef `json:"repositoryRef,omitempty"` -} - -// RepositoryRef identifies a reference to a Repository resource. -type RepositoryRef struct { - // Name of the Repository resource referenced. - Name string `json:"name"` -} - -type SecretRef struct { - // Name of the secret. The secret is expected to be located in the same namespace as the resource containing the reference. - Name string `json:"name"` -} - -type FunctionEval struct { - // `Image` specifies the function image, such as `gcr.io/kpt-fn/gatekeeper:v0.2`. Use of `Image` is mutually exclusive with `FunctionRef`. - Image string `json:"image,omitempty"` - // `FunctionRef` specifies the function by reference to a Function resource. Mutually exclusive with `Image`. - FunctionRef *FunctionRef `json:"functionRef,omitempty"` - // `ConfigMap` specifies the function config (https://kpt.dev/reference/cli/fn/eval/). - ConfigMap map[string]string `json:"configMap,omitempty"` -} - -// `FunctionRef` is a reference to a `Function` resource. -type FunctionRef struct { - // `Name` is the name of the `Function` resource referenced. The resource is expected to be within the same namespace. - Name string `json:"name"` -} - -const ( - // Type of the Repository condition. - RepositoryReady = "Ready" - - // Reason for the condition is error. - ReasonError = "Error" - // Reason for the condition is the repository is ready. - ReasonReady = "Ready" -) - -// RepositoryStatus defines the observed state of Repository -type RepositoryStatus struct { - // Conditions describes the reconciliation state of the object. - Conditions []metav1.Condition `json:"conditions,omitempty"` -} - -//+kubebuilder:object:root=true - -// RepositoryList contains a list of Repo -type RepositoryList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []Repository `json:"items"` -} diff --git a/porch/api/porchconfig/v1alpha1/types_functions.go b/porch/api/porchconfig/v1alpha1/types_functions.go deleted file mode 100644 index 2cfd87039e..0000000000 --- a/porch/api/porchconfig/v1alpha1/types_functions.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2022 The kpt 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. - -package v1alpha1 - -import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:resource:path=functions,singular=function - -// Function represents a kpt function discovered in a repository -// Function resources are created automatically by discovery in a registered Repository. -// Function resource names will be computed as : -// to ensure uniqueness of names, and will follow formatting of -// [DNS Subdomain Names](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names). -type Function struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec FunctionSpec `json:"spec,omitempty"` - Status FunctionStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// FunctionList -type FunctionList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - - Items []Function `json:"items"` -} - -type FunctionType string - -const ( - FunctionTypeValidator FunctionType = "validator" - FunctionTypeMutator FunctionType = "mutator" -) - -// FunctionSpec defines the desired state of a Function -type FunctionSpec struct { - // Image specifies the function image, such as 'gcr.io/kpt-fn/gatekeeper:v0.2'. - Image string `json:"image"` - - // RepositoryRef references the repository in which the function is located. - RepositoryRef RepositoryRef `json:"repositoryRef"` - - // FunctionType specifies the function types (mutator, validator or/and others). - FunctionTypes []FunctionType `json:"functionTypes,omitempty"` - - FunctionConfigs []FunctionConfig `json:"functionConfigs,omitempty"` - - // Keywords are used as filters to provide correlation in function discovery. - Keywords []string `json:"keywords,omitempty"` - - // Description is a short description of the function. - Description string `json:"description"` - - // `DocumentationUrl specifies the URL of comprehensive function documentation` - DocumentationUrl string `json:"documentationUrl,omitempty"` - - // InputTypes specifies to which input KRM types the function applies. Specified as Group Version Kind. - // For example: - // - // inputTypes: - // - kind: RoleBinding - // # If version is unspecified, applies to all versions - // apiVersion: rbac.authorization.k8s.io - // - kind: ClusterRoleBinding - // apiVersion: rbac.authorization.k8s.io/v1 - // InputTypes []metav1.TypeMeta - - // OutputTypes specifies types of any KRM resources the function creates - // For example: - // - // outputTypes: - // - kind: ConfigMap - // apiVersion: v1 - // OutputTypes []metav1.TypeMeta - -} - -// FunctionConfig specifies all the valid types of the function config for this function. -// If unspecified, defaults to v1/ConfigMap. For example, function `set-namespace` accepts both `ConfigMap` and `SetNamespace` -type FunctionConfig struct { - metav1.TypeMeta `json:",inline"` - // Experimental: requiredFields tells necessary fields and is aimed to help users write the FunctionConfig. - // Otherwise, users can get the required fields info from the function evaluation error message. - RequiredFields []string `json:"requiredFields,omitempty"` -} - -// FunctionStatus defines the observed state of Function -type FunctionStatus struct { -} diff --git a/porch/api/porchconfig/v1alpha1/zz_generated.deepcopy.go b/porch/api/porchconfig/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index 1072eb6b66..0000000000 --- a/porch/api/porchconfig/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,412 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// Copyright 2023 The kpt 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 controller-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Function) DeepCopyInto(out *Function) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - out.Status = in.Status -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Function. -func (in *Function) DeepCopy() *Function { - if in == nil { - return nil - } - out := new(Function) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Function) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionConfig) DeepCopyInto(out *FunctionConfig) { - *out = *in - out.TypeMeta = in.TypeMeta - if in.RequiredFields != nil { - in, out := &in.RequiredFields, &out.RequiredFields - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionConfig. -func (in *FunctionConfig) DeepCopy() *FunctionConfig { - if in == nil { - return nil - } - out := new(FunctionConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionEval) DeepCopyInto(out *FunctionEval) { - *out = *in - if in.FunctionRef != nil { - in, out := &in.FunctionRef, &out.FunctionRef - *out = new(FunctionRef) - **out = **in - } - if in.ConfigMap != nil { - in, out := &in.ConfigMap, &out.ConfigMap - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionEval. -func (in *FunctionEval) DeepCopy() *FunctionEval { - if in == nil { - return nil - } - out := new(FunctionEval) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionList) DeepCopyInto(out *FunctionList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Function, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionList. -func (in *FunctionList) DeepCopy() *FunctionList { - if in == nil { - return nil - } - out := new(FunctionList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FunctionList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionRef) DeepCopyInto(out *FunctionRef) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionRef. -func (in *FunctionRef) DeepCopy() *FunctionRef { - if in == nil { - return nil - } - out := new(FunctionRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionSpec) DeepCopyInto(out *FunctionSpec) { - *out = *in - out.RepositoryRef = in.RepositoryRef - if in.FunctionTypes != nil { - in, out := &in.FunctionTypes, &out.FunctionTypes - *out = make([]FunctionType, len(*in)) - copy(*out, *in) - } - if in.FunctionConfigs != nil { - in, out := &in.FunctionConfigs, &out.FunctionConfigs - *out = make([]FunctionConfig, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Keywords != nil { - in, out := &in.Keywords, &out.Keywords - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionSpec. -func (in *FunctionSpec) DeepCopy() *FunctionSpec { - if in == nil { - return nil - } - out := new(FunctionSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionStatus) DeepCopyInto(out *FunctionStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionStatus. -func (in *FunctionStatus) DeepCopy() *FunctionStatus { - if in == nil { - return nil - } - out := new(FunctionStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GitRepository) DeepCopyInto(out *GitRepository) { - *out = *in - out.SecretRef = in.SecretRef -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitRepository. -func (in *GitRepository) DeepCopy() *GitRepository { - if in == nil { - return nil - } - out := new(GitRepository) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OciRepository) DeepCopyInto(out *OciRepository) { - *out = *in - out.SecretRef = in.SecretRef -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OciRepository. -func (in *OciRepository) DeepCopy() *OciRepository { - if in == nil { - return nil - } - out := new(OciRepository) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Repository) DeepCopyInto(out *Repository) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Repository. -func (in *Repository) DeepCopy() *Repository { - if in == nil { - return nil - } - out := new(Repository) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Repository) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RepositoryList) DeepCopyInto(out *RepositoryList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Repository, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RepositoryList. -func (in *RepositoryList) DeepCopy() *RepositoryList { - if in == nil { - return nil - } - out := new(RepositoryList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RepositoryList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RepositoryRef) DeepCopyInto(out *RepositoryRef) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RepositoryRef. -func (in *RepositoryRef) DeepCopy() *RepositoryRef { - if in == nil { - return nil - } - out := new(RepositoryRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RepositorySpec) DeepCopyInto(out *RepositorySpec) { - *out = *in - if in.Git != nil { - in, out := &in.Git, &out.Git - *out = new(GitRepository) - **out = **in - } - if in.Oci != nil { - in, out := &in.Oci, &out.Oci - *out = new(OciRepository) - **out = **in - } - if in.Upstream != nil { - in, out := &in.Upstream, &out.Upstream - *out = new(UpstreamRepository) - (*in).DeepCopyInto(*out) - } - if in.Mutators != nil { - in, out := &in.Mutators, &out.Mutators - *out = make([]FunctionEval, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Validators != nil { - in, out := &in.Validators, &out.Validators - *out = make([]FunctionEval, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RepositorySpec. -func (in *RepositorySpec) DeepCopy() *RepositorySpec { - if in == nil { - return nil - } - out := new(RepositorySpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RepositoryStatus) DeepCopyInto(out *RepositoryStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RepositoryStatus. -func (in *RepositoryStatus) DeepCopy() *RepositoryStatus { - if in == nil { - return nil - } - out := new(RepositoryStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecretRef) DeepCopyInto(out *SecretRef) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretRef. -func (in *SecretRef) DeepCopy() *SecretRef { - if in == nil { - return nil - } - out := new(SecretRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *UpstreamRepository) DeepCopyInto(out *UpstreamRepository) { - *out = *in - if in.Git != nil { - in, out := &in.Git, &out.Git - *out = new(GitRepository) - **out = **in - } - if in.Oci != nil { - in, out := &in.Oci, &out.Oci - *out = new(OciRepository) - **out = **in - } - if in.RepositoryRef != nil { - in, out := &in.RepositoryRef, &out.RepositoryRef - *out = new(RepositoryRef) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpstreamRepository. -func (in *UpstreamRepository) DeepCopy() *UpstreamRepository { - if in == nil { - return nil - } - out := new(UpstreamRepository) - in.DeepCopyInto(out) - return out -} diff --git a/porch/build/Dockerfile.apiserver b/porch/build/Dockerfile.apiserver deleted file mode 100644 index e67d5a69bd..0000000000 --- a/porch/build/Dockerfile.apiserver +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2022 The kpt 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. - -FROM golang:1.21.6-bookworm as builder - -WORKDIR /workspace/src -RUN git clone https://github.com/kubernetes/kubernetes --branch v1.23.2 --depth=1 -WORKDIR /workspace/src/kubernetes -RUN apt-get update && apt-get install --yes rsync -RUN make generated_files -RUN CGO_ENABLED=0 go build -o /workspace/artifacts/kube-apiserver ./cmd/kube-apiserver - -FROM gcr.io/distroless/static -COPY --from=builder /workspace/artifacts/kube-apiserver /kube-apiserver - -#USER 65532:65532 - -ENTRYPOINT ["/kube-apiserver"] diff --git a/porch/build/Dockerfile.etcd b/porch/build/Dockerfile.etcd deleted file mode 100644 index 80b7d1493c..0000000000 --- a/porch/build/Dockerfile.etcd +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. - -FROM golang:1.21.6-bookworm as builder - -WORKDIR /workspace -ARG ETCD_VER=v3.5.1 -RUN curl -L https://github.com/etcd-io/etcd/releases/download/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz \ - | tar --strip-components 1 -xvz "etcd-${ETCD_VER}-linux-amd64/etcd" - -FROM gcr.io/distroless/static -WORKDIR /data -COPY --from=builder /workspace/etcd /etcd - -ENTRYPOINT ["/etcd"] diff --git a/porch/build/Dockerfile.porch b/porch/build/Dockerfile.porch deleted file mode 100644 index 98fcc8f582..0000000000 --- a/porch/build/Dockerfile.porch +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2022 The kpt 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. - - -FROM golang:1.21.6-bookworm as builder - -WORKDIR /go/src/github.com/GoogleContainerTools/kpt - -# cache deps before building and copying source so that we don't need to re-download as much -# and so that source changes don't invalidate our downloaded layer - -COPY go.mod go.sum ./ -COPY porch/go.mod porch/go.sum porch/ -COPY porch/api/go.mod porch/api/go.sum porch/api/ - -RUN echo "Downloading root modules ..." \ - && go mod download -RUN echo "Downloading porch modules ..." \ - && cd porch && go mod download -RUN echo "Downloading api modules ..." \ - && cd porch/api && go mod download - -ENV CGO_ENABLED=0 -# Prebuild some library dependencies to warm the cache -RUN cd porch; go build -v \ - google.golang.org/grpc \ - k8s.io/apiserver/pkg/server \ - k8s.io/component-base/cli \ - k8s.io/klog/v2 \ - github.com/google/go-containerregistry/pkg/gcrane \ - k8s.io/client-go/kubernetes/scheme \ - github.com/go-git/go-git/v5 \ - sigs.k8s.io/kustomize/kyaml/... - -COPY internal internal -COPY pkg pkg -COPY porch/api porch/api -COPY porch/cmd porch/cmd -COPY porch/pkg porch/pkg -COPY porch/internal porch/internal -COPY porch/controllers porch/controllers -COPY porch/func porch/func - -RUN cd porch; go build -v -o /porch ./cmd/porch - -FROM gcr.io/distroless/static:nonroot -COPY --from=builder --chown=nonroot:nonroot /porch /home/nonroot/porch -USER nonroot:nonroot -ENTRYPOINT ["/home/nonroot/porch"] diff --git a/porch/cmd/porch/main.go b/porch/cmd/porch/main.go deleted file mode 100644 index 2e92b76f8a..0000000000 --- a/porch/cmd/porch/main.go +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2022 The kpt 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. - -package main - -import ( - "context" - "fmt" - "net/http" - "net/url" - "os" - "strings" - "time" - - "github.com/GoogleContainerTools/kpt/porch/pkg/cmd/server" - "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" - "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" - "go.opentelemetry.io/otel/propagation" - "go.opentelemetry.io/otel/sdk/trace" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - genericapiserver "k8s.io/apiserver/pkg/server" - "k8s.io/component-base/cli" - "k8s.io/klog/v2" -) - -func main() { - code := run() - os.Exit(code) -} - -func run() int { - t := &telemetry{} - t.Start() - defer t.Stop() - - http.DefaultTransport = otelhttp.NewTransport(http.DefaultClient.Transport) - http.DefaultClient.Transport = http.DefaultTransport - - ctx := genericapiserver.SetupSignalContext() - - options := server.NewPorchServerOptions(os.Stdout, os.Stderr) - cmd := server.NewCommandStartPorchServer(ctx, options) - code := cli.Run(cmd) - return code -} - -type telemetry struct { - tp *trace.TracerProvider -} - -func (t *telemetry) Start() error { - config := os.Getenv("OTEL") - if config == "" { - return nil - } - - if config == "stdout" { - exporter, err := stdouttrace.New(stdouttrace.WithPrettyPrint()) - if err != nil { - return fmt.Errorf("error initializing stdout exporter: %w", err) - } - t.tp = trace.NewTracerProvider(trace.WithBatcher(exporter)) - - otel.SetTracerProvider(t.tp) - return nil - } - - // TODO: Is there any convention here? - if strings.HasPrefix(config, "otel://") { - ctx := context.Background() - - u, err := url.Parse(config) - if err != nil { - return fmt.Errorf("error parsing url %q: %w", config, err) - } - - endpoint := u.Host - - klog.Infof("tracing to %q", config) - - // See https://github.com/open-telemetry/opentelemetry-go/issues/1484 - ctx, cancel := context.WithTimeout(ctx, time.Second) - defer cancel() - conn, err := grpc.DialContext(ctx, endpoint, - grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.WithBlock(), - ) - if err != nil { - return fmt.Errorf("failed to create gRPC connection to collector: %w", err) - } - - // Set up a trace exporter - traceExporter, err := otlptracegrpc.New(ctx, otlptracegrpc.WithGRPCConn(conn)) - if err != nil { - return fmt.Errorf("failed to create trace exporter: %w", err) - } - // Register the trace exporter with a TracerProvider, using a batch - // span processor to aggregate spans before export. - bsp := trace.NewBatchSpanProcessor(traceExporter) - t.tp = trace.NewTracerProvider( - trace.WithSpanProcessor(bsp), - ) - otel.SetTracerProvider(t.tp) - - // set global propagator to tracecontext (the default is no-op). - otel.SetTextMapPropagator(propagation.TraceContext{}) - - return nil - } - - return fmt.Errorf("unknown OTEL configuration %q", config) -} - -func (t *telemetry) Stop() { - if t.tp != nil { - if err := t.tp.Shutdown(context.Background()); err != nil { - klog.Warningf("failed to shut down telemetry: %v", err) - } - t.tp = nil - } -} diff --git a/porch/controllers/Dockerfile b/porch/controllers/Dockerfile deleted file mode 100644 index 43b28d735f..0000000000 --- a/porch/controllers/Dockerfile +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2022 The kpt 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. - -FROM golang:1.21.6-bookworm as builder - -WORKDIR /workspace -COPY go.mod go.sum ./ -COPY porch/go.mod porch/go.sum porch/ -COPY porch/api/go.mod porch/api/go.sum porch/api/ - -WORKDIR /workspace/porch/controllers/ -RUN go mod download -# Prebuild some libraries to warm the cache -RUN CGO_ENABLED=0 go build -v \ - k8s.io/klog/v2 \ - k8s.io/klog/v2/klogr \ - sigs.k8s.io/controller-runtime \ - sigs.k8s.io/controller-runtime/pkg/client \ - sigs.k8s.io/controller-runtime/pkg/controller/controllerutil \ - k8s.io/client-go/kubernetes \ - go.opentelemetry.io/otel \ - github.com/google/go-containerregistry/pkg/gcrane \ - github.com/google/go-containerregistry/pkg/v1 \ - github.com/google/go-containerregistry/pkg/v1/cache \ - k8s.io/client-go/discovery/cached - -WORKDIR /workspace -COPY internal/ internal/ -COPY pkg/ pkg/ -COPY porch/api/ porch/api/ -COPY porch/controllers/ porch/controllers/ -COPY porch/pkg/ porch/pkg/ - -WORKDIR /workspace/porch/controllers/ -RUN CGO_ENABLED=0 go build -o /porch-controllers -v . - -FROM gcr.io/distroless/static -WORKDIR /data -COPY --from=builder /porch-controllers /porch-controllers - -ENTRYPOINT ["/porch-controllers"] diff --git a/porch/controllers/Makefile b/porch/controllers/Makefile deleted file mode 100644 index fba06dbcde..0000000000 --- a/porch/controllers/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2022 The kpt 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. - -# GCP project to use for development -GCP_PROJECT_ID ?= $(shell gcloud config get-value project) -IMAGE_TAG ?= latest -IMAGE_REPO ?= gcr.io/$(GCP_PROJECT_ID) -IMAGE_NAME ?= porch-controllers - -.PHONY: push-image -push-image: - cd ../..; docker buildx build --push --tag $(IMAGE_REPO)/$(IMAGE_NAME):$(IMAGE_TAG) -f porch/controllers/Dockerfile . - -.PHONY: build-image -build-image: - cd ../..; docker buildx build --load --tag $(IMAGE_REPO)/$(IMAGE_NAME):$(IMAGE_TAG) -f porch/controllers/Dockerfile . - - -.PHONY: run-local -run-local: - GCP_PROJECT_ID=${GCP_PROJECT_ID} go run . diff --git a/porch/controllers/config/crd/bases/config.porch.kpt.dev_fleetmembershipbindings.yaml b/porch/controllers/config/crd/bases/config.porch.kpt.dev_fleetmembershipbindings.yaml deleted file mode 100644 index 1385ab6c2e..0000000000 --- a/porch/controllers/config/crd/bases/config.porch.kpt.dev_fleetmembershipbindings.yaml +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: fleetmembershipbindings.config.porch.kpt.dev -spec: - group: config.porch.kpt.dev - names: - kind: FleetMembershipBinding - listKind: FleetMembershipBindingList - plural: fleetmembershipbindings - singular: fleetmembershipbinding - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - data: - description: Data contains the discovered (synced) information - properties: - binding: - type: string - labels: - additionalProperties: - type: string - type: object - location: - type: string - membership: - type: string - name: - type: string - project: - type: string - scope: - type: string - scopeFullName: - type: string - scopeLocation: - type: string - scopeProject: - type: string - state: - properties: - code: - type: string - type: object - required: - - membership - type: object - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - status: - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/porch/controllers/config/crd/bases/config.porch.kpt.dev_fleetmemberships.yaml b/porch/controllers/config/crd/bases/config.porch.kpt.dev_fleetmemberships.yaml deleted file mode 100644 index 3b64d3873d..0000000000 --- a/porch/controllers/config/crd/bases/config.porch.kpt.dev_fleetmemberships.yaml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: fleetmemberships.config.porch.kpt.dev -spec: - group: config.porch.kpt.dev - names: - kind: FleetMembership - listKind: FleetMembershipList - plural: fleetmemberships - singular: fleetmembership - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - data: - description: Data contains the discovered (synced) information - properties: - description: - type: string - fullName: - type: string - labels: - additionalProperties: - type: string - type: object - location: - type: string - membership: - type: string - project: - type: string - state: - properties: - code: - type: string - type: object - type: object - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - status: - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/porch/controllers/config/crd/bases/config.porch.kpt.dev_fleetscopes.yaml b/porch/controllers/config/crd/bases/config.porch.kpt.dev_fleetscopes.yaml deleted file mode 100644 index 8999b3f2b3..0000000000 --- a/porch/controllers/config/crd/bases/config.porch.kpt.dev_fleetscopes.yaml +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: fleetscopes.config.porch.kpt.dev -spec: - group: config.porch.kpt.dev - names: - kind: FleetScope - listKind: FleetScopeList - plural: fleetscopes - singular: fleetscope - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - data: - description: Data contains the discovered (synced) information - properties: - fullName: - type: string - labels: - additionalProperties: - type: string - type: object - location: - type: string - project: - type: string - scope: - type: string - state: - properties: - code: - type: string - type: object - type: object - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - status: - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/porch/controllers/config/crd/bases/config.porch.kpt.dev_fleetsyncs.yaml b/porch/controllers/config/crd/bases/config.porch.kpt.dev_fleetsyncs.yaml deleted file mode 100644 index ce69adc937..0000000000 --- a/porch/controllers/config/crd/bases/config.porch.kpt.dev_fleetsyncs.yaml +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: fleetsyncs.config.porch.kpt.dev -spec: - group: config.porch.kpt.dev - names: - kind: FleetSync - listKind: FleetSyncList - plural: fleetsyncs - singular: fleetsync - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - properties: - projectIds: - items: - type: string - type: array - required: - - projectIds - type: object - status: - properties: - conditions: - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - required: - - conditions - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/porch/controllers/config/crd/bases/config.porch.kpt.dev_packagevariants.yaml b/porch/controllers/config/crd/bases/config.porch.kpt.dev_packagevariants.yaml deleted file mode 100644 index eb3865d703..0000000000 --- a/porch/controllers/config/crd/bases/config.porch.kpt.dev_packagevariants.yaml +++ /dev/null @@ -1,424 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: packagevariants.config.porch.kpt.dev -spec: - group: config.porch.kpt.dev - names: - kind: PackageVariant - listKind: PackageVariantList - plural: packagevariants - singular: packagevariant - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: PackageVariant represents an upstream and downstream porch package - pair. The upstream package should already exist. The PackageVariant controller - is responsible for creating the downstream package revisions based on the - spec. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: PackageVariantSpec defines the desired state of PackageVariant - properties: - adoptionPolicy: - type: string - annotations: - additionalProperties: - type: string - type: object - deletionPolicy: - type: string - downstream: - properties: - package: - type: string - repo: - type: string - type: object - injectors: - items: - description: InjectionSelector specifies how to select in-cluster - objects for resolving injection points. - properties: - group: - type: string - kind: - type: string - name: - type: string - version: - type: string - required: - - name - type: object - type: array - labels: - additionalProperties: - type: string - type: object - packageContext: - description: PackageContext defines the data to be added or removed - from the kptfile.kpt.dev ConfigMap during reconciliation. - properties: - data: - additionalProperties: - type: string - type: object - removeKeys: - items: - type: string - type: array - type: object - pipeline: - description: Pipeline declares a pipeline of functions used to mutate - or validate resources. - properties: - mutators: - description: Mutators defines a list of of KRM functions that - mutate resources. - items: - description: Function specifies a KRM function. - properties: - configMap: - additionalProperties: - type: string - description: '`ConfigMap` is a convenient way to specify - a function config of kind ConfigMap.' - type: object - configPath: - description: '`ConfigPath` specifies a slash-delimited relative - path to a file in the current directory containing a KRM - resource used as the function config. This resource is - excluded when resolving ''sources'', and as a result cannot - be operated on by the pipeline.' - type: string - exclude: - description: '`Exclude` are used to specify resources on - which the function should NOT be executed. If not specified, - all resources selected by `Selectors` are selected.' - items: - description: Selector specifies the selection criteria - please update IsEmpty method if more properties are - added - properties: - annotations: - additionalProperties: - type: string - description: Annotations on the target resources - type: object - apiVersion: - description: APIVersion of the target resources - type: string - kind: - description: Kind of the target resources - type: string - labels: - additionalProperties: - type: string - description: Labels on the target resources - type: object - name: - description: Name of the target resources - type: string - namespace: - description: Namespace of the target resources - type: string - type: object - type: array - exec: - description: "Exec specifies the function binary executable. - The executable can be fully qualified or it must exists - in the $PATH e.g: \n exec: set-namespace exec: /usr/local/bin/my-custom-fn" - type: string - image: - description: "`Image` specifies the function container image. - It can either be fully qualified, e.g.: \n image: gcr.io/kpt-fn/set-labels - \n Optionally, kpt can be configured to use a image registry - host-path that will be used to resolve the image path - in case the image path is missing (Defaults to gcr.io/kpt-fn). - e.g. The following resolves to gcr.io/kpt-fn/set-labels: - \n image: set-labels" - type: string - name: - description: '`Name` is used to uniquely identify the function - declaration this is primarily used for merging function - declaration with upstream counterparts' - type: string - selectors: - description: '`Selectors` are used to specify resources - on which the function should be executed if not specified, - all resources are selected' - items: - description: Selector specifies the selection criteria - please update IsEmpty method if more properties are - added - properties: - annotations: - additionalProperties: - type: string - description: Annotations on the target resources - type: object - apiVersion: - description: APIVersion of the target resources - type: string - kind: - description: Kind of the target resources - type: string - labels: - additionalProperties: - type: string - description: Labels on the target resources - type: object - name: - description: Name of the target resources - type: string - namespace: - description: Namespace of the target resources - type: string - type: object - type: array - type: object - type: array - validators: - description: Validators defines a list of KRM functions that validate - resources. Validators are not permitted to mutate resources. - items: - description: Function specifies a KRM function. - properties: - configMap: - additionalProperties: - type: string - description: '`ConfigMap` is a convenient way to specify - a function config of kind ConfigMap.' - type: object - configPath: - description: '`ConfigPath` specifies a slash-delimited relative - path to a file in the current directory containing a KRM - resource used as the function config. This resource is - excluded when resolving ''sources'', and as a result cannot - be operated on by the pipeline.' - type: string - exclude: - description: '`Exclude` are used to specify resources on - which the function should NOT be executed. If not specified, - all resources selected by `Selectors` are selected.' - items: - description: Selector specifies the selection criteria - please update IsEmpty method if more properties are - added - properties: - annotations: - additionalProperties: - type: string - description: Annotations on the target resources - type: object - apiVersion: - description: APIVersion of the target resources - type: string - kind: - description: Kind of the target resources - type: string - labels: - additionalProperties: - type: string - description: Labels on the target resources - type: object - name: - description: Name of the target resources - type: string - namespace: - description: Namespace of the target resources - type: string - type: object - type: array - exec: - description: "Exec specifies the function binary executable. - The executable can be fully qualified or it must exists - in the $PATH e.g: \n exec: set-namespace exec: /usr/local/bin/my-custom-fn" - type: string - image: - description: "`Image` specifies the function container image. - It can either be fully qualified, e.g.: \n image: gcr.io/kpt-fn/set-labels - \n Optionally, kpt can be configured to use a image registry - host-path that will be used to resolve the image path - in case the image path is missing (Defaults to gcr.io/kpt-fn). - e.g. The following resolves to gcr.io/kpt-fn/set-labels: - \n image: set-labels" - type: string - name: - description: '`Name` is used to uniquely identify the function - declaration this is primarily used for merging function - declaration with upstream counterparts' - type: string - selectors: - description: '`Selectors` are used to specify resources - on which the function should be executed if not specified, - all resources are selected' - items: - description: Selector specifies the selection criteria - please update IsEmpty method if more properties are - added - properties: - annotations: - additionalProperties: - type: string - description: Annotations on the target resources - type: object - apiVersion: - description: APIVersion of the target resources - type: string - kind: - description: Kind of the target resources - type: string - labels: - additionalProperties: - type: string - description: Labels on the target resources - type: object - name: - description: Name of the target resources - type: string - namespace: - description: Namespace of the target resources - type: string - type: object - type: array - type: object - type: array - type: object - upstream: - properties: - package: - type: string - repo: - type: string - revision: - type: string - type: object - type: object - status: - description: PackageVariantStatus defines the observed state of PackageVariant - properties: - conditions: - description: Conditions describes the reconciliation state of the - object. - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - downstreamTargets: - description: DownstreamTargets contains the downstream targets that - the PackageVariant either created or adopted. - items: - properties: - name: - type: string - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/porch/controllers/config/crd/bases/config.porch.kpt.dev_packagevariantsets.yaml b/porch/controllers/config/crd/bases/config.porch.kpt.dev_packagevariantsets.yaml deleted file mode 100644 index 5c3c5e9418..0000000000 --- a/porch/controllers/config/crd/bases/config.porch.kpt.dev_packagevariantsets.yaml +++ /dev/null @@ -1,975 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: packagevariantsets.config.porch.kpt.dev -spec: - group: config.porch.kpt.dev - names: - kind: PackageVariantSet - listKind: PackageVariantSetList - plural: packagevariantsets - singular: packagevariantset - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: PackageVariantSet represents an upstream package revision and - a way to target specific downstream repositories where a variant of the - upstream package should be created. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: PackageVariantSetSpec defines the desired state of PackageVariantSet - properties: - adoptionPolicy: - type: string - annotations: - additionalProperties: - type: string - type: object - deletionPolicy: - type: string - labels: - additionalProperties: - type: string - type: object - targets: - items: - properties: - objects: - description: 'option 3: a selector against a set of arbitrary - objects' - properties: - repoName: - properties: - fromField: - type: string - value: - type: string - type: object - selectors: - items: - properties: - annotations: - additionalProperties: - type: string - description: Annotations on the target resources - type: object - apiVersion: - description: APIVersion of the target resources - type: string - kind: - description: Kind of the target resources - type: string - labelSelector: - description: Labels on the target resources - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are - ANDed. - items: - description: A label selector requirement is - a selector that contains values, a key, and - an operator that relates the key and values. - properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. If - the operator is Exists or DoesNotExist, - the values array must be empty. This array - is replaced during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is "In", - and the values array contains only "value". - The requirements are ANDed. - type: object - type: object - name: - description: Name of the target resources - type: string - namespace: - description: Namespace of the target resources - type: string - type: object - type: array - type: object - package: - description: 'option 1: an explicit repo/package name pair' - properties: - name: - type: string - repo: - type: string - type: object - packageName: - description: For options 2 and 3, PackageName specifies how - to create the name of the package variant - properties: - baseName: - properties: - fromField: - type: string - value: - type: string - type: object - namePrefix: - properties: - fromField: - type: string - value: - type: string - type: object - nameSuffix: - properties: - fromField: - type: string - value: - type: string - type: object - type: object - repositories: - description: 'option 2: a label selector against a set of repositories' - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. This - array is replaced during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field is - "key", the operator is "In", and the values array contains - only "value". The requirements are ANDed. - type: object - type: object - type: object - type: array - upstream: - properties: - package: - properties: - name: - type: string - repo: - type: string - type: object - ref: - type: string - revision: - type: string - type: object - type: object - status: - description: PackageVariantSetStatus defines the observed state of PackageVariantSet - properties: - conditions: - description: Conditions describes the reconciliation state of the - object. - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - type: object - type: object - served: false - storage: false - subresources: - status: {} - - name: v1alpha2 - schema: - openAPIV3Schema: - description: PackageVariantSet represents an upstream package revision and - a way to target specific downstream repositories where a variant of the - upstream package should be created. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: PackageVariantSetSpec defines the desired state of PackageVariantSet - properties: - targets: - items: - properties: - objectSelector: - description: 'option 3: a selector against a set of arbitrary - objects' - properties: - apiVersion: - description: APIVersion of the target resources - type: string - kind: - description: Kind of the target resources - type: string - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. This - array is replaced during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field is - "key", the operator is "In", and the values array contains - only "value". The requirements are ANDed. - type: object - name: - description: Name of the target resource - type: string - type: object - repositories: - description: 'Exactly one of Repositories, RepositorySeletor, - and ObjectSelector must be populated option 1: an explicit - repositories and package names' - items: - properties: - name: - description: Name contains the name of the Repository - resource, which must be in the same namespace as the - PackageVariantSet resource. - type: string - packageNames: - description: PackageNames contains names to use for package - instances in this repository; that is, the same upstream - will be instantiated multiple times using these names. - items: - type: string - type: array - required: - - name - type: object - type: array - repositorySelector: - description: 'option 2: a label selector against a set of repositories' - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. This - array is replaced during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field is - "key", the operator is "In", and the values array contains - only "value". The requirements are ANDed. - type: object - type: object - template: - description: Template specifies how to generate a PackageVariant - from a target - properties: - adoptionPolicy: - description: AdoptionPolicy allows overriding the PackageVariant - adoption policy - type: string - annotationExprs: - description: AnnotationsExprs allows specifying the spec.Annotations - field of the generated PackageVariant using CEL to dynamically - create the keys and values. Entries in this field take - precedent over those with the same keys that are present - in Annotations. - items: - description: MapExpr is used for various fields to calculate - map entries. Only one of Key and KeyExpr may be specified; - similarly only on of Value and ValueExpr may be specified. - properties: - key: - type: string - keyExpr: - type: string - value: - type: string - valueExpr: - type: string - type: object - type: array - annotations: - additionalProperties: - type: string - description: Annotations allows specifying the spec.Annotations - field of the generated PackageVariant - type: object - deletionPolicy: - description: DeletionPolicy allows overriding the PackageVariant - deletion policy - type: string - downstream: - description: Downstream allows overriding the default downstream - package and repository name - properties: - package: - type: string - packageExpr: - type: string - repo: - type: string - repoExpr: - type: string - type: object - injectors: - description: Injectors allows specifying the spec.Injectors - field of the generated PackageVariant - items: - description: InjectionSelectorTemplate is used to calculate - the injectors field of the resulting package variants. - Exactly one of the Name and NameExpr fields must be - specified. The other fields are optional. - properties: - group: - type: string - kind: - type: string - name: - type: string - nameExpr: - type: string - version: - type: string - type: object - type: array - labelExprs: - description: LabelsExprs allows specifying the spec.Labels - field of the generated PackageVariant using CEL to dynamically - create the keys and values. Entries in this field take - precedent over those with the same keys that are present - in Labels. - items: - description: MapExpr is used for various fields to calculate - map entries. Only one of Key and KeyExpr may be specified; - similarly only on of Value and ValueExpr may be specified. - properties: - key: - type: string - keyExpr: - type: string - value: - type: string - valueExpr: - type: string - type: object - type: array - labels: - additionalProperties: - type: string - description: Labels allows specifying the spec.Labels field - of the generated PackageVariant - type: object - packageContext: - description: PackageContext allows specifying the spec.PackageContext - field of the generated PackageVariant - properties: - data: - additionalProperties: - type: string - type: object - dataExprs: - items: - description: MapExpr is used for various fields to - calculate map entries. Only one of Key and KeyExpr - may be specified; similarly only on of Value and - ValueExpr may be specified. - properties: - key: - type: string - keyExpr: - type: string - value: - type: string - valueExpr: - type: string - type: object - type: array - removeKeyExprs: - items: - type: string - type: array - removeKeys: - items: - type: string - type: array - type: object - pipeline: - description: Pipeline allows specifying the spec.Pipeline - field of the generated PackageVariant - properties: - mutators: - description: Mutators is used to caculate the pipeline.mutators - field of the resulting package variants. - items: - description: FunctionTemplate is used in generating - KRM function pipeline entries; that is, it is used - to generate Kptfile Function objects. - properties: - configMap: - additionalProperties: - type: string - description: '`ConfigMap` is a convenient way - to specify a function config of kind ConfigMap.' - type: object - configMapExprs: - description: ConfigMapExprs allows use of CEL - to dynamically create the keys and values in - the function config ConfigMap. Entries in this - field take precedent over those with the same - keys that are present in ConfigMap. - items: - description: MapExpr is used for various fields - to calculate map entries. Only one of Key - and KeyExpr may be specified; similarly only - on of Value and ValueExpr may be specified. - properties: - key: - type: string - keyExpr: - type: string - value: - type: string - valueExpr: - type: string - type: object - type: array - configPath: - description: '`ConfigPath` specifies a slash-delimited - relative path to a file in the current directory - containing a KRM resource used as the function - config. This resource is excluded when resolving - ''sources'', and as a result cannot be operated - on by the pipeline.' - type: string - exclude: - description: '`Exclude` are used to specify resources - on which the function should NOT be executed. - If not specified, all resources selected by - `Selectors` are selected.' - items: - description: Selector specifies the selection - criteria please update IsEmpty method if more - properties are added - properties: - annotations: - additionalProperties: - type: string - description: Annotations on the target resources - type: object - apiVersion: - description: APIVersion of the target resources - type: string - kind: - description: Kind of the target resources - type: string - labels: - additionalProperties: - type: string - description: Labels on the target resources - type: object - name: - description: Name of the target resources - type: string - namespace: - description: Namespace of the target resources - type: string - type: object - type: array - exec: - description: "Exec specifies the function binary - executable. The executable can be fully qualified - or it must exists in the $PATH e.g: \n exec: - set-namespace exec: /usr/local/bin/my-custom-fn" - type: string - image: - description: "`Image` specifies the function container - image. It can either be fully qualified, e.g.: - \n image: gcr.io/kpt-fn/set-labels \n Optionally, - kpt can be configured to use a image registry - host-path that will be used to resolve the image - path in case the image path is missing (Defaults - to gcr.io/kpt-fn). e.g. The following resolves - to gcr.io/kpt-fn/set-labels: \n image: set-labels" - type: string - name: - description: '`Name` is used to uniquely identify - the function declaration this is primarily used - for merging function declaration with upstream - counterparts' - type: string - selectors: - description: '`Selectors` are used to specify - resources on which the function should be executed - if not specified, all resources are selected' - items: - description: Selector specifies the selection - criteria please update IsEmpty method if more - properties are added - properties: - annotations: - additionalProperties: - type: string - description: Annotations on the target resources - type: object - apiVersion: - description: APIVersion of the target resources - type: string - kind: - description: Kind of the target resources - type: string - labels: - additionalProperties: - type: string - description: Labels on the target resources - type: object - name: - description: Name of the target resources - type: string - namespace: - description: Namespace of the target resources - type: string - type: object - type: array - type: object - type: array - validators: - description: Validators is used to caculate the pipeline.validators - field of the resulting package variants. - items: - description: FunctionTemplate is used in generating - KRM function pipeline entries; that is, it is used - to generate Kptfile Function objects. - properties: - configMap: - additionalProperties: - type: string - description: '`ConfigMap` is a convenient way - to specify a function config of kind ConfigMap.' - type: object - configMapExprs: - description: ConfigMapExprs allows use of CEL - to dynamically create the keys and values in - the function config ConfigMap. Entries in this - field take precedent over those with the same - keys that are present in ConfigMap. - items: - description: MapExpr is used for various fields - to calculate map entries. Only one of Key - and KeyExpr may be specified; similarly only - on of Value and ValueExpr may be specified. - properties: - key: - type: string - keyExpr: - type: string - value: - type: string - valueExpr: - type: string - type: object - type: array - configPath: - description: '`ConfigPath` specifies a slash-delimited - relative path to a file in the current directory - containing a KRM resource used as the function - config. This resource is excluded when resolving - ''sources'', and as a result cannot be operated - on by the pipeline.' - type: string - exclude: - description: '`Exclude` are used to specify resources - on which the function should NOT be executed. - If not specified, all resources selected by - `Selectors` are selected.' - items: - description: Selector specifies the selection - criteria please update IsEmpty method if more - properties are added - properties: - annotations: - additionalProperties: - type: string - description: Annotations on the target resources - type: object - apiVersion: - description: APIVersion of the target resources - type: string - kind: - description: Kind of the target resources - type: string - labels: - additionalProperties: - type: string - description: Labels on the target resources - type: object - name: - description: Name of the target resources - type: string - namespace: - description: Namespace of the target resources - type: string - type: object - type: array - exec: - description: "Exec specifies the function binary - executable. The executable can be fully qualified - or it must exists in the $PATH e.g: \n exec: - set-namespace exec: /usr/local/bin/my-custom-fn" - type: string - image: - description: "`Image` specifies the function container - image. It can either be fully qualified, e.g.: - \n image: gcr.io/kpt-fn/set-labels \n Optionally, - kpt can be configured to use a image registry - host-path that will be used to resolve the image - path in case the image path is missing (Defaults - to gcr.io/kpt-fn). e.g. The following resolves - to gcr.io/kpt-fn/set-labels: \n image: set-labels" - type: string - name: - description: '`Name` is used to uniquely identify - the function declaration this is primarily used - for merging function declaration with upstream - counterparts' - type: string - selectors: - description: '`Selectors` are used to specify - resources on which the function should be executed - if not specified, all resources are selected' - items: - description: Selector specifies the selection - criteria please update IsEmpty method if more - properties are added - properties: - annotations: - additionalProperties: - type: string - description: Annotations on the target resources - type: object - apiVersion: - description: APIVersion of the target resources - type: string - kind: - description: Kind of the target resources - type: string - labels: - additionalProperties: - type: string - description: Labels on the target resources - type: object - name: - description: Name of the target resources - type: string - namespace: - description: Namespace of the target resources - type: string - type: object - type: array - type: object - type: array - type: object - type: object - type: object - type: array - upstream: - properties: - package: - type: string - repo: - type: string - revision: - type: string - type: object - type: object - status: - description: PackageVariantSetStatus defines the observed state of PackageVariantSet - properties: - conditions: - description: Conditions describes the reconciliation state of the - object. - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/porch/controllers/config/crd/bases/config.porch.kpt.dev_remoterootsyncsets.yaml b/porch/controllers/config/crd/bases/config.porch.kpt.dev_remoterootsyncsets.yaml deleted file mode 100644 index 386c0a437f..0000000000 --- a/porch/controllers/config/crd/bases/config.porch.kpt.dev_remoterootsyncsets.yaml +++ /dev/null @@ -1,303 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: remoterootsyncsets.config.porch.kpt.dev -spec: - group: config.porch.kpt.dev - names: - kind: RemoteRootSyncSet - listKind: RemoteRootSyncSetList - plural: remoterootsyncsets - singular: remoterootsyncset - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.aggregated.applied - name: AppliedCount - type: integer - - jsonPath: .status.aggregated.ready - name: ReadyCount - type: integer - - jsonPath: .status.aggregated.total - name: Total - type: integer - - jsonPath: .status.aggregated.conditions[?(@.type=='Applied')].reason - name: Applied - type: string - - jsonPath: .status.aggregated.conditions[?(@.type=='Ready')].reason - name: Ready - type: string - name: v1alpha1 - schema: - openAPIV3Schema: - description: "RemoteRootSyncSet represents applying a package to multiple - target clusters. In future, this should use ConfigSync, but while we're - iterating on OCI/porch support, and making a few similar iterations (e.g. - what feedback do we need for rollout), we're just applying directly to the - target cluster(s). \n We follow the \"managed remote objects\" pattern; - we don't want to create a mirror object, so we start with the \"ReplicaSet\" - of Pod/ReplicaSet/Deployment. \n spec.clusterRefs specifies the target clusters - \n spec.template maps to the spec of our \"Pod\", in this case a ConfigSync - RootSync/RepoSync. Because we're not actually using ConfigSync in this prototype, - we are only defining a small subset of fields." - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: RemoteRootSyncSetSpec defines the desired state of RemoteRootSync - properties: - clusterRefs: - items: - properties: - apiVersion: - type: string - kind: - type: string - name: - type: string - namespace: - type: string - type: object - type: array - template: - properties: - oci: - description: Git *GitInfo `json:"git,omitempty"` - properties: - repository: - type: string - type: object - packageRef: - description: PackageRef specifies a package as the source of the - objects to be applied. - properties: - name: - type: string - type: object - sourceFormat: - type: string - type: object - type: object - status: - description: RootSyncSetStatus defines the observed state of RootSyncSet - properties: - aggregated: - properties: - applied: - format: int32 - type: integer - conditions: - description: Conditions describes the reconciliation state of - the object. - items: - description: "Condition contains details for one aspect of the - current state of this API Resource. --- This struct is intended - for direct use as an array at the field path .status.conditions. - \ For example, \n type FooStatus struct{ // Represents the - observations of a foo's current state. // Known .status.conditions.type - are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type - // +patchStrategy=merge // +listType=map // +listMapKey=type - Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be - when the underlying condition changed. If that is not - known, then using the time when the API field changed - is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if - .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the - current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values - and meanings for this field, and whether the values are - considered a guaranteed API. The value should be a CamelCase - string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across - resources like Available, but because arbitrary conditions - can be useful (see .node.status.conditions), the ability - to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - ready: - format: int32 - type: integer - total: - format: int32 - type: integer - required: - - applied - - ready - - total - type: object - targets: - items: - properties: - conditions: - description: Conditions describes the reconciliation state of - the object. - items: - description: "Condition contains details for one aspect of - the current state of this API Resource. --- This struct - is intended for direct use as an array at the field path - .status.conditions. For example, \n type FooStatus struct{ - // Represents the observations of a foo's current state. - // Known .status.conditions.type are: \"Available\", \"Progressing\", - and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields - }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should - be when the underlying condition changed. If that is - not known, then using the time when the API field changed - is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, - if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the - current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier - indicating the reason for the condition's last transition. - Producers of specific condition types may define expected - values and meanings for this field, and whether the - values are considered a guaranteed API. The value should - be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across - resources like Available, but because arbitrary conditions - can be useful (see .node.status.conditions), the ability - to deconflict is important. The regex it matches is - (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - ref: - properties: - apiVersion: - type: string - kind: - type: string - name: - type: string - namespace: - type: string - type: object - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/porch/controllers/config/crd/bases/config.porch.kpt.dev_rootsyncdeployments.yaml b/porch/controllers/config/crd/bases/config.porch.kpt.dev_rootsyncdeployments.yaml deleted file mode 100644 index 7b47959164..0000000000 --- a/porch/controllers/config/crd/bases/config.porch.kpt.dev_rootsyncdeployments.yaml +++ /dev/null @@ -1,217 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: rootsyncdeployments.config.porch.kpt.dev -spec: - group: config.porch.kpt.dev - names: - kind: RootSyncDeployment - listKind: RootSyncDeploymentList - plural: rootsyncdeployments - singular: rootsyncdeployment - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: RootSyncDeployment is the Schema for the rootsyncdeployments - API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: RootSyncDeploymentSpec defines the desired state of RootSyncDeployment - properties: - packageRevision: - properties: - name: - type: string - namespace: - type: string - type: object - targets: - properties: - selector: - description: A label selector is a label query over a set of resources. - The result of matchLabels and matchExpressions are ANDed. An - empty label selector matches all objects. A null label selector - matches no objects. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If - the operator is In or NotIn, the values array must - be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced - during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} pairs. A - single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field is "key", - the operator is "In", and the values array contains only - "value". The requirements are ANDed. - type: object - type: object - type: object - type: object - status: - description: RootSyncDeploymentStatus defines the observed state of RootSyncDeployment - properties: - clusterRefStatuses: - items: - properties: - apiVersion: - type: string - kind: - type: string - name: - type: string - namespace: - type: string - revision: - type: string - synced: - type: boolean - required: - - synced - type: object - type: array - conditions: - description: Conditions describes the reconciliation state of the - object. - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - observedGeneration: - format: int64 - type: integer - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/porch/controllers/config/crd/bases/config.porch.kpt.dev_rootsyncrollouts.yaml b/porch/controllers/config/crd/bases/config.porch.kpt.dev_rootsyncrollouts.yaml deleted file mode 100644 index 981148290b..0000000000 --- a/porch/controllers/config/crd/bases/config.porch.kpt.dev_rootsyncrollouts.yaml +++ /dev/null @@ -1,264 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: rootsyncrollouts.config.porch.kpt.dev -spec: - group: config.porch.kpt.dev - names: - kind: RootSyncRollout - listKind: RootSyncRolloutList - plural: rootsyncrollouts - singular: rootsyncrollout - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: RootSyncRollout is the Schema for the rootsyncrollouts API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: RootSyncRolloutSpec - properties: - packages: - properties: - namespace: - type: string - selector: - description: A label selector is a label query over a set of resources. - The result of matchLabels and matchExpressions are ANDed. An - empty label selector matches all objects. A null label selector - matches no objects. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If - the operator is In or NotIn, the values array must - be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced - during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} pairs. A - single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field is "key", - the operator is "In", and the values array contains only - "value". The requirements are ANDed. - type: object - type: object - type: object - targets: - properties: - selector: - description: A label selector is a label query over a set of resources. - The result of matchLabels and matchExpressions are ANDed. An - empty label selector matches all objects. A null label selector - matches no objects. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If - the operator is In or NotIn, the values array must - be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced - during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} pairs. A - single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field is "key", - the operator is "In", and the values array contains only - "value". The requirements are ANDed. - type: object - type: object - type: object - type: object - status: - description: RootSyncRolloutStatus defines the observed state of RootSyncRollout - properties: - conditions: - description: Conditions describes the reconciliation state of the - object. - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - packageStatus: - items: - properties: - package: - type: string - revision: - items: - properties: - count: - type: integer - revision: - type: string - syncedCount: - type: integer - required: - - count - - revision - - syncedCount - type: object - type: array - required: - - package - - revision - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/porch/controllers/config/crd/bases/config.porch.kpt.dev_rootsyncsets.yaml b/porch/controllers/config/crd/bases/config.porch.kpt.dev_rootsyncsets.yaml deleted file mode 100644 index a2324a86ea..0000000000 --- a/porch/controllers/config/crd/bases/config.porch.kpt.dev_rootsyncsets.yaml +++ /dev/null @@ -1,208 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: rootsyncsets.config.porch.kpt.dev -spec: - group: config.porch.kpt.dev - names: - kind: RootSyncSet - listKind: RootSyncSetList - plural: rootsyncsets - singular: rootsyncset - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: RootSyncSet is the Schema for the rootsyncsets API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: RootSyncSetSpec defines the desired state of RootSyncSet - properties: - clusterRefs: - items: - properties: - apiVersion: - type: string - kind: - type: string - name: - type: string - namespace: - type: string - type: object - type: array - template: - properties: - spec: - properties: - git: - properties: - auth: - type: string - branch: - type: string - dir: - type: string - gcpServiceAccountEmail: - type: string - noSSLVerify: - type: boolean - period: - type: string - proxy: - type: string - repo: - type: string - revision: - type: string - secretRef: - description: SecretReference contains the reference to - the secret used to connect to Git source of truth. - properties: - name: - description: Name represents the secret name. - type: string - type: object - required: - - auth - - repo - type: object - sourceFormat: - type: string - type: object - type: object - type: object - status: - description: RootSyncSetStatus defines the observed state of RootSyncSet - properties: - clusterRefStatuses: - items: - properties: - apiVersion: - type: string - kind: - type: string - name: - type: string - namespace: - type: string - syncStatus: - type: string - type: object - type: array - conditions: - description: Conditions describes the reconciliation state of the - object. - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - observedGeneration: - format: int64 - type: integer - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/porch/controllers/config/crd/bases/config.porch.kpt.dev_workloadidentitybindings.yaml b/porch/controllers/config/crd/bases/config.porch.kpt.dev_workloadidentitybindings.yaml deleted file mode 100644 index 8a8592e158..0000000000 --- a/porch/controllers/config/crd/bases/config.porch.kpt.dev_workloadidentitybindings.yaml +++ /dev/null @@ -1,159 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: workloadidentitybindings.config.porch.kpt.dev -spec: - group: config.porch.kpt.dev - names: - kind: WorkloadIdentityBinding - listKind: WorkloadIdentityBindingList - plural: workloadidentitybindings - singular: workloadidentitybinding - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=='Ready')].reason - name: Ready - type: string - name: v1alpha1 - schema: - openAPIV3Schema: - description: WorkloadIdentityBinding - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: WorkloadIdentityBindingSpec defines the desired state of - WorkloadIdentityBinding - properties: - gcpServiceAccountRef: - properties: - external: - type: string - name: - type: string - namespace: - type: string - type: object - kubernetesServiceAccountRef: - properties: - name: - type: string - namespace: - type: string - type: object - type: object - status: - description: WorkloadIdentityBindingStatus defines the observed state - of WorkloadIdentityBinding - properties: - conditions: - description: Conditions describes the reconciliation state of the - object. - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/porch/controllers/config/rbac/role.yaml b/porch/controllers/config/rbac/role.yaml deleted file mode 100644 index d301898724..0000000000 --- a/porch/controllers/config/rbac/role.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - name: porch-controllers -rules: -- apiGroups: - - "" - resources: - - events - verbs: - - create - - patch -- apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - create - - delete - - get - - list - - patch - - update - - watch diff --git a/porch/controllers/config/rbac/rolebinding.yaml b/porch/controllers/config/rbac/rolebinding.yaml deleted file mode 100644 index d2b97ff8be..0000000000 --- a/porch/controllers/config/rbac/rolebinding.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: porch-system:porch-controllers -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: porch-controllers -subjects: -- kind: ServiceAccount - name: porch-controllers - namespace: porch-system \ No newline at end of file diff --git a/porch/controllers/fleetsyncs/api/v1alpha1/fleetmembership_types.go b/porch/controllers/fleetsyncs/api/v1alpha1/fleetmembership_types.go deleted file mode 100644 index d92b19c1db..0000000000 --- a/porch/controllers/fleetsyncs/api/v1alpha1/fleetmembership_types.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2023 The kpt 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. - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type FleetMembershipData struct { - FullName string `json:"fullName,omitempty"` - Project string `json:"project,omitempty"` - Location string `json:"location,omitempty"` - Membership string `json:"membership,omitempty"` - Description string `json:"description,omitempty"` - - Labels map[string]string `json:"labels,omitempty"` - - State MembershipState `json:"state,omitempty"` -} - -type MembershipState struct { - Code MembershipStateCode `json:"code,omitempty"` -} - -type MembershipStateCode string - -const ( - MSCodeUnspecified MembershipStateCode = "unspecified" - MSCodeCreating MembershipStateCode = "creating" - MSCodeReady MembershipStateCode = "ready" - MSCodeDeleting MembershipStateCode = "deleting" - MSCodeUpdating MembershipStateCode = "updating" - MSCodeServiceUpdating MembershipStateCode = "serviceupdating" -) - -type FleetMembershipStatus struct { -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -type FleetMembership struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - // Data contains the discovered (synced) information - Data FleetMembershipData `json:"data,omitempty"` - Status FleetMembershipStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -type FleetMembershipList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []FleetMembership `json:"items"` -} - -func init() { - SchemeBuilder.Register(&FleetMembership{}, &FleetMembershipList{}) -} diff --git a/porch/controllers/fleetsyncs/api/v1alpha1/fleetmembershipbindings_types.go b/porch/controllers/fleetsyncs/api/v1alpha1/fleetmembershipbindings_types.go deleted file mode 100644 index aec5780a1b..0000000000 --- a/porch/controllers/fleetsyncs/api/v1alpha1/fleetmembershipbindings_types.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2023 The kpt 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. - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type FleetMembershipBindingData struct { - FullName string `json:"name,omitempty"` - Project string `json:"project,omitempty"` - Location string `json:"location,omitempty"` - Membership string `json:"membership",omitempty"` - Binding string `json:"binding,omitempty"` - - ScopeFullName string `json:"scopeFullName,omitempty"` - ScopeProject string `json:"scopeProject,omitempty"` - ScopeLocation string `json:"scopeLocation,omitempty"` - Scope string `json:"scope,omitempty"` - - Labels map[string]string `json:"labels,omitempty"` - - State MembershipBindingState `json:"state,omitempty"` -} - -type MembershipBindingState struct { - Code MembershipBindingStateCode `json:"code,omitempty"` -} - -type MembershipBindingStateCode string - -const ( - MBSCodeUnspecified MembershipBindingStateCode = "unspecified" - MBSCodeCreating MembershipBindingStateCode = "creating" - MBSCodeReady MembershipBindingStateCode = "ready" - MBSCodeDeleting MembershipBindingStateCode = "deleting" - MBSCodeUpdating MembershipBindingStateCode = "updating" -) - -type FleetMembershipBindingStatus struct { -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -type FleetMembershipBinding struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - // Data contains the discovered (synced) information - Data FleetMembershipBindingData `json:"data,omitempty"` - Status FleetMembershipBindingStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -type FleetMembershipBindingList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []FleetMembershipBinding `json:"items"` -} - -func init() { - SchemeBuilder.Register(&FleetMembershipBinding{}, &FleetMembershipBindingList{}) -} diff --git a/porch/controllers/fleetsyncs/api/v1alpha1/fleetscope_types.go b/porch/controllers/fleetsyncs/api/v1alpha1/fleetscope_types.go deleted file mode 100644 index c448d6a425..0000000000 --- a/porch/controllers/fleetsyncs/api/v1alpha1/fleetscope_types.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2023 The kpt 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. - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type FleetScopeData struct { - FullName string `json:"fullName,omitempty"` - Project string `json:"project,omitempty"` - Location string `json:"location,omitempty"` - Scope string `json:"scope,omitempty"` - - Labels map[string]string `json:"labels,omitempty"` - - State ScopeState `json:"state,omitempty"` -} - -type ScopeState struct { - Code ScopeStateCode `json:"code,omitempty"` -} - -type ScopeStateCode string - -const ( - SSCodeUnspecified ScopeStateCode = "unspecified" - SSCodeCreating ScopeStateCode = "creating" - SSCodeReady ScopeStateCode = "ready" - SSCodeDeleting ScopeStateCode = "deleting" - SSCodeUpdating ScopeStateCode = "updating" -) - -type FleetScopeStatus struct { -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -type FleetScope struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - // Data contains the discovered (synced) information - Data FleetScopeData `json:"data,omitempty"` - Status FleetScopeStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -type FleetScopeList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []FleetScope `json:"items"` -} - -func init() { - SchemeBuilder.Register(&FleetScope{}, &FleetScopeList{}) -} diff --git a/porch/controllers/fleetsyncs/api/v1alpha1/fleetsync_types.go b/porch/controllers/fleetsyncs/api/v1alpha1/fleetsync_types.go deleted file mode 100644 index 21ade5d883..0000000000 --- a/porch/controllers/fleetsyncs/api/v1alpha1/fleetsync_types.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2023 The kpt 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. - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type FleetSyncSpec struct { - ProjectIds []string `json:"projectIds"` -} - -type FleetSyncStatus struct { - Conditions []metav1.Condition `json:"conditions"` -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -type FleetSync struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec FleetSyncSpec `json:"spec,omitempty"` - Status FleetSyncStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -type FleetSyncList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []FleetSync `json:"items"` -} - -func init() { - SchemeBuilder.Register(&FleetSync{}, &FleetSyncList{}) -} diff --git a/porch/controllers/fleetsyncs/api/v1alpha1/groupversion_info.go b/porch/controllers/fleetsyncs/api/v1alpha1/groupversion_info.go deleted file mode 100644 index 9bfe85dda4..0000000000 --- a/porch/controllers/fleetsyncs/api/v1alpha1/groupversion_info.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2023 The kpt 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. - -// Package v1alpha1 contains API Schema definitions for the config.porch.kpt.dev v1alpha1 API group -// +kubebuilder:object:generate=true -// +groupName=config.porch.kpt.dev -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/scheme" -) - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 object:headerFile="../../../../scripts/boilerplate.go.txt" paths="./..." - -var ( - // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "config.porch.kpt.dev", Version: "v1alpha1"} - - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} - - // AddToScheme adds the types in this group-version to the given scheme. - AddToScheme = SchemeBuilder.AddToScheme -) diff --git a/porch/controllers/fleetsyncs/api/v1alpha1/zz_generated.deepcopy.go b/porch/controllers/fleetsyncs/api/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index b86dfc7e88..0000000000 --- a/porch/controllers/fleetsyncs/api/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,462 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// Copyright 2023 The kpt 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 controller-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetMembership) DeepCopyInto(out *FleetMembership) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Data.DeepCopyInto(&out.Data) - out.Status = in.Status -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetMembership. -func (in *FleetMembership) DeepCopy() *FleetMembership { - if in == nil { - return nil - } - out := new(FleetMembership) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FleetMembership) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetMembershipBinding) DeepCopyInto(out *FleetMembershipBinding) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Data.DeepCopyInto(&out.Data) - out.Status = in.Status -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetMembershipBinding. -func (in *FleetMembershipBinding) DeepCopy() *FleetMembershipBinding { - if in == nil { - return nil - } - out := new(FleetMembershipBinding) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FleetMembershipBinding) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetMembershipBindingData) DeepCopyInto(out *FleetMembershipBindingData) { - *out = *in - if in.Labels != nil { - in, out := &in.Labels, &out.Labels - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - out.State = in.State -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetMembershipBindingData. -func (in *FleetMembershipBindingData) DeepCopy() *FleetMembershipBindingData { - if in == nil { - return nil - } - out := new(FleetMembershipBindingData) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetMembershipBindingList) DeepCopyInto(out *FleetMembershipBindingList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]FleetMembershipBinding, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetMembershipBindingList. -func (in *FleetMembershipBindingList) DeepCopy() *FleetMembershipBindingList { - if in == nil { - return nil - } - out := new(FleetMembershipBindingList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FleetMembershipBindingList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetMembershipBindingStatus) DeepCopyInto(out *FleetMembershipBindingStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetMembershipBindingStatus. -func (in *FleetMembershipBindingStatus) DeepCopy() *FleetMembershipBindingStatus { - if in == nil { - return nil - } - out := new(FleetMembershipBindingStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetMembershipData) DeepCopyInto(out *FleetMembershipData) { - *out = *in - if in.Labels != nil { - in, out := &in.Labels, &out.Labels - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - out.State = in.State -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetMembershipData. -func (in *FleetMembershipData) DeepCopy() *FleetMembershipData { - if in == nil { - return nil - } - out := new(FleetMembershipData) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetMembershipList) DeepCopyInto(out *FleetMembershipList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]FleetMembership, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetMembershipList. -func (in *FleetMembershipList) DeepCopy() *FleetMembershipList { - if in == nil { - return nil - } - out := new(FleetMembershipList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FleetMembershipList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetMembershipStatus) DeepCopyInto(out *FleetMembershipStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetMembershipStatus. -func (in *FleetMembershipStatus) DeepCopy() *FleetMembershipStatus { - if in == nil { - return nil - } - out := new(FleetMembershipStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetScope) DeepCopyInto(out *FleetScope) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Data.DeepCopyInto(&out.Data) - out.Status = in.Status -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetScope. -func (in *FleetScope) DeepCopy() *FleetScope { - if in == nil { - return nil - } - out := new(FleetScope) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FleetScope) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetScopeData) DeepCopyInto(out *FleetScopeData) { - *out = *in - if in.Labels != nil { - in, out := &in.Labels, &out.Labels - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - out.State = in.State -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetScopeData. -func (in *FleetScopeData) DeepCopy() *FleetScopeData { - if in == nil { - return nil - } - out := new(FleetScopeData) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetScopeList) DeepCopyInto(out *FleetScopeList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]FleetScope, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetScopeList. -func (in *FleetScopeList) DeepCopy() *FleetScopeList { - if in == nil { - return nil - } - out := new(FleetScopeList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FleetScopeList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetScopeStatus) DeepCopyInto(out *FleetScopeStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetScopeStatus. -func (in *FleetScopeStatus) DeepCopy() *FleetScopeStatus { - if in == nil { - return nil - } - out := new(FleetScopeStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetSync) DeepCopyInto(out *FleetSync) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetSync. -func (in *FleetSync) DeepCopy() *FleetSync { - if in == nil { - return nil - } - out := new(FleetSync) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FleetSync) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetSyncList) DeepCopyInto(out *FleetSyncList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]FleetSync, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetSyncList. -func (in *FleetSyncList) DeepCopy() *FleetSyncList { - if in == nil { - return nil - } - out := new(FleetSyncList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FleetSyncList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetSyncSpec) DeepCopyInto(out *FleetSyncSpec) { - *out = *in - if in.ProjectIds != nil { - in, out := &in.ProjectIds, &out.ProjectIds - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetSyncSpec. -func (in *FleetSyncSpec) DeepCopy() *FleetSyncSpec { - if in == nil { - return nil - } - out := new(FleetSyncSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetSyncStatus) DeepCopyInto(out *FleetSyncStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetSyncStatus. -func (in *FleetSyncStatus) DeepCopy() *FleetSyncStatus { - if in == nil { - return nil - } - out := new(FleetSyncStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MembershipBindingState) DeepCopyInto(out *MembershipBindingState) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MembershipBindingState. -func (in *MembershipBindingState) DeepCopy() *MembershipBindingState { - if in == nil { - return nil - } - out := new(MembershipBindingState) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MembershipState) DeepCopyInto(out *MembershipState) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MembershipState. -func (in *MembershipState) DeepCopy() *MembershipState { - if in == nil { - return nil - } - out := new(MembershipState) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ScopeState) DeepCopyInto(out *ScopeState) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScopeState. -func (in *ScopeState) DeepCopy() *ScopeState { - if in == nil { - return nil - } - out := new(ScopeState) - in.DeepCopyInto(out) - return out -} diff --git a/porch/controllers/fleetsyncs/config/rbac/role.yaml b/porch/controllers/fleetsyncs/config/rbac/role.yaml deleted file mode 100644 index 1e765f3722..0000000000 --- a/porch/controllers/fleetsyncs/config/rbac/role.yaml +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - name: porch-controllers-fleetsyncs -rules: -- apiGroups: - - config.porch.kpt.dev - resources: - - fleetmembershipbindings - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - config.porch.kpt.dev - resources: - - fleetmemberships - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - config.porch.kpt.dev - resources: - - fleetscopes - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - config.porch.kpt.dev - resources: - - fleetsyncs - verbs: - - get - - list - - watch -- apiGroups: - - config.porch.kpt.dev - resources: - - fleetsyncs/finalizers - verbs: - - update -- apiGroups: - - config.porch.kpt.dev - resources: - - fleetsyncs/status - verbs: - - get - - patch - - update diff --git a/porch/controllers/fleetsyncs/config/rbac/rolebinding.yaml b/porch/controllers/fleetsyncs/config/rbac/rolebinding.yaml deleted file mode 100644 index 1850fbe355..0000000000 --- a/porch/controllers/fleetsyncs/config/rbac/rolebinding.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2023 The kpt 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. - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: porch-system:porch-controllers-fleetsyncs -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: porch-controllers-fleetsyncs -subjects: -- kind: ServiceAccount - name: porch-controllers - namespace: porch-system \ No newline at end of file diff --git a/porch/controllers/fleetsyncs/config/samples/simple.yaml b/porch/controllers/fleetsyncs/config/samples/simple.yaml deleted file mode 100644 index 9310a5d964..0000000000 --- a/porch/controllers/fleetsyncs/config/samples/simple.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2023 The kpt 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. - -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: FleetSync -metadata: - name: simple - namespace: default -spec: - projectIds: - - example diff --git a/porch/controllers/fleetsyncs/pkg/controllers/fleetsync/controller.go b/porch/controllers/fleetsyncs/pkg/controllers/fleetsync/controller.go deleted file mode 100644 index 811e0d1fce..0000000000 --- a/porch/controllers/fleetsyncs/pkg/controllers/fleetsync/controller.go +++ /dev/null @@ -1,718 +0,0 @@ -// Copyright 2023 The kpt 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. - -package fleetsync - -import ( - "context" - "flag" - "fmt" - "strings" - - "k8s.io/client-go/tools/record" - - "github.com/GoogleContainerTools/kpt/porch/controllers/fleetsyncs/api/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/controllers/fleetsyncs/pkg/controllers/fleetsync/fleetpoller" - "github.com/GoogleContainerTools/kpt/porch/pkg/util" - gkehubv1 "google.golang.org/api/gkehub/v1" - "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/api/meta" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/klog/v2" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/source" -) - -const ( - fleetSyncLabel = "fleetsync.porch.kpt.dev/fleetsync" - projectLabel = "fleetsync.porch.kpt.dev/project" - scopeLabel = "fleetsync.porch.kpt.dev/scope" - membershipLabel = "fleetsync.porch.kpt.dev/membership" - nameMaxLen = 63 - nameHashLen = 8 -) - -type Options struct { -} - -func (o *Options) InitDefaults() { -} - -func (o *Options) BindFlags(prefix string, flags *flag.FlagSet) { -} - -func NewFleetSyncReconciler() *FleetSyncReconciler { - return &FleetSyncReconciler{} -} - -type FleetSyncReconciler struct { - Options - - client.Client - - poller *fleetpoller.Poller - recorder record.EventRecorder -} - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 rbac:roleName=porch-controllers-fleetsyncs webhook paths="." output:rbac:artifacts:config=../../../config/rbac - -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=fleetsyncs,verbs=get;list;watch -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=fleetsyncs/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=fleetsyncs/finalizers,verbs=update -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=fleetmemberships,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=fleetmembershipbindings,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=fleetscopes,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups="",resources=events,verbs=create;patch - -func (r *FleetSyncReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - var fleetsync v1alpha1.FleetSync - if err := r.Get(ctx, req.NamespacedName, &fleetsync); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - orig := fleetsync.DeepCopy() - - myFinalizerName := "config.porch.kpt.dev/fleetsyncs" - if fleetsync.ObjectMeta.DeletionTimestamp.IsZero() { - // The object is not being deleted, so if it does not have our finalizer, - // then lets add the finalizer and update the object. This is equivalent - // registering our finalizer. - if !controllerutil.ContainsFinalizer(&fleetsync, myFinalizerName) { - controllerutil.AddFinalizer(&fleetsync, myFinalizerName) - if err := r.Update(ctx, &fleetsync); err != nil { - return ctrl.Result{}, fmt.Errorf("error adding finalizer: %w", err) - } - } - } else { - // The object is being deleted - if controllerutil.ContainsFinalizer(&fleetsync, myFinalizerName) { - // remove our finalizer from the list and update it. - r.poller.StopPollingForFleetSync(req.NamespacedName) - controllerutil.RemoveFinalizer(&fleetsync, myFinalizerName) - if err := r.Update(ctx, &fleetsync); err != nil { - return ctrl.Result{}, fmt.Errorf("failed to update %s after delete finalizer: %w", req.Name, err) - } - } - // Stop reconciliation as the item is being deleted - return ctrl.Result{}, nil - } - klog.Infof("Reconciling %s", req.NamespacedName.String()) - - r.poller.VerifyProjectIdsForFleetSync(req.NamespacedName, fleetsync.Spec.ProjectIds) - - allFailed := true - for _, projectId := range fleetsync.Spec.ProjectIds { - err := r.reconcileProject(ctx, projectId, orig, &fleetsync) - if err != nil { - r.recorder.Event(&fleetsync, corev1.EventTypeWarning, "ProjectSyncError", - fmt.Sprintf("could not sync project %q: %s", projectId, err.Error())) - } else { - allFailed = false - } - } - if allFailed { - r.setErrorCondition(ctx, orig, &fleetsync, "No projects succesfully reconciled") - } - - return ctrl.Result{}, nil -} - -func (r *FleetSyncReconciler) reconcileProject(ctx context.Context, projectId string, orig, fleetsync *v1alpha1.FleetSync) error { - pr, found := r.poller.LatestResult(projectId) - if !found { - r.recorder.Event(fleetsync, corev1.EventTypeNormal, "ProjectSyncPending", - fmt.Sprintf("Waiting for sync for project %q", projectId)) - return nil - } - - // If there are any errors for this project ID, we will not - // sync any data for the project. - if pr.HasError() { - return pr.ErrorSummary() - } - - err := r.reconcileMemberships(ctx, projectId, pr, fleetsync) - if err != nil { - return err - } - - err = r.reconcileScopes(ctx, projectId, pr, fleetsync) - if err != nil { - return err - } - - err = r.reconcileMembershipBindings(ctx, projectId, pr, fleetsync) - if err != nil { - return err - } - - r.setReadyCondition(ctx, orig, fleetsync) - return nil -} - -func (r *FleetSyncReconciler) reconcileMemberships(ctx context.Context, projectId string, pr *fleetpoller.PollResult, fleetsync *v1alpha1.FleetSync) error { - existingMemberships, err := r.findExistingMemberships(ctx, fleetsync.Name, fleetsync.Namespace, projectId) - if err != nil { - return err - } - - for _, hubm := range pr.Memberships { - name, err := membershipId(hubm) - if err != nil { - klog.Warningf("could not create new membership: %s", err.Error()) - continue - } - - existing, found := existingMemberships[name] - if !found { - m, err := newMembership(hubm, fleetsync) - if err != nil { - klog.Warningf("could not create new membership: %s", err.Error()) - continue - } - // TODO: We should probably use SSA here rather than Create/Update. - if err := r.Create(ctx, m); err != nil { - return err - } - continue - } - - updated := existing.DeepCopy() - err = updateMembership(hubm, fleetsync, updated) - if err != nil { - klog.Warningf("could not update membership: %s", err.Error()) - continue - } - - if !equality.Semantic.DeepEqual(updated.Data, existing.Data) { - if err := r.Update(ctx, updated); err != nil { - return err - } - } - } - - for name, m := range existingMemberships { - found := false - for _, hubm := range pr.Memberships { - hubmName, err := membershipId(hubm) - if err != nil { - klog.Warning(err) - continue - } - if hubmName == name { - found = true - } - } - if !found { - if err := r.Delete(ctx, m); err != nil { - return err - } - } - } - - return nil -} - -func (r *FleetSyncReconciler) reconcileScopes(ctx context.Context, projectId string, pr *fleetpoller.PollResult, fleetsync *v1alpha1.FleetSync) error { - existingScopes, err := r.findExistingScopes(ctx, fleetsync.Name, fleetsync.Namespace, projectId) - if err != nil { - return err - } - - for _, res := range pr.Scopes { - name, err := scopeId(res) - if err != nil { - klog.Warningf("could not create new scope: %s", err.Error()) - continue - } - - existing, found := existingScopes[name] - if !found { - m, err := newScope(res, fleetsync) - if err != nil { - klog.Warningf("could not create new scope: %s", err.Error()) - continue - } - // TODO: We should probably use SSA here rather than Create/Update. - if err := r.Create(ctx, m); err != nil { - return err - } - continue - } - - updated := existing.DeepCopy() - err = updateScope(res, fleetsync, updated) - if err != nil { - klog.Warningf("could not update scope: %s", err.Error()) - continue - } - - if !equality.Semantic.DeepEqual(updated.Data, existing.Data) { - if err := r.Update(ctx, updated); err != nil { - return err - } - } - } - - for name, m := range existingScopes { - found := false - for _, res := range pr.Scopes { - resName, err := scopeId(res) - if err != nil { - klog.Warning(err) - continue - } - if resName == name { - found = true - } - } - if !found { - if err := r.Delete(ctx, m); err != nil { - return err - } - } - } - - return nil -} - -func (r *FleetSyncReconciler) reconcileMembershipBindings(ctx context.Context, projectId string, pr *fleetpoller.PollResult, fleetsync *v1alpha1.FleetSync) error { - existingBindings, err := r.findExistingMembershipBindings(ctx, fleetsync.Name, fleetsync.Namespace, projectId) - if err != nil { - return err - } - - for _, res := range pr.Bindings { - name, err := bindingId(res) - if err != nil { - klog.Warningf("could not create new binding: %s", err.Error()) - continue - } - - existing, found := existingBindings[name] - if !found { - m, err := newMembershipBinding(res, fleetsync) - if err != nil { - klog.Warningf("could not create new binding: %s", err.Error()) - continue - } - // TODO: We should probably use SSA here rather than Create/Update. - if err := r.Create(ctx, m); err != nil { - return err - } - continue - } - - updated := existing.DeepCopy() - err = updateMembershipBinding(res, fleetsync, updated) - if err != nil { - klog.Warningf("could not update binding: %s", err.Error()) - continue - } - - if !equality.Semantic.DeepEqual(updated.Data, existing.Data) { - if err := r.Update(ctx, updated); err != nil { - return err - } - } - } - - for name, m := range existingBindings { - found := false - for _, res := range pr.Bindings { - resName, err := bindingId(res) - if err != nil { - klog.Warning(err) - continue - } - if resName == name { - found = true - } - } - if !found { - if err := r.Delete(ctx, m); err != nil { - return err - } - } - } - - return nil -} - -func (r *FleetSyncReconciler) setReadyCondition(ctx context.Context, orig, fleetsync *v1alpha1.FleetSync) { - meta.SetStatusCondition(&fleetsync.Status.Conditions, metav1.Condition{ - Type: "Ready", - Status: metav1.ConditionTrue, - ObservedGeneration: fleetsync.Generation, - Reason: "Synced", - }) - meta.SetStatusCondition(&fleetsync.Status.Conditions, metav1.Condition{ - Type: "Stalled", - Status: metav1.ConditionFalse, - ObservedGeneration: fleetsync.Generation, - Reason: "Synced", - }) - if err := r.updateStatus(ctx, orig, fleetsync); err != nil { - klog.Errorf("Error updating status for %s/%s: %v", fleetsync.Namespace, fleetsync.Name, err) - } -} - -func (r *FleetSyncReconciler) setErrorCondition(ctx context.Context, orig, fleetsync *v1alpha1.FleetSync, message string) { - meta.SetStatusCondition(&fleetsync.Status.Conditions, metav1.Condition{ - Type: "Ready", - Status: metav1.ConditionFalse, - ObservedGeneration: fleetsync.Generation, - Reason: "FleetSyncError", - }) - meta.SetStatusCondition(&fleetsync.Status.Conditions, metav1.Condition{ - Type: "Stalled", - Status: metav1.ConditionTrue, - ObservedGeneration: fleetsync.Generation, - Reason: "FleetSyncError", - Message: message, - }) - if err := r.updateStatus(ctx, orig, fleetsync); err != nil { - klog.Errorf("Error updating status for %s/%s: %v", fleetsync.Namespace, fleetsync.Name, err) - } -} - -func newMembership(hubMembership *gkehubv1.Membership, fleetsync *v1alpha1.FleetSync) (*v1alpha1.FleetMembership, error) { - id, err := membershipId(hubMembership) - if err != nil { - return nil, err - } - - t := true - fm := &v1alpha1.FleetMembership{ - ObjectMeta: metav1.ObjectMeta{ - Name: id, - Namespace: fleetsync.Namespace, - Labels: map[string]string{}, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: fleetsync.APIVersion, - Kind: fleetsync.Kind, - Name: fleetsync.Name, - UID: fleetsync.UID, - Controller: &t, - }, - }, - }, - } - - return fm, updateMembership(hubMembership, fleetsync, fm) -} - -func updateMembership(hubMembership *gkehubv1.Membership, fleetsync *v1alpha1.FleetSync, fm *v1alpha1.FleetMembership) error { - segments := strings.Split(hubMembership.Name, "/") - if len(segments) != 6 { - return fmt.Errorf("invalid membership name %q; should be 6 segments", hubMembership.Name) - } - - fm.ObjectMeta.Labels[fleetSyncLabel] = fleetsync.Name - fm.ObjectMeta.Labels[projectLabel] = segments[1] - fm.ObjectMeta.Labels[membershipLabel] = segments[5] - - fm.Data = v1alpha1.FleetMembershipData{ - FullName: hubMembership.Name, - Project: segments[1], - Location: segments[3], - Membership: segments[5], - Description: hubMembership.Description, - Labels: hubMembership.Labels, - State: v1alpha1.MembershipState{ - Code: toMembershipStateCode(hubMembership.State), - }, - } - - return nil -} - -func toMembershipStateCode(ms *gkehubv1.MembershipState) v1alpha1.MembershipStateCode { - if ms == nil { - return v1alpha1.MSCodeUnspecified - } - - switch ms.Code { - case "CODE_UNSPECIFIED": - return v1alpha1.MSCodeUnspecified - case "CREATING": - return v1alpha1.MSCodeCreating - case "READY": - return v1alpha1.MSCodeReady - case "DELETING": - return v1alpha1.MSCodeDeleting - case "UPDATING": - return v1alpha1.MSCodeUpdating - case "SERVICE_UPDATING": - return v1alpha1.MSCodeServiceUpdating - default: - return v1alpha1.MSCodeUnspecified - } -} - -func membershipId(hubMembership *gkehubv1.Membership) (string, error) { - // projects/*/locations/*/memberships/{membership_id} - segments := strings.Split(hubMembership.Name, "/") - if len(segments) != 6 { - return "", fmt.Errorf("invalid membership name %q; should be 6 segments", hubMembership.Name) - } - return util.KubernetesName(segments[1]+"-"+segments[3]+"-"+segments[5], nameHashLen, nameMaxLen), nil -} - -func newScope(hubScope *gkehubv1.Scope, fleetsync *v1alpha1.FleetSync) (*v1alpha1.FleetScope, error) { - id, err := scopeId(hubScope) - if err != nil { - return nil, err - } - - t := true - f := &v1alpha1.FleetScope{ - ObjectMeta: metav1.ObjectMeta{ - Name: id, - Namespace: fleetsync.Namespace, - Labels: map[string]string{}, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: fleetsync.APIVersion, - Kind: fleetsync.Kind, - Name: fleetsync.Name, - UID: fleetsync.UID, - Controller: &t, - }, - }, - }, - } - - return f, updateScope(hubScope, fleetsync, f) -} - -func updateScope(hubScope *gkehubv1.Scope, fleetsync *v1alpha1.FleetSync, f *v1alpha1.FleetScope) error { - segments := strings.Split(hubScope.Name, "/") - if len(segments) != 6 { - return fmt.Errorf("invalid scope name %q; should be 6 segments", hubScope.Name) - } - - f.ObjectMeta.Labels[fleetSyncLabel] = fleetsync.Name - f.ObjectMeta.Labels[projectLabel] = segments[1] - f.ObjectMeta.Labels[scopeLabel] = segments[5] - - f.Data = v1alpha1.FleetScopeData{ - FullName: hubScope.Name, - Project: segments[1], - Location: segments[3], - Scope: segments[5], - Labels: hubScope.Labels, - State: v1alpha1.ScopeState{ - Code: toScopeStateCode(hubScope.State), - }, - } - - return nil -} - -func toScopeStateCode(ms *gkehubv1.ScopeLifecycleState) v1alpha1.ScopeStateCode { - if ms == nil { - return v1alpha1.SSCodeUnspecified - } - - switch ms.Code { - case "CODE_UNSPECIFIED": - return v1alpha1.SSCodeUnspecified - case "CREATING": - return v1alpha1.SSCodeCreating - case "READY": - return v1alpha1.SSCodeReady - case "DELETING": - return v1alpha1.SSCodeDeleting - case "UPDATING": - return v1alpha1.SSCodeUpdating - default: - return v1alpha1.SSCodeUnspecified - } -} - -func scopeId(scope *gkehubv1.Scope) (string, error) { - // `projects/{project}/locations/{location}/scopes/{scope}` - segments := strings.Split(scope.Name, "/") - if len(segments) != 6 { - return "", fmt.Errorf("invalid scope name %q; should be 6 segments", scope.Name) - } - return util.KubernetesName(segments[1]+"-"+segments[3]+"-"+segments[5], nameHashLen, nameMaxLen), nil -} - -func newMembershipBinding(hubBinding *gkehubv1.MembershipBinding, fleetsync *v1alpha1.FleetSync) (*v1alpha1.FleetMembershipBinding, error) { - id, err := bindingId(hubBinding) - if err != nil { - return nil, err - } - - t := true - f := &v1alpha1.FleetMembershipBinding{ - ObjectMeta: metav1.ObjectMeta{ - Name: id, - Namespace: fleetsync.Namespace, - Labels: map[string]string{}, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: fleetsync.APIVersion, - Kind: fleetsync.Kind, - Name: fleetsync.Name, - UID: fleetsync.UID, - Controller: &t, - }, - }, - }, - } - - return f, updateMembershipBinding(hubBinding, fleetsync, f) -} - -func updateMembershipBinding(hubBinding *gkehubv1.MembershipBinding, fleetsync *v1alpha1.FleetSync, f *v1alpha1.FleetMembershipBinding) error { - segments := strings.Split(hubBinding.Name, "/") - if len(segments) != 8 { - return fmt.Errorf("invalid binding name %q; should be 8 segments", hubBinding.Name) - } - - scopeSegs := strings.Split(hubBinding.Scope, "/") - if len(scopeSegs) != 6 { - return fmt.Errorf("invalid scope name %q; should be 6 segments", hubBinding.Scope) - } - - f.ObjectMeta.Labels[fleetSyncLabel] = fleetsync.Name - f.ObjectMeta.Labels[projectLabel] = segments[1] - f.ObjectMeta.Labels[membershipLabel] = segments[5] - f.ObjectMeta.Labels[scopeLabel] = scopeSegs[5] - - f.Data = v1alpha1.FleetMembershipBindingData{ - FullName: hubBinding.Name, - Project: segments[1], - Location: segments[3], - Membership: segments[5], - Binding: segments[7], - Scope: hubBinding.Scope, - Labels: hubBinding.Labels, - State: v1alpha1.MembershipBindingState{ - Code: toMembershipBindingStateCode(hubBinding.State), - }, - } - - return nil -} - -func toMembershipBindingStateCode(ms *gkehubv1.MembershipBindingLifecycleState) v1alpha1.MembershipBindingStateCode { - if ms == nil { - return v1alpha1.MBSCodeUnspecified - } - - switch ms.Code { - case "CODE_UNSPECIFIED": - return v1alpha1.MBSCodeUnspecified - case "CREATING": - return v1alpha1.MBSCodeCreating - case "READY": - return v1alpha1.MBSCodeReady - case "DELETING": - return v1alpha1.MBSCodeDeleting - case "UPDATING": - return v1alpha1.MBSCodeUpdating - default: - return v1alpha1.MBSCodeUnspecified - } -} - -func bindingId(binding *gkehubv1.MembershipBinding) (string, error) { - // `projects/{project}/locations/{location}/memberships/{membership}/bindings/{membershipbinding}` - segments := strings.Split(binding.Name, "/") - if len(segments) != 8 { - return "", fmt.Errorf("invalid membership binding name %q; should be 8 segments", binding.Name) - } - return util.KubernetesName(segments[1]+"-"+segments[3]+"-"+segments[5]+"-"+segments[7], nameHashLen, nameMaxLen), nil -} - -func (r *FleetSyncReconciler) updateStatus(ctx context.Context, orig, new *v1alpha1.FleetSync) error { - if equality.Semantic.DeepEqual(orig.Status, new.Status) { - return nil - } - return r.Status().Update(ctx, new) -} - -func (r *FleetSyncReconciler) findExistingMemberships(ctx context.Context, fsName, fsNamespace, projectId string) (map[string]*v1alpha1.FleetMembership, error) { - var list v1alpha1.FleetMembershipList - if err := r.List(ctx, &list, client.MatchingLabels{fleetSyncLabel: fsName, projectLabel: projectId}, client.InNamespace(fsNamespace)); err != nil { - return nil, err - } - - items := make(map[string]*v1alpha1.FleetMembership, len(list.Items)) - for i := range list.Items { - item := &list.Items[i] - items[item.Name] = item - } - return items, nil -} - -func (r *FleetSyncReconciler) findExistingScopes(ctx context.Context, fsName, fsNamespace, projectId string) (map[string]*v1alpha1.FleetScope, error) { - var list v1alpha1.FleetScopeList - if err := r.List(ctx, &list, client.MatchingLabels{fleetSyncLabel: fsName, projectLabel: projectId}, client.InNamespace(fsNamespace)); err != nil { - return nil, err - } - - items := make(map[string]*v1alpha1.FleetScope, len(list.Items)) - for i := range list.Items { - item := &list.Items[i] - items[item.Name] = item - } - return items, nil -} - -func (r *FleetSyncReconciler) findExistingMembershipBindings(ctx context.Context, fsName, fsNamespace, projectId string) (map[string]*v1alpha1.FleetMembershipBinding, error) { - var list v1alpha1.FleetMembershipBindingList - if err := r.List(ctx, &list, client.MatchingLabels{fleetSyncLabel: fsName, projectLabel: projectId}, client.InNamespace(fsNamespace)); err != nil { - return nil, err - } - - items := make(map[string]*v1alpha1.FleetMembershipBinding, len(list.Items)) - for i := range list.Items { - item := &list.Items[i] - items[item.Name] = item - } - return items, nil -} - -// SetupWithManager sets up the controller with the Manager. -func (r *FleetSyncReconciler) SetupWithManager(mgr ctrl.Manager) error { - if err := v1alpha1.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - - r.Client = mgr.GetClient() - r.recorder = mgr.GetEventRecorderFor("fleetsync-controller") - - channel := make(chan event.GenericEvent) - r.poller = fleetpoller.NewPoller(channel) - r.poller.Start() - - return ctrl.NewControllerManagedBy(mgr). - For(&v1alpha1.FleetSync{}). - Owns(&v1alpha1.FleetMembership{}). - Owns(&v1alpha1.FleetScope{}). - Owns(&v1alpha1.FleetMembershipBinding{}). - Watches(&source.Channel{Source: channel}, &handler.EnqueueRequestForObject{}). - Complete(r) -} diff --git a/porch/controllers/fleetsyncs/pkg/controllers/fleetsync/fleetpoller/poller.go b/porch/controllers/fleetsyncs/pkg/controllers/fleetsync/fleetpoller/poller.go deleted file mode 100644 index b90ab83c08..0000000000 --- a/porch/controllers/fleetsyncs/pkg/controllers/fleetsync/fleetpoller/poller.go +++ /dev/null @@ -1,307 +0,0 @@ -// Copyright 2023 The kpt 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. - -package fleetpoller - -import ( - "context" - "fmt" - "strings" - "sync" - "time" - - "github.com/GoogleContainerTools/kpt/porch/controllers/fleetsyncs/api/v1alpha1" - gkehubv1 "google.golang.org/api/gkehub/v1" - "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/types" - "k8s.io/klog/v2" - "sigs.k8s.io/controller-runtime/pkg/event" -) - -func NewPoller(channel chan event.GenericEvent) *Poller { - return &Poller{ - channel: channel, - projectIds: make(map[string][]types.NamespacedName), - } -} - -type Poller struct { - channel chan event.GenericEvent - cancelFunc context.CancelFunc - - projectIds map[string][]types.NamespacedName - pollResult map[string]*PollResult - mutex sync.Mutex -} - -func (p *Poller) Start() { - ctx, cancelFunc := context.WithCancel(context.Background()) - p.cancelFunc = cancelFunc - go func() { - ticker := time.NewTicker(30 * time.Second) - for { - select { - case <-ticker.C: - p.pollOnce(ctx) - case <-ctx.Done(): - return - } - } - }() -} - -func (p *Poller) VerifyProjectIdsForFleetSync(fleetSync types.NamespacedName, projectIds []string) { - p.mutex.Lock() - defer p.mutex.Unlock() - // This is not a very efficient way to do this... - for projectId, nns := range p.projectIds { - var newNns []types.NamespacedName - for _, nn := range nns { - if nn != fleetSync { - newNns = append(newNns, nn) - } - } - p.projectIds[projectId] = newNns - } - - for _, projectId := range projectIds { - if nns, found := p.projectIds[projectId]; !found { - p.projectIds[projectId] = []types.NamespacedName{fleetSync} - } else { - p.projectIds[projectId] = append(nns, fleetSync) - } - } - - klog.Infof("projectIds count %d", len(p.projectIds)) - for projectId := range p.projectIds { - klog.Infof("ProjectId: %s", projectId) - } -} - -func (p *Poller) StopPollingForFleetSync(fleetSync types.NamespacedName) { - p.mutex.Lock() - defer p.mutex.Unlock() - // This is not a very efficient way to do this... - for projectId, nns := range p.projectIds { - var newNns []types.NamespacedName - for _, nn := range nns { - if nn != fleetSync { - newNns = append(newNns, nn) - } - } - p.projectIds[projectId] = newNns - } -} - -func (p *Poller) LatestResult(projectId string) (*PollResult, bool) { - p.mutex.Lock() - defer p.mutex.Unlock() - res, found := p.pollResult[projectId] - if !found { - return nil, false - } - return res, true -} - -type PollResult struct { - MembershipsErr error - Memberships []*gkehubv1.Membership - - ScopesErr error - Scopes []*gkehubv1.Scope - - BindingsErrs []error - Bindings []*gkehubv1.MembershipBinding -} - -func (pr *PollResult) HasError() bool { - return pr.MembershipsErr != nil || pr.ScopesErr != nil || len(pr.BindingsErrs) > 0 -} - -func (pr *PollResult) ErrorSummary() error { - if !pr.HasError() { - return nil - } - - var builder strings.Builder - builder.WriteString("Errors:") - if pr.MembershipsErr != nil { - builder.WriteString(fmt.Sprintf(" [memberships: %s]", pr.MembershipsErr.Error())) - } - if pr.ScopesErr != nil { - builder.WriteString(fmt.Sprintf(" [scopes: %s]", pr.ScopesErr.Error())) - } - if len(pr.BindingsErrs) > 0 { - builder.WriteString(fmt.Sprintf(" [bindings: %d errors", len(pr.BindingsErrs))) - for _, err := range pr.BindingsErrs { - builder.WriteString(fmt.Sprintf(", %s", err.Error())) - } - } - return fmt.Errorf(builder.String()) -} - -func (p *Poller) pollOnce(ctx context.Context) { - var projectIds map[string][]types.NamespacedName - var previousPollResult map[string]*PollResult - func() { - p.mutex.Lock() - defer p.mutex.Unlock() - projectIds = p.projectIds - previousPollResult = p.pollResult - }() - - klog.Infof("Polling %d projects", len(projectIds)) - - newPollResult := p.poll(ctx, projectIds) - - toNotify := make(map[types.NamespacedName]struct{}) - for projectId, newRes := range newPollResult { - klog.Infof("Checking for changes for projectId %s", projectId) - oldRes, found := previousPollResult[projectId] - // No result from a previous run means it must have been - // added later. Schedule a reconcile for all FleetSyncs - // referencing the projectId. - if !found { - klog.Infof("Not found") - nns := projectIds[projectId] - for _, nn := range nns { - toNotify[nn] = struct{}{} - } - continue - } - // If either the previous poll or the current poll errored - // out, trigger a reconcile. - if newRes.HasError() || oldRes.HasError() { - klog.Infof("Has errors") - nns := projectIds[projectId] - for _, nn := range nns { - toNotify[nn] = struct{}{} - } - continue - } - - // If any of the memberships have changed, trigger a reconcile. - if !equality.Semantic.DeepEqual(newRes, oldRes) { - klog.Infof("Not equal") - nns := projectIds[projectId] - for _, nn := range nns { - toNotify[nn] = struct{}{} - } - } - } - - func() { - p.mutex.Lock() - defer p.mutex.Unlock() - p.pollResult = newPollResult - }() - - // Notify after we have updated the poll result, so any triggered - // reconcile will see the latest data. - for nn := range toNotify { - klog.Infof("Triggering reconcile for %s", nn.String()) - fs := &v1alpha1.FleetSync{} - fs.SetName(nn.Name) - fs.SetNamespace(nn.Namespace) - p.channel <- event.GenericEvent{ - Object: fs, - } - } -} - -func (p *Poller) poll(ctx context.Context, projectIds map[string][]types.NamespacedName) map[string]*PollResult { - res := make(map[string]*PollResult) - for projectId := range projectIds { - pr := &PollResult{} - res[projectId] = pr - respM, err := p.listMemberships(ctx, projectId) - if err != nil { - pr.MembershipsErr = err - klog.Infof("Membership polling failed: %v", err) - } else { - pr.Memberships = respM.Resources - klog.Infof("Polling %s found %d memberships", projectId, len(respM.Resources)) - } - - respS, err := p.listScopes(ctx, projectId) - if err != nil { - pr.ScopesErr = err - klog.Infof("Scope polling failed: %v", err) - } else { - pr.Scopes = respS.Scopes - klog.Infof("Polling %s found %d scopes", projectId, len(respS.Scopes)) - } - - if pr.MembershipsErr != nil { - pr.BindingsErrs = []error{fmt.Errorf("Could not list bindings due to membership retrieval error")} - continue - } - - for _, mbr := range pr.Memberships { - respMB, err := p.listMembershipBindings(ctx, mbr.Name) - if err != nil { - pr.BindingsErrs = append(pr.BindingsErrs, err) - klog.Infof("MembershipBinding polling failed: %v", err) - } else { - pr.Bindings = append(pr.Bindings, respMB.MembershipBindings...) - klog.Infof("Polling %s found %d membership bindings", projectId, len(respMB.MembershipBindings)) - } - } - - } - return res -} - -func (p *Poller) listMemberships(ctx context.Context, projectId string) (*gkehubv1.ListMembershipsResponse, error) { - hubClient, err := gkehubv1.NewService(ctx) - if err != nil { - return nil, err - } - - parent := fmt.Sprintf("projects/%s/locations/global", projectId) - resp, err := hubClient.Projects.Locations.Memberships.List(parent).Do() - if err != nil { - return nil, err - } - - return resp, nil -} - -func (p *Poller) listScopes(ctx context.Context, projectId string) (*gkehubv1.ListScopesResponse, error) { - hubClient, err := gkehubv1.NewService(ctx) - if err != nil { - return nil, err - } - - parent := fmt.Sprintf("projects/%s/locations/global", projectId) - resp, err := hubClient.Projects.Locations.Scopes.List(parent).Do() - if err != nil { - return nil, err - } - - return resp, nil -} -func (p *Poller) listMembershipBindings(ctx context.Context, membership string) (*gkehubv1.ListMembershipBindingsResponse, error) { - hubClient, err := gkehubv1.NewService(ctx) - if err != nil { - return nil, err - } - - resp, err := hubClient.Projects.Locations.Memberships.Bindings.List(membership).Do() - if err != nil { - return nil, err - } - - return resp, nil -} diff --git a/porch/controllers/functiondiscovery/config/rbac/role.yaml b/porch/controllers/functiondiscovery/config/rbac/role.yaml deleted file mode 100644 index f65803581c..0000000000 --- a/porch/controllers/functiondiscovery/config/rbac/role.yaml +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - name: porch-controllers-functiondiscovery -rules: -- apiGroups: - - config.porch.kpt.dev - resources: - - functions - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - config.porch.kpt.dev - resources: - - functions/finalizers - verbs: - - update -- apiGroups: - - config.porch.kpt.dev - resources: - - functions/status - verbs: - - get - - patch - - update -- apiGroups: - - config.porch.kpt.dev - resources: - - repositories - verbs: - - get - - list - - watch diff --git a/porch/controllers/functiondiscovery/config/rbac/rolebinding.yaml b/porch/controllers/functiondiscovery/config/rbac/rolebinding.yaml deleted file mode 100644 index 4600278c67..0000000000 --- a/porch/controllers/functiondiscovery/config/rbac/rolebinding.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: porch-system:porch-controllers-functiondiscovery -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: porch-controllers-functiondiscovery -subjects: -- kind: ServiceAccount - name: porch-controllers - namespace: porch-system \ No newline at end of file diff --git a/porch/controllers/functiondiscovery/controller.go b/porch/controllers/functiondiscovery/controller.go deleted file mode 100644 index da89bb1a5b..0000000000 --- a/porch/controllers/functiondiscovery/controller.go +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2022 The kpt 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. - -package functiondiscovery - -import ( - "context" - "flag" - "fmt" - "math/rand" - "time" - - kptoci "github.com/GoogleContainerTools/kpt/pkg/oci" - api "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/controllers/remoterootsyncsets/pkg/applyset" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/discovery" - memory "k8s.io/client-go/discovery/cached" - "k8s.io/client-go/dynamic" - "k8s.io/client-go/rest" - "k8s.io/client-go/restmapper" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -type Options struct { -} - -func (o *Options) InitDefaults() { -} - -func (o *Options) BindFlags(prefix string, flags *flag.FlagSet) { -} - -// FunctionReconciler creates Function objects -type FunctionReconciler struct { - Options - - client client.Client - restConfig *rest.Config - - ociStorage *kptoci.Storage -} - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 rbac:roleName=porch-controllers-functions webhook paths="." output:rbac:artifacts:config=config/rbac - -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=repositories,verbs=get;list;watch -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=functions,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=functions/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=functions/finalizers,verbs=update - -// Reconcile implements the main kubernetes reconciliation loop. -func (r *FunctionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - var subject api.Repository - if err := r.client.Get(ctx, req.NamespacedName, &subject); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - - applyResults, err := r.reconcileRepository(ctx, &subject) - if err != nil { - // TODO: Update status? - // TODO: Post event? - return ctrl.Result{}, err - } - - if applyResults != nil && !(applyResults.AllApplied() && applyResults.AllHealthy()) { - return ctrl.Result{Requeue: true}, nil - } - - // Poll the repo every 15 minutes (with some jitter) - jitter := time.Duration(rand.Intn(60)) * time.Second - pollInterval := 15*time.Minute + jitter - return ctrl.Result{RequeueAfter: pollInterval}, nil -} - -func (r *FunctionReconciler) reconcileRepository(ctx context.Context, subject *api.Repository) (*applyset.ApplyResults, error) { - // TODO: Cache dynamicClient / discovery etc - restConfig := r.restConfig - - client, err := dynamic.NewForConfig(restConfig) - if err != nil { - return nil, fmt.Errorf("failed to create a new dynamic client: %w", err) - } - - // TODO: Use a better discovery client - discovery, err := discovery.NewDiscoveryClientForConfig(restConfig) - if err != nil { - return nil, fmt.Errorf("error building discovery client: %w", err) - } - - cached := memory.NewMemCacheClient(discovery) - - restMapper := restmapper.NewDeferredDiscoveryRESTMapper(cached) - - objects, err := r.buildObjectsToApply(ctx, subject) - if err != nil { - return nil, err - } - - // TODO: Cache applyset - patchOptions := metav1.PatchOptions{ - FieldManager: "functions-" + subject.GetNamespace() + "-" + subject.GetName(), - } - - // We force to overcome errors like: Apply failed with 1 conflict: conflict with "kubectl-client-side-apply" using apps/v1: .spec.template.spec.containers[name="porch-server"].image - // TODO: How to handle this better - force := true - patchOptions.Force = &force - - applyset, err := applyset.New(applyset.Options{ - RESTMapper: restMapper, - Client: client, - PatchOptions: patchOptions, - }) - if err != nil { - return nil, err - } - - if err := applyset.ReplaceAllObjects(objects); err != nil { - return nil, err - } - - results, err := applyset.ApplyOnce(ctx) - if err != nil { - return nil, fmt.Errorf("failed to apply: %w", err) - } - - // TODO: Implement pruning - - return results, nil -} - -// buildObjectsToApply discovers the functions in the repository. -func (r *FunctionReconciler) buildObjectsToApply(ctx context.Context, subject *api.Repository) ([]applyset.ApplyableObject, error) { - functions, err := r.listFunctions(ctx, subject) - if err != nil { - return nil, err - } - - var applyables []applyset.ApplyableObject - for _, function := range functions { - function.APIVersion = api.TypeFunction.APIVersion() - function.Kind = api.TypeFunction.Kind - applyables = append(applyables, function) - } - return applyables, nil -} - -// SetupWithManager sets up the controller with the Manager. -func (r *FunctionReconciler) SetupWithManager(mgr ctrl.Manager) error { - if err := api.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - - r.restConfig = mgr.GetConfig() - r.client = mgr.GetClient() - - if err := ctrl.NewControllerManagedBy(mgr). - For(&api.Repository{}). - Complete(r); err != nil { - return err - } - - cacheDir := "./.cache" - - ociStorage, err := kptoci.NewStorage(cacheDir) - if err != nil { - return err - } - - r.ociStorage = ociStorage - - return nil -} diff --git a/porch/controllers/functiondiscovery/controller_test.go b/porch/controllers/functiondiscovery/controller_test.go deleted file mode 100644 index 1d17ccbd41..0000000000 --- a/porch/controllers/functiondiscovery/controller_test.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2022 The kpt 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. - -package functiondiscovery - -import ( - "path/filepath" - "sort" - "strings" - "testing" - - api "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/test/testhelpers" - "github.com/google/go-containerregistry/pkg/crane" - v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/google/go-containerregistry/pkg/v1/empty" - "github.com/google/go-containerregistry/pkg/v1/mutate" - "sigs.k8s.io/yaml" -) - -func TestFunctionDiscoveryController(t *testing.T) { - h := testhelpers.NewHarness(t) - - oci := h.StartOCIServer() - ociURL := oci.Endpoint() + "/testrepo" - - testdir := filepath.Join("testdata", "testfunctiondiscoverycontroller", "oci") - - repoYAML := ` -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Repository -metadata: - name: kpt-functions - namespace: default -spec: - description: Standard library of core kpt functions to manipulate KRM blueprints. - content: Function - type: oci - oci: - registry: "{{ociURL}}" -` - - // Push some empty functions that we expect to be discovered - imageTags := []string{ - "enable-gcp-services:v0", - "enable-gcp-services:v0.0", - "enable-gcp-services:v0.0.0", - "set-labels:unstable", - "set-labels:v0", - "set-labels:v0.2", - "set-labels:v0.2.0", - "set-labels:v0.1", - "set-labels:v0.1.5", - "set-labels:v0.1.3", - "set-labels:v0.1.4", - } - - for _, image := range imageTags { - img := mutate.Annotations(empty.Image, map[string]string{ - "dev.kpt.fn.meta.description": "description for " + image, - "dev.kpt.fn.meta.documentationurl": "documentation for " + image, - }).(v1.Image) - dest := ociURL + "/" + image - if err := crane.Push(img, dest); err != nil { - t.Fatalf("failed to push image %q: %v", dest, err) - } - } - - repoYAML = strings.ReplaceAll(repoYAML, "{{ociURL}}", ociURL) - - repo := &api.Repository{} - if err := yaml.Unmarshal([]byte(repoYAML), repo); err != nil { - t.Fatalf("error parsing yaml: %v", err) - } - - r := &FunctionReconciler{} - objectsToApply, err := r.buildObjectsToApply(h.Ctx, repo) - if err != nil { - t.Fatalf("error from buildObjectsToApply: %v", err) - } - - sort.Slice(objectsToApply, func(i, j int) bool { - return objectsToApply[i].GetName() < objectsToApply[j].GetName() - }) - - got := testhelpers.ToYAML(h, objectsToApply) - got = strings.ReplaceAll(got, ociURL+"/", "ociurl/") - - h.AssertMatchesFile(filepath.Join(testdir, "expected.yaml"), got) -} diff --git a/porch/controllers/functiondiscovery/doc.go b/porch/controllers/functiondiscovery/doc.go deleted file mode 100644 index 914fac899a..0000000000 --- a/porch/controllers/functiondiscovery/doc.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2022 The kpt 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. - -package functiondiscovery - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 rbac:roleName=porch-controllers-functiondiscovery webhook paths="./..." output:rbac:artifacts:config=config/rbac diff --git a/porch/controllers/functiondiscovery/oci.go b/porch/controllers/functiondiscovery/oci.go deleted file mode 100644 index c4f32ffb6e..0000000000 --- a/porch/controllers/functiondiscovery/oci.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2022 The kpt 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. - -package functiondiscovery - -import ( - "context" - "fmt" - - api "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/oci" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/trace" - "sigs.k8s.io/controller-runtime/pkg/log" -) - -var tracer = otel.Tracer("functioncontroller") - -func (r *FunctionReconciler) listFunctions(ctx context.Context, subject *api.Repository) ([]*api.Function, error) { - log := log.FromContext(ctx) - - ctx, span := tracer.Start(ctx, "FunctionReconciler::listFunctions", trace.WithAttributes()) - defer span.End() - - // Repository whose content type is not Function contains no Function resources. - if subject.Spec.Content != api.RepositoryContentFunction { - log.Info("repository doesn't contain functions") - return nil, nil - } - - if subject.Spec.Oci == nil { - return nil, fmt.Errorf("expected spec.oci to be set") - } - - registry := subject.Spec.Oci.Registry - if registry == "" { - return nil, fmt.Errorf("spec.oci.registry is not set") - } - - repo, err := oci.OpenRepository(subject.Name, subject.Namespace, subject.Spec.Content, subject.Spec.Oci, subject.Spec.Deployment, r.ociStorage) - if err != nil { - return nil, err - } - - functionRepository, ok := (repo).(repository.FunctionRepository) - if !ok { - return nil, fmt.Errorf("repository was not of expected type, expected FunctionRepository, got %T", repo) - } - - functions, err := functionRepository.ListFunctions(ctx) - if err != nil { - return nil, err - } - - var functionObjects []*api.Function - for _, f := range functions { - functionObject, err := f.GetCRD() - if err != nil { - return nil, err - } - functionObject.Namespace = subject.Namespace - // TODO: Set ownerRef? - // TODO: Set labels? - functionObjects = append(functionObjects, functionObject) - } - - return functionObjects, nil -} diff --git a/porch/controllers/functiondiscovery/testdata/testfunctiondiscoverycontroller/oci/expected.yaml b/porch/controllers/functiondiscovery/testdata/testfunctiondiscoverycontroller/oci/expected.yaml deleted file mode 100644 index 2e014aec0b..0000000000 --- a/porch/controllers/functiondiscovery/testdata/testfunctiondiscoverycontroller/oci/expected.yaml +++ /dev/null @@ -1,163 +0,0 @@ -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Function -metadata: - creationTimestamp: null - name: kpt-functions.enable-gcp-services.v0 - namespace: default -spec: - description: description for enable-gcp-services:v0 - documentationUrl: documentation for enable-gcp-services:v0 - image: ociurl/enable-gcp-services:v0 - repositoryRef: - name: kpt-functions -status: {} - ---- -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Function -metadata: - creationTimestamp: null - name: kpt-functions.enable-gcp-services.v0.0 - namespace: default -spec: - description: description for enable-gcp-services:v0.0 - documentationUrl: documentation for enable-gcp-services:v0.0 - image: ociurl/enable-gcp-services:v0.0 - repositoryRef: - name: kpt-functions -status: {} - ---- -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Function -metadata: - creationTimestamp: null - name: kpt-functions.enable-gcp-services.v0.0.0 - namespace: default -spec: - description: description for enable-gcp-services:v0.0.0 - documentationUrl: documentation for enable-gcp-services:v0.0.0 - image: ociurl/enable-gcp-services:v0.0.0 - repositoryRef: - name: kpt-functions -status: {} - ---- -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Function -metadata: - creationTimestamp: null - name: kpt-functions.set-labels.unstable - namespace: default -spec: - description: description for set-labels:unstable - documentationUrl: documentation for set-labels:unstable - image: ociurl/set-labels:unstable - repositoryRef: - name: kpt-functions -status: {} - ---- -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Function -metadata: - creationTimestamp: null - name: kpt-functions.set-labels.v0 - namespace: default -spec: - description: description for set-labels:v0 - documentationUrl: documentation for set-labels:v0 - image: ociurl/set-labels:v0 - repositoryRef: - name: kpt-functions -status: {} - ---- -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Function -metadata: - creationTimestamp: null - name: kpt-functions.set-labels.v0.1 - namespace: default -spec: - description: description for set-labels:v0.1 - documentationUrl: documentation for set-labels:v0.1 - image: ociurl/set-labels:v0.1 - repositoryRef: - name: kpt-functions -status: {} - ---- -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Function -metadata: - creationTimestamp: null - name: kpt-functions.set-labels.v0.1.3 - namespace: default -spec: - description: description for set-labels:v0.1.3 - documentationUrl: documentation for set-labels:v0.1.3 - image: ociurl/set-labels:v0.1.3 - repositoryRef: - name: kpt-functions -status: {} - ---- -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Function -metadata: - creationTimestamp: null - name: kpt-functions.set-labels.v0.1.4 - namespace: default -spec: - description: description for set-labels:v0.1.4 - documentationUrl: documentation for set-labels:v0.1.4 - image: ociurl/set-labels:v0.1.4 - repositoryRef: - name: kpt-functions -status: {} - ---- -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Function -metadata: - creationTimestamp: null - name: kpt-functions.set-labels.v0.1.5 - namespace: default -spec: - description: description for set-labels:v0.1.5 - documentationUrl: documentation for set-labels:v0.1.5 - image: ociurl/set-labels:v0.1.5 - repositoryRef: - name: kpt-functions -status: {} - ---- -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Function -metadata: - creationTimestamp: null - name: kpt-functions.set-labels.v0.2 - namespace: default -spec: - description: description for set-labels:v0.2 - documentationUrl: documentation for set-labels:v0.2 - image: ociurl/set-labels:v0.2 - repositoryRef: - name: kpt-functions -status: {} - ---- -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Function -metadata: - creationTimestamp: null - name: kpt-functions.set-labels.v0.2.0 - namespace: default -spec: - description: description for set-labels:v0.2.0 - documentationUrl: documentation for set-labels:v0.2.0 - image: ociurl/set-labels:v0.2.0 - repositoryRef: - name: kpt-functions -status: {} diff --git a/porch/controllers/go.mod b/porch/controllers/go.mod deleted file mode 100644 index 204af0d994..0000000000 --- a/porch/controllers/go.mod +++ /dev/null @@ -1,145 +0,0 @@ -module github.com/GoogleContainerTools/kpt/porch/controllers - -go 1.21 - -replace ( - github.com/GoogleContainerTools/kpt => ../../ - github.com/GoogleContainerTools/kpt/porch => ../ - github.com/GoogleContainerTools/kpt/porch/api => ../api - github.com/go-git/go-git/v5 v5.4.3-0.20220408232334-4f916225cb2f => github.com/platkrm/go-git/v5 v5.4.3-0.20220410165046-c76b262044ce -) - -require ( - cloud.google.com/go/container v1.24.0 - github.com/GoogleContainerTools/kpt v0.0.0-00010101000000-000000000000 - github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20230427202446-3255accc518d - github.com/GoogleContainerTools/kpt/porch v0.0.0-00010101000000-000000000000 - github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20230121152246-dc44dbd18a33 - github.com/google/cel-go v0.14.0 - github.com/google/go-containerregistry v0.14.0 - github.com/stretchr/testify v1.8.3 - go.opentelemetry.io/otel v1.16.0 - go.opentelemetry.io/otel/trace v1.16.0 - golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b - golang.org/x/mod v0.9.0 - golang.org/x/oauth2 v0.12.0 - google.golang.org/api v0.142.0 - google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d - k8s.io/api v0.26.9 - k8s.io/apimachinery v0.26.9 - k8s.io/client-go v0.26.9 - k8s.io/klog/v2 v2.90.1 - k8s.io/utils v0.0.0-20230115233650-391b47cb4029 - sigs.k8s.io/cli-utils v0.35.0 - sigs.k8s.io/controller-runtime v0.14.1 - sigs.k8s.io/kustomize/kyaml v0.13.9 - sigs.k8s.io/yaml v1.3.0 -) - -require ( - cloud.google.com/go/compute v1.23.0 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v1.1.1 // indirect - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect - github.com/GoogleContainerTools/kpt-functions-sdk/go/api v0.0.0-20220720212527-133180134b93 // indirect - github.com/MakeNowJust/heredoc v1.0.0 // indirect - github.com/acomagu/bufpipe v1.0.4-0.20210605013841-cd7a5f79d3c4 // indirect - github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/chai2010/gettext-go v1.0.2 // indirect - github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/docker/cli v23.0.1+incompatible // indirect - github.com/docker/distribution v2.8.2+incompatible // indirect - github.com/docker/docker v24.0.9+incompatible // indirect - github.com/docker/docker-credential-helpers v0.7.0 // indirect - github.com/emicklei/go-restful/v3 v3.9.0 // indirect - github.com/evanphx/json-patch v4.12.0+incompatible // indirect - github.com/evanphx/json-patch/v5 v5.6.0 // indirect - github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-errors/errors v1.4.2 // indirect - github.com/go-git/gcfg v1.5.0 // indirect - github.com/go-git/go-billy/v5 v5.3.1 // indirect - github.com/go-git/go-git/v5 v5.4.3-0.20220408232334-4f916225cb2f // indirect - github.com/go-logr/logr v1.2.4 // indirect - github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.1 // indirect - github.com/go-openapi/swag v0.22.3 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/google/btree v1.1.2 // indirect - github.com/google/gnostic v0.6.9 // indirect - github.com/google/go-cmp v0.5.9 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/google/s2a-go v0.1.7 // indirect - github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/google/uuid v1.3.1 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect - github.com/googleapis/gax-go/v2 v2.12.0 // indirect - github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect - github.com/imdario/mergo v0.3.12 // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.16.0 // indirect - github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/go-wordwrap v1.0.0 // indirect - github.com/moby/spdystream v0.2.0 // indirect - github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // 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 - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc2 // indirect - github.com/peterbourgon/diskv v2.0.1+incompatible // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/sirupsen/logrus v1.9.0 // indirect - github.com/spf13/cobra v1.6.1 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/stoewer/go-strcase v1.2.0 // indirect - github.com/vbatts/tar-split v0.11.2 // indirect - github.com/xlab/treeprint v1.1.0 // indirect - go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/otel/metric v1.16.0 // indirect - go.starlark.net v0.0.0-20210901212718-87f333178d59 // indirect - golang.org/x/crypto v0.21.0 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/term v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.3.0 // indirect - gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb // indirect - google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.33.0 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/warnings.v0 v0.1.2 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.26.9 // indirect - k8s.io/cli-runtime v0.26.9 // indirect - k8s.io/component-base v0.26.9 // indirect - k8s.io/kube-openapi v0.0.0-20230109183929-3758b55a6596 // indirect - k8s.io/kubectl v0.26.9 // indirect - sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect - sigs.k8s.io/kustomize/api v0.12.1 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect -) diff --git a/porch/controllers/go.sum b/porch/controllers/go.sum deleted file mode 100644 index faa7851f88..0000000000 --- a/porch/controllers/go.sum +++ /dev/null @@ -1,838 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -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= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o= -cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/container v1.24.0 h1:N51t/cgQJFqDD/W7Mb+IvmAPHrf8AbPx7Bb7aF4lROE= -cloud.google.com/go/container v1.24.0/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= -cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -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/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/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/GoogleContainerTools/kpt-functions-sdk/go/api v0.0.0-20220720212527-133180134b93 h1:c1GhPzYzU2a3E+/2WB9OxoljK2pNYfsBF5Fz9GkdYXs= -github.com/GoogleContainerTools/kpt-functions-sdk/go/api v0.0.0-20220720212527-133180134b93/go.mod h1:gkK43tTaPXFNASpbIbQImzhmt1hdcdin++kvzTblykc= -github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20230427202446-3255accc518d h1:kgC/R6Kl+tBjsRvcPr4Beae1MiHumNMtbmUTy7qlPZI= -github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20230427202446-3255accc518d/go.mod h1:Pnd3ImgaWS3OBVjztSiGMACMf+CDs20l5nT5Oljy/tA= -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.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= -github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= -github.com/acomagu/bufpipe v1.0.4-0.20210605013841-cd7a5f79d3c4 h1:LLzKXLcKO8rAXpUHeNI5FkJKivErqhBKdeMzrpBFqS4= -github.com/acomagu/bufpipe v1.0.4-0.20210605013841-cd7a5f79d3c4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= -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/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -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= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -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/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/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/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= -github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= -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/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= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= -github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= -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.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= -github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -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/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.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 v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0= -github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= -github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -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/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= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -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 v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= -github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= -github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= -github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= -github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= -github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= -github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= -github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-git-fixtures/v4 v4.3.1 h1:y5z6dd3qi8Hl+stezc8p3JxDkoTRqMAlKnXHuzrfjTQ= -github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -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-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -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-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -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.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= -github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= -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.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= -github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -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= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -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/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= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -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/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.14.0 h1:LFobwuUDslWUHdQ48SXVXvQgPH2X1XVhsgOGNioAEZ4= -github.com/google/cel-go v0.14.0/go.mod h1:YzWEoI07MC/a/wj9in8GeVatqfypkldgBlwXh9bCwqY= -github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= -github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/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.14.0 h1:z58vMqHxuwvAsVwvKEkmVBz2TlgBgH5k6koEXBtlYkw= -github.com/google/go-containerregistry v0.14.0/go.mod h1:aiJ2fp/SXvkWgmYHioXnbMdlgB8eXiiYOY55gfN91Wk= -github.com/google/gofuzz v1.0.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= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= -github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= -github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= -github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -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.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -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= -github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -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.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.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= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -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/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= -github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM= -github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -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/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI= -github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= -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= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -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/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/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo/v2 v2.7.0 h1:/XxtEV3I3Eif/HobnVx9YmJgk8ENdRsuUmM+fLCFNow= -github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= -github.com/onsi/gomega v1.24.2 h1:J/tulyYK6JwBldPViHJReihxxZ+22FHs0piGjQAvoUE= -github.com/onsi/gomega v1.24.2/go.mod h1:gs3J10IS7Z7r7eXRoNJIrNqU4ToQukCJhFtKrWgHWnk= -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.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= -github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= -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/pkg/errors v0.8.0/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/platkrm/go-git/v5 v5.4.3-0.20220410165046-c76b262044ce h1:HuO44EsG+4+mGBkomtK/tTEiegvrN2mROsWDenSLF0Y= -github.com/platkrm/go-git/v5 v5.4.3-0.20220410165046-c76b262044ce/go.mod h1:U7oc8MDRtQhVD6StooNkBMVsh/Y4J/2Vl36Mo4IclvM= -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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -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.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -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= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -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/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= -github.com/sergi/go-diff v1.2.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.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -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.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= -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= -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.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.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -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= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -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/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME= -github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI= -github.com/xanzy/ssh-agent v0.3.1/go.mod h1:QIE4lCeL7nkC25x+yA3LBIYfwCc1TFziCtG7cBAac6w= -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 v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= -github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -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= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= -go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= -go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.starlark.net v0.0.0-20210901212718-87f333178d59 h1:F8ArBy9n1l7HE1JjzOIYqweEqoUlywy5+L3bR0tIa9g= -go.starlark.net v0.0.0-20210901212718-87f333178d59/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= -go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/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-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-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -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-20220916125017-b168a2c6b86b h1:SCE/18RnFsLrjydh/R/s5EVvHoZprqEQUuoxK8q2Pc4= -golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= -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-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.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-20181114220301-adae6a3d119a/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-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-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-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -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-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= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -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-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-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-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/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-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= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/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-20190215142949-d0b11bdaac8a/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-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-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/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-20200122134326-e047566fdf82/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-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= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -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-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/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-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/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-20210630005230-0f9fa26af87c/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-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -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.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -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.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/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= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/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= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -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-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-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-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= -gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= -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= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.142.0 h1:mf+7EJ94fi5ZcnpPy+m0Yv2dkz8bKm+UL0snTCuwXlY= -google.golang.org/api v0.142.0/go.mod h1:zJAN5o6HRqR7O+9qJUFOWrZkYE66RH+efPBdTLA4xBA= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -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= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -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-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-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= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -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-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= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -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-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-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q= -google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb h1:Isk1sSH7bovx8Rti2wZK0UZF6oraBDK74uoyLEEVFN0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -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.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= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -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-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -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= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/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/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= -gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= -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= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -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.26.9 h1:s8Y+G1u2JM55b90+Yo2RVb3PGT/hkWNVPN4idPERxJg= -k8s.io/api v0.26.9/go.mod h1:W/W4fEWRVzPD36820LlVUQfNBiSbiq0VPWRFJKwzmUg= -k8s.io/apiextensions-apiserver v0.26.9 h1:aJqWRuBj9i9J6tIDniqUDYM5QCRajTKXK/GO+zEccGQ= -k8s.io/apiextensions-apiserver v0.26.9/go.mod h1:L1uysxOP2kC1vkZTlHGUlUl5WSpa7e4GHJmGEZY7yLg= -k8s.io/apimachinery v0.26.9 h1:5yAV9cFR7Z4gIorKcAjWnx4uxtxiFsERwq4Pvmx0CCg= -k8s.io/apimachinery v0.26.9/go.mod h1:qYzLkrQ9lhrZRh0jNKo2cfvf/R1/kQONnSiyB7NUJU0= -k8s.io/cli-runtime v0.26.9 h1:Iv095J30ieAvYvQabW/ds3BPwC8n7RvFN+mLRWNcTB8= -k8s.io/cli-runtime v0.26.9/go.mod h1:fnnTrhjj3dZz4ULolimyUrBiChVSBKgoyPnJT1WV1GE= -k8s.io/client-go v0.26.9 h1:TGWi/6guEjIgT0Hg871Gsmx0qFuoGyGFjlFedrk7It0= -k8s.io/client-go v0.26.9/go.mod h1:tU1FZS0bwAmAFyPYpZycUQrQnUMzQ5MHloop7EbX6ow= -k8s.io/component-base v0.26.9 h1:qQVdQgyEIUe8EUkB3EEuQ9l5sgVlG2KgOB519yWEBGw= -k8s.io/component-base v0.26.9/go.mod h1:3WmW9lH9tbjpuvpAc22cPF/6C3VxCjMxkOU1j2mpzr8= -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-20230109183929-3758b55a6596 h1:8cNCQs+WqqnSpZ7y0LMQPKD+RZUHU17VqLPMW3qxnxc= -k8s.io/kube-openapi v0.0.0-20230109183929-3758b55a6596/go.mod h1:/BYxry62FuDzmI+i9B+X2pqfySRmSOW2ARmj5Zbqhj0= -k8s.io/kubectl v0.26.9 h1:0Z8wEFQoXqWbWfT7G9si5EKVjYf5KG4hocSB7B8Jkbc= -k8s.io/kubectl v0.26.9/go.mod h1:Rl9W561iyUZtzwgstHcKChzUo2xMaGqb7Za6jUDMKP4= -k8s.io/utils v0.0.0-20230115233650-391b47cb4029 h1:L8zDtT4jrxj+TaQYD0k8KNlr556WaVQylDXswKmX+dE= -k8s.io/utils v0.0.0-20230115233650-391b47cb4029/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/cli-utils v0.35.0 h1:dfSJaF1W0frW74PtjwiyoB4cwdRygbHnC7qe7HF0g/Y= -sigs.k8s.io/cli-utils v0.35.0/go.mod h1:ITitykCJxP1vaj1Cew/FZEaVJ2YsTN9Q71m02jebkoE= -sigs.k8s.io/controller-runtime v0.14.1 h1:vThDes9pzg0Y+UbCPY3Wj34CGIYPgdmspPm2GIpxpzM= -sigs.k8s.io/controller-runtime v0.14.1/go.mod h1:GaRkrY8a7UZF0kqFFbUKG7n9ICiTY5T55P1RiE3UZlU= -sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= -sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM= -sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s= -sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk= -sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= -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.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/porch/controllers/klippy/README.md b/porch/controllers/klippy/README.md deleted file mode 100644 index b33536bb93..0000000000 --- a/porch/controllers/klippy/README.md +++ /dev/null @@ -1,44 +0,0 @@ -# Overview - -klippy is a controller that proposes creating packages as a child of a -parent package, where all the bindings can be satisfied. - -The idea is that packages in this "proposed by robot" state can -provide a guided authoring experience, and we can communicate these -paths through the existing API. - -The controller and the idea of package proposals should be considered -exploration / experimental. - -# Bindings - -The idea of bindings is that a blueprint author can include some -objects that are specially marked with the -`config.kubernetes.io/local-config` = `binding` annotation. Those are -binding objects. - -Because those binding objects are `local-config`, they will not be -applied to the cluster as part of the package. Instead, those objects -normally come from a parent package. - -The value of a binding object comes when we replace the placeholder -values with the actual values from the parent. We do a semantically -aware rename, so - for example - if a binding objects is a namespace, -all the objects in the binding placeholder namespace would be changed -to be in the newly bound namespace. - -If the object is something like a ConfigMap, we would update all the -references to that ConfigMap, for example in pod volumes. - -# klippy: auto-binding - -The idea of the klippy controller therefore is to eagerly look for -places where we can instantiate a child package under a parent -package, where all the bindings can be satisfied. - -We match bindings based on the Group/Version/Kind. Additionally, if -the binding object has labels, we'll look for those labels on the -parent package object (this was needed because otherwise we were -over-proposing on common objects like Namespaces, in practice we need -some sort of "intent" label on Namespaces or GCP Projects/Folders, -that indicates what we expect them to contain) diff --git a/porch/controllers/klippy/config/rbac/role.yaml b/porch/controllers/klippy/config/rbac/role.yaml deleted file mode 100644 index 39ceea3e07..0000000000 --- a/porch/controllers/klippy/config/rbac/role.yaml +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - name: porch-controllers-klippy -rules: -- apiGroups: - - porch.kpt.dev - resources: - - packagerevisionresources - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - porch.kpt.dev - resources: - - packagerevisionresources/status - verbs: - - get - - patch - - update -- apiGroups: - - porch.kpt.dev - resources: - - packagerevisions - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - porch.kpt.dev - resources: - - packagerevisions/status - verbs: - - get - - patch - - update diff --git a/porch/controllers/klippy/config/rbac/rolebinding.yaml b/porch/controllers/klippy/config/rbac/rolebinding.yaml deleted file mode 100644 index 6b37a60dd4..0000000000 --- a/porch/controllers/klippy/config/rbac/rolebinding.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: porch-system:porch-controllers-klippy -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: porch-controllers-klippy -subjects: -- kind: ServiceAccount - name: porch-controllers - namespace: porch-system \ No newline at end of file diff --git a/porch/controllers/klippy/doc.go b/porch/controllers/klippy/doc.go deleted file mode 100644 index 6eb10cdb57..0000000000 --- a/porch/controllers/klippy/doc.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2022 The kpt 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. - -package klippy - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 rbac:roleName=porch-controllers-klippy webhook paths="./..." output:rbac:artifacts:config=config/rbac diff --git a/porch/controllers/klippy/pkg/controllers/klippy/klippy_controller.go b/porch/controllers/klippy/pkg/controllers/klippy/klippy_controller.go deleted file mode 100644 index 59dfadf7bb..0000000000 --- a/porch/controllers/klippy/pkg/controllers/klippy/klippy_controller.go +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright 2022 The kpt 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. - -package klippy - -import ( - "context" - "flag" - "fmt" - "strings" - - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/controllers/remoterootsyncsets/pkg/applyset" - "github.com/GoogleContainerTools/kpt/porch/pkg/objects" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/dynamic" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" -) - -type Options struct { - // BindFunction is the image name for the "bind" function - BindFunction string -} - -func (o *Options) InitDefaults() { - o.BindFunction = "bind" -} - -func (o *Options) BindFlags(prefix string, flagset *flag.FlagSet) { - flagset.StringVar(&o.BindFunction, prefix+"bindFunction", o.BindFunction, "image name for the bind function") -} - -// KlippyReconciler reconciles Klippy objects -type KlippyReconciler struct { - Options - - client client.Client - - dynamicClient dynamic.Interface - restMapper meta.RESTMapper -} - -//+kubebuilder:rbac:groups=porch.kpt.dev,resources=packagerevisionresources,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=porch.kpt.dev,resources=packagerevisionresources/status,verbs=get;update;patch - -//+kubebuilder:rbac:groups=porch.kpt.dev,resources=packagerevisions,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=porch.kpt.dev,resources=packagerevisions/status,verbs=get;update;patch - -// Reconcile implements the main kubernetes reconciliation loop. -func (r *KlippyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - log := log.FromContext(ctx) - - log.Info("reconciling object", "id", req.NamespacedName) - - var parent api.PackageRevision - if err := r.client.Get(ctx, req.NamespacedName, &parent); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - - // TODO: Can we filter the watch? - if !parent.Status.Deployment { - log.V(2).Info("ignoring package not in deployments repository", "package", parent.Spec.PackageName) - return ctrl.Result{}, nil - } - - var parentResources api.PackageRevisionResources - if err := r.client.Get(ctx, req.NamespacedName, &parentResources); err != nil { - // Not found here is unexpected - return ctrl.Result{}, err - } - - if err := r.reconcile(ctx, &parent, &parentResources); err != nil { - // TODO: raise event? - log.Error(err, "error reconciling", "id", req.NamespacedName) - return ctrl.Result{}, err - } - - return ctrl.Result{}, nil -} - -func (r *KlippyReconciler) reconcile(ctx context.Context, parent *api.PackageRevision, parentResources *api.PackageRevisionResources) error { - log := log.FromContext(ctx) - - var blueprintPackageRevisions api.PackageRevisionList - if err := r.client.List(ctx, &blueprintPackageRevisions); err != nil { - return fmt.Errorf("error listing blueprints: %w", err) - } - - // TODO: We should be able to cache this - blueprints, err := r.parseBlueprints(ctx, &blueprintPackageRevisions) - if err != nil { - return err - } - - parentObjects, err := objects.Parser{}.AsUnstructureds(parentResources.Spec.Resources) - if err != nil { - return err - } - - var allProposals []*api.PackageRevision - for _, blueprint := range blueprints { - proposals, err := r.buildProposals(ctx, parent, parentObjects, blueprint) - if err != nil { - return err - } - allProposals = append(allProposals, proposals...) - } - - log.Info("built proposals", "proposal", allProposals) - if err := r.storeProposals(ctx, parent, allProposals); err != nil { - return err - } - - return nil -} - -func (r *KlippyReconciler) parseBlueprints(ctx context.Context, packageRevisions *api.PackageRevisionList) ([]*blueprint, error) { - var blueprints []*blueprint - - for i := range packageRevisions.Items { - packageRevision := &packageRevisions.Items[i] - - // Only match blueprint packages - // TODO: Push-down into a field selector? - if packageRevision.Status.Deployment { - continue - } - - // TODO: Cache - - var packageRevisionResources api.PackageRevisionResources - id := types.NamespacedName{ - Namespace: packageRevision.Namespace, - Name: packageRevision.Name, - } - if err := r.client.Get(ctx, id, &packageRevisionResources); err != nil { - return nil, fmt.Errorf("error fetching PackageRevisionResources %v: %w", id, err) - } - - objects, err := objects.Parser{}.AsUnstructureds(packageRevisionResources.Spec.Resources) - if err != nil { - return nil, err - } - - blueprint := &blueprint{ - Objects: objects, - ID: id, - PackageName: packageRevision.Spec.PackageName, - } - blueprints = append(blueprints, blueprint) - } - return blueprints, nil -} - -type bindingSlotRequirements struct { - MatchLabels map[string]string -} - -type blueprint struct { - ID types.NamespacedName - PackageName string - Objects []*unstructured.Unstructured -} - -func (r *KlippyReconciler) buildProposals(ctx context.Context, parent *api.PackageRevision, parentObjects []*unstructured.Unstructured, blueprint *blueprint) ([]*api.PackageRevision, error) { - log := log.FromContext(ctx) - - var proposals []*api.PackageRevision - - slots := make(map[schema.GroupKind]*bindingSlotRequirements) - for _, obj := range blueprint.Objects { - annotations := obj.GetAnnotations() - if annotations["config.kubernetes.io/local-config"] != "binding" { - continue - } - - gk := obj.GroupVersionKind().GroupKind() - - requirements := &bindingSlotRequirements{} - requirements.MatchLabels = obj.GetLabels() - - slots[gk] = requirements - } - - if len(slots) == 0 { - // Though technically this is "a match", it tends to be incorrect and leads to over-proposing - return nil, nil - } - - isMatch := false - bindings := make(map[schema.GroupKind]*unstructured.Unstructured) - { - for _, obj := range parentObjects { - annotations := obj.GetAnnotations() - if annotations["config.kubernetes.io/local-config"] == "binding" { - // Ignore binding objects in the "parent"; they don't satisfy bindings - continue - } - - gk := obj.GroupVersionKind().GroupKind() - - requirements, found := slots[gk] - if !found { - continue - } - - matchesLabels := true - for k, v := range requirements.MatchLabels { - if obj.GetLabels()[k] != v { - matchesLabels = false - } - } - if !matchesLabels { - continue - } - bindings[gk] = obj - } - - isMatch = len(bindings) == len(slots) - if !isMatch { - log.Info("package does not match", "parent", parent.Spec.PackageName, "child", blueprint.PackageName) - } - } - - if isMatch { - log.Info("matched package", "parent", parent.Spec.PackageName, "child", blueprint.PackageName) - // TODO: How to avoid collisions - name := "packagename-" + strings.ReplaceAll(blueprint.PackageName, "/", "-") - packageName := blueprint.PackageName - - clone := &api.PackageCloneTaskSpec{} - clone.Upstream = api.UpstreamPackage{ - UpstreamRef: &api.PackageRevisionRef{ - Name: blueprint.ID.Name, - }, - } - - parentName := parent.Spec.PackageName - objectName := packageName + "-" + parentName + "-" + name - - // TODO: How to sanitize? - // packageName can be something like dir/name, and that isn't allowed in names - objectName = strings.ReplaceAll(objectName, "/", "-") - - proposal := &api.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: api.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: parent.GetNamespace(), - Name: objectName, - }, - Spec: api.PackageRevisionSpec{ - PackageName: name, - Revision: "v1", - RepositoryName: parent.Spec.RepositoryName, - // TODO: Speculative: true, - Tasks: []api.Task{ - { - Type: api.TaskTypeClone, - Clone: clone, - }, - }, - }, - } - proposal.Labels = map[string]string{ - "alpha.kpt.dev/proposal": "", - } - proposal.Spec.Parent = &api.ParentReference{ - Name: parent.Name, - } - - // TODO: Share the workspace? Create a new one? - proposal.Spec.WorkspaceName = parent.Spec.WorkspaceName - - for _, bindingObj := range bindings { - bindingCore := &unstructured.Unstructured{} - bindingCore.SetAPIVersion(bindingObj.GetAPIVersion()) - bindingCore.SetKind(bindingObj.GetKind()) - bindingCore.SetName(bindingObj.GetName()) - if bindingObj.GetNamespace() != "" { - bindingCore.SetNamespace(bindingObj.GetNamespace()) - } - - var bindingConfig runtime.RawExtension - bindingConfig.Object = bindingCore - - image := r.Options.BindFunction - - proposal.Spec.Tasks = append(proposal.Spec.Tasks, api.Task{ - Type: api.TaskTypeEval, - Eval: &api.FunctionEvalTaskSpec{ - Image: image, - Config: bindingConfig, - }, - }) - - } - - proposals = append(proposals, proposal) - } - - return proposals, nil -} - -func (r *KlippyReconciler) storeProposals(ctx context.Context, parent *api.PackageRevision, children []*api.PackageRevision) error { - log := log.FromContext(ctx) - - // TODO: Cache applyset - - // TODO: Should the fieldmanager just be klippy? These objects should be owned - patchOptions := metav1.PatchOptions{ - FieldManager: "klippy-" + parent.GetNamespace() + "-" + parent.GetName(), - } - - // We force to overcome errors like: Apply failed with 1 conflict: conflict with "kubectl-client-side-apply" using apps/v1: .spec.template.spec.containers[name="porch-server"].image - // TODO: How to handle this better - force := true - patchOptions.Force = &force - - applier, err := applyset.New(applyset.Options{ - RESTMapper: r.restMapper, - Client: r.dynamicClient, - PatchOptions: patchOptions, - }) - if err != nil { - return err - } - - // TODO: Set owner refs - - var applyableObjects []applyset.ApplyableObject - for _, o := range children { - applyableObjects = append(applyableObjects, o) - } - if err := applier.ReplaceAllObjects(applyableObjects); err != nil { - return err - } - - results, err := applier.ApplyOnce(ctx) - if err != nil { - return fmt.Errorf("failed to apply proposals: %w", err) - } - - // TODO: Signal that we don't care about health? - - log.Info("applied objects", "results", results) - - // TODO: Implement pruning - - return nil -} - -// SetupWithManager sets up the controller with the Manager. -func (r *KlippyReconciler) SetupWithManager(mgr ctrl.Manager) error { - if err := api.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - - r.client = mgr.GetClient() - - r.restMapper = mgr.GetRESTMapper() - - restConfig := mgr.GetConfig() - - client, err := dynamic.NewForConfig(restConfig) - if err != nil { - return fmt.Errorf("failed to create a new dynamic client: %w", err) - } - r.dynamicClient = client - - if err := ctrl.NewControllerManagedBy(mgr). - For(&api.PackageRevisionResources{}). - Complete(r); err != nil { - return err - } - - return nil -} diff --git a/porch/controllers/main.go b/porch/controllers/main.go deleted file mode 100644 index 60010d83d8..0000000000 --- a/porch/controllers/main.go +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright 2022 The kpt 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. - -package main - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 rbac:roleName=porch-controllers webhook paths="." - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 crd paths="./..." output:crd:artifacts:config=config/crd/bases - -import ( - "context" - "flag" - "fmt" - "os" - "strings" - - // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) - // to ensure that exec-entrypoint and run can make use of them. - "golang.org/x/exp/slices" - _ "k8s.io/client-go/plugin/pkg/client/auth" - "k8s.io/client-go/tools/leaderelection/resourcelock" - "k8s.io/klog/v2" - "k8s.io/klog/v2/klogr" - - "k8s.io/apimachinery/pkg/runtime" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/healthz" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - "github.com/GoogleContainerTools/kpt/porch/controllers/fleetsyncs/pkg/controllers/fleetsync" - "github.com/GoogleContainerTools/kpt/porch/controllers/functiondiscovery" - "github.com/GoogleContainerTools/kpt/porch/controllers/klippy/pkg/controllers/klippy" - "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariants/pkg/controllers/packagevariant" - "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset" - "github.com/GoogleContainerTools/kpt/porch/controllers/remoterootsyncsets/pkg/controllers/remoterootsyncset" - "github.com/GoogleContainerTools/kpt/porch/controllers/rootsyncdeployments/pkg/controllers/rootsyncdeployment" - "github.com/GoogleContainerTools/kpt/porch/controllers/rootsyncrollouts/pkg/controllers/rootsyncrollout" - "github.com/GoogleContainerTools/kpt/porch/controllers/rootsyncsets/pkg/controllers/rootsyncset" - "github.com/GoogleContainerTools/kpt/porch/controllers/workloadidentitybindings/pkg/controllers/workloadidentitybinding" - "github.com/GoogleContainerTools/kpt/porch/pkg/controllerrestmapper" - //+kubebuilder:scaffold:imports -) - -var ( - reconcilers = map[string]Reconciler{ - "packagevariants": &packagevariant.PackageVariantReconciler{}, - "packagevariantsets": &packagevariantset.PackageVariantSetReconciler{}, - "rootsyncsets": &rootsyncset.RootSyncSetReconciler{}, - "remoterootsyncsets": &remoterootsyncset.RemoteRootSyncSetReconciler{}, - "workloadidentitybindings": &workloadidentitybinding.WorkloadIdentityBindingReconciler{}, - "klippy": &klippy.KlippyReconciler{}, - "rootsyncdeployments": rootsyncdeployment.NewRootSyncDeploymentReconciler(), - "functiondiscovery": &functiondiscovery.FunctionReconciler{}, - "rootsyncrollouts": rootsyncrollout.NewRootSyncRolloutReconciler(), - "fleetsyncs": fleetsync.NewFleetSyncReconciler(), - } -) - -// Reconciler is the interface implemented by (our) reconcilers, which includes some configuration and initialization. -type Reconciler interface { - reconcile.Reconciler - - // InitDefaults populates default values into our options - InitDefaults() - - // BindFlags binds options to flags - BindFlags(prefix string, flags *flag.FlagSet) - - // SetupWithManager registers the reconciler to run under the specified manager - SetupWithManager(ctrl.Manager) error -} - -// We include our lease / events permissions in the main RBAC role - -//+kubebuilder:rbac:groups=coordination.k8s.io,resources=leases,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups="",resources=events,verbs=create;patch - -func main() { - err := run(context.Background()) - if err != nil { - fmt.Fprintf(os.Stderr, "%v\n", err) - os.Exit(1) - } -} - -func run(ctx context.Context) error { - // var metricsAddr string - // var enableLeaderElection bool - // var probeAddr string - var enabledReconcilersString string - - for _, reconciler := range reconcilers { - reconciler.InitDefaults() - } - - klog.InitFlags(nil) - - // flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") - // flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") - // flag.BoolVar(&enableLeaderElection, "leader-elect", false, - // "Enable leader election for controller manager. "+ - // "Enabling this will ensure there is only one active controller manager.") - flag.StringVar(&enabledReconcilersString, "reconcilers", "", "reconcilers that should be enabled; use * to mean 'enable all'") - - for name, reconciler := range reconcilers { - reconciler.BindFlags(name+".", flag.CommandLine) - } - - flag.Parse() - - if len(flag.Args()) != 0 { - return fmt.Errorf("unexpected additional (non-flag) arguments: %v", flag.Args()) - } - - scheme := runtime.NewScheme() - if err := clientgoscheme.AddToScheme(scheme); err != nil { - return fmt.Errorf("error initializing scheme: %w", err) - } - - managerOptions := ctrl.Options{ - Scheme: scheme, - MetricsBindAddress: ":8080", - Port: 9443, - HealthProbeBindAddress: ":8081", - LeaderElection: false, - LeaderElectionID: "porch-operators.config.porch.kpt.dev", - LeaderElectionResourceLock: resourcelock.LeasesResourceLock, - MapperProvider: controllerrestmapper.New, - } - - ctrl.SetLogger(klogr.New()) - - mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), managerOptions) - if err != nil { - return fmt.Errorf("error creating manager: %w", err) - } - - enabledReconcilers := parseReconcilers(enabledReconcilersString) - var enabled []string - for name, reconciler := range reconcilers { - if !reconcilerIsEnabled(enabledReconcilers, name) { - continue - } - if err = reconciler.SetupWithManager(mgr); err != nil { - return fmt.Errorf("error creating %s reconciler: %w", name, err) - } - enabled = append(enabled, name) - } - - if len(enabled) == 0 { - klog.Warningf("no reconcilers are enabled; did you forget to pass the --reconcilers flag?") - } else { - klog.Infof("enabled reconcilers: %v", strings.Join(enabled, ",")) - } - - //+kubebuilder:scaffold:builder - if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { - return fmt.Errorf("error adding health check: %w", err) - } - if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { - return fmt.Errorf("error adding ready check: %w", err) - } - - klog.Infof("starting manager") - if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { - return fmt.Errorf("error running manager: %w", err) - } - return nil -} - -func parseReconcilers(reconcilers string) []string { - return strings.Split(reconcilers, ",") -} - -func reconcilerIsEnabled(reconcilers []string, reconciler string) bool { - if slices.Contains(reconcilers, "*") { - return true - } - if slices.Contains(reconcilers, reconciler) { - return true - } - if _, found := os.LookupEnv(fmt.Sprintf("ENABLE_%s", strings.ToUpper(reconciler))); found { - return true - } - return false -} diff --git a/porch/controllers/packagevariants/api/v1alpha1/groupversion_info.go b/porch/controllers/packagevariants/api/v1alpha1/groupversion_info.go deleted file mode 100644 index b0010b886f..0000000000 --- a/porch/controllers/packagevariants/api/v1alpha1/groupversion_info.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2022 The kpt 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. - -// Package v1alpha1 contains API Schema definitions for the config.porch.kpt.dev v1alpha1 API group -// +kubebuilder:object:generate=true -// +groupName=config.porch.kpt.dev -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/scheme" -) - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 object:headerFile="../../../../scripts/boilerplate.go.txt" paths="./..." - -var ( - // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "config.porch.kpt.dev", Version: "v1alpha1"} - - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} - - // AddToScheme adds the types in this group-version to the given scheme. - AddToScheme = SchemeBuilder.AddToScheme -) diff --git a/porch/controllers/packagevariants/api/v1alpha1/packagevariant_types.go b/porch/controllers/packagevariants/api/v1alpha1/packagevariant_types.go deleted file mode 100644 index 89d4027134..0000000000 --- a/porch/controllers/packagevariants/api/v1alpha1/packagevariant_types.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2022 The kpt 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. - -package v1alpha1 - -import ( - kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// PackageVariant represents an upstream and downstream porch package pair. -// The upstream package should already exist. The PackageVariant controller is -// responsible for creating the downstream package revisions based on the spec. -type PackageVariant struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec PackageVariantSpec `json:"spec,omitempty"` - Status PackageVariantStatus `json:"status,omitempty"` -} - -func (o *PackageVariant) GetSpec() *PackageVariantSpec { - if o == nil { - return nil - } - return &o.Spec -} - -type AdoptionPolicy string -type DeletionPolicy string - -const ( - AdoptionPolicyAdoptExisting AdoptionPolicy = "adoptExisting" - AdoptionPolicyAdoptNone AdoptionPolicy = "adoptNone" - - DeletionPolicyDelete DeletionPolicy = "delete" - DeletionPolicyOrphan DeletionPolicy = "orphan" - - Finalizer = "config.porch.kpt.dev/packagevariants" -) - -// PackageVariantSpec defines the desired state of PackageVariant -type PackageVariantSpec struct { - Upstream *Upstream `json:"upstream,omitempty"` - Downstream *Downstream `json:"downstream,omitempty"` - - AdoptionPolicy AdoptionPolicy `json:"adoptionPolicy,omitempty"` - DeletionPolicy DeletionPolicy `json:"deletionPolicy,omitempty"` - - Labels map[string]string `json:"labels,omitempty"` - Annotations map[string]string `json:"annotations,omitempty"` - - PackageContext *PackageContext `json:"packageContext,omitempty"` - Pipeline *kptfilev1.Pipeline `json:"pipeline,omitempty"` - Injectors []InjectionSelector `json:"injectors,omitempty"` -} - -type Upstream struct { - Repo string `json:"repo,omitempty"` - Package string `json:"package,omitempty"` - Revision string `json:"revision,omitempty"` -} - -type Downstream struct { - Repo string `json:"repo,omitempty"` - Package string `json:"package,omitempty"` -} - -// PackageContext defines the data to be added or removed from the -// kptfile.kpt.dev ConfigMap during reconciliation. -type PackageContext struct { - Data map[string]string `json:"data,omitempty"` - RemoveKeys []string `json:"removeKeys,omitempty"` -} - -// InjectionSelector specifies how to select in-cluster objects for -// resolving injection points. -type InjectionSelector struct { - Group *string `json:"group,omitempty"` - Version *string `json:"version,omitempty"` - Kind *string `json:"kind,omitempty"` - Name string `json:"name"` -} - -// PackageVariantStatus defines the observed state of PackageVariant -type PackageVariantStatus struct { - // Conditions describes the reconciliation state of the object. - Conditions []metav1.Condition `json:"conditions,omitempty"` - - // DownstreamTargets contains the downstream targets that the PackageVariant - // either created or adopted. - DownstreamTargets []DownstreamTarget `json:"downstreamTargets,omitempty"` -} - -type DownstreamTarget struct { - Name string `json:"name,omitempty"` -} - -//+kubebuilder:object:root=true - -// PackageVariantList contains a list of PackageVariant -type PackageVariantList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []PackageVariant `json:"items"` -} - -func init() { - SchemeBuilder.Register(&PackageVariant{}, &PackageVariantList{}) -} diff --git a/porch/controllers/packagevariants/api/v1alpha1/zz_generated.deepcopy.go b/porch/controllers/packagevariants/api/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index b20874ca49..0000000000 --- a/porch/controllers/packagevariants/api/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,270 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// Copyright 2023 The kpt 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 controller-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Downstream) DeepCopyInto(out *Downstream) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Downstream. -func (in *Downstream) DeepCopy() *Downstream { - if in == nil { - return nil - } - out := new(Downstream) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DownstreamTarget) DeepCopyInto(out *DownstreamTarget) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DownstreamTarget. -func (in *DownstreamTarget) DeepCopy() *DownstreamTarget { - if in == nil { - return nil - } - out := new(DownstreamTarget) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InjectionSelector) DeepCopyInto(out *InjectionSelector) { - *out = *in - if in.Group != nil { - in, out := &in.Group, &out.Group - *out = new(string) - **out = **in - } - if in.Version != nil { - in, out := &in.Version, &out.Version - *out = new(string) - **out = **in - } - if in.Kind != nil { - in, out := &in.Kind, &out.Kind - *out = new(string) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InjectionSelector. -func (in *InjectionSelector) DeepCopy() *InjectionSelector { - if in == nil { - return nil - } - out := new(InjectionSelector) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageContext) DeepCopyInto(out *PackageContext) { - *out = *in - if in.Data != nil { - in, out := &in.Data, &out.Data - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.RemoveKeys != nil { - in, out := &in.RemoveKeys, &out.RemoveKeys - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageContext. -func (in *PackageContext) DeepCopy() *PackageContext { - if in == nil { - return nil - } - out := new(PackageContext) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageVariant) DeepCopyInto(out *PackageVariant) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageVariant. -func (in *PackageVariant) DeepCopy() *PackageVariant { - if in == nil { - return nil - } - out := new(PackageVariant) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackageVariant) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageVariantList) DeepCopyInto(out *PackageVariantList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]PackageVariant, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageVariantList. -func (in *PackageVariantList) DeepCopy() *PackageVariantList { - if in == nil { - return nil - } - out := new(PackageVariantList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackageVariantList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageVariantSpec) DeepCopyInto(out *PackageVariantSpec) { - *out = *in - if in.Upstream != nil { - in, out := &in.Upstream, &out.Upstream - *out = new(Upstream) - **out = **in - } - if in.Downstream != nil { - in, out := &in.Downstream, &out.Downstream - *out = new(Downstream) - **out = **in - } - if in.Labels != nil { - in, out := &in.Labels, &out.Labels - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.Annotations != nil { - in, out := &in.Annotations, &out.Annotations - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.PackageContext != nil { - in, out := &in.PackageContext, &out.PackageContext - *out = new(PackageContext) - (*in).DeepCopyInto(*out) - } - if in.Pipeline != nil { - in, out := &in.Pipeline, &out.Pipeline - *out = new(v1.Pipeline) - (*in).DeepCopyInto(*out) - } - if in.Injectors != nil { - in, out := &in.Injectors, &out.Injectors - *out = make([]InjectionSelector, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageVariantSpec. -func (in *PackageVariantSpec) DeepCopy() *PackageVariantSpec { - if in == nil { - return nil - } - out := new(PackageVariantSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageVariantStatus) DeepCopyInto(out *PackageVariantStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]metav1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.DownstreamTargets != nil { - in, out := &in.DownstreamTargets, &out.DownstreamTargets - *out = make([]DownstreamTarget, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageVariantStatus. -func (in *PackageVariantStatus) DeepCopy() *PackageVariantStatus { - if in == nil { - return nil - } - out := new(PackageVariantStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Upstream) DeepCopyInto(out *Upstream) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Upstream. -func (in *Upstream) DeepCopy() *Upstream { - if in == nil { - return nil - } - out := new(Upstream) - in.DeepCopyInto(out) - return out -} diff --git a/porch/controllers/packagevariants/config/rbac/role.yaml b/porch/controllers/packagevariants/config/rbac/role.yaml deleted file mode 100644 index 7324867a7c..0000000000 --- a/porch/controllers/packagevariants/config/rbac/role.yaml +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - name: porch-controllers-packagevariants -rules: -- apiGroups: - - config.porch.kpt.dev - resources: - - packagevariants - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - config.porch.kpt.dev - resources: - - packagevariants/finalizers - verbs: - - update -- apiGroups: - - config.porch.kpt.dev - resources: - - packagevariants/status - verbs: - - get - - patch - - update -- apiGroups: - - porch.kpt.dev - resources: - - packagerevisionresources - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - porch.kpt.dev - resources: - - packagerevisions - verbs: - - create - - delete - - get - - list - - patch - - update - - watch diff --git a/porch/controllers/packagevariants/config/rbac/rolebinding.yaml b/porch/controllers/packagevariants/config/rbac/rolebinding.yaml deleted file mode 100644 index dd367ab70b..0000000000 --- a/porch/controllers/packagevariants/config/rbac/rolebinding.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: porch-system:porch-controllers-packagevariants -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: porch-controllers-packagevariants -subjects: -- kind: ServiceAccount - name: porch-controllers - namespace: porch-system \ No newline at end of file diff --git a/porch/controllers/packagevariants/config/samples/dp.yaml b/porch/controllers/packagevariants/config/samples/dp.yaml deleted file mode 100644 index 54123b2741..0000000000 --- a/porch/controllers/packagevariants/config/samples/dp.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: PackageVariant -metadata: - name: my-dp - namespace: default -spec: - upstream: - repo: blueprints - package: foo - revision: v3 - downstream: - repo: deployments - package: bar - diff --git a/porch/controllers/packagevariants/pkg/controllers/packagevariant/fake_client.go b/porch/controllers/packagevariants/pkg/controllers/packagevariant/fake_client.go deleted file mode 100644 index df086373d4..0000000000 --- a/porch/controllers/packagevariants/pkg/controllers/packagevariant/fake_client.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2023 The kpt 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. - -package packagevariant - -import ( - "context" - "fmt" - - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/yaml" -) - -type fakeClient struct { - output []string - client.Client -} - -var _ client.Client = &fakeClient{} - -func (f *fakeClient) Create(_ context.Context, obj client.Object, _ ...client.CreateOption) error { - f.output = append(f.output, fmt.Sprintf("creating object: %s", obj.GetName())) - return nil -} - -func (f *fakeClient) Delete(_ context.Context, obj client.Object, _ ...client.DeleteOption) error { - f.output = append(f.output, fmt.Sprintf("deleting object: %s", obj.GetName())) - return nil -} - -func (f *fakeClient) Update(_ context.Context, obj client.Object, _ ...client.UpdateOption) error { - f.output = append(f.output, fmt.Sprintf("updating object: %s", obj.GetName())) - return nil -} - -func (f *fakeClient) List(_ context.Context, obj client.ObjectList, _ ...client.ListOption) error { - cmList := `apiVersion: v1 -kind: ConfigMapList -metadata: - name: my-cm-list -items: -- apiVersion: v1 - kind: ConfigMap - metadata: - name: us-east1-endpoints - data: - db: db.us-east1.example.com -- apiVersion: v1 - kind: ConfigMap - metadata: - name: us-east2-endpoints - data: - db: db.us-east2.example.com -- apiVersion: v1 - kind: ConfigMap - metadata: - name: us-east3-endpoints - data: - db: db.us-east3.example.com` - - teamList := `apiVersion: v1 -kind: TeamList -metadata: - name: my-team-list -items: -- apiVersion: hr.example.com/v1alpha1 - kind: Team - metadata: - name: dev-team-alpha - spec: - chargeCode: ab -- apiVersion: hr.example.com/v1alpha1 - kind: Team - metadata: - name: dev-team-beta - spec: - chargeCode: cd -- apiVersion: hr.example.com/v1alpha1 - kind: Team - metadata: - name: prod-team - spec: - chargeCode: ef` - - var err error - switch v := obj.(type) { - case *unstructured.UnstructuredList: - gvk := v.GroupVersionKind() - switch gvk.Kind { - case "Team": - err = yaml.Unmarshal([]byte(teamList), v) - case "ConfigMap": - err = yaml.Unmarshal([]byte(cmList), v) - default: - return fmt.Errorf("unsupported kind") - } - default: - return fmt.Errorf("unsupported type") - } - return err -} diff --git a/porch/controllers/packagevariants/pkg/controllers/packagevariant/injection.go b/porch/controllers/packagevariants/pkg/controllers/packagevariant/injection.go deleted file mode 100644 index 1a9938f278..0000000000 --- a/porch/controllers/packagevariants/pkg/controllers/packagevariant/injection.go +++ /dev/null @@ -1,423 +0,0 @@ -// Copyright 2023 The kpt 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. - -package packagevariant - -import ( - "context" - "fmt" - "path/filepath" - "sigs.k8s.io/kustomize/kyaml/kio" - "sort" - "strings" - - "github.com/GoogleContainerTools/kpt-functions-sdk/go/fn" - kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - api "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariants/api/v1alpha1" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - ConfigInjectionAnnotation = "kpt.dev/config-injection" - InjectedResourceAnnotation = "kpt.dev/injected-resource" -) - -func injectionConditionType(object *fn.KubeObject) string { - return strings.Join([]string{"config", "injection", object.GetKind(), object.GetName()}, ".") -} - -type injectableField struct { - Group string - Kind string - Field string -} - -// TODO: consider giving the admin control over this -var allowedInjectionFields = []injectableField{ - {Group: "", Kind: "ConfigMap", Field: "data"}, - {Group: "*", Kind: "*", Field: "spec"}, -} - -type injectionPoint struct { - file string - object *fn.KubeObject - conditionType string - required bool - errors []string - injected bool - injectedName string - inClusterResources []*unstructured.Unstructured -} - -func newInjectionPoint(file string, object *fn.KubeObject) *injectionPoint { - annotations := object.GetAnnotations() - annotation, ok := annotations[ConfigInjectionAnnotation] - if !ok { - return nil - } - ip := &injectionPoint{ - file: file, - object: object, - conditionType: injectionConditionType(object), - } - if annotation == "required" { - ip.required = true - } else if annotation == "optional" { - ip.required = false - } else { - ip.errors = append(ip.errors, fmt.Sprintf("%s: %s/%s has invalid %q annotation value of %q", - file, object.GetKind(), object.GetName(), ConfigInjectionAnnotation, annotation)) - } - return ip -} - -func ensureConfigInjection(ctx context.Context, - c client.Client, - pv *api.PackageVariant, - prr *porchapi.PackageRevisionResources) error { - - files, err := parseFiles(prr) - if err != nil { - return err - } - - injectionPoints := findInjectionPoints(files) - - err = validateInjectionPoints(injectionPoints) - if err != nil { - return err - } - - injectResources(ctx, c, pv.Namespace, pv.Spec.Injectors, injectionPoints) - - // find which files need to be updated - // this might do some files more than once, but that's ok - for _, ip := range injectionPoints { - if ip.injected { - prr.Spec.Resources[ip.file] = kubeobjectsToYaml(files[ip.file]) - } - } - - kptfile, err := getFileKubeObject(prr, "Kptfile", "Kptfile", "") - if err != nil { - return err - } - - setInjectionPointConditionsAndGates(kptfile, injectionPoints) - - prr.Spec.Resources["Kptfile"] = kptfile.String() - - return nil -} - -func kubeobjectsToYaml(kos fn.KubeObjects) string { - var yamls []string - for _, ko := range kos { - yamls = append(yamls, ko.String()) - } - return strings.Join(yamls, "---\n") -} - -func parseFiles(prr *porchapi.PackageRevisionResources) (map[string]fn.KubeObjects, error) { - result := make(map[string]fn.KubeObjects) - for file, r := range prr.Spec.Resources { - if !includeFile(file) { - continue - } - - // Convert to KubeObjects for easier processing - kos, err := fn.ParseKubeObjects([]byte(r)) - if err != nil { - return nil, fmt.Errorf("%s: %s", file, err.Error()) - } - result[file] = kos - } - return result, nil -} - -func findInjectionPoints(files map[string]fn.KubeObjects) []*injectionPoint { - var injectionPoints []*injectionPoint - for file, kos := range files { - // Loop through the resources and find all injection points - for _, ko := range kos { - ip := newInjectionPoint(file, ko) - if ip != nil { - injectionPoints = append(injectionPoints, ip) - } - } - } - return injectionPoints -} - -func validateInjectionPoints(injectionPoints []*injectionPoint) error { - var allErrs []string - // check if there are any duplicated condition types; this will be an error - checkCT := make(map[string]*injectionPoint) - for _, ip := range injectionPoints { - allErrs = append(allErrs, ip.errors...) - if origIP, ok := checkCT[ip.conditionType]; ok { - allErrs = append(allErrs, - fmt.Sprintf("duplicate injection conditionType %q (%s and %s)", ip.conditionType, - origIP.file, ip.file)) - } - checkCT[ip.conditionType] = ip - } - - if len(allErrs) > 0 { - return fmt.Errorf("errors in injection points: %s", strings.Join(allErrs, ", ")) - } - - return nil -} - -func injectResources(ctx context.Context, c client.Client, namespace string, injectors []api.InjectionSelector, injectionPoints []*injectionPoint) { - for _, ip := range injectionPoints { - if len(injectors) == 0 { - ip.errors = append(ip.errors, "no injectors defined") - continue - } - if err := ip.loadInClusterResources(ctx, c, namespace); err != nil { - ip.errors = append(ip.errors, err.Error()) - continue - } - ip.inject(injectors) - } -} - -func (ip *injectionPoint) inject(injectors []api.InjectionSelector) { - if len(ip.inClusterResources) == 0 { - ip.errors = append(ip.errors, fmt.Sprintf("no in-cluster resources of type %s.%s", ip.object.GetAPIVersion(), ip.object.GetKind())) - return - } - - for _, injector := range injectors { - u := ip.matchSelector(injector) - if u == nil { - continue - } - - ip.injectResource(u) - break - } -} - -func (ip *injectionPoint) injectResource(u *unstructured.Unstructured) { - ip.injected = true - ip.injectedName = u.GetName() - - g, _ := fn.ParseGroupVersion(u.GetAPIVersion()) - - for _, allowed := range allowedInjectionFields { - if allowed.Group != "*" && allowed.Group != g { - continue - } - if allowed.Kind != "*" && allowed.Kind != u.GetKind() { - continue - } - - obj, ok := u.Object[allowed.Field] - if !ok { - ip.injected = false - ip.errors = append(ip.errors, fmt.Sprintf("field %q not found in resource %q", allowed.Field, u.GetName())) - return - } - - err := ip.object.SetNestedField(obj, allowed.Field) - if err != nil { - ip.injected = false - ip.errors = append(ip.errors, err.Error()) - return - } - err = ip.object.SetAnnotation(InjectedResourceAnnotation, u.GetName()) - if err != nil { - ip.injected = false - ip.errors = append(ip.errors, err.Error()) - return - } - break - } -} - -func (ip *injectionPoint) matchSelector(injector api.InjectionSelector) *unstructured.Unstructured { - // Check if this selector matches this in-package object - g, v := fn.ParseGroupVersion(ip.object.GetAPIVersion()) - if injector.Group != nil && *injector.Group != g { - return nil - } - if injector.Version != nil && *injector.Version != v { - return nil - } - if injector.Kind != nil && *injector.Kind != ip.object.GetKind() { - return nil - } - - // This injector applies to this in-package object - // So, check the in-cluster objects for a match - // We already know the GVK matches, we just need to check - // the names - - for _, u := range ip.inClusterResources { - if u.GetName() == injector.Name { - return u - } - } - - return nil -} - -func setInjectionPointConditionsAndGates(kptfileKubeObject *fn.KubeObject, injectionPoints []*injectionPoint) error { - var kptfile kptfilev1.KptFile - err := kptfileKubeObject.As(&kptfile) - if err != nil { - return err - } - - info := kptfile.Info - if info == nil { - info = &kptfilev1.PackageInfo{} - } - // generate a unique list of gates (append is not idempotent) - gateMap := make(map[string]bool) - for _, gate := range info.ReadinessGates { - gateMap[gate.ConditionType] = true - } - - status := kptfile.Status - if status == nil { - status = &kptfilev1.Status{} - } - conditions := convertConditionsToMeta(status.Conditions) - // set a condition for each injection point - for _, ip := range injectionPoints { - if ip.required { - gateMap[ip.conditionType] = true - } - var condStatus metav1.ConditionStatus - condStatus = "False" - condReason := "NoResourceSelected" - condMessage := "no resource matched any injection selector for this injection point" - if len(ip.errors) > 0 { - condMessage = strings.Join(ip.errors, ", ") - } - if ip.injected { - condStatus = "True" - condReason = "ConfigInjected" - condMessage = fmt.Sprintf("injected resource %q from cluster", ip.injectedName) - } - - meta.SetStatusCondition(&conditions, metav1.Condition{ - Type: ip.conditionType, - Status: condStatus, - Reason: condReason, - Message: condMessage, - }) - - } - - // update the readiness gates - // TODO: this loses comments right now, fix that - var gates []kptfilev1.ReadinessGate - for k := range gateMap { - gates = append(gates, kptfilev1.ReadinessGate{ConditionType: k}) - } - sort.SliceStable(gates, func(i, j int) bool { return gates[i].ConditionType < gates[j].ConditionType }) - - if gates != nil { - info.ReadinessGates = gates - err = kptfileKubeObject.SetNestedField(info, "info") - if err != nil { - return err - } - } - - // update the status conditions - if conditions != nil { - sort.SliceStable(conditions, func(i, j int) bool { return conditions[i].Type < conditions[j].Type }) - status.Conditions = convertConditionsFromMetaToKptfile(conditions) - err = kptfileKubeObject.SetNestedField(status, "status") - if err != nil { - return err - } - } - - return nil -} - -func convertConditionsFromMetaToKptfile(conditions []metav1.Condition) []kptfilev1.Condition { - var result []kptfilev1.Condition - for _, c := range conditions { - result = append(result, kptfilev1.Condition{ - Type: c.Type, - Reason: c.Reason, - Status: kptfilev1.ConditionStatus(c.Status), - Message: c.Message, - }) - } - return result -} - -func convertConditionsToMeta(conditions []kptfilev1.Condition) []metav1.Condition { - var result []metav1.Condition - for _, c := range conditions { - result = append(result, metav1.Condition{ - Type: c.Type, - Reason: c.Reason, - Status: metav1.ConditionStatus(c.Status), - Message: c.Message, - }) - } - return result -} - -var matchResourceContents = append(kio.MatchAll, kptfilev1.KptFileName) - -// TODO: Move to a utility function -// includeFile checks if the file should be parsed for resources -func includeFile(path string) bool { - for _, m := range matchResourceContents { - // Only use the filename for the check for whether we should - // include the file. - f := filepath.Base(path) - if matched, err := filepath.Match(m, f); err == nil && matched { - return true - } - } - return false -} - -func (ip *injectionPoint) loadInClusterResources(ctx context.Context, c client.Client, namespace string) error { - uList := &unstructured.UnstructuredList{} - group, version := fn.ParseGroupVersion(ip.object.GetAPIVersion()) - uList.SetGroupVersionKind(schema.GroupVersionKind{ - Group: group, - Version: version, - Kind: ip.object.GetKind(), - }) - - opts := []client.ListOption{client.InNamespace(namespace)} - if err := c.List(ctx, uList, opts...); err != nil { - return err - } - - for _, u := range uList.Items { - ip.inClusterResources = append(ip.inClusterResources, u.DeepCopy()) - } - - return nil -} diff --git a/porch/controllers/packagevariants/pkg/controllers/packagevariant/injection_test.go b/porch/controllers/packagevariants/pkg/controllers/packagevariant/injection_test.go deleted file mode 100644 index eb6a450e34..0000000000 --- a/porch/controllers/packagevariants/pkg/controllers/packagevariant/injection_test.go +++ /dev/null @@ -1,865 +0,0 @@ -// Copyright 2023 The kpt 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. - -package packagevariant - -import ( - "context" - "fmt" - "sort" - "testing" - - "github.com/GoogleContainerTools/kpt-functions-sdk/go/fn" - kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - api "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariants/api/v1alpha1" - "github.com/stretchr/testify/require" - "sigs.k8s.io/yaml" -) - -func TestFindInjectionPoints(t *testing.T) { - - prrBase := `apiVersion: porch.kpt.dev/v1alpha1 -kind: PackageRevisionResources -metadata: - name: prr - namespace: default -spec: - packageName: nephio-system - repository: nephio-packages - resources: - Kptfile: | - apiVersion: kpt.dev/v1 - kind: Kptfile - metadata: - name: prr - annotations: - config.kubernetes.io/local-config: "true" - info: - description: Example - package-context.yaml: | - apiVersion: v1 - kind: ConfigMap - metadata: - name: kptfile.kpt.dev - annotations: - config.kubernetes.io/local-config: "true" - data: - name: example -` - - testCases := map[string]struct { - resources string - expectedErr string - expected []*injectionPoint - }{ - "parse error": { - resources: ` junk.yaml: | - baddata`, - expectedErr: "junk.yaml: failed to extract objects: unhandled node kind 8", - }, - "no injection points": { - resources: ``, - expected: nil, - }, - "one optional injection point": { - resources: ` file.yaml: | - apiVersion: v1 - kind: ConfigMap - metadata: - name: foo - annotations: - config.kubernetes.io/local-config: "true" - kpt.dev/config-injection: optional - data: - foo: bar -`, - expected: []*injectionPoint{ - { - file: "file.yaml", - required: false, - conditionType: "config.injection.ConfigMap.foo", - }, - }, - }, - "one invalid injection point": { - resources: ` file.yaml: | - apiVersion: v1 - kind: ConfigMap - metadata: - name: foo - annotations: - config.kubernetes.io/local-config: "true" - kpt.dev/config-injection: invalid - data: - foo: bar -`, - expected: []*injectionPoint{ - { - file: "file.yaml", - required: false, - conditionType: "config.injection.ConfigMap.foo", - errors: []string{"file.yaml: ConfigMap/foo has invalid \"kpt.dev/config-injection\" annotation value of \"invalid\""}, - }, - }, - }, - "one required injection point": { - resources: ` file2.yaml: | - apiVersion: v1 - kind: ConfigMap - metadata: - name: foo - annotations: - kpt.dev/config-injection: required - data: - foo: bar -`, - expected: []*injectionPoint{ - { - file: "file2.yaml", - required: true, - conditionType: "config.injection.ConfigMap.foo", - }, - }, - }, - "multiple injection points in one file": { - resources: ` file.yaml: | - apiVersion: v1 - kind: ConfigMap - metadata: - name: foo - annotations: - kpt.dev/config-injection: required - data: - foo: bar - --- - apiVersion: bigco.com/v2 - kind: MyType - metadata: - name: foo - annotations: - kpt.dev/config-injection: optional - spec: - foo: bar - bar: foofoo -`, - expected: []*injectionPoint{ - { - file: "file.yaml", - required: true, - conditionType: "config.injection.ConfigMap.foo", - }, - { - file: "file.yaml", - required: false, - conditionType: "config.injection.MyType.foo", - }, - }, - }, - "multiple injection points across files": { - resources: ` file.yaml: | - apiVersion: v1 - kind: ConfigMap - metadata: - name: foo - annotations: - kpt.dev/config-injection: required - data: - foo: bar - --- - apiVersion: bigco.com/v2 - kind: MyType - metadata: - name: foo - annotations: - kpt.dev/config-injection: optional - spec: - foo: bar - bar: foofoo - some-file.yaml: | - apiVersion: bigco.com/v2 - kind: MyType - metadata: - name: foo2 - annotations: - kpt.dev/config-injection: required - spec: - foo: bar - bar: foofoo -`, - expected: []*injectionPoint{ - { - file: "file.yaml", - required: true, - conditionType: "config.injection.ConfigMap.foo", - }, - { - file: "file.yaml", - required: false, - conditionType: "config.injection.MyType.foo", - }, - { - file: "some-file.yaml", - required: true, - conditionType: "config.injection.MyType.foo2", - }, - }, - }, - } - - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - var prr porchapi.PackageRevisionResources - require.NoError(t, yaml.Unmarshal([]byte(prrBase+tc.resources), &prr)) - - actualFiles, actualErr := parseFiles(&prr) - if tc.expectedErr == "" { - require.NoError(t, actualErr) - } else { - require.EqualError(t, actualErr, tc.expectedErr) - } - - actualInjectionPoints := findInjectionPoints(actualFiles) - require.Equal(t, len(tc.expected), len(actualInjectionPoints)) - - // ensure a stable ordering - sort.Slice(actualInjectionPoints, - func(i, j int) bool { - return actualInjectionPoints[i].conditionType < actualInjectionPoints[j].conditionType - }) - for i, ip := range actualInjectionPoints { - require.Equal(t, tc.expected[i].conditionType, ip.conditionType) - require.Equal(t, tc.expected[i].file, ip.file) - require.Equal(t, tc.expected[i].required, ip.required) - require.Equal(t, tc.expected[i].errors, ip.errors) - } - }) - } -} - -func TestValidateInjectionPoints(t *testing.T) { - testCases := map[string]struct { - injectionPoints []*injectionPoint - expected error - }{ - "no injection points": { - injectionPoints: nil, - expected: nil, - }, - "one optional injection point": { - injectionPoints: []*injectionPoint{ - { - file: "file.yaml", - required: false, - conditionType: "config.injection.ConfigMap.foo", - }, - }, - expected: nil, - }, - "one invalid injection point": { - injectionPoints: []*injectionPoint{ - { - file: "file.yaml", - required: false, - conditionType: "config.injection.ConfigMap.foo", - errors: []string{"e1"}, - }, - }, - expected: fmt.Errorf("errors in injection points: e1"), - }, - "multiple distinct, valid injection points": { - injectionPoints: []*injectionPoint{ - { - file: "file.yaml", - required: true, - conditionType: "config.injection.ConfigMap.foo", - }, - { - file: "file.yaml", - required: false, - conditionType: "config.injection.MyType.foo", - }, - }, - expected: nil, - }, - "multiple distinct, invalid injection points": { - injectionPoints: []*injectionPoint{ - { - file: "file.yaml", - required: false, - conditionType: "config.injection.ConfigMap.foo", - errors: []string{"e1", "e2"}, - }, - { - file: "file.yaml", - required: false, - conditionType: "config.injection.ConfigMap.foo2", - errors: []string{"e3"}, - }, - }, - expected: fmt.Errorf("errors in injection points: e1, e2, e3"), - }, - "multiple ambiguous injection points": { - injectionPoints: []*injectionPoint{ - { - file: "file.yaml", - required: false, - conditionType: "config.injection.ConfigMap.foo", - }, - { - file: "file2.yaml", - required: false, - conditionType: "config.injection.ConfigMap.foo", - }, - { - file: "file3.yaml", - required: false, - conditionType: "config.injection.ConfigMap.foo", - }, - }, - expected: fmt.Errorf("errors in injection points: duplicate injection conditionType \"config.injection.ConfigMap.foo\" (file.yaml and file2.yaml), duplicate injection conditionType \"config.injection.ConfigMap.foo\" (file2.yaml and file3.yaml)"), - }, - } - - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - allErrs := validateInjectionPoints(tc.injectionPoints) - require.Equal(t, tc.expected, allErrs) - }) - } -} - -func TestSetInjectionPointConditionsAndGates(t *testing.T) { - kptfileWithGates := &kptfilev1.KptFile{ - Info: &kptfilev1.PackageInfo{ - ReadinessGates: []kptfilev1.ReadinessGate{ - { - ConditionType: "test", - }, - { - ConditionType: "test3", - }, - }, - }, - Status: &kptfilev1.Status{ - Conditions: []kptfilev1.Condition{ - { - Type: "test", - Status: "False", - Reason: "test", - Message: "test", - }, - { - Type: "test2", - Status: "True", - Reason: "test2", - Message: "test2", - }, - { - Type: "test3", - Status: "True", - Reason: "test3", - Message: "test3", - }, - }, - }, - } - - testCases := map[string]struct { - initialKptfile *kptfilev1.KptFile - injectionPoints []*injectionPoint - expectedKptfile *kptfilev1.KptFile - expectedErr string - }{ - "no injection points": { - initialKptfile: &kptfilev1.KptFile{}, - injectionPoints: nil, - expectedKptfile: &kptfilev1.KptFile{}, - }, - "no injection points, existing gates and conditions": { - initialKptfile: kptfileWithGates, - injectionPoints: nil, - expectedKptfile: kptfileWithGates, - }, - "optional, not injected": { - initialKptfile: &kptfilev1.KptFile{}, - injectionPoints: []*injectionPoint{ - { - file: "file.yaml", - required: false, - conditionType: "config.injection.ConfigMap.foo", - }, - }, - expectedKptfile: &kptfilev1.KptFile{ - Status: &kptfilev1.Status{ - Conditions: []kptfilev1.Condition{ - { - Type: "config.injection.ConfigMap.foo", - Status: "False", - Reason: "NoResourceSelected", - Message: "no resource matched any injection selector for this injection point", - }, - }, - }, - }, - }, - "required, not injected": { - initialKptfile: &kptfilev1.KptFile{}, - injectionPoints: []*injectionPoint{ - { - file: "file.yaml", - required: true, - conditionType: "config.injection.ConfigMap.foo", - }, - }, - expectedKptfile: &kptfilev1.KptFile{ - Info: &kptfilev1.PackageInfo{ - ReadinessGates: []kptfilev1.ReadinessGate{ - { - ConditionType: "config.injection.ConfigMap.foo", - }, - }, - }, - Status: &kptfilev1.Status{ - Conditions: []kptfilev1.Condition{ - { - Type: "config.injection.ConfigMap.foo", - Status: "False", - Reason: "NoResourceSelected", - Message: "no resource matched any injection selector for this injection point", - }, - }, - }, - }, - }, - "optional, injected": { - initialKptfile: &kptfilev1.KptFile{}, - injectionPoints: []*injectionPoint{ - { - file: "file.yaml", - required: false, - conditionType: "config.injection.ConfigMap.foo", - injected: true, - injectedName: "my-injected-resource", - }, - }, - expectedKptfile: &kptfilev1.KptFile{ - Status: &kptfilev1.Status{ - Conditions: []kptfilev1.Condition{ - { - Type: "config.injection.ConfigMap.foo", - Status: "True", - Reason: "ConfigInjected", - Message: "injected resource \"my-injected-resource\" from cluster", - }, - }, - }, - }, - }, - "multiple optional": { - initialKptfile: &kptfilev1.KptFile{}, - injectionPoints: []*injectionPoint{ - { - file: "file.yaml", - required: false, - conditionType: "config.injection.ConfigMap.foo", - injected: true, - injectedName: "my-injected-resource", - }, - { - file: "file.yaml", - required: false, - conditionType: "config.injection.SomeResource.foo", - injected: true, - injectedName: "some-injected-resource", - }, - { - file: "file.yaml", - required: false, - conditionType: "config.injection.AnotherResource.foo", - injected: false, - injectedName: "another-injected-resource", - }, - }, - expectedKptfile: &kptfilev1.KptFile{ - Status: &kptfilev1.Status{ - Conditions: []kptfilev1.Condition{ - { - Type: "config.injection.AnotherResource.foo", - Status: "False", - Reason: "NoResourceSelected", - Message: "no resource matched any injection selector for this injection point", - }, - { - Type: "config.injection.ConfigMap.foo", - Status: "True", - Reason: "ConfigInjected", - Message: "injected resource \"my-injected-resource\" from cluster", - }, - { - Type: "config.injection.SomeResource.foo", - Status: "True", - Reason: "ConfigInjected", - Message: "injected resource \"some-injected-resource\" from cluster", - }, - }, - }, - }, - }, - "mixed existing, optional, required": { - initialKptfile: kptfileWithGates, - injectionPoints: []*injectionPoint{ - { - file: "file.yaml", - required: false, - conditionType: "config.injection.ConfigMap.foo", - injected: true, - injectedName: "my-injected-resource", - }, - { - file: "file.yaml", - required: true, - conditionType: "config.injection.SomeResource.foo", - injected: true, - injectedName: "some-injected-resource", - }, - { - file: "file.yaml", - required: false, - conditionType: "config.injection.AnotherResource.foo", - injected: false, - injectedName: "another-injected-resource", - }, - }, - expectedKptfile: &kptfilev1.KptFile{ - Info: &kptfilev1.PackageInfo{ - ReadinessGates: []kptfilev1.ReadinessGate{ - { - ConditionType: "config.injection.SomeResource.foo", - }, - { - ConditionType: "test", - }, - { - ConditionType: "test3", - }, - }, - }, - Status: &kptfilev1.Status{ - Conditions: []kptfilev1.Condition{ - { - Type: "config.injection.AnotherResource.foo", - Status: "False", - Reason: "NoResourceSelected", - Message: "no resource matched any injection selector for this injection point", - }, - { - Type: "config.injection.ConfigMap.foo", - Status: "True", - Reason: "ConfigInjected", - Message: "injected resource \"my-injected-resource\" from cluster", - }, - { - Type: "config.injection.SomeResource.foo", - Status: "True", - Reason: "ConfigInjected", - Message: "injected resource \"some-injected-resource\" from cluster", - }, - { - Type: "test", - Status: "False", - Reason: "test", - Message: "test", - }, - { - Type: "test2", - Status: "True", - Reason: "test2", - Message: "test2", - }, - { - Type: "test3", - Status: "True", - Reason: "test3", - Message: "test3", - }, - }, - }, - }, - }, - } - - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - ko, err := fn.NewFromTypedObject(tc.initialKptfile) - require.NoError(t, err) - err = setInjectionPointConditionsAndGates(ko, tc.injectionPoints) - if tc.expectedErr == "" { - require.NoError(t, err) - var actualKptfile kptfilev1.KptFile - err = ko.As(&actualKptfile) - require.NoError(t, err) - require.Equal(t, tc.expectedKptfile, &actualKptfile) - } else { - require.EqualError(t, err, tc.expectedErr) - } - }) - } -} -func TestEnsureConfigInjection(t *testing.T) { - - pvBase := `apiVersion: config.porch.kpt.dev -kind: PackageVariant -metadata: - name: my-pv - uid: pv-uid -spec: - upstream: - repo: blueprints - package: foo - revision: v1 - downstream: - repo: deployments - package: bar -` - - prrBase := `apiVersion: porch.kpt.dev/v1alpha1 -kind: PackageRevisionResources -metadata: - name: prr - namespace: default -spec: - packageName: nephio-system - repository: nephio-packages - resources: - package-context.yaml: | - apiVersion: v1 - kind: ConfigMap - metadata: - name: kptfile.kpt.dev - annotations: - config.kubernetes.io/local-config: "true" - data: - name: example` - - baseKptfile := ` - Kptfile: | - apiVersion: kpt.dev/v1 - kind: Kptfile - metadata: - name: prr - annotations: - config.kubernetes.io/local-config: "true" - info: - description: Example -` - - testCases := map[string]struct { - injectors string - injectionPoints string - expectedErr string - expectedPRR string - }{ - "empty injectors": { - injectors: ``, - injectionPoints: ``, - expectedErr: "", - expectedPRR: prrBase + baseKptfile, - }, - "one ConfigMap injection point": { - injectors: ` injectors: - - name: us-east1-endpoints -`, - injectionPoints: ` configmap.yaml: | - apiVersion: v1 - kind: ConfigMap - metadata: - name: regional-endpoints - annotations: - kpt.dev/config-injection: required - data: - db: example -`, - expectedErr: "", - expectedPRR: prrBase + ` - Kptfile: | - apiVersion: kpt.dev/v1 - kind: Kptfile - metadata: - name: prr - annotations: - config.kubernetes.io/local-config: "true" - info: - readinessGates: - - conditionType: config.injection.ConfigMap.regional-endpoints - description: Example - status: - conditions: - - type: config.injection.ConfigMap.regional-endpoints - status: "True" - message: injected resource "us-east1-endpoints" from cluster - reason: ConfigInjected - configmap.yaml: | - apiVersion: v1 - kind: ConfigMap - metadata: - name: regional-endpoints - annotations: - kpt.dev/config-injection: required - kpt.dev/injected-resource: us-east1-endpoints - data: - db: db.us-east1.example.com -`, - }, - "one non-ConfigMap injection point": { - injectors: ` injectors: - - name: dev-team-beta - group: hr.example.com - kind: Team -`, - injectionPoints: ` team.yaml: | - apiVersion: hr.example.com/v1alpha1 - kind: Team - metadata: - name: team - annotations: - kpt.dev/config-injection: required - spec: - chargeCode: example -`, - expectedErr: "", - expectedPRR: prrBase + ` - Kptfile: | - apiVersion: kpt.dev/v1 - kind: Kptfile - metadata: - name: prr - annotations: - config.kubernetes.io/local-config: "true" - info: - readinessGates: - - conditionType: config.injection.Team.team - description: Example - status: - conditions: - - type: config.injection.Team.team - status: "True" - message: injected resource "dev-team-beta" from cluster - reason: ConfigInjected - team.yaml: | - apiVersion: hr.example.com/v1alpha1 - kind: Team - metadata: - name: team - annotations: - kpt.dev/config-injection: required - kpt.dev/injected-resource: dev-team-beta - spec: - chargeCode: cd -`, - }, - "mixed injection points": { - injectors: ` injectors: - - name: us-east2-endpoints - - name: dev-team-beta - group: hr.example.com - kind: Team -`, - injectionPoints: ` more.yaml: | - apiVersion: v1 - kind: ConfigMap - metadata: - name: my-cm - annotations: - kpt.dev/config-injection: optional - data: - db: db.example.com - --- - apiVersion: hr.example.com/v1alpha1 - kind: Team - metadata: - name: team - annotations: - kpt.dev/config-injection: required - spec: - chargeCode: example -`, - expectedErr: "", - expectedPRR: prrBase + ` - Kptfile: | - apiVersion: kpt.dev/v1 - kind: Kptfile - metadata: - name: prr - annotations: - config.kubernetes.io/local-config: "true" - info: - readinessGates: - - conditionType: config.injection.Team.team - description: Example - status: - conditions: - - type: config.injection.ConfigMap.my-cm - status: "True" - message: injected resource "us-east2-endpoints" from cluster - reason: ConfigInjected - - type: config.injection.Team.team - status: "True" - message: injected resource "dev-team-beta" from cluster - reason: ConfigInjected - more.yaml: | - apiVersion: v1 - kind: ConfigMap - metadata: - name: my-cm - annotations: - kpt.dev/config-injection: optional - kpt.dev/injected-resource: us-east2-endpoints - data: - db: db.us-east2.example.com - --- - apiVersion: hr.example.com/v1alpha1 - kind: Team - metadata: - name: team - annotations: - kpt.dev/config-injection: required - kpt.dev/injected-resource: dev-team-beta - spec: - chargeCode: cd -`, - }, - } - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - var pv api.PackageVariant - require.NoError(t, yaml.Unmarshal([]byte(pvBase+tc.injectors), &pv)) - var prr porchapi.PackageRevisionResources - require.NoError(t, yaml.Unmarshal([]byte(prrBase+baseKptfile+tc.injectionPoints), &prr)) - - c := &fakeClient{} - actualErr := ensureConfigInjection(context.Background(), c, &pv, &prr) - if tc.expectedErr == "" { - require.NoError(t, actualErr) - } else { - require.EqualError(t, actualErr, tc.expectedErr) - } - - var expectedPRR porchapi.PackageRevisionResources - require.NoError(t, yaml.Unmarshal([]byte(tc.expectedPRR), &expectedPRR)) - - require.Equal(t, expectedPRR, prr) - }) - } -} diff --git a/porch/controllers/packagevariants/pkg/controllers/packagevariant/packagevariant_controller.go b/porch/controllers/packagevariants/pkg/controllers/packagevariant/packagevariant_controller.go deleted file mode 100644 index 3c17df3c62..0000000000 --- a/porch/controllers/packagevariants/pkg/controllers/packagevariant/packagevariant_controller.go +++ /dev/null @@ -1,1051 +0,0 @@ -// Copyright 2022 The kpt 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. - -package packagevariant - -import ( - "context" - "flag" - "fmt" - "strconv" - "strings" - "time" - - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - api "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariants/api/v1alpha1" - - "github.com/GoogleContainerTools/kpt-functions-sdk/go/fn" - kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/pkg/kptfile/kptfileutil" - - "golang.org/x/mod/semver" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/validation/field" - "k8s.io/klog/v2" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" -) - -type Options struct{} - -func (o *Options) InitDefaults() {} -func (o *Options) BindFlags(_ string, _ *flag.FlagSet) {} - -// PackageVariantReconciler reconciles a PackageVariant object -type PackageVariantReconciler struct { - client.Client - Options -} - -const ( - workspaceNamePrefix = "packagevariant-" - - ConditionTypeStalled = "Stalled" // whether or not the packagevariant object is making progress or not - ConditionTypeReady = "Ready" // whether or notthe reconciliation succeded - - requeueDuration = 30 * time.Second -) - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 rbac:roleName=porch-controllers-packagevariants webhook paths="." output:rbac:artifacts:config=../../../config/rbac - -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=packagevariants,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=packagevariants/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=packagevariants/finalizers,verbs=update -//+kubebuilder:rbac:groups=porch.kpt.dev,resources=packagerevisions,verbs=create;delete;get;list;patch;update;watch -//+kubebuilder:rbac:groups=porch.kpt.dev,resources=packagerevisionresources,verbs=create;delete;get;list;patch;update;watch - -// Reconcile implements the main kubernetes reconciliation loop. -func (r *PackageVariantReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - pv, prList, err := r.init(ctx, req) - if err != nil { - return ctrl.Result{}, err - } - if pv == nil { - // maybe the pv was deleted - return ctrl.Result{}, nil - } - - defer func() { - if err := r.Client.Status().Update(ctx, pv); err != nil { - klog.Errorf("could not update status: %s\n", err.Error()) - } - }() - - if !pv.ObjectMeta.DeletionTimestamp.IsZero() { - // This object is being deleted, so we need to make sure the packagerevisions owned by this object - // are deleted. Normally, garbage collection can handle this, but we have a special case here because - // (a) we cannot delete published packagerevisions and instead have to propose deletion of them - // (b) we may want to orphan packagerevisions instead of deleting them. - for _, pr := range prList.Items { - if r.hasOurOwnerReference(pv, pr.OwnerReferences) { - r.deleteOrOrphan(ctx, &pr, pv) - if pr.Spec.Lifecycle == porchapi.PackageRevisionLifecycleDeletionProposed { - // We need to orphan this package revision; otherwise it will automatically - // get deleted after its parent PackageVariant object is deleted. - r.orphanPackageRevision(ctx, &pr, pv) - } - } - } - // Remove our finalizer from the list and update it. - controllerutil.RemoveFinalizer(pv, api.Finalizer) - if err := r.Update(ctx, pv); err != nil { - return ctrl.Result{}, fmt.Errorf("failed to update %s after delete finalizer: %w", req.Name, err) - } - return ctrl.Result{}, nil - } - - // the object is not being deleted, so let's ensure that our finalizer is here - if !controllerutil.ContainsFinalizer(pv, api.Finalizer) { - controllerutil.AddFinalizer(pv, api.Finalizer) - if err := r.Update(ctx, pv); err != nil { - return ctrl.Result{}, fmt.Errorf("failed to update %s after add finalizer: %w", req.Name, err) - } - } - - if errs := validatePackageVariant(pv); len(errs) > 0 { - setStalledConditionsToTrue(pv, combineErrors(errs)) - // do not requeue; failed validation requires a PV change - return ctrl.Result{}, nil - } - upstream, err := r.getUpstreamPR(pv.Spec.Upstream, prList) - if err != nil { - setStalledConditionsToTrue(pv, err.Error()) - // requeue, as the upstream may appear - return ctrl.Result{RequeueAfter: requeueDuration}, err - } - meta.SetStatusCondition(&pv.Status.Conditions, metav1.Condition{ - Type: ConditionTypeStalled, - Status: "False", - Reason: "Valid", - Message: "all validation checks passed", - }) - - targets, err := r.ensurePackageVariant(ctx, pv, upstream, prList) - if err != nil { - meta.SetStatusCondition(&pv.Status.Conditions, metav1.Condition{ - Type: ConditionTypeReady, - Status: "False", - Reason: "Error", - Message: err.Error(), - }) - // requeue; it may be an intermittent error - return ctrl.Result{RequeueAfter: requeueDuration}, nil - } - - setTargetStatusConditions(pv, targets) - - return ctrl.Result{}, nil -} - -func (r *PackageVariantReconciler) init(ctx context.Context, - req ctrl.Request) (*api.PackageVariant, *porchapi.PackageRevisionList, error) { - var pv api.PackageVariant - if err := r.Client.Get(ctx, req.NamespacedName, &pv); err != nil { - return nil, nil, client.IgnoreNotFound(err) - } - - var prList porchapi.PackageRevisionList - if err := r.Client.List(ctx, &prList, client.InNamespace(pv.Namespace)); err != nil { - return nil, nil, err - } - - return &pv, &prList, nil -} - -func validatePackageVariant(pv *api.PackageVariant) []string { - var allErrs []string - if pv.Spec.Upstream == nil { - allErrs = append(allErrs, "missing required field spec.upstream") - } else { - if pv.Spec.Upstream.Repo == "" { - allErrs = append(allErrs, "missing required field spec.upstream.repo") - } - if pv.Spec.Upstream.Package == "" { - allErrs = append(allErrs, "missing required field spec.upstream.package") - } - if pv.Spec.Upstream.Revision == "" { - allErrs = append(allErrs, "missing required field spec.upstream.revision") - } - } - if pv.Spec.Downstream == nil { - allErrs = append(allErrs, "missing required field spec.downstream") - } else { - if pv.Spec.Downstream.Repo == "" { - allErrs = append(allErrs, "missing required field spec.downstream.repo") - } - if pv.Spec.Downstream.Package == "" { - allErrs = append(allErrs, "missing required field spec.downstream.package") - } - } - if pv.Spec.AdoptionPolicy == "" { - pv.Spec.AdoptionPolicy = api.AdoptionPolicyAdoptNone - } - if pv.Spec.DeletionPolicy == "" { - pv.Spec.DeletionPolicy = api.DeletionPolicyDelete - } - if pv.Spec.AdoptionPolicy != api.AdoptionPolicyAdoptNone && pv.Spec.AdoptionPolicy != api.AdoptionPolicyAdoptExisting { - allErrs = append(allErrs, fmt.Sprintf("spec.adoptionPolicy field can only be %q or %q", - api.AdoptionPolicyAdoptNone, api.AdoptionPolicyAdoptExisting)) - } - if pv.Spec.DeletionPolicy != api.DeletionPolicyOrphan && pv.Spec.DeletionPolicy != api.DeletionPolicyDelete { - allErrs = append(allErrs, fmt.Sprintf("spec.deletionPolicy can only be %q or %q", - api.DeletionPolicyOrphan, api.DeletionPolicyDelete)) - } - if pc := pv.Spec.PackageContext; pc != nil { - invalidKeys := []string{"name", "package-path"} - for _, invalid := range invalidKeys { - if len(pc.Data) > 0 { - if _, ok := pc.Data[invalid]; ok { - allErrs = append(allErrs, field.Invalid( - field.NewPath("spec", "packageContext", "data"), - pv.Spec.PackageContext.Data, - fmt.Sprintf("must not contain the key %q", invalid)).Error()) - } - } - if len(pc.RemoveKeys) > 0 { - for _, k := range pc.RemoveKeys { - if k == invalid { - allErrs = append(allErrs, field.Invalid( - field.NewPath("spec", "packageContext", "removeKeys"), - pv.Spec.PackageContext.RemoveKeys, - fmt.Sprintf("must not contain the key %q", invalid)).Error()) - } - } - } - } - } - if len(pv.Spec.Injectors) > 0 { - for i, injector := range pv.Spec.Injectors { - if injector.Name == "" { - allErrs = append(allErrs, fmt.Sprintf("spec.injectors[%d].name must not be empty", i)) - } - } - } - return allErrs -} - -func combineErrors(errs []string) string { - var errMsgs []string - for _, e := range errs { - if e != "" { - errMsgs = append(errMsgs, e) - } - } - return strings.Join(errMsgs, "; ") -} - -func (r *PackageVariantReconciler) getUpstreamPR(upstream *api.Upstream, - prList *porchapi.PackageRevisionList) (*porchapi.PackageRevision, error) { - for _, pr := range prList.Items { - if pr.Spec.RepositoryName == upstream.Repo && - pr.Spec.PackageName == upstream.Package && - pr.Spec.Revision == upstream.Revision { - return &pr, nil - } - } - return nil, fmt.Errorf("could not find upstream package revision '%s/%s' in repo '%s'", - upstream.Package, upstream.Revision, upstream.Repo) -} - -func setStalledConditionsToTrue(pv *api.PackageVariant, message string) { - meta.SetStatusCondition(&pv.Status.Conditions, metav1.Condition{ - Type: ConditionTypeStalled, - Status: "True", - Reason: "ValidationError", - Message: message, - }) - meta.SetStatusCondition(&pv.Status.Conditions, metav1.Condition{ - Type: ConditionTypeReady, - Status: "False", - Reason: "Error", - Message: "invalid packagevariant object", - }) -} - -// ensurePackageVariant needs to: -// - Check if the downstream package revision already exists. If not, create it. -// - If it does already exist, we need to make sure it is up-to-date. If there are -// downstream package drafts, we look at all drafts. Otherwise, we look at the latest -// published downstream package revision. -// - Compare pd.Spec.Upstream.Revision to the revision number that the downstream -// package is based on. If it is different, we need to do an update (could be an upgrade -// or a downgrade). -// - Delete or orphan other package revisions owned by this controller that are no -// longer needed. -func (r *PackageVariantReconciler) ensurePackageVariant(ctx context.Context, - pv *api.PackageVariant, - upstream *porchapi.PackageRevision, - prList *porchapi.PackageRevisionList) ([]*porchapi.PackageRevision, error) { - - existing, err := r.findAndUpdateExistingRevisions(ctx, pv, upstream, prList) - if err != nil { - return nil, err - } - if existing != nil { - return existing, nil - } - - // No downstream package created by this controller exists. Create one. - newPR := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: pv.Namespace, - OwnerReferences: []metav1.OwnerReference{constructOwnerReference(pv)}, - Labels: pv.Spec.Labels, - Annotations: pv.Spec.Annotations, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: pv.Spec.Downstream.Package, - RepositoryName: pv.Spec.Downstream.Repo, - WorkspaceName: newWorkspaceName(prList, pv.Spec.Downstream.Package, pv.Spec.Downstream.Repo), - Tasks: []porchapi.Task{ - { - Type: porchapi.TaskTypeClone, - Clone: &porchapi.PackageCloneTaskSpec{ - Upstream: porchapi.UpstreamPackage{ - UpstreamRef: &porchapi.PackageRevisionRef{ - Name: upstream.Name, - }, - }, - }, - }, - }, - }, - } - - if err = r.Client.Create(ctx, newPR); err != nil { - return nil, err - } - klog.Infoln(fmt.Sprintf("package variant %q created package revision %q", pv.Name, newPR.Name)) - - prr, changed, err := r.calculateDraftResources(ctx, pv, newPR) - if err != nil { - return nil, err - } - if changed { - // Save the updated PackageRevisionResources - if err = r.Update(ctx, prr); err != nil { - return nil, err - } - klog.Infoln(fmt.Sprintf("package variant %q applied mutations to package revision %q", pv.Name, newPR.Name)) - } - - return []*porchapi.PackageRevision{newPR}, nil -} - -func (r *PackageVariantReconciler) findAndUpdateExistingRevisions(ctx context.Context, - pv *api.PackageVariant, - upstream *porchapi.PackageRevision, - prList *porchapi.PackageRevisionList) ([]*porchapi.PackageRevision, error) { - downstreams := r.getDownstreamPRs(ctx, pv, prList) - if downstreams == nil { - // If there are no existing target downstream packages, just return nil. The - // caller will create one. - return nil, nil - } - - var err error - for i, downstream := range downstreams { - if downstream.Spec.Lifecycle == porchapi.PackageRevisionLifecycleDeletionProposed { - // We proposed this package revision for deletion in the past, but now it - // matches our target, so we no longer want it to be deleted. - downstream.Spec.Lifecycle = porchapi.PackageRevisionLifecyclePublished - // We update this now, because later we may use a Porch call to clone or update - // and we want to make sure the server is in sync with us - if err := r.Client.Update(ctx, downstream); err != nil { - klog.Errorf("error updating package revision lifecycle: %v", err) - return nil, err - } - } - - // see if the package needs updating due to an upstream change - if !r.isUpToDate(pv, downstream) { - // we need to copy a published package to a new draft before updating - if porchapi.LifecycleIsPublished(downstream.Spec.Lifecycle) { - klog.Infoln(fmt.Sprintf("package variant %q needs to update package revision %q for new upstream revision, creating new draft", pv.Name, downstream.Name)) - oldDS := downstream - downstream, err = r.copyPublished(ctx, downstream, pv, prList) - if err != nil { - klog.Errorf("package variant %q failed to copy %q: %s", pv.Name, oldDS.Name, err.Error()) - return nil, err - } - klog.Infoln(fmt.Sprintf("package variant %q created %q based on %q", pv.Name, downstream.Name, oldDS.Name)) - } - downstreams[i], err = r.updateDraft(ctx, downstream, upstream) - if err != nil { - return nil, err - } - klog.Infoln(fmt.Sprintf("package variant %q updated package revision %q to upstream revision %s", pv.Name, downstream.Name, upstream.Spec.Revision)) - } - - // finally, see if any other changes are needed to the resources - prr, changed, err := r.calculateDraftResources(ctx, pv, downstreams[i]) - if err != nil { - return nil, err - } - - // if there are changes, save them - if changed { - // if no pkg update was needed, we may still be a published package - // so, clone to a new Draft if that's the case - if porchapi.LifecycleIsPublished(downstream.Spec.Lifecycle) { - klog.Infoln(fmt.Sprintf("package variant %q needs to mutate to package revision %q, creating new draft", pv.Name, downstream.Name)) - oldDS := downstream - downstream, err = r.copyPublished(ctx, downstream, pv, prList) - if err != nil { - klog.Errorf("package variant %q failed to copy %q: %s", pv.Name, oldDS.Name, err.Error()) - return nil, err - } - klog.Infoln(fmt.Sprintf("package variant %q created %q based on %q", pv.Name, downstream.Name, oldDS.Name)) - downstreams[i] = downstream - // recalculate from the new Draft - prr, _, err = r.calculateDraftResources(ctx, pv, downstreams[i]) - if err != nil { - return nil, err - } - - } - // Save the updated PackageRevisionResources - if err := r.Update(ctx, prr); err != nil { - return nil, err - } - klog.Infoln(fmt.Sprintf("package variant %q updated package revision %q for new mutations", pv.Name, downstream.Name)) - } - } - return downstreams, nil -} - -// If there are any drafts that are owned by us and match the target package -// revision, return them all. If there are no drafts, return the latest published -// package revision owned by us. -func (r *PackageVariantReconciler) getDownstreamPRs(ctx context.Context, - pv *api.PackageVariant, - prList *porchapi.PackageRevisionList) []*porchapi.PackageRevision { - downstream := pv.Spec.Downstream - - var latestPublished *porchapi.PackageRevision - var drafts []*porchapi.PackageRevision - // the first package revision number that porch assigns is "v1", - // so use v0 as a placeholder for comparison - latestVersion := "v0" - - for _, pr := range prList.Items { - // TODO: When we have a way to find the upstream packagerevision without - // listing all packagerevisions, we should add a label to the resources we - // own so that we can fetch only those packagerevisions. (A caveat here is - // that if the adoptionPolicy is set to adoptExisting, we will still have - // to fetch all the packagerevisions so that we can determine which ones - // we need to adopt. A mechanism to filter packagerevisions by repo/package - // would be helpful for that.) - owned := r.hasOurOwnerReference(pv, pr.ObjectMeta.OwnerReferences) - if !owned && pv.Spec.AdoptionPolicy != api.AdoptionPolicyAdoptExisting { - // this package revision doesn't belong to us - continue - } - - // check that the repo and package name match - if pr.Spec.RepositoryName != downstream.Repo || - pr.Spec.PackageName != downstream.Package { - if owned { - // We own this package, but it isn't a match for our downstream target, - // which means that we created it but no longer need it. - r.deleteOrOrphan(ctx, &pr, pv) - } - continue - } - - // this package matches, check if we need to adopt it - if !owned && pv.Spec.AdoptionPolicy == api.AdoptionPolicyAdoptExisting { - klog.Infoln(fmt.Sprintf("package variant %q is adopting package revision %q", pv.Name, pr.Name)) - if err := r.adoptPackageRevision(ctx, &pr, pv); err != nil { - klog.Errorf("error adopting package revision: %w", err) - } - } - - if porchapi.LifecycleIsPublished(pr.Spec.Lifecycle) { - latestPublished, latestVersion = compare(&pr, latestPublished, latestVersion) - } else { - drafts = append(drafts, pr.DeepCopy()) - } - } - - if len(drafts) > 0 { - return drafts - } - if latestPublished != nil { - return []*porchapi.PackageRevision{latestPublished} - } - return nil -} - -func compare(pr, latestPublished *porchapi.PackageRevision, latestVersion string) (*porchapi.PackageRevision, string) { - switch cmp := semver.Compare(pr.Spec.Revision, latestVersion); { - case cmp == 0: - // Same revision. - case cmp < 0: - // current < latest; no change - case cmp > 0: - // current > latest; update latest - latestVersion = pr.Spec.Revision - latestPublished = pr.DeepCopy() - } - return latestPublished, latestVersion -} - -// check that the downstream package was created by this PackageVariant object -func (r *PackageVariantReconciler) hasOurOwnerReference(pv *api.PackageVariant, owners []metav1.OwnerReference) bool { - for _, owner := range owners { - if owner.UID == pv.UID { - return true - } - } - return false -} - -func (r *PackageVariantReconciler) deleteOrOrphan(ctx context.Context, - pr *porchapi.PackageRevision, - pv *api.PackageVariant) { - switch pv.Spec.DeletionPolicy { - case "", api.DeletionPolicyDelete: - klog.Infoln(fmt.Sprintf("package variant %q is deleting package revision %q", pv.Name, pr.Name)) - r.deletePackageRevision(ctx, pr) - case api.DeletionPolicyOrphan: - klog.Infoln(fmt.Sprintf("package variant %q is orphaning package revision %q", pv.Name, pr.Name)) - r.orphanPackageRevision(ctx, pr, pv) - default: - // this should never happen, because the pv should already be validated beforehand - klog.Errorf("invalid deletion policy %s", pv.Spec.DeletionPolicy) - } -} - -func (r *PackageVariantReconciler) orphanPackageRevision(ctx context.Context, - pr *porchapi.PackageRevision, - pv *api.PackageVariant) { - pr.ObjectMeta.OwnerReferences = removeOwnerRefByUID(pr.OwnerReferences, pv.UID) - if err := r.Client.Update(ctx, pr); err != nil { - klog.Errorf("error orphaning package revision: %v", err) - } -} - -func removeOwnerRefByUID(ownerRefs []metav1.OwnerReference, - ownerToRemove types.UID) []metav1.OwnerReference { - var result []metav1.OwnerReference - for _, owner := range ownerRefs { - if owner.UID != ownerToRemove { - result = append(result, owner) - } - } - return result -} - -// When we adopt a package revision, we need to make sure that the package revision -// has our owner reference and also the labels/annotations specified in pv.Spec. -func (r *PackageVariantReconciler) adoptPackageRevision(ctx context.Context, - pr *porchapi.PackageRevision, - pv *api.PackageVariant) error { - pr.ObjectMeta.OwnerReferences = append(pr.OwnerReferences, constructOwnerReference(pv)) - if len(pv.Spec.Labels) > 0 && pr.ObjectMeta.Labels == nil { - pr.ObjectMeta.Labels = make(map[string]string) - } - for k, v := range pv.Spec.Labels { - pr.ObjectMeta.Labels[k] = v - } - if len(pv.Spec.Annotations) > 0 && pr.ObjectMeta.Annotations == nil { - pr.ObjectMeta.Annotations = make(map[string]string) - } - for k, v := range pv.Spec.Annotations { - pr.ObjectMeta.Annotations[k] = v - } - return r.Client.Update(ctx, pr) -} - -func (r *PackageVariantReconciler) deletePackageRevision(ctx context.Context, pr *porchapi.PackageRevision) { - switch pr.Spec.Lifecycle { - case "", porchapi.PackageRevisionLifecycleDraft, porchapi.PackageRevisionLifecycleProposed: - if err := r.Client.Delete(ctx, pr); err != nil { - klog.Errorf("error deleting package revision: %v", err) - } - case porchapi.PackageRevisionLifecyclePublished: - pr.Spec.Lifecycle = porchapi.PackageRevisionLifecycleDeletionProposed - if err := r.Client.Update(ctx, pr); err != nil { - klog.Errorf("error proposing deletion for published package revision: %v", err) - } - case porchapi.PackageRevisionLifecycleDeletionProposed: - // we don't have to do anything - default: - // if this ever happens, there's something going wrong with porch - klog.Errorf("invalid lifecycle value for package revision %s: %s", pr.Name, pr.Spec.Lifecycle) - } -} - -// determine if the downstream PR needs to be updated -func (r *PackageVariantReconciler) isUpToDate(pv *api.PackageVariant, downstream *porchapi.PackageRevision) bool { - upstreamLock := downstream.Status.UpstreamLock - lastIndex := strings.LastIndex(upstreamLock.Git.Ref, "/") - if strings.HasPrefix(upstreamLock.Git.Ref, "drafts") { - // The current upstream is a draft, and the target upstream - // will always be a published revision, so we will need to do an update. - return false - } - currentUpstreamRevision := upstreamLock.Git.Ref[lastIndex+1:] - return currentUpstreamRevision == pv.Spec.Upstream.Revision -} - -func (r *PackageVariantReconciler) copyPublished(ctx context.Context, - source *porchapi.PackageRevision, - pv *api.PackageVariant, - prList *porchapi.PackageRevisionList) (*porchapi.PackageRevision, error) { - newPR := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: source.Namespace, - OwnerReferences: []metav1.OwnerReference{constructOwnerReference(pv)}, - Labels: pv.Spec.Labels, - Annotations: pv.Spec.Annotations, - }, - Spec: source.Spec, - } - - newPR.Spec.Revision = "" - newPR.Spec.WorkspaceName = newWorkspaceName(prList, newPR.Spec.PackageName, newPR.Spec.RepositoryName) - newPR.Spec.Lifecycle = porchapi.PackageRevisionLifecycleDraft - - klog.Infoln(fmt.Sprintf("package variant %q is creating package revision %q", pv.Name, newPR.Name)) - if err := r.Client.Create(ctx, newPR); err != nil { - return nil, err - } - - return newPR, nil -} - -func newWorkspaceName(prList *porchapi.PackageRevisionList, - packageName string, repo string) porchapi.WorkspaceName { - wsNum := 0 - for _, pr := range prList.Items { - if pr.Spec.PackageName != packageName || pr.Spec.RepositoryName != repo { - continue - } - oldWorkspaceName := string(pr.Spec.WorkspaceName) - if !strings.HasPrefix(oldWorkspaceName, workspaceNamePrefix) { - continue - } - wsNumStr := strings.TrimPrefix(oldWorkspaceName, workspaceNamePrefix) - newWsNum, _ := strconv.Atoi(wsNumStr) - if newWsNum > wsNum { - wsNum = newWsNum - } - } - wsNum++ - return porchapi.WorkspaceName(fmt.Sprintf(workspaceNamePrefix+"%d", wsNum)) -} - -func constructOwnerReference(pv *api.PackageVariant) metav1.OwnerReference { - tr := true - return metav1.OwnerReference{ - APIVersion: pv.APIVersion, - Kind: pv.Kind, - Name: pv.Name, - UID: pv.UID, - Controller: &tr, - BlockOwnerDeletion: nil, - } -} - -func (r *PackageVariantReconciler) updateDraft(ctx context.Context, - draft *porchapi.PackageRevision, - newUpstreamPR *porchapi.PackageRevision) (*porchapi.PackageRevision, error) { - - draft = draft.DeepCopy() - tasks := draft.Spec.Tasks - - updateTask := porchapi.Task{ - Type: porchapi.TaskTypeUpdate, - Update: &porchapi.PackageUpdateTaskSpec{ - Upstream: tasks[0].Clone.Upstream, - }, - } - updateTask.Update.Upstream.UpstreamRef.Name = newUpstreamPR.Name - draft.Spec.Tasks = append(tasks, updateTask) - - err := r.Client.Update(ctx, draft) - if err != nil { - return nil, err - } - return draft, nil -} - -func setTargetStatusConditions(pv *api.PackageVariant, targets []*porchapi.PackageRevision) { - pv.Status.DownstreamTargets = nil - for _, t := range targets { - pv.Status.DownstreamTargets = append(pv.Status.DownstreamTargets, api.DownstreamTarget{ - Name: t.GetName(), - }) - } - meta.SetStatusCondition(&pv.Status.Conditions, metav1.Condition{ - Type: ConditionTypeReady, - Status: "True", - Reason: "NoErrors", - Message: "successfully ensured downstream package variant", - }) -} - -// SetupWithManager sets up the controller with the Manager. -func (r *PackageVariantReconciler) SetupWithManager(mgr ctrl.Manager) error { - if err := api.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - if err := porchapi.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - if err := configapi.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - - r.Client = mgr.GetClient() - - //TODO: establish watches on resource types injected in all the Package Revisions - // we own, and use those to generate requests - return ctrl.NewControllerManagedBy(mgr). - For(&api.PackageVariant{}). - Watches(&source.Kind{Type: &porchapi.PackageRevision{}}, - handler.EnqueueRequestsFromMapFunc(r.mapObjectsToRequests)). - Complete(r) -} - -func (r *PackageVariantReconciler) mapObjectsToRequests(obj client.Object) []reconcile.Request { - attachedPackageVariants := &api.PackageVariantList{} - err := r.List(context.TODO(), attachedPackageVariants, &client.ListOptions{ - Namespace: obj.GetNamespace(), - }) - if err != nil { - return []reconcile.Request{} - } - requests := make([]reconcile.Request, len(attachedPackageVariants.Items)) - for i, item := range attachedPackageVariants.Items { - requests[i] = reconcile.Request{ - NamespacedName: types.NamespacedName{ - Name: item.GetName(), - Namespace: item.GetNamespace(), - }, - } - } - return requests -} - -func (r *PackageVariantReconciler) calculateDraftResources(ctx context.Context, - pv *api.PackageVariant, - draft *porchapi.PackageRevision) (*porchapi.PackageRevisionResources, bool, error) { - - // Load the PackageRevisionResources - var prr porchapi.PackageRevisionResources - prrKey := types.NamespacedName{Name: draft.GetName(), Namespace: draft.GetNamespace()} - if err := r.Client.Get(ctx, prrKey, &prr); err != nil { - return nil, false, err - } - - // Check if it's a valid PRR - if prr.Spec.Resources == nil { - return nil, false, fmt.Errorf("nil resources found for PackageRevisionResources '%s/%s'", prr.Namespace, prr.Name) - } - - origResources := make(map[string]string, len(prr.Spec.Resources)) - for k, v := range prr.Spec.Resources { - origResources[k] = v - } - - // Apply our mutations - if err := ensurePackageContext(pv, &prr); err != nil { - return nil, false, err - } - - if err := ensureKRMFunctions(pv, &prr); err != nil { - return nil, false, err - } - - if err := ensureConfigInjection(ctx, r.Client, pv, &prr); err != nil { - return nil, false, err - } - - if len(prr.Spec.Resources) != len(origResources) { - // files were added or deleted - klog.Infoln(fmt.Sprintf("PackageVariant %q, PackageRevision %q, resources changed: %d original files, %d new files", pv.Name, prr.Name, len(origResources), len(prr.Spec.Resources))) - return &prr, true, nil - } - - for k, v := range origResources { - newValue, ok := prr.Spec.Resources[k] - if !ok { - // a file was deleted - klog.Infoln(fmt.Sprintf("PackageVariant %q, PackageRevision %q, resources changed: %q in original files, not in new files", pv.Name, prr.Name, k)) - return &prr, true, nil - } - - if newValue != v { - // HACK ALERT - TODO(jbelamaric): Fix this - // Currently nephio controllers and package variant controller are rendering Kptfiles slightly differently in YAML - // not sure why, need to investigate more. It may be due to different versions of kyaml. So, here, just for Kptfiles, - // we will parse and compare semantically. - // - if k == "Kptfile" && kptfilesEqual(v, newValue) { - klog.Infoln(fmt.Sprintf("PackageVariant %q, PackageRevision %q, resources changed: Kptfiles differ, but not semantically", pv.Name, prr.Name)) - continue - } - - // a file was changed - klog.Infoln(fmt.Sprintf("PackageVariant %q, PackageRevision %q, resources changed: %q different", pv.Name, prr.Name, k)) - return &prr, true, nil - } - } - - // all files in orig are in new, no new files, and all contents match - // so no change - klog.Infoln(fmt.Sprintf("PackageVariant %q, PackageRevision %q, resources unchanged", pv.Name, prr.Name)) - return &prr, false, nil -} - -func parseKptfile(kf string) (*kptfilev1.KptFile, error) { - ko, err := fn.ParseKubeObject([]byte(kf)) - if err != nil { - return nil, err - } - var kptfile kptfilev1.KptFile - err = ko.As(&kptfile) - if err != nil { - return nil, err - } - - return &kptfile, nil -} - -func kptfilesEqual(a, b string) bool { - akf, err := parseKptfile(a) - if err != nil { - return false - } - - bkf, err := parseKptfile(b) - if err != nil { - return false - } - - equal, err := kptfileutil.Equal(akf, bkf) - if err != nil { - return false - } - return equal -} - -func ensurePackageContext(pv *api.PackageVariant, - prr *porchapi.PackageRevisionResources) error { - - if pv.Spec.PackageContext == nil { - return nil - } - - if len(pv.Spec.PackageContext.Data) == 0 && len(pv.Spec.PackageContext.RemoveKeys) == 0 { - return nil - } - - cm, err := getFileKubeObject(prr, "package-context.yaml", "ConfigMap", "kptfile.kpt.dev") - if err != nil { - return err - } - - // Set the data fields - data, ok, err := cm.NestedStringMap("data") - if err != nil { - return fmt.Errorf("PackageRevisionResources %s/%s PackageContext invalid data field: %w", prr.Namespace, prr.Name, err) - } - - if !ok { - return fmt.Errorf("PackageRevisionResources %s/%s PackageContext no data field found", prr.Namespace, prr.Name) - } - - // set or add keys that should be there - for k, v := range pv.Spec.PackageContext.Data { - data[k] = v - } - - // remove any keys that should go - for _, k := range pv.Spec.PackageContext.RemoveKeys { - delete(data, k) - } - - err = cm.SetNestedField(data, "data") - if err != nil { - return fmt.Errorf("could not set package conext data: %w", err) - } - prr.Spec.Resources["package-context.yaml"] = cm.String() - return nil -} - -func getFileKubeObject(prr *porchapi.PackageRevisionResources, file, kind, name string) (*fn.KubeObject, error) { - if prr.Spec.Resources == nil { - return nil, fmt.Errorf("nil resources found for PackageRevisionResources '%s/%s'", prr.Namespace, prr.Name) - } - - if _, ok := prr.Spec.Resources[file]; !ok { - return nil, fmt.Errorf("%q not found in PackageRevisionResources '%s/%s'", file, prr.Namespace, prr.Name) - } - - ko, err := fn.ParseKubeObject([]byte(prr.Spec.Resources[file])) - if err != nil { - return nil, fmt.Errorf("failed to parse %q of PackageRevisionResources %s/%s: %w", file, prr.Namespace, prr.Name, err) - } - if kind != "" && ko.GetKind() != kind { - return nil, fmt.Errorf("%q does not contain kind %q in PackageRevisionResources '%s/%s'", file, kind, prr.Namespace, prr.Name) - } - if name != "" && ko.GetName() != name { - return nil, fmt.Errorf("%q does not contain resource named %q in PackageRevisionResources '%s/%s'", file, name, prr.Namespace, prr.Name) - } - - return ko, nil -} - -// ensureKRMFunctions adds mutators and validators specified in the PackageVariant to the kptfile inside the PackageRevisionResources. -// It generates a unique name that identifies the func (see func generatePVFuncname) and moves it to the top of the mutator sequence. -// It does not preserve yaml indent-style. -func ensureKRMFunctions(pv *api.PackageVariant, - prr *porchapi.PackageRevisionResources) error { - - // parse kptfile - kptfile, err := getFileKubeObject(prr, kptfilev1.KptFileName, "", "") - if err != nil { - return err - } - pipeline := kptfile.UpsertMap("pipeline") - - fieldlist := map[string][]kptfilev1.Function{ - "validators": nil, - "mutators": nil, - } - // retrieve fields if pipeline is not nil, to avoid nilpointer exception - if pv.Spec.Pipeline != nil { - fieldlist["validators"] = pv.Spec.Pipeline.Validators - fieldlist["mutators"] = pv.Spec.Pipeline.Mutators - } - - for fieldname, field := range fieldlist { - var newFieldVal = fn.SliceSubObjects{} - - existingFields, ok, err := pipeline.NestedSlice(fieldname) - if err != nil { - return err - } - if !ok || existingFields == nil { - existingFields = fn.SliceSubObjects{} - } - - for _, existingField := range existingFields { - ok, err := isPackageVariantFunc(existingField, pv.ObjectMeta.Name) - if err != nil { - return err - } - if !ok { - newFieldVal = append(newFieldVal, existingField) - } - } - - var newPVFieldVal = fn.SliceSubObjects{} - for i, newFields := range field { - newFieldVal := newFields.DeepCopy() - newFieldVal.Name = generatePVFuncName(newFields.Name, pv.ObjectMeta.Name, i) - f, err := fn.NewFromTypedObject(newFieldVal) - if err != nil { - return err - } - newPVFieldVal = append(newPVFieldVal, &f.SubObject) - } - - newFieldVal = append(newPVFieldVal, newFieldVal...) - - // if there are new mutators/validators, set them. Otherwise delete the field. This avoids ugly dangling `mutators: []` fields in the final kptfile - if len(newFieldVal) > 0 { - if err := pipeline.SetSlice(newFieldVal, fieldname); err != nil { - return err - } - } else { - if _, err := pipeline.RemoveNestedField(fieldname); err != nil { - return err - } - } - } - - // if there are no mutators and no validators, remove the dangling pipeline field - if pipeline.GetMap("mutators") == nil && pipeline.GetMap("validators") == nil { - if _, err := kptfile.RemoveNestedField("pipeline"); err != nil { - return err - } - } - - // update kptfile - prr.Spec.Resources[kptfilev1.KptFileName] = kptfile.String() - - return nil -} - -const PackageVariantFuncPrefix = "PackageVariant" - -// isPackageVariantFunc returns true if a function has been created via a PackageVariant. -// It uses the name of the func to determine its origin and compares it with the supplied pvName. -func isPackageVariantFunc(fn *fn.SubObject, pvName string) (bool, error) { - origname, ok, err := fn.NestedString("name") - if err != nil { - return false, fmt.Errorf("could not retrieve field name: %w", err) - } - if !ok { - return false, nil - } - - name := strings.Split(origname, ".") - - // if more or less than 3 dots have been used, return false - if len(name) != 4 { - return false, nil - } - - // if PackageVariantFuncPrefix has not been used, return false - if name[0] != PackageVariantFuncPrefix { - return false, nil - } - - // if pv-names don't match, return false - if name[1] != pvName { - return false, nil - } - - // if the last segment is not an integer, return false - if _, err := strconv.Atoi(name[3]); err != nil { - return false, nil - } - - return true, nil -} - -func generatePVFuncName(funcName, pvName string, pos int) string { - return fmt.Sprintf("%s.%s.%s.%d", PackageVariantFuncPrefix, pvName, funcName, pos) -} diff --git a/porch/controllers/packagevariants/pkg/controllers/packagevariant/packagevariant_controller_test.go b/porch/controllers/packagevariants/pkg/controllers/packagevariant/packagevariant_controller_test.go deleted file mode 100644 index c77ad340f3..0000000000 --- a/porch/controllers/packagevariants/pkg/controllers/packagevariant/packagevariant_controller_test.go +++ /dev/null @@ -1,1579 +0,0 @@ -// Copyright 2022 The kpt 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. - -package packagevariant - -import ( - "context" - "fmt" - "testing" - - "github.com/GoogleContainerTools/kpt-functions-sdk/go/fn" - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - api "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariants/api/v1alpha1" - "github.com/stretchr/testify/require" - "sigs.k8s.io/yaml" -) - -func TestValidatePackageVariant(t *testing.T) { - packageVariantHeader := `apiVersion: config.porch.kpt.dev -kind: PackageVariant -metadata: - name: my-pv` - - testCases := map[string]struct { - packageVariant string - expectedErr string - }{ - "empty spec": { - packageVariant: packageVariantHeader, - expectedErr: "missing required field spec.upstream; missing required field spec.downstream", - }, - - "missing package names": { - packageVariant: packageVariantHeader + ` -spec: - upstream: - revision: v1 - repo: blueprints - downstream: - repo: deployments -`, - expectedErr: "missing required field spec.upstream.package; missing required field spec.downstream.package", - }, - - "empty adoption and deletion policies": { - packageVariant: packageVariantHeader + ` -spec: - upstream: - package: foo - revision: v1 - repo: blueprints - downstream: - package: foo - repo: deployments -`, - }, - - "invalid adoption and deletion policies": { - packageVariant: packageVariantHeader + ` -spec: - upstream: - package: foo - revision: v1 - repo: blueprints - downstream: - package: foo - repo: deployments - adoptionPolicy: invalid - deletionPolicy: invalid -`, - expectedErr: "spec.adoptionPolicy field can only be \"adoptNone\" or \"adoptExisting\"; spec.deletionPolicy can only be \"orphan\" or \"delete\"", - }, - - "valid adoption and deletion policies": { - packageVariant: packageVariantHeader + ` -spec: - upstream: - package: foo - revision: v1 - repo: blueprints - downstream: - package: foo - repo: deployments - adoptionPolicy: adoptExisting - deletionPolicy: orphan -`, - }, - - "validate package context": { - packageVariant: packageVariantHeader + ` -spec: - upstream: - package: foo - revision: v1 - repo: blueprints - downstream: - package: foo - repo: deployments - packageContext: - data: - foo: bar - hello: there - removeKeys: - - bar - - foobar -`, - }, - - "name in package context data": { - packageVariant: packageVariantHeader + ` -spec: - upstream: - package: foo - revision: v1 - repo: blueprints - downstream: - package: foo - repo: deployments - packageContext: - data: - name: test -`, - expectedErr: "spec.packageContext.data: Invalid value: map[string]string{\"name\":\"test\"}: must not contain the key \"name\"", - }, - - "name in package context removeKeys": { - packageVariant: packageVariantHeader + ` -spec: - upstream: - package: foo - revision: v1 - repo: blueprints - downstream: - package: foo - repo: deployments - packageContext: - removeKeys: - - name -`, - expectedErr: "spec.packageContext.removeKeys: Invalid value: []string{\"name\"}: must not contain the key \"name\"", - }, - - "package-path in package context data": { - packageVariant: packageVariantHeader + ` -spec: - upstream: - package: foo - revision: v1 - repo: blueprints - downstream: - package: foo - repo: deployments - packageContext: - data: - package-path: test -`, - expectedErr: "spec.packageContext.data: Invalid value: map[string]string{\"package-path\":\"test\"}: must not contain the key \"package-path\"", - }, - "package-path in package context removeKeys": { - packageVariant: packageVariantHeader + ` -spec: - upstream: - package: foo - revision: v1 - repo: blueprints - downstream: - package: foo - repo: deployments - packageContext: - removeKeys: - - package-path -`, - expectedErr: "spec.packageContext.removeKeys: Invalid value: []string{\"package-path\"}: must not contain the key \"package-path\"", - }, - "valid injectors": { - packageVariant: packageVariantHeader + ` -spec: - upstream: - package: foo - revision: v1 - repo: blueprints - downstream: - package: foo - repo: deployments - injectors: - - group: porch.kpt.dev - version: v1alpha1 - kind: Repository - name: foo - - name: bar -`, - }, - "invalid injectors": { - packageVariant: packageVariantHeader + ` -spec: - upstream: - package: foo - revision: v1 - repo: blueprints - downstream: - package: foo - repo: deployments - injectors: - - group: porch.kpt.dev - version: v1alpha1 - kind: Repository - name: foo - - name: "" -`, - expectedErr: "spec.injectors[1].name must not be empty", - }, - } - - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - var pv api.PackageVariant - require.NoError(t, yaml.Unmarshal([]byte(tc.packageVariant), &pv)) - actualErr := combineErrors(validatePackageVariant(&pv)) - require.Equal(t, tc.expectedErr, actualErr) - }) - } -} - -func TestNewWorkspaceName(t *testing.T) { - prListHeader := `apiVersion: porch.kpt.dev -kind: PackageRevisionList -metadata: - name: my-pr-list` - - testCases := map[string]struct { - packageRevisionList string - expected string - }{ - "empty list": { - packageRevisionList: prListHeader, - expected: "packagevariant-1", - }, - - "two elements with packagevariant prefix": { - packageRevisionList: prListHeader + ` -items: -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr - spec: - workspaceName: packagevariant-1 -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr - spec: - workspaceName: packagevariant-2`, - expected: "packagevariant-3", - }, - - "two elements, one with packagevariant prefix": { - packageRevisionList: prListHeader + ` -items: -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr - spec: - workspaceName: packagevariant-1 -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr - spec: - workspaceName: foo`, - expected: "packagevariant-2", - }, - - "two elements, neither with packagevariant prefix": { - packageRevisionList: prListHeader + ` -items: -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr - spec: - workspaceName: foo-1 -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr - spec: - workspaceName: foo-2`, - expected: "packagevariant-1", - }, - - "two elements with packagevariant prefix, one doesn't match package": { - packageRevisionList: prListHeader + ` -items: -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr - spec: - workspaceName: packagevariant-1 -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr - spec: - workspaceName: packagevariant-2 - packageName: some-other-package`, - expected: "packagevariant-2", - }, - } - - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - var prList porchapi.PackageRevisionList - require.NoError(t, yaml.Unmarshal([]byte(tc.packageRevisionList), &prList)) - actual := string(newWorkspaceName(&prList, "", "")) - require.Equal(t, tc.expected, actual) - }) - } -} - -func TestGetDownstreamPRs(t *testing.T) { - prListHeader := `apiVersion: porch.kpt.dev -kind: PackageRevisionList -metadata: - name: my-pr-list` - - pvStr := `apiVersion: config.porch.kpt.dev -kind: PackageVariant -metadata: - name: my-pv - uid: pv-uid -spec: - upstream: - repo: blueprints - package: foo - revision: v1 - downstream: - repo: deployments - package: bar` - - testCases := map[string]struct { - packageRevisionList string - expected []string - fcOutput []string - }{ - - // should return nil - "empty list": { - packageRevisionList: prListHeader, - expected: nil, - }, - - // should return the draft that we own - "two drafts, one owned": { - packageRevisionList: prListHeader + ` -items: -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid - spec: - workspaceName: packagevariant-1 - lifecycle: Draft - repository: deployments - packageName: bar -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr - spec: - workspaceName: packagevariant-2 - lifecycle: Draft - repository: deployments - packageName: bar`, - expected: []string{`apiVersion: porch.kpt.dev -kind: PackageRevision -metadata: - creationTimestamp: null - name: my-pr - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid -spec: - lifecycle: Draft - packageName: bar - repository: deployments - workspaceName: packagevariant-1 -status: - publishTimestamp: null -`, - }, - }, - - // should return both drafts that we own - "one published and two drafts, all owned": { - packageRevisionList: prListHeader + ` -items: -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid - spec: - revision: v1 - workspaceName: packagevariant-1 - lifecycle: Published - repository: deployments - packageName: bar -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid - spec: - workspaceName: packagevariant-2 - lifecycle: Draft - repository: deployments - packageName: bar -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid - spec: - workspaceName: packagevariant-3 - lifecycle: Draft - repository: deployments - packageName: bar`, - expected: []string{`apiVersion: porch.kpt.dev -kind: PackageRevision -metadata: - creationTimestamp: null - name: my-pr - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid -spec: - lifecycle: Draft - packageName: bar - repository: deployments - workspaceName: packagevariant-2 -status: - publishTimestamp: null -`, `apiVersion: porch.kpt.dev -kind: PackageRevision -metadata: - creationTimestamp: null - name: my-pr - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid -spec: - lifecycle: Draft - packageName: bar - repository: deployments - workspaceName: packagevariant-3 -status: - publishTimestamp: null -`, - }, - }, - - // should return the latest published that we own - "three published, latest one not owned": { - packageRevisionList: prListHeader + ` -items: -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid - spec: - revision: v2 - workspaceName: packagevariant-2 - lifecycle: Published - repository: deployments - packageName: bar -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid - spec: - revision: v1 - workspaceName: packagevariant-1 - lifecycle: Published - repository: deployments - packageName: bar -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: some-other-uid-1 - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: some-other-uid-2 - spec: - revision: v3 - workspaceName: packagevariant-3 - lifecycle: Published - repository: deployments - packageName: bar`, - expected: []string{`apiVersion: porch.kpt.dev -kind: PackageRevision -metadata: - creationTimestamp: null - name: my-pr - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid -spec: - lifecycle: Published - packageName: bar - repository: deployments - revision: v2 - workspaceName: packagevariant-2 -status: - publishTimestamp: null -`, - }, - }, - - // should return just the published and delete the two drafts - "one published and two drafts, all owned, drafts from different package": { - packageRevisionList: prListHeader + ` -items: -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid - spec: - revision: v1 - workspaceName: packagevariant-1 - lifecycle: Published - repository: deployments - packageName: bar -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr-2 - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid - spec: - workspaceName: packagevariant-2 - lifecycle: Draft - repository: deployments - packageName: foo -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr-3 - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid - spec: - workspaceName: packagevariant-3 - lifecycle: Draft - repository: deployments - packageName: foo`, - fcOutput: []string{`deleting object: my-pr-2`, `deleting object: my-pr-3`}, - expected: []string{`apiVersion: porch.kpt.dev -kind: PackageRevision -metadata: - creationTimestamp: null - name: my-pr - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid -spec: - lifecycle: Published - packageName: bar - repository: deployments - revision: v1 - workspaceName: packagevariant-1 -status: - publishTimestamp: null -`, - }, - }, - } - - var pv api.PackageVariant - require.NoError(t, yaml.Unmarshal([]byte(pvStr), &pv)) - - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - var prList porchapi.PackageRevisionList - require.NoError(t, yaml.Unmarshal([]byte(tc.packageRevisionList), &prList)) - - fc := &fakeClient{} - reconciler := &PackageVariantReconciler{Client: fc} - - actualStr := reconciler.getDownstreamPRs(context.TODO(), &pv, &prList) - var actual []string - for _, pr := range actualStr { - bytes, err := yaml.Marshal(pr) - require.NoError(t, err) - actual = append(actual, string(bytes)) - } - - require.Equal(t, tc.expected, actual) - require.Equal(t, tc.fcOutput, fc.output) - }) - } -} - -func TestDeleteOrOrphan(t *testing.T) { - prStr := `apiVersion: porch.kpt.dev -kind: PackageRevision -metadata: - name: my-pr - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: some-other-uid -spec: - lifecycle: %s - packageName: bar - repository: deployments - workspaceName: packagevariant-3 -` - - pvStr := `apiVersion: config.porch.kpt.dev -kind: PackageVariant -metadata: - name: my-pv - uid: pv-uid -spec: - upstream: - repo: blueprints - package: foo - revision: v1 - downstream: - repo: deployments - package: bar - deletionPolicy: %s` - - testCases := map[string]struct { - deletionPolicy string - prLifecycle string - expectedOutput []string - expectedPR string - }{ - - // should delete the PR - "deletionPolicy delete, lifecycle draft": { - deletionPolicy: string(api.DeletionPolicyDelete), - prLifecycle: string(porchapi.PackageRevisionLifecycleDraft), - expectedOutput: []string{"deleting object: my-pr"}, - }, - - // should delete the PR - "deletionPolicy delete, lifecycle proposed": { - deletionPolicy: string(api.DeletionPolicyDelete), - prLifecycle: string(porchapi.PackageRevisionLifecycleProposed), - expectedOutput: []string{"deleting object: my-pr"}, - }, - - // should propose the PR for deletion - "deletionPolicy delete, lifecycle published": { - deletionPolicy: string(api.DeletionPolicyDelete), - prLifecycle: string(porchapi.PackageRevisionLifecyclePublished), - expectedOutput: []string{"updating object: my-pr"}, - expectedPR: `apiVersion: porch.kpt.dev -kind: PackageRevision -metadata: - creationTimestamp: null - name: my-pr - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: some-other-uid -spec: - lifecycle: DeletionProposed - packageName: bar - repository: deployments - workspaceName: packagevariant-3 -status: - publishTimestamp: null -`, - }, - - // should do nothing - "deletionPolicy delete, lifecycle deletionProposed": { - deletionPolicy: string(api.DeletionPolicyDelete), - prLifecycle: string(porchapi.PackageRevisionLifecycleDeletionProposed), - expectedOutput: nil, - }, - - // should remove the pv's owner reference from the pr - "deletionPolicy orphan, lifecycle draft": { - deletionPolicy: string(api.DeletionPolicyOrphan), - prLifecycle: string(porchapi.PackageRevisionLifecycleDraft), - expectedOutput: []string{"updating object: my-pr"}, - expectedPR: `apiVersion: porch.kpt.dev -kind: PackageRevision -metadata: - creationTimestamp: null - name: my-pr - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: some-other-uid -spec: - lifecycle: Draft - packageName: bar - repository: deployments - workspaceName: packagevariant-3 -status: - publishTimestamp: null -`, - }, - } - - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - var pv api.PackageVariant - require.NoError(t, yaml.Unmarshal( - []byte(fmt.Sprintf(pvStr, tc.deletionPolicy)), &pv)) - - var pr porchapi.PackageRevision - require.NoError(t, yaml.Unmarshal( - []byte(fmt.Sprintf(prStr, tc.prLifecycle)), &pr)) - - fc := &fakeClient{} - reconciler := &PackageVariantReconciler{Client: fc} - reconciler.deleteOrOrphan(context.Background(), &pr, &pv) - - require.Equal(t, tc.expectedOutput, fc.output) - - if tc.expectedPR != "" { - prAfter, err := yaml.Marshal(&pr) - require.NoError(t, err) - require.Equal(t, tc.expectedPR, string(prAfter)) - } - }) - } -} - -func TestAdoptionPolicy(t *testing.T) { - prListHeader := `apiVersion: porch.kpt.dev -kind: PackageRevisionList -metadata: - name: my-pr-list` - - pvStr := `apiVersion: config.porch.kpt.dev -kind: PackageVariant -metadata: - name: my-pv - uid: pv-uid -spec: - upstream: - repo: blueprints - package: foo - revision: v1 - downstream: - repo: deployments - package: bar - adoptionPolicy: %s` - - testCases := map[string]struct { - packageRevisionList string - adoptionPolicy string - expected []string - clientOutput []string - }{ - - // should return the previously unowned draft, with owner references added - "owned published, unowned draft, adoptExisting": { - packageRevisionList: prListHeader + ` -items: -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr-1 - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid - spec: - workspaceName: packagevariant-1 - lifecycle: Published - revision: v1 - repository: deployments - packageName: bar -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr-2 - spec: - workspaceName: packagevariant-2 - lifecycle: Draft - repository: deployments - packageName: bar`, - adoptionPolicy: string(api.AdoptionPolicyAdoptExisting), - clientOutput: []string{"updating object: my-pr-2"}, - expected: []string{`apiVersion: porch.kpt.dev -kind: PackageRevision -metadata: - creationTimestamp: null - name: my-pr-2 - ownerReferences: - - apiVersion: config.porch.kpt.dev - controller: true - kind: PackageVariant - name: my-pv - uid: pv-uid -spec: - lifecycle: Draft - packageName: bar - repository: deployments - workspaceName: packagevariant-2 -status: - publishTimestamp: null -`, - }, - }, - - // should return just the draft that we own - "two drafts, one owned, adoptNone": { - packageRevisionList: prListHeader + ` -items: -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr-1 - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid - spec: - workspaceName: packagevariant-1 - lifecycle: Draft - repository: deployments - packageName: bar -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr-2 - spec: - workspaceName: packagevariant-2 - lifecycle: Draft - repository: deployments - packageName: bar`, - adoptionPolicy: string(api.AdoptionPolicyAdoptNone), - clientOutput: nil, - expected: []string{`apiVersion: porch.kpt.dev -kind: PackageRevision -metadata: - creationTimestamp: null - name: my-pr-1 - ownerReferences: - - apiVersion: config.porch.kpt.dev - kind: PackageVariant - name: my-pv - uid: pv-uid -spec: - lifecycle: Draft - packageName: bar - repository: deployments - workspaceName: packagevariant-1 -status: - publishTimestamp: null -`, - }, - }, - - // this should return nil and should not attempt to adopt nor - // delete the package revision - "unowned draft, but package name doesn't match, adoptExisting": { - packageRevisionList: prListHeader + ` -items: -- apiVersion: porch.kpt.dev - kind: PackageRevision - metadata: - name: my-pr-1 - spec: - workspaceName: packagevariant-1 - lifecycle: Draft - repository: deployments - packageName: foo -`, - adoptionPolicy: string(api.AdoptionPolicyAdoptExisting), - clientOutput: nil, - expected: nil, - }, - } - - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - fc := &fakeClient{} - reconciler := &PackageVariantReconciler{Client: fc} - var prList porchapi.PackageRevisionList - require.NoError(t, yaml.Unmarshal([]byte(tc.packageRevisionList), &prList)) - - var pv api.PackageVariant - require.NoError(t, yaml.Unmarshal( - []byte(fmt.Sprintf(pvStr, tc.adoptionPolicy)), &pv)) - - actualStr := reconciler.getDownstreamPRs(context.TODO(), &pv, &prList) - var actual []string - for _, pr := range actualStr { - bytes, err := yaml.Marshal(pr) - require.NoError(t, err) - actual = append(actual, string(bytes)) - } - - require.Equal(t, tc.expected, actual) - require.Equal(t, tc.clientOutput, fc.output) - }) - } -} - -func TestEnsurePackageContext(t *testing.T) { - - pvBase := `apiVersion: config.porch.kpt.dev -kind: PackageVariant -metadata: - name: my-pv - uid: pv-uid -spec: - upstream: - repo: blueprints - package: foo - revision: v1 - downstream: - repo: deployments - package: bar -` - - prrBase := `apiVersion: porch.kpt.dev/v1alpha1 -kind: PackageRevisionResources -metadata: - name: prr - namespace: default -spec: - packageName: nephio-system - repository: nephio-packages - resources: - Kptfile: | - apiVersion: kpt.dev/v1 - kind: Kptfile - metadata: - name: prr - annotations: - config.kubernetes.io/local-config: "true" - info: - description: Example - package-context.yaml: | - apiVersion: v1 - kind: ConfigMap - metadata: - name: kptfile.kpt.dev - annotations: - config.kubernetes.io/local-config: "true" - data: - name: example -` - - testCases := map[string]struct { - spec string - initialData string - expectedErr string - expectedPRR string - }{ - "empty package context": { - spec: ``, - initialData: ``, - expectedErr: "", - expectedPRR: prrBase, - }, - "add one entry": { - spec: ` packageContext: - data: - foo: bar -`, - initialData: ``, - expectedErr: "", - expectedPRR: prrBase + " foo: bar\n", - }, - "add two entries": { - spec: ` packageContext: - data: - foo: bar - foobar: barfoo -`, - initialData: ``, - expectedErr: "", - expectedPRR: prrBase + " foo: bar\n foobar: barfoo\n", - }, - "add one with existing": { - spec: ` packageContext: - data: - foo: bar -`, - initialData: " hello: there\n", - expectedErr: "", - expectedPRR: prrBase + " foo: bar\n hello: there\n", - }, - "change existing": { - spec: ` packageContext: - data: - foo: bar -`, - initialData: " foo: there\n", - expectedErr: "", - expectedPRR: prrBase + " foo: bar\n", - }, - "remove one entry": { - spec: ` packageContext: - removeKeys: - - hello -`, - initialData: " hello: there\n", - expectedErr: "", - expectedPRR: prrBase, - }, - "remove entry, leave existing": { - spec: ` packageContext: - removeKeys: - - hello -`, - initialData: " hello: there\n foo: bar\n", - expectedErr: "", - expectedPRR: prrBase + " foo: bar\n", - }, - "remove and add entries": { - spec: ` packageContext: - data: - foobar: barfoo - there: hello - removeKeys: - - hello -`, - initialData: " hello: there\n foo: bar\n", - expectedErr: "", - expectedPRR: prrBase + " foo: bar\n foobar: barfoo\n there: hello\n", - }, - } - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - var pv api.PackageVariant - require.NoError(t, yaml.Unmarshal([]byte(pvBase+tc.spec), &pv)) - var prr porchapi.PackageRevisionResources - require.NoError(t, yaml.Unmarshal([]byte(prrBase+tc.initialData), &prr)) - - actualErr := ensurePackageContext(&pv, &prr) - if tc.expectedErr == "" { - require.NoError(t, actualErr) - } else { - require.EqualError(t, actualErr, tc.expectedErr) - } - - var expectedPRR porchapi.PackageRevisionResources - require.NoError(t, yaml.Unmarshal([]byte(tc.expectedPRR), &expectedPRR)) - - require.Equal(t, expectedPRR, prr) - }) - } -} - -func TestEnsureKRMFunctions(t *testing.T) { - pvBase := ` -apiVersion: config.porch.kpt.dev -kind: PackageVariant -metadata: - name: my-pv - uid: pv-uid -spec: - upstream: - repo: blueprints - package: foo - revision: v1 - downstream: - repo: deployments - package: bar - pipeline: -`[1:] - - prrBase := ` -apiVersion: porch.kpt.dev/v1alpha1 -kind: PackageRevisionResources -metadata: - name: prr - namespace: default -spec: - packageName: nephio-system - repository: nephio-packages - resources: - Kptfile: | - apiVersion: kpt.dev/v1 - kind: Kptfile - metadata: - name: prr - annotations: - config.kubernetes.io/local-config: "true" - info: - description: Example -`[1:] - - testCases := map[string]struct { - initialPipeline string - pvPipeline string - expectedErr string - expectedPrr string - }{ - "add one mutator with existing mutators": { - initialPipeline: ` - mutators: - - image: gcr.io/kpt-fn/set-labels:v0.1 - name: set-labels - configMap: - app: foo - - image: gcr.io/kpt-fn/set-annotations:v0.1 - name: set-annotations`[1:], - pvPipeline: ` - mutators: - - image: gcr.io/kpt-fn/set-namespace:v0.1 - name: set-namespace - configMap: - namespace: my-ns`[1:], - expectedErr: "", - expectedPrr: prrBase + ` - pipeline: - mutators: - - name: PackageVariant.my-pv.set-namespace.0 - image: gcr.io/kpt-fn/set-namespace:v0.1 - configMap: - namespace: my-ns - - image: gcr.io/kpt-fn/set-labels:v0.1 - name: set-labels - configMap: - app: foo - - image: gcr.io/kpt-fn/set-annotations:v0.1 - name: set-annotations -`[1:], - }, - "add two mutators with existing": { - initialPipeline: ` - mutators: - - image: gcr.io/kpt-fn/set-labels:v0.1 - name: set-labels - configMap: - app: foo - - image: gcr.io/kpt-fn/set-annotations:v0.1 - name: set-annotations`[1:], - pvPipeline: ` - mutators: - - image: gcr.io/kpt-fn/set-namespace:v0.1 - name: set-namespace - configMap: - namespace: my-ns - - image: gcr.io/kpt-fn/format:unstable - name: format`[1:], - expectedErr: "", - expectedPrr: prrBase + ` - pipeline: - mutators: - - name: PackageVariant.my-pv.set-namespace.0 - image: gcr.io/kpt-fn/set-namespace:v0.1 - configMap: - namespace: my-ns - - name: PackageVariant.my-pv.format.1 - image: gcr.io/kpt-fn/format:unstable - - image: gcr.io/kpt-fn/set-labels:v0.1 - name: set-labels - configMap: - app: foo - - image: gcr.io/kpt-fn/set-annotations:v0.1 - name: set-annotations -`[1:], - }, - "add one mutator with none existing": { - initialPipeline: "", - pvPipeline: ` - mutators: - - image: gcr.io/kpt-fn/set-namespace:v0.1 - name: set-namespace - configMap: - namespace: my-ns`[1:], - expectedErr: "", - expectedPrr: prrBase + ` - pipeline: - mutators: - - name: PackageVariant.my-pv.set-namespace.0 - image: gcr.io/kpt-fn/set-namespace:v0.1 - configMap: - namespace: my-ns -`[1:], - }, - "add none with existing mutators": { - initialPipeline: ` - mutators: - - image: gcr.io/kpt-fn/set-labels:v0.1 - name: set-labels - configMap: - app: foo - - image: gcr.io/kpt-fn/set-annotations:v0.1 - name: set-annotations`[1:], - pvPipeline: "", - expectedErr: "", - expectedPrr: prrBase + ` - pipeline: - mutators: - - image: gcr.io/kpt-fn/set-labels:v0.1 - name: set-labels - configMap: - app: foo - - image: gcr.io/kpt-fn/set-annotations:v0.1 - name: set-annotations -`[1:], - }, - "add one mutator with existing with comments": { - initialPipeline: ` - mutators: - - image: gcr.io/kpt-fn/set-labels:v0.1 - # this is a comment - name: set-labels - configMap: - app: foo - - image: gcr.io/kpt-fn/set-annotations:v0.1 - name: set-annotations`[1:], - pvPipeline: ` - mutators: - - image: gcr.io/kpt-fn/set-namespace:v0.1 - name: set-namespace - configMap: - namespace: my-ns`[1:], - expectedErr: "", - expectedPrr: prrBase + ` - pipeline: - mutators: - - name: PackageVariant.my-pv.set-namespace.0 - image: gcr.io/kpt-fn/set-namespace:v0.1 - configMap: - namespace: my-ns - - image: gcr.io/kpt-fn/set-labels:v0.1 - # this is a comment - name: set-labels - configMap: - app: foo - - image: gcr.io/kpt-fn/set-annotations:v0.1 - name: set-annotations -`[1:], - }, - "add one validator with existing validators": { - initialPipeline: ` - validators: - - image: gcr.io/kpt-fn/gatekeeper-validate:v0.1 - name: gatekeeper-validate`[1:], - pvPipeline: ` - validators: - - image: gcr.io/kpt-fn/validate-name:undefined - name: validate-name `[1:], - expectedErr: "", - expectedPrr: prrBase + ` - pipeline: - validators: - - name: PackageVariant.my-pv.validate-name.0 - image: gcr.io/kpt-fn/validate-name:undefined - - image: gcr.io/kpt-fn/gatekeeper-validate:v0.1 - name: gatekeeper-validate -`[1:], - }, - "add two validators with existing validators": { - initialPipeline: ` - validators: - - image: gcr.io/kpt-fn/gatekeeper-validate:v0.1 - name: gatekeeper-validate`[1:], - pvPipeline: ` - validators: - - image: gcr.io/kpt-fn/validate-name:undefined - name: validate-name `[1:], - expectedErr: "", - expectedPrr: prrBase + ` - pipeline: - validators: - - name: PackageVariant.my-pv.validate-name.0 - image: gcr.io/kpt-fn/validate-name:undefined - - image: gcr.io/kpt-fn/gatekeeper-validate:v0.1 - name: gatekeeper-validate -`[1:], - }, - "add none with existing validator": { - initialPipeline: ` - validators: - - image: gcr.io/kpt-fn/gatekeeper-validate:v0.1 - name: gatekeeper-validate`[1:], - pvPipeline: "", - expectedErr: "", - expectedPrr: prrBase + ` - pipeline: - validators: - - image: gcr.io/kpt-fn/gatekeeper-validate:v0.1 - name: gatekeeper-validate -`[1:], - }, - "add validator and mutator with existing": { - initialPipeline: ` - validators: - - image: gcr.io/val1 - name: val1 - - image: gcr.io/val2 - name: val2 - mutators: - - image: gcr.io/mut1 - name: mut1 - - image: gcr.io/mut2 - name: mut2`[1:], - pvPipeline: ` - validators: - - image: gcr.io/val3 - name: val3 - - image: gcr.io/val4 - name: val4 - mutators: - - image: gcr.io/mut3 - name: mut3 - - image: gcr.io/mut4 - name: mut4 -`[1:], - expectedErr: "", - expectedPrr: prrBase + ` - pipeline: - validators: - - name: PackageVariant.my-pv.val3.0 - image: gcr.io/val3 - - name: PackageVariant.my-pv.val4.1 - image: gcr.io/val4 - - image: gcr.io/val1 - name: val1 - - image: gcr.io/val2 - name: val2 - mutators: - - name: PackageVariant.my-pv.mut3.0 - image: gcr.io/mut3 - - name: PackageVariant.my-pv.mut4.1 - image: gcr.io/mut4 - - image: gcr.io/mut1 - name: mut1 - - image: gcr.io/mut2 - name: mut2 -`[1:], - }, - "remove pv mutator": { - initialPipeline: ` - mutators: - - image: gcr.io/mut:v1 - name: PackageVariant.my-pv.mut.0`[1:], - pvPipeline: "", - expectedErr: "", - expectedPrr: prrBase + "\n", - }, - "remove pv validator": { - initialPipeline: ` - validators: - - image: gcr.io/val:v1 - name: PackageVariant.my-pv.val.0`[1:], - pvPipeline: "", - expectedErr: "", - expectedPrr: prrBase + "\n", - }, - "remove pv validator, keep prr one": { - initialPipeline: ` - validators: - - image: gcr.io/val:v1 - name: PackageVariant.my-pv.val.0 - - image: gcr.io/val:v1 - name: non-pv-val`[1:], - pvPipeline: "", - expectedErr: "", - expectedPrr: prrBase + ` - pipeline: - validators: - - image: gcr.io/val:v1 - name: non-pv-val -`[1:], - }, - } - - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - locPrrBase := prrBase - if tc.initialPipeline != "" { - locPrrBase += " pipeline:\n" - } - var prr porchapi.PackageRevisionResources - require.NoError(t, yaml.Unmarshal([]byte(locPrrBase+tc.initialPipeline), &prr)) - var pv api.PackageVariant - require.NoError(t, yaml.Unmarshal([]byte(pvBase+tc.pvPipeline), &pv)) - - actualErr := ensureKRMFunctions(&pv, &prr) - if tc.expectedErr == "" { - require.NoError(t, actualErr) - } else { - require.EqualError(t, actualErr, tc.expectedErr) - } - var expectedPRR porchapi.PackageRevisionResources - require.NoError(t, yaml.Unmarshal([]byte(tc.expectedPrr), &expectedPRR)) - - require.Equal(t, expectedPRR, prr) - - // test idempotence - idemErr := ensureKRMFunctions(&pv, &prr) - if tc.expectedErr == "" { - require.NoError(t, idemErr) - } else { - require.EqualError(t, idemErr, tc.expectedErr) - } - require.Equal(t, expectedPRR, prr) // check that prr still matches expected - }) - } -} - -func TestGeneratePVFuncName(t *testing.T) { - tt := map[string]struct { - funcName string - pvName string - pos int - expectedName string - }{ - "regular func": { - funcName: "my-func", - pvName: "my-pv", - pos: 3, - expectedName: "PackageVariant.my-pv.my-func.3", - }, - "empty func name": { - funcName: "", - pvName: "my-pv", - pos: 0, - expectedName: "PackageVariant.my-pv..0", - }, - } - - for name, tc := range tt { - t.Run(name, func(t *testing.T) { - res := generatePVFuncName(tc.funcName, tc.pvName, tc.pos) - - require.Equal(t, tc.expectedName, res) - }) - } -} - -func TestIsPackageVariantFunc(t *testing.T) { - tt := map[string]struct { - funcyaml string - pvName string - expectedRes bool - }{ - "valid func name": { - funcyaml: "name: PackageVariant.my-pv.my-func.0", - pvName: "my-pv", - expectedRes: true, - }, - "field name is missing": { - funcyaml: "otherkey: PackageVariant.my-pv.my-func.0", - pvName: "my-pv", - expectedRes: false, - }, - "additional dots": { - funcyaml: "name: PackageVariant.too.many.dots.0", - pvName: "too", - expectedRes: false, - }, - "not enough dots": { - funcyaml: "name: PackageVariant.not-enough.dots", - pvName: "not-enough", - expectedRes: false, - }, - "no PackageVariantPrefix": { - funcyaml: "name: noprefix.my-pv.my-func.0", - pvName: "my-pv", - expectedRes: false, - }, - "pv-name mismatch": { - funcyaml: "name: PackageVariant.my-pv.my-func.0", - pvName: "actually-a-different-pv", - expectedRes: false, - }, - "empty func name": { - funcyaml: "name: PackageVariant.my-pv..0", - pvName: "my-pv", - expectedRes: true, - }, - "positional location is not an int": { - funcyaml: "name: PackageVariant.my-pv.my-func.str", - pvName: "my-pv", - expectedRes: false, - }, - } - - for name, tc := range tt { - t.Run(name, func(t *testing.T) { - o, err := fn.ParseKubeObject([]byte(tc.funcyaml)) - require.NoError(t, err) - res, _ := isPackageVariantFunc(&o.SubObject, tc.pvName) - - require.Equal(t, tc.expectedRes, res) - }) - } -} diff --git a/porch/controllers/packagevariantsets/api/v1alpha1/groupversion_info.go b/porch/controllers/packagevariantsets/api/v1alpha1/groupversion_info.go deleted file mode 100644 index b0010b886f..0000000000 --- a/porch/controllers/packagevariantsets/api/v1alpha1/groupversion_info.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2022 The kpt 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. - -// Package v1alpha1 contains API Schema definitions for the config.porch.kpt.dev v1alpha1 API group -// +kubebuilder:object:generate=true -// +groupName=config.porch.kpt.dev -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/scheme" -) - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 object:headerFile="../../../../scripts/boilerplate.go.txt" paths="./..." - -var ( - // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "config.porch.kpt.dev", Version: "v1alpha1"} - - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} - - // AddToScheme adds the types in this group-version to the given scheme. - AddToScheme = SchemeBuilder.AddToScheme -) diff --git a/porch/controllers/packagevariantsets/api/v1alpha1/packagevariantset_types.go b/porch/controllers/packagevariantsets/api/v1alpha1/packagevariantset_types.go deleted file mode 100644 index 953d3a097c..0000000000 --- a/porch/controllers/packagevariantsets/api/v1alpha1/packagevariantset_types.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2022 The kpt 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. - -package v1alpha1 - -import ( - kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - pkgvarapi "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariants/api/v1alpha1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status -// +kubebuilder:unservedversion -// -// PackageVariantSet represents an upstream package revision and a way to -// target specific downstream repositories where a variant of the upstream -// package should be created. -type PackageVariantSet struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec PackageVariantSetSpec `json:"spec,omitempty"` - Status PackageVariantSetStatus `json:"status,omitempty"` -} - -func (o *PackageVariantSet) GetSpec() *PackageVariantSetSpec { - if o == nil { - return nil - } - return &o.Spec -} - -// PackageVariantSetSpec defines the desired state of PackageVariantSet -type PackageVariantSetSpec struct { - Upstream *Upstream `json:"upstream,omitempty"` - Targets []Target `json:"targets,omitempty"` - - AdoptionPolicy pkgvarapi.AdoptionPolicy `json:"adoptionPolicy,omitempty"` - DeletionPolicy pkgvarapi.DeletionPolicy `json:"deletionPolicy,omitempty"` - - Labels map[string]string `json:"labels,omitempty"` - Annotations map[string]string `json:"annotations,omitempty"` -} - -type Upstream struct { - Package *Package `json:"package,omitempty"` - - Revision string `json:"revision,omitempty"` - - Tag string `json:"ref,omitempty"` -} - -type Target struct { - // option 1: an explicit repo/package name pair - Package *Package `json:"package,omitempty"` - - // option 2: a label selector against a set of repositories - Repositories *metav1.LabelSelector `json:"repositories,omitempty"` - - // option 3: a selector against a set of arbitrary objects - Objects *ObjectSelector `json:"objects,omitempty"` - - // For options 2 and 3, PackageName specifies how to create the name of the - // package variant - PackageName *PackageName `json:"packageName,omitempty"` -} - -type Package struct { - Repo string `json:"repo,omitempty"` - Name string `json:"name,omitempty"` -} - -type ObjectSelector struct { - Selectors []Selector `json:"selectors,omitempty"` - - RepoName *ValueOrFromField `json:"repoName,omitempty"` -} - -type Selector struct { - // APIVersion of the target resources - APIVersion string `yaml:"apiVersion,omitempty" json:"apiVersion,omitempty"` - // Kind of the target resources - Kind string `yaml:"kind,omitempty" json:"kind,omitempty"` - // Name of the target resources - Name string `yaml:"name,omitempty" json:"name,omitempty"` - // Namespace of the target resources - Namespace string `yaml:"namespace,omitempty" json:"namespace,omitempty"` - // Labels on the target resources - Labels *metav1.LabelSelector `yaml:"labelSelector,omitempty" json:"labelSelector,omitempty"` - // Annotations on the target resources - Annotations map[string]string `yaml:"annotations,omitempty" json:"annotations,omitempty"` -} - -func (s *Selector) ToKptfileSelector() kptfilev1.Selector { - var labels map[string]string - if s.Labels != nil { - labels = s.Labels.MatchLabels - } - return kptfilev1.Selector{ - APIVersion: s.APIVersion, - Kind: s.Kind, - Name: s.Name, - Namespace: s.Namespace, - Labels: labels, - Annotations: s.Annotations, - } -} - -type PackageName struct { - Name *ValueOrFromField `json:"baseName,omitempty"` - - NameSuffix *ValueOrFromField `json:"nameSuffix,omitempty"` - - NamePrefix *ValueOrFromField `json:"namePrefix,omitempty"` -} - -type ValueOrFromField struct { - Value string `json:"value,omitempty"` - FromField string `json:"fromField,omitempty"` -} - -// PackageVariantSetStatus defines the observed state of PackageVariantSet -type PackageVariantSetStatus struct { - // Conditions describes the reconciliation state of the object. - Conditions []metav1.Condition `json:"conditions,omitempty"` -} - -//+kubebuilder:object:root=true - -// PackageVariantSetList contains a list of PackageVariantSet -type PackageVariantSetList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []PackageVariantSet `json:"items"` -} - -func init() { - SchemeBuilder.Register(&PackageVariantSet{}, &PackageVariantSetList{}) -} diff --git a/porch/controllers/packagevariantsets/api/v1alpha1/zz_generated.deepcopy.go b/porch/controllers/packagevariantsets/api/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index 9fd0c82507..0000000000 --- a/porch/controllers/packagevariantsets/api/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,316 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// Copyright 2023 The kpt 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 controller-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ObjectSelector) DeepCopyInto(out *ObjectSelector) { - *out = *in - if in.Selectors != nil { - in, out := &in.Selectors, &out.Selectors - *out = make([]Selector, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.RepoName != nil { - in, out := &in.RepoName, &out.RepoName - *out = new(ValueOrFromField) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectSelector. -func (in *ObjectSelector) DeepCopy() *ObjectSelector { - if in == nil { - return nil - } - out := new(ObjectSelector) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Package) DeepCopyInto(out *Package) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Package. -func (in *Package) DeepCopy() *Package { - if in == nil { - return nil - } - out := new(Package) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageName) DeepCopyInto(out *PackageName) { - *out = *in - if in.Name != nil { - in, out := &in.Name, &out.Name - *out = new(ValueOrFromField) - **out = **in - } - if in.NameSuffix != nil { - in, out := &in.NameSuffix, &out.NameSuffix - *out = new(ValueOrFromField) - **out = **in - } - if in.NamePrefix != nil { - in, out := &in.NamePrefix, &out.NamePrefix - *out = new(ValueOrFromField) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageName. -func (in *PackageName) DeepCopy() *PackageName { - if in == nil { - return nil - } - out := new(PackageName) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageVariantSet) DeepCopyInto(out *PackageVariantSet) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageVariantSet. -func (in *PackageVariantSet) DeepCopy() *PackageVariantSet { - if in == nil { - return nil - } - out := new(PackageVariantSet) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackageVariantSet) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageVariantSetList) DeepCopyInto(out *PackageVariantSetList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]PackageVariantSet, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageVariantSetList. -func (in *PackageVariantSetList) DeepCopy() *PackageVariantSetList { - if in == nil { - return nil - } - out := new(PackageVariantSetList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackageVariantSetList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageVariantSetSpec) DeepCopyInto(out *PackageVariantSetSpec) { - *out = *in - if in.Upstream != nil { - in, out := &in.Upstream, &out.Upstream - *out = new(Upstream) - (*in).DeepCopyInto(*out) - } - if in.Targets != nil { - in, out := &in.Targets, &out.Targets - *out = make([]Target, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Labels != nil { - in, out := &in.Labels, &out.Labels - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.Annotations != nil { - in, out := &in.Annotations, &out.Annotations - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageVariantSetSpec. -func (in *PackageVariantSetSpec) DeepCopy() *PackageVariantSetSpec { - if in == nil { - return nil - } - out := new(PackageVariantSetSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageVariantSetStatus) DeepCopyInto(out *PackageVariantSetStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageVariantSetStatus. -func (in *PackageVariantSetStatus) DeepCopy() *PackageVariantSetStatus { - if in == nil { - return nil - } - out := new(PackageVariantSetStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Selector) DeepCopyInto(out *Selector) { - *out = *in - if in.Labels != nil { - in, out := &in.Labels, &out.Labels - *out = new(v1.LabelSelector) - (*in).DeepCopyInto(*out) - } - if in.Annotations != nil { - in, out := &in.Annotations, &out.Annotations - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Selector. -func (in *Selector) DeepCopy() *Selector { - if in == nil { - return nil - } - out := new(Selector) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Target) DeepCopyInto(out *Target) { - *out = *in - if in.Package != nil { - in, out := &in.Package, &out.Package - *out = new(Package) - **out = **in - } - if in.Repositories != nil { - in, out := &in.Repositories, &out.Repositories - *out = new(v1.LabelSelector) - (*in).DeepCopyInto(*out) - } - if in.Objects != nil { - in, out := &in.Objects, &out.Objects - *out = new(ObjectSelector) - (*in).DeepCopyInto(*out) - } - if in.PackageName != nil { - in, out := &in.PackageName, &out.PackageName - *out = new(PackageName) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Target. -func (in *Target) DeepCopy() *Target { - if in == nil { - return nil - } - out := new(Target) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Upstream) DeepCopyInto(out *Upstream) { - *out = *in - if in.Package != nil { - in, out := &in.Package, &out.Package - *out = new(Package) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Upstream. -func (in *Upstream) DeepCopy() *Upstream { - if in == nil { - return nil - } - out := new(Upstream) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ValueOrFromField) DeepCopyInto(out *ValueOrFromField) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ValueOrFromField. -func (in *ValueOrFromField) DeepCopy() *ValueOrFromField { - if in == nil { - return nil - } - out := new(ValueOrFromField) - in.DeepCopyInto(out) - return out -} diff --git a/porch/controllers/packagevariantsets/api/v1alpha2/groupversion_info.go b/porch/controllers/packagevariantsets/api/v1alpha2/groupversion_info.go deleted file mode 100644 index 5b38b9e530..0000000000 --- a/porch/controllers/packagevariantsets/api/v1alpha2/groupversion_info.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2023 The kpt 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. - -// Package v1alpha1 contains API Schema definitions for the config.porch.kpt.dev v1alpha1 API group -// +kubebuilder:object:generate=true -// +groupName=config.porch.kpt.dev -package v1alpha2 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/scheme" -) - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 object:headerFile="../../../../scripts/boilerplate.go.txt" paths="./..." - -var ( - // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "config.porch.kpt.dev", Version: "v1alpha2"} - - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} - - // AddToScheme adds the types in this group-version to the given scheme. - AddToScheme = SchemeBuilder.AddToScheme -) diff --git a/porch/controllers/packagevariantsets/api/v1alpha2/packagevariantset_types.go b/porch/controllers/packagevariantsets/api/v1alpha2/packagevariantset_types.go deleted file mode 100644 index da8421d99c..0000000000 --- a/porch/controllers/packagevariantsets/api/v1alpha2/packagevariantset_types.go +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright 2023 The kpt 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. - -package v1alpha2 - -import ( - kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - pkgvarapi "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariants/api/v1alpha1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// +kubebuilder:object:root=true -// +kubebuilder:storageversion -// +kubebuilder:subresource:status -// -// PackageVariantSet represents an upstream package revision and a way to -// target specific downstream repositories where a variant of the upstream -// package should be created. -type PackageVariantSet struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec PackageVariantSetSpec `json:"spec,omitempty"` - Status PackageVariantSetStatus `json:"status,omitempty"` -} - -func (o *PackageVariantSet) GetSpec() *PackageVariantSetSpec { - if o == nil { - return nil - } - return &o.Spec -} - -// PackageVariantSetSpec defines the desired state of PackageVariantSet -type PackageVariantSetSpec struct { - Upstream *pkgvarapi.Upstream `json:"upstream,omitempty"` - Targets []Target `json:"targets,omitempty"` -} - -type Target struct { - // Exactly one of Repositories, RepositorySeletor, and ObjectSelector must be - // populated - // option 1: an explicit repositories and package names - Repositories []RepositoryTarget `json:"repositories,omitempty"` - - // option 2: a label selector against a set of repositories - RepositorySelector *metav1.LabelSelector `json:"repositorySelector,omitempty"` - - // option 3: a selector against a set of arbitrary objects - ObjectSelector *ObjectSelector `json:"objectSelector,omitempty"` - - // Template specifies how to generate a PackageVariant from a target - Template *PackageVariantTemplate `json:"template,omitempty"` -} - -type RepositoryTarget struct { - // Name contains the name of the Repository resource, which must be in - // the same namespace as the PackageVariantSet resource. - // +required - Name string `json:"name"` - - // PackageNames contains names to use for package instances in this repository; - // that is, the same upstream will be instantiated multiple times using these names. - // +optional - PackageNames []string `json:"packageNames,omitempty"` -} - -type ObjectSelector struct { - metav1.LabelSelector `json:",inline"` - - // APIVersion of the target resources - APIVersion string `yaml:"apiVersion,omitempty" json:"apiVersion,omitempty"` - - // Kind of the target resources - Kind string `yaml:"kind,omitempty" json:"kind,omitempty"` - - // Name of the target resource - // +optional - Name *string `yaml:"name,omitempty" json:"name,omitempty"` - - // Note: while v1alpha1 had Namespace, that is not allowed; the namespace - // must match the namespace of the PackageVariantSet resource -} - -type PackageVariantTemplate struct { - // Downstream allows overriding the default downstream package and repository name - // +optional - Downstream *DownstreamTemplate `json:"downstream,omitempty"` - - // AdoptionPolicy allows overriding the PackageVariant adoption policy - // +optional - AdoptionPolicy *pkgvarapi.AdoptionPolicy `json:"adoptionPolicy,omitempty"` - - // DeletionPolicy allows overriding the PackageVariant deletion policy - // +optional - DeletionPolicy *pkgvarapi.DeletionPolicy `json:"deletionPolicy,omitempty"` - - // Labels allows specifying the spec.Labels field of the generated PackageVariant - // +optional - Labels map[string]string `json:"labels,omitempty"` - - // LabelsExprs allows specifying the spec.Labels field of the generated PackageVariant - // using CEL to dynamically create the keys and values. Entries in this field take precedent over - // those with the same keys that are present in Labels. - // +optional - LabelExprs []MapExpr `json:"labelExprs,omitempty"` - - // Annotations allows specifying the spec.Annotations field of the generated PackageVariant - // +optional - Annotations map[string]string `json:"annotations,omitempty"` - - // AnnotationsExprs allows specifying the spec.Annotations field of the generated PackageVariant - // using CEL to dynamically create the keys and values. Entries in this field take precedent over - // those with the same keys that are present in Annotations. - // +optional - AnnotationExprs []MapExpr `json:"annotationExprs,omitempty"` - - // PackageContext allows specifying the spec.PackageContext field of the generated PackageVariant - // +optional - PackageContext *PackageContextTemplate `json:"packageContext,omitempty"` - - // Pipeline allows specifying the spec.Pipeline field of the generated PackageVariant - // +optional - Pipeline *PipelineTemplate `json:"pipeline,omitempty"` - - // Injectors allows specifying the spec.Injectors field of the generated PackageVariant - // +optional - Injectors []InjectionSelectorTemplate `json:"injectors,omitempty"` -} - -// DownstreamTemplate is used to calculate the downstream field of the resulting -// package variants. Only one of Repo and RepoExpr may be specified; -// similarly only one of Package and PackageExpr may be specified. -type DownstreamTemplate struct { - Repo *string `json:"repo,omitempty"` - Package *string `json:"package,omitempty"` - RepoExpr *string `json:"repoExpr,omitempty"` - PackageExpr *string `json:"packageExpr,omitempty"` -} - -// PackageContextTemplate is used to calculate the packageContext field of the -// resulting package variants. The plain fields and Exprs fields will be -// merged, with the Exprs fields taking precedence. -type PackageContextTemplate struct { - Data map[string]string `json:"data,omitempty"` - RemoveKeys []string `json:"removeKeys,omitempty"` - DataExprs []MapExpr `json:"dataExprs,omitempty"` - RemoveKeyExprs []string `json:"removeKeyExprs,omitempty"` -} - -// InjectionSelectorTemplate is used to calculate the injectors field of the -// resulting package variants. Exactly one of the Name and NameExpr fields must -// be specified. The other fields are optional. -type InjectionSelectorTemplate struct { - Group *string `json:"group,omitempty"` - Version *string `json:"version,omitempty"` - Kind *string `json:"kind,omitempty"` - Name *string `json:"name,omitempty"` - - NameExpr *string `json:"nameExpr,omitempty"` -} - -// MapExpr is used for various fields to calculate map entries. Only one of -// Key and KeyExpr may be specified; similarly only on of Value and ValueExpr -// may be specified. -type MapExpr struct { - Key *string `json:"key,omitempty"` - Value *string `json:"value,omitempty"` - KeyExpr *string `json:"keyExpr,omitempty"` - ValueExpr *string `json:"valueExpr,omitempty"` -} - -// PipelineTemplate is used to calculate the pipeline field of the resulting -// package variants. -type PipelineTemplate struct { - // Validators is used to caculate the pipeline.validators field of the - // resulting package variants. - // +optional - Validators []FunctionTemplate `json:"validators,omitempty"` - - // Mutators is used to caculate the pipeline.mutators field of the - // resulting package variants. - // +optional - Mutators []FunctionTemplate `json:"mutators,omitempty"` -} - -// FunctionTemplate is used in generating KRM function pipeline entries; that -// is, it is used to generate Kptfile Function objects. -type FunctionTemplate struct { - kptfilev1.Function `json:",inline"` - - // ConfigMapExprs allows use of CEL to dynamically create the keys and values in the - // function config ConfigMap. Entries in this field take precedent over those with - // the same keys that are present in ConfigMap. - // +optional - ConfigMapExprs []MapExpr `json:"configMapExprs,omitempty"` -} - -// PackageVariantSetStatus defines the observed state of PackageVariantSet -type PackageVariantSetStatus struct { - // Conditions describes the reconciliation state of the object. - Conditions []metav1.Condition `json:"conditions,omitempty"` -} - -//+kubebuilder:object:root=true - -// PackageVariantSetList contains a list of PackageVariantSet -type PackageVariantSetList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []PackageVariantSet `json:"items"` -} - -func init() { - SchemeBuilder.Register(&PackageVariantSet{}, &PackageVariantSetList{}) -} diff --git a/porch/controllers/packagevariantsets/api/v1alpha2/zz_generated.deepcopy.go b/porch/controllers/packagevariantsets/api/v1alpha2/zz_generated.deepcopy.go deleted file mode 100644 index 86d95fb318..0000000000 --- a/porch/controllers/packagevariantsets/api/v1alpha2/zz_generated.deepcopy.go +++ /dev/null @@ -1,488 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// Copyright 2023 The kpt 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 controller-gen. DO NOT EDIT. - -package v1alpha2 - -import ( - "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariants/api/v1alpha1" - "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DownstreamTemplate) DeepCopyInto(out *DownstreamTemplate) { - *out = *in - if in.Repo != nil { - in, out := &in.Repo, &out.Repo - *out = new(string) - **out = **in - } - if in.Package != nil { - in, out := &in.Package, &out.Package - *out = new(string) - **out = **in - } - if in.RepoExpr != nil { - in, out := &in.RepoExpr, &out.RepoExpr - *out = new(string) - **out = **in - } - if in.PackageExpr != nil { - in, out := &in.PackageExpr, &out.PackageExpr - *out = new(string) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DownstreamTemplate. -func (in *DownstreamTemplate) DeepCopy() *DownstreamTemplate { - if in == nil { - return nil - } - out := new(DownstreamTemplate) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FunctionTemplate) DeepCopyInto(out *FunctionTemplate) { - *out = *in - in.Function.DeepCopyInto(&out.Function) - if in.ConfigMapExprs != nil { - in, out := &in.ConfigMapExprs, &out.ConfigMapExprs - *out = make([]MapExpr, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionTemplate. -func (in *FunctionTemplate) DeepCopy() *FunctionTemplate { - if in == nil { - return nil - } - out := new(FunctionTemplate) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InjectionSelectorTemplate) DeepCopyInto(out *InjectionSelectorTemplate) { - *out = *in - if in.Group != nil { - in, out := &in.Group, &out.Group - *out = new(string) - **out = **in - } - if in.Version != nil { - in, out := &in.Version, &out.Version - *out = new(string) - **out = **in - } - if in.Kind != nil { - in, out := &in.Kind, &out.Kind - *out = new(string) - **out = **in - } - if in.Name != nil { - in, out := &in.Name, &out.Name - *out = new(string) - **out = **in - } - if in.NameExpr != nil { - in, out := &in.NameExpr, &out.NameExpr - *out = new(string) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InjectionSelectorTemplate. -func (in *InjectionSelectorTemplate) DeepCopy() *InjectionSelectorTemplate { - if in == nil { - return nil - } - out := new(InjectionSelectorTemplate) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MapExpr) DeepCopyInto(out *MapExpr) { - *out = *in - if in.Key != nil { - in, out := &in.Key, &out.Key - *out = new(string) - **out = **in - } - if in.Value != nil { - in, out := &in.Value, &out.Value - *out = new(string) - **out = **in - } - if in.KeyExpr != nil { - in, out := &in.KeyExpr, &out.KeyExpr - *out = new(string) - **out = **in - } - if in.ValueExpr != nil { - in, out := &in.ValueExpr, &out.ValueExpr - *out = new(string) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MapExpr. -func (in *MapExpr) DeepCopy() *MapExpr { - if in == nil { - return nil - } - out := new(MapExpr) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ObjectSelector) DeepCopyInto(out *ObjectSelector) { - *out = *in - in.LabelSelector.DeepCopyInto(&out.LabelSelector) - if in.Name != nil { - in, out := &in.Name, &out.Name - *out = new(string) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectSelector. -func (in *ObjectSelector) DeepCopy() *ObjectSelector { - if in == nil { - return nil - } - out := new(ObjectSelector) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageContextTemplate) DeepCopyInto(out *PackageContextTemplate) { - *out = *in - if in.Data != nil { - in, out := &in.Data, &out.Data - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.RemoveKeys != nil { - in, out := &in.RemoveKeys, &out.RemoveKeys - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.DataExprs != nil { - in, out := &in.DataExprs, &out.DataExprs - *out = make([]MapExpr, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.RemoveKeyExprs != nil { - in, out := &in.RemoveKeyExprs, &out.RemoveKeyExprs - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageContextTemplate. -func (in *PackageContextTemplate) DeepCopy() *PackageContextTemplate { - if in == nil { - return nil - } - out := new(PackageContextTemplate) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageVariantSet) DeepCopyInto(out *PackageVariantSet) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageVariantSet. -func (in *PackageVariantSet) DeepCopy() *PackageVariantSet { - if in == nil { - return nil - } - out := new(PackageVariantSet) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackageVariantSet) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageVariantSetList) DeepCopyInto(out *PackageVariantSetList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]PackageVariantSet, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageVariantSetList. -func (in *PackageVariantSetList) DeepCopy() *PackageVariantSetList { - if in == nil { - return nil - } - out := new(PackageVariantSetList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackageVariantSetList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageVariantSetSpec) DeepCopyInto(out *PackageVariantSetSpec) { - *out = *in - if in.Upstream != nil { - in, out := &in.Upstream, &out.Upstream - *out = new(v1alpha1.Upstream) - **out = **in - } - if in.Targets != nil { - in, out := &in.Targets, &out.Targets - *out = make([]Target, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageVariantSetSpec. -func (in *PackageVariantSetSpec) DeepCopy() *PackageVariantSetSpec { - if in == nil { - return nil - } - out := new(PackageVariantSetSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageVariantSetStatus) DeepCopyInto(out *PackageVariantSetStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageVariantSetStatus. -func (in *PackageVariantSetStatus) DeepCopy() *PackageVariantSetStatus { - if in == nil { - return nil - } - out := new(PackageVariantSetStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageVariantTemplate) DeepCopyInto(out *PackageVariantTemplate) { - *out = *in - if in.Downstream != nil { - in, out := &in.Downstream, &out.Downstream - *out = new(DownstreamTemplate) - (*in).DeepCopyInto(*out) - } - if in.AdoptionPolicy != nil { - in, out := &in.AdoptionPolicy, &out.AdoptionPolicy - *out = new(v1alpha1.AdoptionPolicy) - **out = **in - } - if in.DeletionPolicy != nil { - in, out := &in.DeletionPolicy, &out.DeletionPolicy - *out = new(v1alpha1.DeletionPolicy) - **out = **in - } - if in.Labels != nil { - in, out := &in.Labels, &out.Labels - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.LabelExprs != nil { - in, out := &in.LabelExprs, &out.LabelExprs - *out = make([]MapExpr, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Annotations != nil { - in, out := &in.Annotations, &out.Annotations - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.AnnotationExprs != nil { - in, out := &in.AnnotationExprs, &out.AnnotationExprs - *out = make([]MapExpr, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.PackageContext != nil { - in, out := &in.PackageContext, &out.PackageContext - *out = new(PackageContextTemplate) - (*in).DeepCopyInto(*out) - } - if in.Pipeline != nil { - in, out := &in.Pipeline, &out.Pipeline - *out = new(PipelineTemplate) - (*in).DeepCopyInto(*out) - } - if in.Injectors != nil { - in, out := &in.Injectors, &out.Injectors - *out = make([]InjectionSelectorTemplate, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageVariantTemplate. -func (in *PackageVariantTemplate) DeepCopy() *PackageVariantTemplate { - if in == nil { - return nil - } - out := new(PackageVariantTemplate) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PipelineTemplate) DeepCopyInto(out *PipelineTemplate) { - *out = *in - if in.Validators != nil { - in, out := &in.Validators, &out.Validators - *out = make([]FunctionTemplate, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Mutators != nil { - in, out := &in.Mutators, &out.Mutators - *out = make([]FunctionTemplate, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PipelineTemplate. -func (in *PipelineTemplate) DeepCopy() *PipelineTemplate { - if in == nil { - return nil - } - out := new(PipelineTemplate) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RepositoryTarget) DeepCopyInto(out *RepositoryTarget) { - *out = *in - if in.PackageNames != nil { - in, out := &in.PackageNames, &out.PackageNames - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RepositoryTarget. -func (in *RepositoryTarget) DeepCopy() *RepositoryTarget { - if in == nil { - return nil - } - out := new(RepositoryTarget) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Target) DeepCopyInto(out *Target) { - *out = *in - if in.Repositories != nil { - in, out := &in.Repositories, &out.Repositories - *out = make([]RepositoryTarget, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.RepositorySelector != nil { - in, out := &in.RepositorySelector, &out.RepositorySelector - *out = new(v1.LabelSelector) - (*in).DeepCopyInto(*out) - } - if in.ObjectSelector != nil { - in, out := &in.ObjectSelector, &out.ObjectSelector - *out = new(ObjectSelector) - (*in).DeepCopyInto(*out) - } - if in.Template != nil { - in, out := &in.Template, &out.Template - *out = new(PackageVariantTemplate) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Target. -func (in *Target) DeepCopy() *Target { - if in == nil { - return nil - } - out := new(Target) - in.DeepCopyInto(out) - return out -} diff --git a/porch/controllers/packagevariantsets/config/rbac/role.yaml b/porch/controllers/packagevariantsets/config/rbac/role.yaml deleted file mode 100644 index f8cbbe33dd..0000000000 --- a/porch/controllers/packagevariantsets/config/rbac/role.yaml +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - name: porch-controllers-packagevariantsets -rules: -- apiGroups: - - '*' - resources: - - '*' - verbs: - - list -- apiGroups: - - config.porch.kpt.dev - resources: - - packagevariants - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - config.porch.kpt.dev - resources: - - packagevariantsets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - config.porch.kpt.dev - resources: - - packagevariantsets/finalizers - verbs: - - update -- apiGroups: - - config.porch.kpt.dev - resources: - - packagevariantsets/status - verbs: - - get - - patch - - update diff --git a/porch/controllers/packagevariantsets/config/rbac/rolebinding.yaml b/porch/controllers/packagevariantsets/config/rbac/rolebinding.yaml deleted file mode 100644 index a2f7b4798b..0000000000 --- a/porch/controllers/packagevariantsets/config/rbac/rolebinding.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: porch-system:porch-controllers-packagevariantsets -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: porch-controllers-packagevariantsets -subjects: -- kind: ServiceAccount - name: porch-controllers - namespace: porch-system \ No newline at end of file diff --git a/porch/controllers/packagevariantsets/config/samples/pvs-v1alpha1.yaml b/porch/controllers/packagevariantsets/config/samples/pvs-v1alpha1.yaml deleted file mode 100644 index d51b2bf694..0000000000 --- a/porch/controllers/packagevariantsets/config/samples/pvs-v1alpha1.yaml +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: PackageVariantSet -metadata: - name: my-pvs - namespace: default -spec: - upstream: - package: - repo: blueprints - name: foo - revision: v3 - targets: - - package: - repo: blueprints - name: alpha - - repositories: - matchLabels: - abc: def - packageName: - baseName: - value: beta - - objects: - selectors: - - apiVersion: v1 - kind: Pod - name: my-pod - repoName: - value: blueprints - packageName: - baseName: - value: gamma diff --git a/porch/controllers/packagevariantsets/config/samples/pvs-v1alpha2.yaml b/porch/controllers/packagevariantsets/config/samples/pvs-v1alpha2.yaml deleted file mode 100644 index 81933af842..0000000000 --- a/porch/controllers/packagevariantsets/config/samples/pvs-v1alpha2.yaml +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2023 The kpt 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. - -apiVersion: config.porch.kpt.dev/v1alpha2 -kind: PackageVariantSet -metadata: - name: example -spec: - upstream: - repo: catalog - package: foo - revision: v2 - targets: - - repositories: - - name: cluster-01 - packageNames: - - foo-01 - - foo-02 - - foo-03 - name: cluster-02 - template: - downstream: - packageExpr: "target.package + '-' + repository.labels['env']" - - repositorySelector: - matchLabels: - env: prod - org: hr - template: - labels: - foo: bar - # injectors: - # group: infra.bigco.com - # kind: Endpoints - # nameExpr: "repository.labels['region'] + '-endpoints'" - - objectSelector: - apiVersion: hr.bigco.com/v1 - kind: Team - matchLabels: - org: hr - role: dev - template: - downstream: - repo: cluster-hr-dev - packageExpr: "target.name + '-shared'" - labels: - pkg-type: namespace - labelExprs: - - key: org - valueExpr: "target.labels['org']" - - key: role - valueExpr: "target.labels['role']" - - keyExpr: "target.labels['role'] + '-namespace'" - valueExpr: "target.name + '-shared'" diff --git a/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/fake_client.go b/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/fake_client.go deleted file mode 100644 index a4219080e9..0000000000 --- a/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/fake_client.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2022 The kpt 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. - -package packagevariantset - -import ( - "context" - "fmt" - - pkgvarapi "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariants/api/v1alpha1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/yaml" -) - -type fakeClient struct { - objects []client.Object - created []client.Object - updated []client.Object - deleted []client.Object - client.Client -} - -var _ client.Client = &fakeClient{} - -func (f *fakeClient) Create(_ context.Context, obj client.Object, _ ...client.CreateOption) error { - fmt.Println("Creating", obj.GetName()) - f.created = append(f.created, obj) - return nil -} - -func (f *fakeClient) Delete(_ context.Context, obj client.Object, _ ...client.DeleteOption) error { - fmt.Println("Deleting", obj.GetName()) - f.deleted = append(f.deleted, obj) - return nil -} - -func (f *fakeClient) Update(_ context.Context, obj client.Object, _ ...client.UpdateOption) error { - fmt.Println("Updating", obj.GetName()) - f.updated = append(f.updated, obj) - return nil -} - -func (f *fakeClient) List(_ context.Context, obj client.ObjectList, _ ...client.ListOption) error { - podList := `apiVersion: v1 -kind: PodList -metadata: - name: my-pod-list -items: -- apiVersion: v1 - kind: Pod - metadata: - name: my-pod-1 - labels: - foo: bar - abc: def -- apiVersion: v1 - kind: Pod - metadata: - name: my-pod-2 - labels: - abc: def - efg: hij` - - pvList := `apiVersion: config.porch.kpt.dev -kind: PackageVariantList -metadata: - name: my-pv-list -items: -- apiVersion: config.porch.kpt.dev - kind: PackageVariant - metadata: - name: my-pvs-dnrepo1-dnpkg1 - spec: - upstream: - repo: up - package: up - revision: up - downstream: - repo: dnrepo1 - package: dnpkg1 -- apiVersion: config.porch.kpt.dev - kind: PackageVariant - metadata: - name: my-pvs-dnrepo2-dnpkg2 - spec: - upstream: - repo: up - package: up - revision: up - downstream: - repo: dnrepo2 - package: dnpkg2` - - var err error - switch v := obj.(type) { - case *unstructured.UnstructuredList: - err = yaml.Unmarshal([]byte(podList), v) - for _, o := range v.Items { - f.objects = append(f.objects, o.DeepCopy()) - } - case *pkgvarapi.PackageVariantList: - err = yaml.Unmarshal([]byte(pvList), v) - for _, o := range v.Items { - f.objects = append(f.objects, o.DeepCopy()) - } - default: - return fmt.Errorf("unsupported type") - } - return err -} diff --git a/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/packagevariantset_controller.go b/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/packagevariantset_controller.go deleted file mode 100644 index 9cc8633458..0000000000 --- a/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/packagevariantset_controller.go +++ /dev/null @@ -1,432 +0,0 @@ -// Copyright 2022 The kpt 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. - -package packagevariantset - -import ( - "bytes" - "context" - "crypto/sha1" - "encoding/hex" - "flag" - "fmt" - - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - pkgvarapi "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariants/api/v1alpha1" - api "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariantsets/api/v1alpha2" - - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/runtime/serializer/json" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/klog/v2" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - "sigs.k8s.io/kustomize/kyaml/resid" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -type Options struct{} - -func (o *Options) InitDefaults() {} -func (o *Options) BindFlags(_ string, _ *flag.FlagSet) {} - -// PackageVariantSetReconciler reconciles a PackageVariantSet object -type PackageVariantSetReconciler struct { - client.Client - Options - - serializer *json.Serializer -} - -const ( - PackageVariantSetOwnerLabel = "config.porch.kpt.dev/packagevariantset" - - ConditionTypeStalled = "Stalled" // whether or not the resource reconciliation is making progress or not - ConditionTypeReady = "Ready" // whether or not the reconciliation succeeded - - PackageVariantNameMaxLength = 63 - PackageVariantNameHashLength = 8 -) - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 rbac:roleName=porch-controllers-packagevariantsets webhook paths="." output:rbac:artifacts:config=../../../config/rbac - -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=packagevariantsets,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=packagevariantsets/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=packagevariantsets/finalizers,verbs=update -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=packagevariants,verbs=create;delete;get;list;patch;update;watch -//+kubebuilder:rbac:groups=*,resources=*,verbs=list - -// Reconcile implements the main kubernetes reconciliation loop. -func (r *PackageVariantSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - pvs, prList, repoList, err := r.init(ctx, req) - if err != nil { - return ctrl.Result{}, err - } - if pvs == nil { - // maybe the pvs was deleted - return ctrl.Result{}, nil - } - - defer func() { - if err := r.Client.Status().Update(ctx, pvs); err != nil { - klog.Errorf("could not update status: %w\n", err) - } - }() - - if errs := validatePackageVariantSet(pvs); len(errs) > 0 { - setStalledConditionsToTrue(pvs, "ValidationError", combineErrors(errs)) - return ctrl.Result{}, nil - } - - upstreamPR, err := r.getUpstreamPR(pvs.Spec.Upstream, prList) - if err != nil { - setStalledConditionsToTrue(pvs, "UpstreamNotFound", err.Error()) - // Currently we watch all PackageRevisions, so no need to requeue - // here, as we will get triggered if a new upstream appears - return ctrl.Result{}, nil - } - - downstreams, err := r.unrollDownstreamTargets(ctx, pvs) - if err != nil { - if meta.IsNoMatchError(err) { - setStalledConditionsToTrue(pvs, "NoMatchingTargets", err.Error()) - return ctrl.Result{}, nil - } - setStalledConditionsToTrue(pvs, "UnexpectedError", err.Error()) - return ctrl.Result{}, nil - } - - meta.SetStatusCondition(&pvs.Status.Conditions, metav1.Condition{ - Type: ConditionTypeStalled, - Status: "False", - Reason: "Valid", - Message: "all validation checks passed", - }) - - err = r.ensurePackageVariants(ctx, pvs, repoList, upstreamPR, downstreams) - if err != nil { - setStalledConditionsToTrue(pvs, "UnexpectedError", err.Error()) - return ctrl.Result{}, nil - } - - meta.SetStatusCondition(&pvs.Status.Conditions, metav1.Condition{ - Type: ConditionTypeReady, - Status: "True", - Reason: "Reconciled", - Message: "package variants successfully reconciled", - }) - - return ctrl.Result{}, nil -} - -func (r *PackageVariantSetReconciler) init(ctx context.Context, req ctrl.Request) (*api.PackageVariantSet, - *porchapi.PackageRevisionList, *configapi.RepositoryList, error) { - var pvs api.PackageVariantSet - if err := r.Client.Get(ctx, req.NamespacedName, &pvs); err != nil { - return nil, nil, nil, client.IgnoreNotFound(err) - } - - var prList porchapi.PackageRevisionList - if err := r.Client.List(ctx, &prList, client.InNamespace(pvs.Namespace)); err != nil { - return nil, nil, nil, err - } - - var repoList configapi.RepositoryList - if err := r.Client.List(ctx, &repoList, client.InNamespace(pvs.Namespace)); err != nil { - return nil, nil, nil, err - } - - return &pvs, &prList, &repoList, nil -} - -func (r *PackageVariantSetReconciler) getUpstreamPR(upstream *pkgvarapi.Upstream, - prList *porchapi.PackageRevisionList) (*porchapi.PackageRevision, error) { - - for _, pr := range prList.Items { - if pr.Spec.RepositoryName == upstream.Repo && - pr.Spec.PackageName == upstream.Package && - pr.Spec.Revision == upstream.Revision { - return &pr, nil - } - } - return nil, fmt.Errorf("could not find upstream package revision '%s/%s' in repo '%s'", - upstream.Package, upstream.Revision, upstream.Repo) -} - -type pvContext struct { - template *api.PackageVariantTemplate - repoDefault string - packageDefault string - object *unstructured.Unstructured -} - -func (r *PackageVariantSetReconciler) unrollDownstreamTargets(ctx context.Context, - pvs *api.PackageVariantSet) ([]pvContext, error) { - - upstreamPackageName := pvs.Spec.Upstream.Package - var result []pvContext - - for i, target := range pvs.Spec.Targets { - if len(target.Repositories) > 0 { - for _, rt := range target.Repositories { - pns := []string{upstreamPackageName} - if len(rt.PackageNames) > 0 { - pns = rt.PackageNames - } - - for _, pn := range pns { - result = append(result, pvContext{ - template: target.Template, - repoDefault: rt.Name, - packageDefault: pn, - }) - } - } - continue - } - - objSel := target.ObjectSelector - if target.RepositorySelector != nil { - // a label selector against a set of repositories - // equivlanet to object selector with apiVersion/kind pre-set - - objSel = &api.ObjectSelector{ - LabelSelector: *target.RepositorySelector, - APIVersion: configapi.TypeRepository.APIVersion(), - Kind: configapi.TypeRepository.Kind, - } - } - // a selector against a set of arbitrary objects - uList := &unstructured.UnstructuredList{} - group, version := resid.ParseGroupVersion(objSel.APIVersion) - uList.SetGroupVersionKind(schema.GroupVersionKind{ - Group: group, - Version: version, - Kind: objSel.Kind, - }) - - opts := []client.ListOption{client.InNamespace(pvs.Namespace)} - labelSelector, err := metav1.LabelSelectorAsSelector(&objSel.LabelSelector) - if err != nil { - return nil, err - } - opts = append(opts, client.MatchingLabelsSelector{Selector: labelSelector}) - - if err := r.Client.List(ctx, uList, opts...); err != nil { - return nil, err - } - - // TODO: fire event; set condition? - if len(uList.Items) == 0 { - klog.Warningf("no objects selected by spec.targets[%d]", i) - } - for _, u := range uList.Items { - result = append(result, pvContext{ - template: target.Template, - repoDefault: u.GetName(), - packageDefault: upstreamPackageName, - object: u.DeepCopy(), - }) - - } - } - return result, nil -} - -func (r *PackageVariantSetReconciler) convertObjectToRNode(obj runtime.Object) (*yaml.RNode, error) { - var buffer bytes.Buffer - if err := r.serializer.Encode(obj, &buffer); err != nil { - return nil, err - } - return yaml.Parse(buffer.String()) -} - -func (r *PackageVariantSetReconciler) ensurePackageVariants(ctx context.Context, pvs *api.PackageVariantSet, - repoList *configapi.RepositoryList, upstreamPR *porchapi.PackageRevision, - downstreams []pvContext) error { - - var pvList pkgvarapi.PackageVariantList - if err := r.Client.List(ctx, &pvList, - client.InNamespace(pvs.Namespace), - client.MatchingLabels{ - PackageVariantSetOwnerLabel: string(pvs.UID), - }); err != nil { - return fmt.Errorf("error listing package variants %v", err) - } - - // existingPackageVariantMap holds the PackageVariant objects that currently exist. - existingPackageVariantMap := make(map[string]*pkgvarapi.PackageVariant, len(pvList.Items)) - // desiredPackageVariantMap holds the PackageVariant objects that we want to exist. - desiredPackageVariantMap := make(map[string]*pkgvarapi.PackageVariant, len(downstreams)) - - for _, pv := range pvList.Items { - pvId := packageVariantIdentifier(pvs.Name, &pv.Spec) - existingPackageVariantMap[pvId] = pv.DeepCopy() - } - - tr := true - for _, downstream := range downstreams { - pvSpec, err := renderPackageVariantSpec(ctx, pvs, repoList, upstreamPR, downstream) - if err != nil { - return err - } - pvId := packageVariantIdentifier(pvs.Name, pvSpec) - pv := pkgvarapi.PackageVariant{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageVariant", - APIVersion: "config.porch.kpt.dev", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: packageVariantName(pvId), - Namespace: pvs.Namespace, - Finalizers: []string{pkgvarapi.Finalizer}, - Labels: map[string]string{PackageVariantSetOwnerLabel: string(pvs.UID)}, - OwnerReferences: []metav1.OwnerReference{{ - APIVersion: pvs.APIVersion, - Kind: pvs.Kind, - Name: pvs.Name, - UID: pvs.UID, - Controller: &tr, - BlockOwnerDeletion: nil, - }}, - }, - Spec: *pvSpec, - } - desiredPackageVariantMap[pvId] = &pv - } - - for existingPvId, existingPV := range existingPackageVariantMap { - if _, found := desiredPackageVariantMap[existingPvId]; found { - // this PackageVariant exists in both the desired PackageVariant set and the - // existing PackageVariant set, so we don't need to do anything. - } else { - // this PackageVariant exists in the existing PackageVariant set, but not - // the desired PackageVariant set, so we need to delete it. - err := r.Client.Delete(ctx, existingPV) - if err != nil { - return err - } - } - } - - for desiredPvId, desiredPv := range desiredPackageVariantMap { - if existingPv, found := existingPackageVariantMap[desiredPvId]; found { - // this PackageVariant exists in both the desired PackageVariant set and the - // existing PackageVariant set, so we update it - // we only change the spec - existingPv.Spec = desiredPv.Spec - err := r.Client.Update(ctx, existingPv) - if err != nil { - return err - } - } else { - // this PackageVariant exists in the desired PackageVariant set, but not - // the existing PackageVariant set, so we need to create it. - err := r.Client.Create(ctx, desiredPv) - if err != nil { - return err - } - } - } - - return nil -} - -func packageVariantIdentifier(pvsName string, spec *pkgvarapi.PackageVariantSpec) string { - return pvsName + "-" + spec.Downstream.Repo + "-" + spec.Downstream.Package -} - -func packageVariantName(pvId string) string { - if len(pvId) <= PackageVariantNameMaxLength { - return pvId - } - - hash := sha1.Sum([]byte(pvId)) - stubIdx := PackageVariantNameMaxLength - PackageVariantNameHashLength - 1 - return fmt.Sprintf("%s-%s", pvId[:stubIdx], hex.EncodeToString(hash[:])[:PackageVariantNameHashLength]) -} - -// SetupWithManager sets up the controller with the Manager. -func (r *PackageVariantSetReconciler) SetupWithManager(mgr ctrl.Manager) error { - if err := api.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - if err := porchapi.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - if err := configapi.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - if err := pkgvarapi.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - if err := scheme.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - - r.Client = mgr.GetClient() - r.serializer = json.NewSerializerWithOptions(json.DefaultMetaFactory, nil, nil, json.SerializerOptions{Yaml: true}) - - return ctrl.NewControllerManagedBy(mgr). - For(&api.PackageVariantSet{}). - Watches(&source.Kind{Type: &pkgvarapi.PackageVariant{}}, - handler.EnqueueRequestsFromMapFunc(r.mapObjectsToRequests)). - Watches(&source.Kind{Type: &porchapi.PackageRevision{}}, - handler.EnqueueRequestsFromMapFunc(r.mapObjectsToRequests)). - Complete(r) -} - -func (r *PackageVariantSetReconciler) mapObjectsToRequests(obj client.Object) []reconcile.Request { - attachedPackageVariants := &api.PackageVariantSetList{} - err := r.List(context.TODO(), attachedPackageVariants, &client.ListOptions{ - Namespace: obj.GetNamespace(), - }) - if err != nil { - return []reconcile.Request{} - } - requests := make([]reconcile.Request, len(attachedPackageVariants.Items)) - for i, item := range attachedPackageVariants.Items { - requests[i] = reconcile.Request{ - NamespacedName: types.NamespacedName{ - Name: item.GetName(), - Namespace: item.GetNamespace(), - }, - } - } - return requests -} - -func setStalledConditionsToTrue(pvs *api.PackageVariantSet, reason, message string) { - meta.SetStatusCondition(&pvs.Status.Conditions, metav1.Condition{ - Type: ConditionTypeStalled, - Status: "True", - Reason: reason, - Message: message, - }) - meta.SetStatusCondition(&pvs.Status.Conditions, metav1.Condition{ - Type: ConditionTypeReady, - Status: "False", - Reason: reason, - Message: message, - }) -} diff --git a/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/packagevariantset_controller_test.go b/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/packagevariantset_controller_test.go deleted file mode 100644 index 6096c9a93a..0000000000 --- a/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/packagevariantset_controller_test.go +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2023 The kpt 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. - -package packagevariantset - -import ( - "context" - "sort" - "testing" - - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - pkgvarapi "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariants/api/v1alpha1" - api "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariantsets/api/v1alpha2" - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/serializer/json" - "sigs.k8s.io/yaml" -) - -func TestConvertObjectToRNode(t *testing.T) { - s := json.NewSerializerWithOptions(json.DefaultMetaFactory, nil, nil, json.SerializerOptions{Yaml: true}) - r := PackageVariantSetReconciler{serializer: s} - - t.Run("pod", func(t *testing.T) { - input := `apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: null - name: my-pod -spec: - containers: null -status: {} -` - var pod corev1.Pod - require.NoError(t, yaml.Unmarshal([]byte(input), &pod)) - n, err := r.convertObjectToRNode(&pod) - require.NoError(t, err) - require.Equal(t, input, n.MustString()) - }) - - t.Run("repository", func(t *testing.T) { - input := `apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Repository -metadata: - creationTimestamp: null - name: my-repo -spec: {} -status: {} -` - var repo configapi.Repository - require.NoError(t, yaml.Unmarshal([]byte(input), &repo)) - n, err := r.convertObjectToRNode(&repo) - require.NoError(t, err) - require.Equal(t, input, n.MustString()) - }) -} - -func TestUnrollDownstreamTargets(t *testing.T) { - pvs := &api.PackageVariantSet{ - ObjectMeta: metav1.ObjectMeta{Name: "my-pvs"}, - Spec: api.PackageVariantSetSpec{ - Upstream: &pkgvarapi.Upstream{Repo: "up", Package: "up", Revision: "up"}, - Targets: []api.Target{ - { - Repositories: []api.RepositoryTarget{ - {Name: "r1", PackageNames: []string{"p1", "p2", "p3"}}, - {Name: "r2"}, - }, - }, - { - RepositorySelector: &metav1.LabelSelector{}, - }, - }, - }, - } - - fc := &fakeClient{} - reconciler := &PackageVariantSetReconciler{Client: fc} - downstreams, err := reconciler.unrollDownstreamTargets(context.Background(), pvs) - require.NoError(t, err) - require.Equal(t, 6, len(downstreams)) - require.Equal(t, downstreams[0].repoDefault, "r1") - require.Equal(t, downstreams[0].packageDefault, "p1") - require.Equal(t, downstreams[1].repoDefault, "r1") - require.Equal(t, downstreams[1].packageDefault, "p2") - require.Equal(t, downstreams[2].repoDefault, "r1") - require.Equal(t, downstreams[2].packageDefault, "p3") - - require.Equal(t, downstreams[3].repoDefault, "r2") - require.Equal(t, downstreams[3].packageDefault, "up") - - // from the RepositorySelector, but fake client returns pods anyway - require.Equal(t, downstreams[4].repoDefault, "my-pod-1") - require.Equal(t, downstreams[4].packageDefault, "up") - require.Equal(t, downstreams[4].object.GetName(), "my-pod-1") - - require.Equal(t, downstreams[5].repoDefault, "my-pod-2") - require.Equal(t, downstreams[5].packageDefault, "up") - require.Equal(t, downstreams[5].object.GetName(), "my-pod-2") - -} - -func TestEnsurePackageVariants(t *testing.T) { - downstreams := []pvContext{ - {repoDefault: "dnrepo2", packageDefault: "dnpkg2"}, - {repoDefault: "dnrepo3", packageDefault: "dnpkg3"}, - {repoDefault: "dnrepo4", packageDefault: "supersupersuperloooooooooooooooooooooooooooooooooooooooooooooooooongpkgname"}, - } - fc := &fakeClient{} - reconciler := &PackageVariantSetReconciler{Client: fc} - require.NoError(t, reconciler.ensurePackageVariants(context.Background(), - &api.PackageVariantSet{ - ObjectMeta: metav1.ObjectMeta{Name: "my-pvs"}, - Spec: api.PackageVariantSetSpec{ - Upstream: &pkgvarapi.Upstream{Repo: "up", Package: "up", Revision: "up"}, - }, - }, - &configapi.RepositoryList{}, - &porchapi.PackageRevision{}, - downstreams)) - require.Equal(t, 1, len(fc.deleted)) - require.Equal(t, "my-pvs-dnrepo1-dnpkg1", fc.deleted[0].GetName()) - require.Equal(t, 1, len(fc.updated)) - require.Equal(t, "my-pvs-dnrepo2-dnpkg2", fc.updated[0].GetName()) - require.Equal(t, 2, len(fc.created)) - // ordering of calls to create is not stable (map iteration) - sort.Slice(fc.created, func(i, j int) bool { - return fc.created[i].GetName() < fc.created[j].GetName() - }) - require.Equal(t, "my-pvs-dnrepo3-dnpkg3", fc.created[0].GetName()) - require.Equal(t, "my-pvs-dnrepo4-supersupersuperlooooooooooooooooooooooo-bec36506", fc.created[1].GetName()) -} diff --git a/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/render.go b/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/render.go deleted file mode 100644 index 97c3ec5c43..0000000000 --- a/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/render.go +++ /dev/null @@ -1,367 +0,0 @@ -// Copyright 2023 The kpt 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. - -package packagevariantset - -import ( - "context" - "fmt" - "reflect" - "sort" - - "github.com/google/cel-go/cel" - - kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - pkgvarapi "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariants/api/v1alpha1" - api "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariantsets/api/v1alpha2" - - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - // TODO: including this requires many dependency updates, at some point - // we should do that so the CEL evaluation here is consistent with - // K8s. There are a few other lines to uncomment in that case. - //"k8s.io/apiserver/pkg/cel/library" -) - -const ( - RepoDefaultVarName = "repoDefault" - PackageDefaultVarName = "packageDefault" - UpstreamVarName = "upstream" - RepositoryVarName = "repository" - TargetVarName = "target" -) - -func renderPackageVariantSpec(ctx context.Context, pvs *api.PackageVariantSet, repoList *configapi.RepositoryList, - upstreamPR *porchapi.PackageRevision, downstream pvContext) (*pkgvarapi.PackageVariantSpec, error) { - - spec := &pkgvarapi.PackageVariantSpec{ - Upstream: pvs.Spec.Upstream, - Downstream: &pkgvarapi.Downstream{ - Repo: downstream.repoDefault, - Package: downstream.packageDefault, - }, - } - - pvt := downstream.template - if pvt == nil { - return spec, nil - } - - inputs, err := buildBaseInputs(upstreamPR, downstream) - if err != nil { - return nil, err - } - - repo := downstream.repoDefault - - if pvt.Downstream != nil { - if pvt.Downstream.Repo != nil && *pvt.Downstream.Repo != "" { - repo = *pvt.Downstream.Repo - } - - if pvt.Downstream.RepoExpr != nil && *pvt.Downstream.RepoExpr != "" { - repo, err = evalExpr(*pvt.Downstream.RepoExpr, inputs) - if err != nil { - return nil, fmt.Errorf("template.downstream.repoExpr: %s", err.Error()) - } - } - - spec.Downstream.Repo = repo - } - - for _, r := range repoList.Items { - if r.Name == repo { - repoInput, err := objectToInput(&r) - if err != nil { - return nil, err - } - inputs[RepositoryVarName] = repoInput - break - } - } - - if _, ok := inputs[RepositoryVarName]; !ok { - return nil, fmt.Errorf("repository %q could not be loaded", repo) - } - - if pvt.Downstream != nil { - if pvt.Downstream.Package != nil && *pvt.Downstream.Package != "" { - spec.Downstream.Package = *pvt.Downstream.Package - } - - if pvt.Downstream.PackageExpr != nil && *pvt.Downstream.PackageExpr != "" { - spec.Downstream.Package, err = evalExpr(*pvt.Downstream.PackageExpr, inputs) - if err != nil { - return nil, fmt.Errorf("template.downstream.packageExpr: %s", err.Error()) - } - } - } - - if pvt.AdoptionPolicy != nil { - spec.AdoptionPolicy = *pvt.AdoptionPolicy - } - - if pvt.DeletionPolicy != nil { - spec.DeletionPolicy = *pvt.DeletionPolicy - } - spec.Labels, err = copyAndOverlayMapExpr("template.labelExprs", pvt.Labels, pvt.LabelExprs, inputs) - if err != nil { - return nil, err - } - - spec.Annotations, err = copyAndOverlayMapExpr("template.annotationExprs", pvt.Annotations, pvt.AnnotationExprs, inputs) - if err != nil { - return nil, err - } - - if pvt.PackageContext != nil { - data, err := copyAndOverlayMapExpr("template.packageContext.dataExprs", pvt.PackageContext.Data, pvt.PackageContext.DataExprs, inputs) - if err != nil { - return nil, err - } - - removeKeys, err := copyAndOverlayStringSlice("template.packageContext.removeKeyExprs", pvt.PackageContext.RemoveKeys, - pvt.PackageContext.RemoveKeyExprs, inputs) - if err != nil { - return nil, err - } - spec.PackageContext = &pkgvarapi.PackageContext{ - Data: data, - RemoveKeys: removeKeys, - } - } - - for i, injTemplate := range pvt.Injectors { - injector := pkgvarapi.InjectionSelector{ - Group: injTemplate.Group, - Version: injTemplate.Version, - Kind: injTemplate.Kind, - } - if injTemplate.Name != nil && *injTemplate.Name != "" { - injector.Name = *injTemplate.Name - } - - if injTemplate.NameExpr != nil && *injTemplate.NameExpr != "" { - injector.Name, err = evalExpr(*injTemplate.NameExpr, inputs) - if err != nil { - return nil, fmt.Errorf("template.injectors[%d].nameExpr: %s", i, err.Error()) - } - } - - spec.Injectors = append(spec.Injectors, injector) - } - - if pvt.Pipeline != nil { - pipeline := kptfilev1.Pipeline{} - pipeline.Validators, err = renderFunctionTemplateList("template.pipeline.validators", pvt.Pipeline.Validators, inputs) - if err != nil { - return nil, err - } - pipeline.Mutators, err = renderFunctionTemplateList("template.pipeline.mutators", pvt.Pipeline.Mutators, inputs) - if err != nil { - return nil, err - } - if len(pipeline.Validators) > 0 || len(pipeline.Mutators) > 0 { - spec.Pipeline = &pipeline - } - } - - return spec, nil -} - -func renderFunctionTemplateList(field string, templateList []api.FunctionTemplate, inputs map[string]interface{}) ([]kptfilev1.Function, error) { - var results []kptfilev1.Function - for i, ft := range templateList { - var err error - f := ft.Function - f.ConfigMap, err = copyAndOverlayMapExpr(fmt.Sprintf("%s[%d].configMapExprs", field, i), ft.ConfigMap, ft.ConfigMapExprs, inputs) - if err != nil { - return nil, err - } - - results = append(results, f) - } - return results, nil -} - -func buildBaseInputs(upstreamPR *porchapi.PackageRevision, downstream pvContext) (map[string]interface{}, error) { - inputs := make(map[string]interface{}, 5) - inputs[RepoDefaultVarName] = downstream.repoDefault - inputs[PackageDefaultVarName] = downstream.packageDefault - - upstreamInput, err := objectToInput(upstreamPR) - if err != nil { - return nil, err - } - inputs[UpstreamVarName] = upstreamInput - - if downstream.object != nil { - targetInput, err := objectToInput(downstream.object) - if err != nil { - return nil, err - } - inputs[TargetVarName] = targetInput - } else { - inputs[TargetVarName] = map[string]string{ - "repo": downstream.repoDefault, - "package": downstream.packageDefault, - } - } - - return inputs, nil -} - -func objectToInput(obj interface{}) (map[string]interface{}, error) { - - result := make(map[string]interface{}) - - uo, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) - if err != nil { - return nil, err - } - - u := unstructured.Unstructured{Object: uo} - - //TODO: allow an administrator-configurable allow list of fields, - // on a per-GVK basis - result["name"] = u.GetName() - result["namespace"] = u.GetNamespace() - result["labels"] = u.GetLabels() - result["annotations"] = u.GetAnnotations() - - return result, nil -} - -func copyAndOverlayMapExpr(fieldName string, inMap map[string]string, mapExprs []api.MapExpr, inputs map[string]interface{}) (map[string]string, error) { - outMap := make(map[string]string, len(inMap)) - for k, v := range inMap { - outMap[k] = v - } - - var err error - for i, me := range mapExprs { - var k, v string - if me.Key != nil { - k = *me.Key - } - if me.KeyExpr != nil { - k, err = evalExpr(*me.KeyExpr, inputs) - if err != nil { - return nil, fmt.Errorf("%s[%d].keyExpr: %s", fieldName, i, err.Error()) - } - } - if me.Value != nil { - v = *me.Value - } - if me.ValueExpr != nil { - v, err = evalExpr(*me.ValueExpr, inputs) - if err != nil { - return nil, fmt.Errorf("%s[%d].valueExpr: %s", fieldName, i, err.Error()) - } - } - outMap[k] = v - } - - if len(outMap) == 0 { - return nil, nil - } - - return outMap, nil -} - -func copyAndOverlayStringSlice(fieldName string, in, exprs []string, inputs map[string]interface{}) ([]string, error) { - outMap := make(map[string]bool, len(in)+len(exprs)) - - for _, v := range in { - outMap[v] = true - } - for i, e := range exprs { - v, err := evalExpr(e, inputs) - if err != nil { - return nil, fmt.Errorf("%s[%d]: %s", fieldName, i, err.Error()) - } - outMap[v] = true - } - - if len(outMap) == 0 { - return nil, nil - } - - var out []string - for k := range outMap { - out = append(out, k) - } - sort.Strings(out) - return out, nil -} - -func evalExpr(expr string, inputs map[string]interface{}) (string, error) { - prog, err := compileExpr(expr) - if err != nil { - return "", err - } - - val, _, err := prog.Eval(inputs) - if err != nil { - return "", err - } - - result, err := val.ConvertToNative(reflect.TypeOf("")) - if err != nil { - return "", err - } - - s, ok := result.(string) - if !ok { - return "", fmt.Errorf("expression returned non-string value: %v", result) - } - - return s, nil -} - -// compileExpr returns a compiled CEL expression. -func compileExpr(expr string) (cel.Program, error) { - var opts []cel.EnvOption - opts = append(opts, cel.HomogeneousAggregateLiterals()) - opts = append(opts, cel.EagerlyValidateDeclarations(true), cel.DefaultUTCTimeZone(true)) - // TODO: uncomment after updating to latest k8s - //opts = append(opts, library.ExtensionLibs...) - opts = append(opts, cel.Variable(RepoDefaultVarName, cel.StringType)) - opts = append(opts, cel.Variable(PackageDefaultVarName, cel.StringType)) - opts = append(opts, cel.Variable(UpstreamVarName, cel.DynType)) - opts = append(opts, cel.Variable(TargetVarName, cel.DynType)) - opts = append(opts, cel.Variable(RepositoryVarName, cel.DynType)) - - env, err := cel.NewEnv(opts...) - if err != nil { - return nil, err - } - - ast, issues := env.Compile(expr) - if issues != nil { - return nil, issues.Err() - } - - _, err = cel.AstToCheckedExpr(ast) - if err != nil { - return nil, err - } - return env.Program(ast, - cel.EvalOptions(cel.OptOptimize), - // TODO: uncomment after updating to latest k8s - //cel.OptimizeRegex(library.ExtensionLibRegexOptimizations...), - ) -} diff --git a/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/render_test.go b/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/render_test.go deleted file mode 100644 index 187e001f27..0000000000 --- a/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/render_test.go +++ /dev/null @@ -1,665 +0,0 @@ -// Copyright 2023 The kpt 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. - -package packagevariantset - -import ( - "context" - "testing" - - kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - pkgvarapi "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariants/api/v1alpha1" - api "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariantsets/api/v1alpha2" - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/pointer" - "sigs.k8s.io/yaml" -) - -var repoListYaml = []byte(` -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: RepositoryList -metadata: - name: my-repo-list -items: -- apiVersion: config.porch.kpt.dev/v1alpha1 - kind: Repository - metadata: - name: my-repo-1 - labels: - foo: bar - abc: def -- apiVersion: config.porch.kpt.dev/v1alpha1 - kind: Repository - metadata: - name: my-repo-2 - labels: - foo: bar - abc: def - efg: hij -`) - -func TestRenderPackageVariantSpec(t *testing.T) { - var repoList configapi.RepositoryList - require.NoError(t, yaml.Unmarshal(repoListYaml, &repoList)) - - adoptExisting := pkgvarapi.AdoptionPolicyAdoptExisting - deletionPolicyDelete := pkgvarapi.DeletionPolicyDelete - pvs := api.PackageVariantSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-pvs", - Namespace: "default", - }, - Spec: api.PackageVariantSetSpec{ - Upstream: &pkgvarapi.Upstream{Repo: "up-repo", Package: "up-pkg", Revision: "v2"}, - }, - } - upstreamPR := porchapi.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Name: "p", - Namespace: "default", - Labels: map[string]string{ - "vendor": "bigco.com", - "product": "snazzy", - "version": "1.6.8", - }, - Annotations: map[string]string{ - "bigco.com/team": "us-platform", - }, - }, - } - testCases := map[string]struct { - downstream pvContext - expectedSpec pkgvarapi.PackageVariantSpec - expectedErrs []string - }{ - "no template": { - downstream: pvContext{ - repoDefault: "my-repo-1", - packageDefault: "p", - }, - expectedSpec: pkgvarapi.PackageVariantSpec{ - Upstream: pvs.Spec.Upstream, - Downstream: &pkgvarapi.Downstream{ - Repo: "my-repo-1", - Package: "p", - }, - }, - expectedErrs: nil, - }, - "template downstream.repo": { - downstream: pvContext{ - repoDefault: "my-repo-1", - packageDefault: "p", - template: &api.PackageVariantTemplate{ - Downstream: &api.DownstreamTemplate{ - Repo: pointer.String("my-repo-2"), - }, - }, - }, - expectedSpec: pkgvarapi.PackageVariantSpec{ - Upstream: pvs.Spec.Upstream, - Downstream: &pkgvarapi.Downstream{ - Repo: "my-repo-2", - Package: "p", - }, - }, - expectedErrs: nil, - }, - "template downstream.package": { - downstream: pvContext{ - repoDefault: "my-repo-1", - packageDefault: "p", - template: &api.PackageVariantTemplate{ - Downstream: &api.DownstreamTemplate{ - Package: pointer.String("new-p"), - }, - }, - }, - expectedSpec: pkgvarapi.PackageVariantSpec{ - Upstream: pvs.Spec.Upstream, - Downstream: &pkgvarapi.Downstream{ - Repo: "my-repo-1", - Package: "new-p", - }, - }, - expectedErrs: nil, - }, - "template adoption and deletion": { - downstream: pvContext{ - repoDefault: "my-repo-1", - packageDefault: "p", - template: &api.PackageVariantTemplate{ - AdoptionPolicy: &adoptExisting, - DeletionPolicy: &deletionPolicyDelete, - }, - }, - expectedSpec: pkgvarapi.PackageVariantSpec{ - Upstream: pvs.Spec.Upstream, - Downstream: &pkgvarapi.Downstream{ - Repo: "my-repo-1", - Package: "p", - }, - AdoptionPolicy: "adoptExisting", - DeletionPolicy: "delete", - }, - expectedErrs: nil, - }, - "template static labels and annotations": { - downstream: pvContext{ - repoDefault: "my-repo-1", - packageDefault: "p", - template: &api.PackageVariantTemplate{ - Labels: map[string]string{ - "foo": "bar", - "hello": "there", - }, - Annotations: map[string]string{ - "foobar": "barfoo", - }, - }, - }, - expectedSpec: pkgvarapi.PackageVariantSpec{ - Upstream: pvs.Spec.Upstream, - Downstream: &pkgvarapi.Downstream{ - Repo: "my-repo-1", - Package: "p", - }, - Labels: map[string]string{ - "foo": "bar", - "hello": "there", - }, - Annotations: map[string]string{ - "foobar": "barfoo", - }, - }, - expectedErrs: nil, - }, - "template static packageContext": { - downstream: pvContext{ - repoDefault: "my-repo-1", - packageDefault: "p", - template: &api.PackageVariantTemplate{ - PackageContext: &api.PackageContextTemplate{ - Data: map[string]string{ - "foo": "bar", - "hello": "there", - }, - RemoveKeys: []string{"foobar", "barfoo"}, - }, - }, - }, - expectedSpec: pkgvarapi.PackageVariantSpec{ - Upstream: pvs.Spec.Upstream, - Downstream: &pkgvarapi.Downstream{ - Repo: "my-repo-1", - Package: "p", - }, - PackageContext: &pkgvarapi.PackageContext{ - Data: map[string]string{ - "foo": "bar", - "hello": "there", - }, - RemoveKeys: []string{"barfoo", "foobar"}, - }, - }, - expectedErrs: nil, - }, - "template downstream with expressions": { - downstream: pvContext{ - repoDefault: "my-repo-1", - packageDefault: "p", - template: &api.PackageVariantTemplate{ - Downstream: &api.DownstreamTemplate{ - RepoExpr: pointer.String("'my-repo-2'"), - PackageExpr: pointer.String("repoDefault + '-' + packageDefault"), - }, - }, - }, - expectedSpec: pkgvarapi.PackageVariantSpec{ - Upstream: pvs.Spec.Upstream, - Downstream: &pkgvarapi.Downstream{ - Repo: "my-repo-2", - Package: "my-repo-1-p", - }, - }, - expectedErrs: nil, - }, - "template labels and annotations with expressions": { - downstream: pvContext{ - repoDefault: "my-repo-1", - packageDefault: "p", - template: &api.PackageVariantTemplate{ - Downstream: &api.DownstreamTemplate{ - RepoExpr: pointer.String("'my-repo-2'"), - PackageExpr: pointer.String("repoDefault + '-' + packageDefault"), - }, - Labels: map[string]string{ - "foo": "bar", - "hello": "there", - }, - LabelExprs: []api.MapExpr{ - { - Key: pointer.String("foo"), - ValueExpr: pointer.String("repoDefault"), - }, - { - KeyExpr: pointer.String("repository.labels['efg']"), - ValueExpr: pointer.String("packageDefault + '-' + repository.name"), - }, - { - Key: pointer.String("hello"), - Value: pointer.String("goodbye"), - }, - }, - Annotations: map[string]string{ - "bigco.com/sample-annotation": "some-annotation", - "foo.org/id": "123456", - }, - AnnotationExprs: []api.MapExpr{ - { - Key: pointer.String("foo.org/id"), - Value: pointer.String("54321"), - }, - { - Key: pointer.String("bigco.com/team"), - ValueExpr: pointer.String("upstream.annotations['bigco.com/team']"), - }, - }, - }, - }, - expectedSpec: pkgvarapi.PackageVariantSpec{ - Upstream: pvs.Spec.Upstream, - Downstream: &pkgvarapi.Downstream{ - Repo: "my-repo-2", - Package: "my-repo-1-p", - }, - Labels: map[string]string{ - "foo": "my-repo-1", - "hello": "goodbye", - "hij": "p-my-repo-2", - }, - Annotations: map[string]string{ - "bigco.com/sample-annotation": "some-annotation", - "foo.org/id": "54321", - "bigco.com/team": "us-platform", - }, - }, - expectedErrs: nil, - }, - "template with packageContext with expressions": { - downstream: pvContext{ - repoDefault: "my-repo-1", - packageDefault: "p", - template: &api.PackageVariantTemplate{ - PackageContext: &api.PackageContextTemplate{ - Data: map[string]string{ - "foo": "bar", - "hello": "there", - }, - DataExprs: []api.MapExpr{ - { - Key: pointer.String("foo"), - ValueExpr: pointer.String("upstream.name"), - }, - { - KeyExpr: pointer.String("upstream.namespace"), - ValueExpr: pointer.String("upstream.name"), - }, - { - KeyExpr: pointer.String("upstream.name"), - Value: pointer.String("foo"), - }, - }, - RemoveKeys: []string{"foobar", "barfoo"}, - RemoveKeyExprs: []string{"repository.labels['abc']"}, - }, - }, - }, - expectedSpec: pkgvarapi.PackageVariantSpec{ - Upstream: pvs.Spec.Upstream, - Downstream: &pkgvarapi.Downstream{ - Repo: "my-repo-1", - Package: "p", - }, - PackageContext: &pkgvarapi.PackageContext{ - Data: map[string]string{ - "foo": "p", - "hello": "there", - "default": "p", - "p": "foo", - }, - RemoveKeys: []string{"barfoo", "def", "foobar"}, - }, - }, - expectedErrs: nil, - }, - "template injectors": { - downstream: pvContext{ - repoDefault: "my-repo-1", - packageDefault: "p", - template: &api.PackageVariantTemplate{ - Injectors: []api.InjectionSelectorTemplate{ - { - Group: pointer.String("kpt.dev"), - Version: pointer.String("v1alpha1"), - Kind: pointer.String("Foo"), - Name: pointer.String("bar"), - }, - { - Group: pointer.String("kpt.dev"), - Version: pointer.String("v1alpha1"), - Kind: pointer.String("Foo"), - NameExpr: pointer.String("repository.labels['abc']"), - }, - { - NameExpr: pointer.String("repository.name + '-test'"), - }, - }, - }, - }, - expectedSpec: pkgvarapi.PackageVariantSpec{ - Upstream: pvs.Spec.Upstream, - Downstream: &pkgvarapi.Downstream{ - Repo: "my-repo-1", - Package: "p", - }, - Injectors: []pkgvarapi.InjectionSelector{ - { - Group: pointer.String("kpt.dev"), - Version: pointer.String("v1alpha1"), - Kind: pointer.String("Foo"), - Name: "bar", - }, - { - Group: pointer.String("kpt.dev"), - Version: pointer.String("v1alpha1"), - Kind: pointer.String("Foo"), - Name: "def", - }, - { - Name: "my-repo-1-test", - }, - }, - }, - expectedErrs: nil, - }, - "pipeline injectors": { - downstream: pvContext{ - repoDefault: "my-repo-1", - packageDefault: "p", - template: &api.PackageVariantTemplate{ - Pipeline: &api.PipelineTemplate{ - Validators: []api.FunctionTemplate{ - { - Function: kptfilev1.Function{ - Image: "foo:bar", - Name: "hey", - }, - }, - { - Function: kptfilev1.Function{ - Image: "foo:bar", - ConfigMap: map[string]string{ - "k1": "v1", - "k2": "v2", - }, - }, - ConfigMapExprs: []api.MapExpr{ - { - Key: pointer.String("k1"), - ValueExpr: pointer.String("repository.name"), - }, - { - KeyExpr: pointer.String("'k3'"), - Value: pointer.String("bar"), - }, - }, - }, - }, - Mutators: []api.FunctionTemplate{ - { - Function: kptfilev1.Function{ - Image: "mutates", - }, - ConfigMapExprs: []api.MapExpr{ - { - Key: pointer.String("k1"), - Value: pointer.String("yo"), - }, - }, - }, - }, - }, - }, - }, - expectedSpec: pkgvarapi.PackageVariantSpec{ - Upstream: pvs.Spec.Upstream, - Downstream: &pkgvarapi.Downstream{ - Repo: "my-repo-1", - Package: "p", - }, - Pipeline: &kptfilev1.Pipeline{ - Validators: []kptfilev1.Function{ - { - Image: "foo:bar", - Name: "hey", - }, - { - Image: "foo:bar", - ConfigMap: map[string]string{ - "k1": "my-repo-1", - "k2": "v2", - "k3": "bar", - }, - }, - }, - Mutators: []kptfilev1.Function{ - { - Image: "mutates", - ConfigMap: map[string]string{ - "k1": "yo", - }, - }, - }, - }, - }, - expectedErrs: nil, - }, - } - - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - pvSpec, err := renderPackageVariantSpec(context.Background(), &pvs, &repoList, &upstreamPR, tc.downstream) - require.NoError(t, err) - require.Equal(t, &tc.expectedSpec, pvSpec) - }) - } -} - -func TestEvalExpr(t *testing.T) { - baseInputs := map[string]interface{}{ - "repoDefault": "foo-repo", - "packageDefault": "bar-package", - } - var repoList configapi.RepositoryList - require.NoError(t, yaml.Unmarshal(repoListYaml, &repoList)) - - r1Input, err := objectToInput(&repoList.Items[0]) - require.NoError(t, err) - - testCases := map[string]struct { - expr string - target interface{} - expectedResult string - expectedErr string - }{ - "no vars": { - expr: "'foo'", - expectedResult: "foo", - expectedErr: "", - }, - "repoDefault": { - expr: "repoDefault", - expectedResult: "foo-repo", - expectedErr: "", - }, - "packageDefault": { - expr: "packageDefault", - expectedResult: "bar-package", - expectedErr: "", - }, - "concat defaults": { - expr: "packageDefault + '-' + repoDefault", - expectedResult: "bar-package-foo-repo", - expectedErr: "", - }, - "repositories target": { - expr: "target.repo + '/' + target.package", - target: map[string]any{ - "repo": "my-repo", - "package": "my-package", - }, - expectedResult: "my-repo/my-package", - expectedErr: "", - }, - "repository target": { - expr: "target.name + '/' + target.labels['foo']", - target: r1Input, - expectedResult: "my-repo-1/bar", - expectedErr: "", - }, - "bad variable": { - expr: "badvar", - expectedErr: "ERROR: :1:1: undeclared reference to 'badvar' (in container '')\n | badvar\n | ^", - }, - "bad expr": { - expr: "/", - expectedErr: "ERROR: :1:1: Syntax error: mismatched input '/' expecting {'[', '{', '(', '.', '-', '!', 'true', 'false', 'null', NUM_FLOAT, NUM_INT, NUM_UINT, STRING, BYTES, IDENTIFIER}\n | /\n | ^\nERROR: :1:2: Syntax error: mismatched input '' expecting {'[', '{', '(', '.', '-', '!', 'true', 'false', 'null', NUM_FLOAT, NUM_INT, NUM_UINT, STRING, BYTES, IDENTIFIER}\n | /\n | .^", - }, - "missing label": { - expr: "target.name + '/' + target.labels['no-such-label']", - target: r1Input, - expectedErr: "no such key: no-such-label", - }, - } - - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - inputs := map[string]any{} - for k, v := range baseInputs { - inputs[k] = v - } - inputs["target"] = tc.target - val, err := evalExpr(tc.expr, inputs) - if tc.expectedErr == "" { - require.NoError(t, err) - require.Equal(t, tc.expectedResult, val) - } else { - require.EqualError(t, err, tc.expectedErr) - } - }) - } -} - -func TestCopyAndOverlayMapExpr(t *testing.T) { - baseInputs := map[string]interface{}{ - "repoDefault": "foo-repo", - "packageDefault": "bar-package", - } - - testCases := map[string]struct { - inMap map[string]string - mapExprs []api.MapExpr - expectedResult map[string]string - expectedErr string - }{ - "empty starting map": { - inMap: map[string]string{}, - mapExprs: []api.MapExpr{ - { - Key: pointer.String("foo"), - Value: pointer.String("bar"), - }, - { - KeyExpr: pointer.String("repoDefault"), - Value: pointer.String("barbar"), - }, - { - Key: pointer.String("bar"), - ValueExpr: pointer.String("packageDefault"), - }, - }, - expectedResult: map[string]string{ - "foo": "bar", - "foo-repo": "barbar", - "bar": "bar-package", - }, - }, - "static overlay": { - inMap: map[string]string{ - "foo": "bar", - "bar": "foo", - }, - mapExprs: []api.MapExpr{ - { - Key: pointer.String("foo"), - Value: pointer.String("new-bar"), - }, - { - Key: pointer.String("foofoo"), - Value: pointer.String("barbar"), - }, - }, - expectedResult: map[string]string{ - "foo": "new-bar", - "bar": "foo", - "foofoo": "barbar", - }, - }, - "exprs overlay": { - inMap: map[string]string{ - "foo": "bar", - "bar": "foo", - }, - mapExprs: []api.MapExpr{ - { - KeyExpr: pointer.String("'foo'"), - Value: pointer.String("new-bar"), - }, - { - Key: pointer.String("bar"), - ValueExpr: pointer.String("packageDefault"), - }, - }, - expectedResult: map[string]string{ - "foo": "new-bar", - "bar": "bar-package", - }, - }, - } - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - outMap, err := copyAndOverlayMapExpr("f", tc.inMap, tc.mapExprs, baseInputs) - if tc.expectedErr == "" { - require.NoError(t, err) - require.Equal(t, tc.expectedResult, outMap) - } else { - require.EqualError(t, err, tc.expectedErr) - } - }) - } -} diff --git a/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/validate.go b/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/validate.go deleted file mode 100644 index b1092bebb7..0000000000 --- a/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/validate.go +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2023 The kpt 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. - -package packagevariantset - -import ( - "fmt" - "strings" - - pkgvarapi "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariants/api/v1alpha1" - api "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariantsets/api/v1alpha2" -) - -func validatePackageVariantSet(pvs *api.PackageVariantSet) []error { - var allErrs []error - if pvs.Spec.Upstream == nil { - allErrs = append(allErrs, fmt.Errorf("spec.upstream is a required field")) - } else { - if pvs.Spec.Upstream.Package == "" { - allErrs = append(allErrs, fmt.Errorf("spec.upstream.package is a required field")) - } - if pvs.Spec.Upstream.Repo == "" { - allErrs = append(allErrs, fmt.Errorf("spec.upstream.repo is a required field")) - } - if pvs.Spec.Upstream.Revision == "" { - allErrs = append(allErrs, fmt.Errorf("spec.upstream.revision is a required field")) - } - } - - if len(pvs.Spec.Targets) == 0 { - allErrs = append(allErrs, fmt.Errorf("must specify at least one item in spec.targets")) - } - for i, target := range pvs.Spec.Targets { - allErrs = append(allErrs, validateTarget(i, target)...) - } - - return allErrs -} - -func validateTarget(i int, target api.Target) []error { - var allErrs []error - count := 0 - if target.Repositories != nil { - count++ - - if len(target.Repositories) == 0 { - allErrs = append(allErrs, fmt.Errorf("spec.targets[%d].repositories must not be an empty list if specified", i)) - } - - for j, rt := range target.Repositories { - if rt.Name == "" { - allErrs = append(allErrs, fmt.Errorf("spec.targets[%d].repositories[%d].name cannot be empty", i, j)) - } - - for k, pn := range rt.PackageNames { - if pn == "" { - allErrs = append(allErrs, fmt.Errorf("spec.targets[%d].repositories[%d].packageNames[%d] cannot be empty", i, j, k)) - } - } - } - } - - if target.RepositorySelector != nil { - count++ - } - - if target.ObjectSelector != nil { - count++ - if target.ObjectSelector.APIVersion == "" { - allErrs = append(allErrs, fmt.Errorf("spec.targets[%d].objectselector.apiVersion cannot be empty", i)) - } - if target.ObjectSelector.Kind == "" { - allErrs = append(allErrs, fmt.Errorf("spec.targets[%d].objectselector.kind cannot be empty", i)) - } - } - - if count != 1 { - allErrs = append(allErrs, fmt.Errorf("spec.targets[%d] must specify one of `repositories`, `repositorySelector`, or `objectSelector`", i)) - } - - if target.Template == nil { - return allErrs - } - - return append(allErrs, validateTemplate(target.Template, fmt.Sprintf("spec.targets[%d].template", i))...) -} - -func validateTemplate(template *api.PackageVariantTemplate, field string) []error { - var allErrs []error - if template.AdoptionPolicy != nil && *template.AdoptionPolicy != pkgvarapi.AdoptionPolicyAdoptNone && - *template.AdoptionPolicy != pkgvarapi.AdoptionPolicyAdoptExisting { - allErrs = append(allErrs, fmt.Errorf("%s.adoptionPolicy can only be %q or %q", field, - pkgvarapi.AdoptionPolicyAdoptNone, pkgvarapi.AdoptionPolicyAdoptExisting)) - } - - if template.DeletionPolicy != nil && *template.DeletionPolicy != pkgvarapi.DeletionPolicyOrphan && - *template.DeletionPolicy != pkgvarapi.DeletionPolicyDelete { - allErrs = append(allErrs, fmt.Errorf("%s.deletionPolicy can only be %q or %q", field, - pkgvarapi.DeletionPolicyOrphan, pkgvarapi.DeletionPolicyDelete)) - } - - if template.Downstream != nil { - if template.Downstream.Repo != nil && template.Downstream.RepoExpr != nil { - allErrs = append(allErrs, fmt.Errorf("%s may specify only one of `downstream.repo` and `downstream.repoExpr`", field)) - } - if template.Downstream.Package != nil && template.Downstream.PackageExpr != nil { - allErrs = append(allErrs, fmt.Errorf("%s may specify only one of `downstream.package` and `downstream.packageExpr`", field)) - } - } - - if template.LabelExprs != nil { - allErrs = append(allErrs, validateMapExpr(template.LabelExprs, fmt.Sprintf("%s.labelExprs", field))...) - } - - if template.AnnotationExprs != nil { - allErrs = append(allErrs, validateMapExpr(template.AnnotationExprs, fmt.Sprintf("%s.annotationExprs", field))...) - } - - if template.PackageContext != nil && template.PackageContext.DataExprs != nil { - allErrs = append(allErrs, validateMapExpr(template.PackageContext.DataExprs, fmt.Sprintf("%s.packageContext.dataExprs", field))...) - } - - for i, injector := range template.Injectors { - if injector.Name != nil && injector.NameExpr != nil { - allErrs = append(allErrs, fmt.Errorf("%s.injectors[%d] may specify only one of `name` and `nameExpr`", field, i)) - } - - if injector.Name == nil && injector.NameExpr == nil { - allErrs = append(allErrs, fmt.Errorf("%s.injectors[%d] must specify either `name` or `nameExpr`", field, i)) - } - } - - if template.Pipeline != nil { - for i, f := range template.Pipeline.Validators { - allErrs = append(allErrs, validateFunction(&f, fmt.Sprintf("%s.pipeline.validators[%d]", field, i))...) - } - for i, f := range template.Pipeline.Mutators { - allErrs = append(allErrs, validateFunction(&f, fmt.Sprintf("%s.pipeline.mutators[%d]", field, i))...) - } - } - - return allErrs -} - -func validateMapExpr(m []api.MapExpr, fieldName string) []error { - var allErrs []error - for j, me := range m { - if me.Key != nil && me.KeyExpr != nil { - allErrs = append(allErrs, fmt.Errorf("%s[%d] may specify only one of `key` and `keyExpr`", fieldName, j)) - } - if me.Value != nil && me.ValueExpr != nil { - allErrs = append(allErrs, fmt.Errorf("%s[%d] may specify only one of `value` and `valueExpr`", fieldName, j)) - } - } - - return allErrs -} - -func validateFunction(f *api.FunctionTemplate, field string) []error { - var allErrs []error - if f.Image == "" { - allErrs = append(allErrs, fmt.Errorf("%s.image must not be empty", field)) - } - if strings.Contains(f.Name, ".") { - allErrs = append(allErrs, fmt.Errorf("%s.name must not contain '.'", field)) - } - return allErrs -} - -func combineErrors(errs []error) string { - var errMsgs []string - for _, e := range errs { - if e.Error() != "" { - errMsgs = append(errMsgs, e.Error()) - } - } - return strings.Join(errMsgs, "; ") -} diff --git a/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/validate_test.go b/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/validate_test.go deleted file mode 100644 index 7a6b1abd41..0000000000 --- a/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/validate_test.go +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright 2023 The kpt 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. - -package packagevariantset - -import ( - "testing" - - api "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariantsets/api/v1alpha2" - "github.com/stretchr/testify/require" - "sigs.k8s.io/yaml" -) - -func TestValidatePackageVariantSet(t *testing.T) { - packageVariantHeader := `apiVersion: config.porch.kpt.dev -kind: PackageVariantSet -metadata: - name: my-pv` - - testCases := map[string]struct { - packageVariant string - expectedErrs []string - }{ - "empty spec": { - packageVariant: packageVariantHeader, - expectedErrs: []string{"spec.upstream is a required field", - "must specify at least one item in spec.targets", - }, - }, - "missing upstream package": { - packageVariant: packageVariantHeader + ` -spec: - upstream: - repo: foo - revision: v1`, - expectedErrs: []string{"spec.upstream.package is a required field", - "must specify at least one item in spec.targets", - }, - }, - "missing upstream repo": { - packageVariant: packageVariantHeader + ` -spec: - upstream: - package: foopkg - revision: v3`, - expectedErrs: []string{"spec.upstream.repo is a required field", - "must specify at least one item in spec.targets", - }, - }, - "missing upstream revision": { - packageVariant: packageVariantHeader + ` -spec: - upstream: - repo: foo - package: foopkg`, - expectedErrs: []string{"spec.upstream.revision is a required field", - "must specify at least one item in spec.targets", - }, - }, - "invalid targets": { - packageVariant: packageVariantHeader + ` -spec: - targets: - - repositories: - - name: "" - - repositories: - - name: bar - repositorySelector: - foo: bar - - repositories: - - name: bar - packageNames: - - "" - - foo - `, - expectedErrs: []string{"spec.upstream is a required field", - "spec.targets[0].repositories[0].name cannot be empty", - "spec.targets[1] must specify one of `repositories`, `repositorySelector`, or `objectSelector`", - "spec.targets[2].repositories[0].packageNames[0] cannot be empty", - }, - }, - "invalid adoption and deletion policies": { - packageVariant: packageVariantHeader + ` -spec: - targets: - - template: - adoptionPolicy: invalid - deletionPolicy: invalid -`, - expectedErrs: []string{"spec.upstream is a required field", - "spec.targets[0] must specify one of `repositories`, `repositorySelector`, or `objectSelector`", - "spec.targets[0].template.adoptionPolicy can only be \"adoptNone\" or \"adoptExisting\"", - "spec.targets[0].template.deletionPolicy can only be \"orphan\" or \"delete\"", - }, - }, - "valid adoption and deletion policies": { - packageVariant: packageVariantHeader + ` -spec: - adoptionPolicy: adoptExisting - deletionPolicy: orphan -`, - expectedErrs: []string{"spec.upstream is a required field", - "must specify at least one item in spec.targets", - }, - }, - "downstream values and expressions do not mix": { - packageVariant: packageVariantHeader + ` -spec: - targets: - - template: - downstream: - repo: "foo" - repoExpr: "'bar'" - package: "p" - packageExpr: "'p'" -`, - expectedErrs: []string{"spec.upstream is a required field", - "spec.targets[0] must specify one of `repositories`, `repositorySelector`, or `objectSelector`", - "spec.targets[0].template may specify only one of `downstream.repo` and `downstream.repoExpr`", - "spec.targets[0].template may specify only one of `downstream.package` and `downstream.packageExpr`", - }, - }, - "MapExprs do not allow both expr-and non-expr for same field": { - packageVariant: packageVariantHeader + ` -spec: - targets: - - template: - labelExprs: - - key: "foo" - keyExpr: "'bar'" - value: "bar" - - key: "foo" - value: "bar" - valueExpr: "'bar'" - annotationExprs: - - key: "foo" - keyExpr: "'bar'" - value: "bar" - - key: "foo" - value: "bar" - valueExpr: "'bar'" - packageContext: - dataExprs: - - key: "foo" - keyExpr: "'bar'" - value: "bar" - - key: "foo" - value: "bar" - valueExpr: "'bar'" -`, - expectedErrs: []string{"spec.upstream is a required field", - "spec.targets[0] must specify one of `repositories`, `repositorySelector`, or `objectSelector`", - "spec.targets[0].template.labelExprs[0] may specify only one of `key` and `keyExpr`", - "spec.targets[0].template.labelExprs[1] may specify only one of `value` and `valueExpr`", - "spec.targets[0].template.annotationExprs[0] may specify only one of `key` and `keyExpr`", - "spec.targets[0].template.annotationExprs[1] may specify only one of `value` and `valueExpr`", - "spec.targets[0].template.packageContext.dataExprs[0] may specify only one of `key` and `keyExpr`", - "spec.targets[0].template.packageContext.dataExprs[1] may specify only one of `value` and `valueExpr`", - }, - }, - "injectors must specify exactly one of name or nameexpr": { - packageVariant: packageVariantHeader + ` -spec: - targets: - - repositories: - - name: bar - template: - injectors: - - name: foo - nameExpr: bar - - group: foo -`, - expectedErrs: []string{"spec.upstream is a required field", - "spec.targets[0].template.injectors[0] may specify only one of `name` and `nameExpr`", - "spec.targets[0].template.injectors[1] must specify either `name` or `nameExpr`", - }, - }, - "pipeline function must be valid": { - packageVariant: packageVariantHeader + ` -spec: - targets: - - repositories: - - name: bar - template: - pipeline: - validators: - - name: foo - - image: foo - name: bar - mutators: - - name: foo.bar - image: bar -`, - expectedErrs: []string{"spec.upstream is a required field", - "spec.targets[0].template.pipeline.validators[0].image must not be empty", - "spec.targets[0].template.pipeline.mutators[0].name must not contain '.'", - }, - }, - } - - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - var pvs api.PackageVariantSet - require.NoError(t, yaml.Unmarshal([]byte(tc.packageVariant), &pvs)) - actualErrs := validatePackageVariantSet(&pvs) - require.Equal(t, len(tc.expectedErrs), len(actualErrs)) - for i := range actualErrs { - require.EqualError(t, actualErrs[i], tc.expectedErrs[i]) - } - - }) - } -} diff --git a/porch/controllers/remoterootsyncsets/api/v1alpha1/groupversion_info.go b/porch/controllers/remoterootsyncsets/api/v1alpha1/groupversion_info.go deleted file mode 100644 index b0010b886f..0000000000 --- a/porch/controllers/remoterootsyncsets/api/v1alpha1/groupversion_info.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2022 The kpt 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. - -// Package v1alpha1 contains API Schema definitions for the config.porch.kpt.dev v1alpha1 API group -// +kubebuilder:object:generate=true -// +groupName=config.porch.kpt.dev -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/scheme" -) - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 object:headerFile="../../../../scripts/boilerplate.go.txt" paths="./..." - -var ( - // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "config.porch.kpt.dev", Version: "v1alpha1"} - - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} - - // AddToScheme adds the types in this group-version to the given scheme. - AddToScheme = SchemeBuilder.AddToScheme -) diff --git a/porch/controllers/remoterootsyncsets/api/v1alpha1/remoterootsyncset_types.go b/porch/controllers/remoterootsyncsets/api/v1alpha1/remoterootsyncset_types.go deleted file mode 100644 index c7e1b9f950..0000000000 --- a/porch/controllers/remoterootsyncsets/api/v1alpha1/remoterootsyncset_types.go +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2022 The kpt 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. - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:printcolumn:name="AppliedCount",type=integer,JSONPath=`.status.aggregated.applied` -//+kubebuilder:printcolumn:name="ReadyCount",type=integer,JSONPath=`.status.aggregated.ready` -//+kubebuilder:printcolumn:name="Total",type=integer,JSONPath=`.status.aggregated.total` -//+kubebuilder:printcolumn:name="Applied",type=string,JSONPath=`.status.aggregated.conditions[?(@.type=='Applied')].reason` -//+kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.aggregated.conditions[?(@.type=='Ready')].reason` - -// RemoteRootSyncSet represents applying a package to multiple target clusters. -// In future, this should use ConfigSync, but while we're iterating on OCI/porch support, -// and making a few similar iterations (e.g. what feedback do we need for rollout), -// we're just applying directly to the target cluster(s). -// -// We follow the "managed remote objects" pattern; we don't want to create a mirror -// object, so we start with the "ReplicaSet" of Pod/ReplicaSet/Deployment. -// -// spec.clusterRefs specifies the target clusters -// -// spec.template maps to the spec of our "Pod", in this case a ConfigSync RootSync/RepoSync. -// Because we're not actually using ConfigSync in this prototype, we are only defining a -// small subset of fields. -type RemoteRootSyncSet struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec RemoteRootSyncSetSpec `json:"spec,omitempty"` - Status RemoteRootSyncSetStatus `json:"status,omitempty"` -} - -func (o *RemoteRootSyncSet) GetSpec() *RemoteRootSyncSetSpec { - if o == nil { - return nil - } - return &o.Spec -} - -// RemoteRootSyncSetSpec defines the desired state of RemoteRootSync -type RemoteRootSyncSetSpec struct { - ClusterRefs []*ClusterRef `json:"clusterRefs,omitempty"` - Template *RootSyncTemplate `json:"template,omitempty"` -} - -func (o *RemoteRootSyncSetSpec) GetTemplate() *RootSyncTemplate { - if o == nil { - return nil - } - return o.Template -} - -type ClusterRef struct { - ApiVersion string `json:"apiVersion,omitempty"` - Kind string `json:"kind,omitempty"` - Name string `json:"name,omitempty"` - Namespace string `json:"namespace,omitempty"` -} - -func (r *ClusterRef) GetKind() string { - return r.Kind -} - -func (r *ClusterRef) GetName() string { - return r.Name -} - -func (r *ClusterRef) GetNamespace() string { - return r.Namespace -} - -func (r *ClusterRef) GetAPIVersion() string { - return r.ApiVersion -} - -type PackageRef struct { - Name string `json:"name,omitempty"` -} - -func (r *PackageRef) GetName() string { - if r == nil { - return "" - } - return r.Name -} - -type RootSyncTemplate struct { - SourceFormat string `json:"sourceFormat,omitempty"` - // Git *GitInfo `json:"git,omitempty"` - OCI *OCISpec `json:"oci,omitempty"` - - // PackageRef specifies a package as the source of the objects to be applied. - PackageRef *PackageRef `json:"packageRef,omitempty"` -} - -func (o *RootSyncTemplate) GetSourceFormat() string { - if o == nil { - return "" - } - return o.SourceFormat -} - -func (o *RootSyncTemplate) GetOCI() *OCISpec { - if o == nil { - return nil - } - return o.OCI -} - -func (o *RootSyncTemplate) GetPackageRef() *PackageRef { - if o == nil { - return nil - } - return o.PackageRef -} - -type OCISpec struct { - Repository string `json:"repository,omitempty"` -} - -func (o *OCISpec) GetRepository() string { - if o == nil { - return "" - } - return o.Repository -} - -// RootSyncSetStatus defines the observed state of RootSyncSet -type RemoteRootSyncSetStatus struct { - Targets []TargetStatus `json:"targets,omitempty"` - AggregatedStatus AggregatedStatus `json:"aggregated,omitempty"` -} - -type TargetStatus struct { - Ref ClusterRef `json:"ref,omitempty"` - // Conditions describes the reconciliation state of the object. - Conditions []metav1.Condition `json:"conditions,omitempty"` -} - -type AggregatedStatus struct { - Targets int32 `json:"total"` - Applied int32 `json:"applied"` - Ready int32 `json:"ready"` - // Conditions describes the reconciliation state of the object. - Conditions []metav1.Condition `json:"conditions,omitempty"` -} - -//+kubebuilder:object:root=true - -// RemoteRootSyncSetList contains a list of RemoteRootSyncSet -type RemoteRootSyncSetList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []RemoteRootSyncSet `json:"items"` -} - -func init() { - SchemeBuilder.Register(&RemoteRootSyncSet{}, &RemoteRootSyncSetList{}) -} diff --git a/porch/controllers/remoterootsyncsets/api/v1alpha1/zz_generated.deepcopy.go b/porch/controllers/remoterootsyncsets/api/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index 4cc60c0147..0000000000 --- a/porch/controllers/remoterootsyncsets/api/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,253 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// Copyright 2023 The kpt 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 controller-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AggregatedStatus) DeepCopyInto(out *AggregatedStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AggregatedStatus. -func (in *AggregatedStatus) DeepCopy() *AggregatedStatus { - if in == nil { - return nil - } - out := new(AggregatedStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ClusterRef) DeepCopyInto(out *ClusterRef) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterRef. -func (in *ClusterRef) DeepCopy() *ClusterRef { - if in == nil { - return nil - } - out := new(ClusterRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OCISpec) DeepCopyInto(out *OCISpec) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OCISpec. -func (in *OCISpec) DeepCopy() *OCISpec { - if in == nil { - return nil - } - out := new(OCISpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRef) DeepCopyInto(out *PackageRef) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRef. -func (in *PackageRef) DeepCopy() *PackageRef { - if in == nil { - return nil - } - out := new(PackageRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RemoteRootSyncSet) DeepCopyInto(out *RemoteRootSyncSet) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemoteRootSyncSet. -func (in *RemoteRootSyncSet) DeepCopy() *RemoteRootSyncSet { - if in == nil { - return nil - } - out := new(RemoteRootSyncSet) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RemoteRootSyncSet) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RemoteRootSyncSetList) DeepCopyInto(out *RemoteRootSyncSetList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]RemoteRootSyncSet, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemoteRootSyncSetList. -func (in *RemoteRootSyncSetList) DeepCopy() *RemoteRootSyncSetList { - if in == nil { - return nil - } - out := new(RemoteRootSyncSetList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RemoteRootSyncSetList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RemoteRootSyncSetSpec) DeepCopyInto(out *RemoteRootSyncSetSpec) { - *out = *in - if in.ClusterRefs != nil { - in, out := &in.ClusterRefs, &out.ClusterRefs - *out = make([]*ClusterRef, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(ClusterRef) - **out = **in - } - } - } - if in.Template != nil { - in, out := &in.Template, &out.Template - *out = new(RootSyncTemplate) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemoteRootSyncSetSpec. -func (in *RemoteRootSyncSetSpec) DeepCopy() *RemoteRootSyncSetSpec { - if in == nil { - return nil - } - out := new(RemoteRootSyncSetSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RemoteRootSyncSetStatus) DeepCopyInto(out *RemoteRootSyncSetStatus) { - *out = *in - if in.Targets != nil { - in, out := &in.Targets, &out.Targets - *out = make([]TargetStatus, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - in.AggregatedStatus.DeepCopyInto(&out.AggregatedStatus) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemoteRootSyncSetStatus. -func (in *RemoteRootSyncSetStatus) DeepCopy() *RemoteRootSyncSetStatus { - if in == nil { - return nil - } - out := new(RemoteRootSyncSetStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RootSyncTemplate) DeepCopyInto(out *RootSyncTemplate) { - *out = *in - if in.OCI != nil { - in, out := &in.OCI, &out.OCI - *out = new(OCISpec) - **out = **in - } - if in.PackageRef != nil { - in, out := &in.PackageRef, &out.PackageRef - *out = new(PackageRef) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RootSyncTemplate. -func (in *RootSyncTemplate) DeepCopy() *RootSyncTemplate { - if in == nil { - return nil - } - out := new(RootSyncTemplate) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TargetStatus) DeepCopyInto(out *TargetStatus) { - *out = *in - out.Ref = in.Ref - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetStatus. -func (in *TargetStatus) DeepCopy() *TargetStatus { - if in == nil { - return nil - } - out := new(TargetStatus) - in.DeepCopyInto(out) - return out -} diff --git a/porch/controllers/remoterootsyncsets/config/rbac/role.yaml b/porch/controllers/remoterootsyncsets/config/rbac/role.yaml deleted file mode 100644 index 4fb18d00f7..0000000000 --- a/porch/controllers/remoterootsyncsets/config/rbac/role.yaml +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - name: porch-controllers-remoterootsyncsets -rules: -- apiGroups: - - config.porch.kpt.dev - resources: - - remoterootsyncsets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - config.porch.kpt.dev - resources: - - remoterootsyncsets/finalizers - verbs: - - update -- apiGroups: - - config.porch.kpt.dev - resources: - - remoterootsyncsets/status - verbs: - - get - - patch - - update -- apiGroups: - - configcontroller.cnrm.cloud.google.com - resources: - - configcontrollerinstances - verbs: - - get - - list - - watch -- apiGroups: - - container.cnrm.cloud.google.com - resources: - - containerclusters - verbs: - - get - - list - - watch -- apiGroups: - - core.cnrm.cloud.google.com - resources: - - configconnectorcontexts - - configconnectors - verbs: - - get - - list - - watch -- apiGroups: - - gkehub.cnrm.cloud.google.com - resources: - - gkehubmemberships - verbs: - - get - - list - - watch -- apiGroups: - - porch.kpt.dev - resources: - - packagerevisionresources - - packagerevisions - verbs: - - get - - list - - watch diff --git a/porch/controllers/remoterootsyncsets/config/rbac/rolebinding.yaml b/porch/controllers/remoterootsyncsets/config/rbac/rolebinding.yaml deleted file mode 100644 index 7120737725..0000000000 --- a/porch/controllers/remoterootsyncsets/config/rbac/rolebinding.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: porch-system:porch-controllers-remoterootsyncsets -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: porch-controllers-remoterootsyncsets -subjects: -- kind: ServiceAccount - name: porch-controllers - namespace: porch-system \ No newline at end of file diff --git a/porch/controllers/remoterootsyncsets/config/samples/apply-to-gke.yaml b/porch/controllers/remoterootsyncsets/config/samples/apply-to-gke.yaml deleted file mode 100644 index edf7e14570..0000000000 --- a/porch/controllers/remoterootsyncsets/config/samples/apply-to-gke.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: container.cnrm.cloud.google.com/v1beta1 -kind: ContainerCluster -metadata: - name: porch-target-1 - namespace: config-control -spec: - description: A test workload cluster - location: us-central1 - initialNodeCount: 1 - releaseChannel: - channel: STABLE - ---- - -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: RemoteRootSyncSet -metadata: - name: example-1 - namespace: config-control -spec: - clusterRefs: - - apiVersion: container.cnrm.cloud.google.com/v1beta1 - kind: ContainerCluster - name: porch-target-1 - namespace: config-control - template: {} \ No newline at end of file diff --git a/porch/controllers/remoterootsyncsets/config/samples/hack-self-apply-rbac.yaml b/porch/controllers/remoterootsyncsets/config/samples/hack-self-apply-rbac.yaml deleted file mode 100644 index a46c556cfd..0000000000 --- a/porch/controllers/remoterootsyncsets/config/samples/hack-self-apply-rbac.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2022 The kpt 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. - -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: porch-controllers-self-apply -rules: -- apiGroups: - - "" - - "apps" - - "rbac.authorization.k8s.io" - - "authentication.k8s.io" - - "authorization.k8s.io" - - "apiregistration.k8s.io" - - "admissionregistration.k8s.io" - - "flowcontrol.apiserver.k8s.io" - - "mutatingwebhookconfigurations" - - "validatingwebhookconfigurations" - resources: ["*"] - verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] - ---- - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: porch-system:porch-controllers:porch-controllers-self-apply -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: porch-controllers-self-apply -subjects: -- kind: ServiceAccount - name: porch-controllers - namespace: porch-system diff --git a/porch/controllers/remoterootsyncsets/config/samples/hack-self-apply.yaml b/porch/controllers/remoterootsyncsets/config/samples/hack-self-apply.yaml deleted file mode 100644 index 6fb9c87ee4..0000000000 --- a/porch/controllers/remoterootsyncsets/config/samples/hack-self-apply.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2022 The kpt 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. - - -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: RemoteRootSyncSet -metadata: - name: loopback-apply - namespace: default -spec: - clusterRefs: - - apiVersion: container.cnrm.cloud.google.com/v1beta1 - kind: ContainerCluster - name: loopback! # TODO: This is a hack used during development, remove once we are more end-to-end enabled. - template: - oci: - #repository: us-west1-docker.pkg.dev/example-google-project-id/packages/porch:v0.0.1 - repository: us-west1-docker.pkg.dev/example-google-project-id/deployment/helloserver:v1 diff --git a/porch/controllers/remoterootsyncsets/pkg/applyset/applyset.go b/porch/controllers/remoterootsyncsets/pkg/applyset/applyset.go deleted file mode 100644 index 6bfbc2e486..0000000000 --- a/porch/controllers/remoterootsyncsets/pkg/applyset/applyset.go +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2022 The kpt 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. - -package applyset - -import ( - "context" - "encoding/json" - "fmt" - "sync" - - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/dynamic" - "k8s.io/klog/v2" - "sigs.k8s.io/cli-utils/pkg/kstatus/status" -) - -// ApplySet is a set of objects that we want to apply to the cluster. -// -// An ApplySet has a few cases which it tries to optimize for: -// * We can change the objects we're applying -// * We want to watch the objects we're applying / be notified of changes -// * We want to know when the objects we apply are "healthy" -// * We expose a "try once" method to better support running from a controller. -// -// TODO: Pluggable health functions. -// TODO: Pruning -type ApplySet struct { - // client is the dynamic kubernetes client used to apply objects to the k8s cluster. - client dynamic.Interface - // restMapper is used to map object kind to resources, and to know if objects are cluster-scoped. - restMapper meta.RESTMapper - // patchOptions holds the options used when applying, in particular the fieldManager - patchOptions metav1.PatchOptions - - // mutex guards trackers - mutex sync.Mutex - // trackers is a (mutable) pointer to the (immutable) objectTrackerList, containing a list of objects we are applying. - trackers *objectTrackerList -} - -// Options holds the parameters for building an ApplySet. -type Options struct { - // Client is the dynamic kubernetes client used to apply objects to the k8s cluster. - Client dynamic.Interface - // RESTMapper is used to map object kind to resources, and to know if objects are cluster-scoped. - RESTMapper meta.RESTMapper - // PatchOptions holds the options used when applying, in particular the fieldManager - PatchOptions metav1.PatchOptions -} - -// New constructs a new ApplySet -func New(options Options) (*ApplySet, error) { - a := &ApplySet{ - client: options.Client, - restMapper: options.RESTMapper, - patchOptions: options.PatchOptions, - } - a.trackers = &objectTrackerList{} - return a, nil -} - -// ReplaceAllObjects is used to replace the desired state of all the objects. -// Any objects not specified are removed from the "desired" set. -func (a *ApplySet) ReplaceAllObjects(objects []ApplyableObject) error { - a.mutex.Lock() - defer a.mutex.Unlock() - - newTrackers := a.trackers.replaceAllObjects(objects) - a.trackers = newTrackers - - return nil -} - -// ApplyResults contains the results of an Apply operation. -type ApplyResults struct { - total int - applySuccessCount int - applyFailCount int - - healthyCount int - unhealthyCount int - // When apply fails, we don't know the health of the object - healthUnknownCount int -} - -// AllApplied is true if the desired state has been successfully applied for all objects. -// Note: you likely also want to check AllHealthy, if you want to be sure the objects are "ready". -func (r *ApplyResults) AllApplied() bool { - r.checkInvariants() - - return r.applyFailCount == 0 -} - -// AllHealthy is true if all the objects have been applied and have converged to a "ready" state. -// Note that this is only meaningful if AllApplied is true. -func (r *ApplyResults) AllHealthy() bool { - r.checkInvariants() - - return r.unhealthyCount == 0 -} - -// checkInvariants is an internal function that warns if the object doesn't match the expected invariants. -func (r *ApplyResults) checkInvariants() { - if r.total != (r.applySuccessCount + r.applyFailCount) { - klog.Warningf("consistency error (apply counts): %#v", r) - } else if r.total != (r.healthyCount + r.unhealthyCount + r.healthUnknownCount) { - // This "invariant" only holds when all objects could be applied - klog.Warningf("consistency error (healthy counts): %#v", r) - } -} - -// applyError records that the apply of an object failed with an error. -func (r *ApplyResults) applyError(gvk schema.GroupVersionKind, nn types.NamespacedName, err error) { - r.applyFailCount++ - r.healthUnknownCount++ - klog.Warningf("error from apply on %s %s: %v", gvk, nn, err) -} - -// applySuccess records that an object was applied and this succeeded. -func (r *ApplyResults) applySuccess(gvk schema.GroupVersionKind, nn types.NamespacedName) { - r.applySuccessCount++ -} - -// reportHealth records the health of an object. -func (r *ApplyResults) reportHealth(gvk schema.GroupVersionKind, nn types.NamespacedName, isHealthy bool) { - if isHealthy { - r.healthyCount++ - } else { - r.unhealthyCount++ - } -} - -// ApplyOnce will make one attempt to apply all objects and observe their health. -// It does not wait for the objects to become healthy, but will report their health. -// -// TODO: Limit the amount of time this takes, particularly if we have thousands of objects. -// -// We don't _have_ to try to apply all objects if it is taking too long. -// -// TODO: We re-apply every object every iteration; we should be able to do better. -func (a *ApplySet) ApplyOnce(ctx context.Context) (*ApplyResults, error) { - // snapshot the state - a.mutex.Lock() - trackers := a.trackers - a.mutex.Unlock() - - results := &ApplyResults{total: len(trackers.items)} - - for i := range trackers.items { - tracker := &trackers.items[i] - obj := tracker.desired - - name := obj.GetName() - ns := obj.GetNamespace() - gvk := obj.GroupVersionKind() - nn := types.NamespacedName{Namespace: ns, Name: name} - - restMapping, err := a.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version) - if err != nil { - results.applyError(gvk, nn, fmt.Errorf("error getting rest mapping for %v: %w", gvk, err)) - continue - } - gvr := restMapping.Resource - - var dynamicResource dynamic.ResourceInterface - - switch restMapping.Scope.Name() { - case meta.RESTScopeNameNamespace: - if ns == "" { - // TODO: Differentiate between server-fixable vs client-fixable errors? - results.applyError(gvk, nn, fmt.Errorf("namespace expected but not provided for object %v %s", gvk, obj.GetName())) - continue - } - dynamicResource = a.client.Resource(gvr).Namespace(ns) - - case meta.RESTScopeNameRoot: - dynamicResource = a.client.Resource(gvr) - - default: - // Internal error ... this is panic-level - return nil, fmt.Errorf("unknown scope for gvk %s: %q", gvk, restMapping.Scope.Name()) - } - - j, err := json.Marshal(obj) - if err != nil { - // TODO: Differentiate between server-fixable vs client-fixable errors? - results.applyError(gvk, nn, fmt.Errorf("failed to marshal object to JSON: %w", err)) - continue - } - - applied, err := dynamicResource.Patch(ctx, name, types.ApplyPatchType, j, a.patchOptions) - if err != nil { - results.applyError(gvk, nn, fmt.Errorf("error from apply: %w", err)) - continue - } - tracker.lastApplied = applied - results.applySuccess(gvk, nn) - - health, err := computeHealth(applied) - if err != nil { - klog.Warningf("error computing health: %v", err) - tracker.isHealthy = false - } else { - switch health.Status { - case status.CurrentStatus: - tracker.isHealthy = true - case status.InProgressStatus: - // TODO: Do we want a different status here? - tracker.isHealthy = false - case status.FailedStatus: - tracker.isHealthy = false - default: - klog.Warningf("unexpected health status %v", health) - tracker.isHealthy = false - } - } - results.reportHealth(gvk, nn, tracker.isHealthy) - } - return results, nil -} diff --git a/porch/controllers/remoterootsyncsets/pkg/applyset/health.go b/porch/controllers/remoterootsyncsets/pkg/applyset/health.go deleted file mode 100644 index 038c8ba05c..0000000000 --- a/porch/controllers/remoterootsyncsets/pkg/applyset/health.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2022 The kpt 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. - -package applyset - -import ( - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - - "sigs.k8s.io/cli-utils/pkg/kstatus/status" -) - -func computeHealth(u *unstructured.Unstructured) (*status.Result, error) { - return status.Compute(u) -} diff --git a/porch/controllers/remoterootsyncsets/pkg/applyset/interfaces.go b/porch/controllers/remoterootsyncsets/pkg/applyset/interfaces.go deleted file mode 100644 index 8923ed5b45..0000000000 --- a/porch/controllers/remoterootsyncsets/pkg/applyset/interfaces.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2022 The kpt 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. - -package applyset - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -type ApplyableObject interface { - GroupVersionKind() schema.GroupVersionKind - GetNamespace() string - GetName() string - - GetOwnerReferences() []metav1.OwnerReference - SetOwnerReferences([]metav1.OwnerReference) -} diff --git a/porch/controllers/remoterootsyncsets/pkg/applyset/tracker.go b/porch/controllers/remoterootsyncsets/pkg/applyset/tracker.go deleted file mode 100644 index fffc428264..0000000000 --- a/porch/controllers/remoterootsyncsets/pkg/applyset/tracker.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2022 The kpt 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. - -package applyset - -import ( - "reflect" - - "k8s.io/apimachinery/pkg/runtime" -) - -// objectTrackerList is a list of objectTrackers, containing the state of the objects we are trying to apply. -// objectTrackerList is immutable (though objectTracker is mutable); we copy-on-write when the list changes. -// TODO: Given objectTracker is mutable, should we just make objectTrackerList mutable? -type objectTrackerList struct { - items []objectTracker -} - -// objectTracker tracks the state for a single object -type objectTracker struct { - desired ApplyableObject - lastApplied runtime.Object - - desiredIsApplied bool - isHealthy bool -} - -// objectKey is the key used in maps; we consider objects with the same GVKNN the same. -type objectKey struct { - Group string - Version string - Kind string - Namespace string - Name string -} - -// computeKey returns the unique key for the object. -func computeKey(u ApplyableObject) objectKey { - gvk := u.GroupVersionKind() - return objectKey{ - Group: gvk.Group, - Version: gvk.Version, - Kind: gvk.Kind, - Namespace: u.GetNamespace(), - Name: u.GetName(), - } -} - -// replaceAllObjects completely replaces the set of objects we are interested in. -// We aim to reuse the current state where it carries over. -// Because objectTrackerList is immutable, we copy-on-write to a new objectTrackerList and return it. -func (l *objectTrackerList) replaceAllObjects(objects []ApplyableObject) *objectTrackerList { - existingTrackers := make(map[objectKey]*objectTracker) - for i := range l.items { - tracker := &l.items[i] - key := computeKey(tracker.desired) - existingTrackers[key] = tracker - } - - newList := &objectTrackerList{} - - for _, obj := range objects { - key := computeKey(obj) - // TODO: Detect duplicate keys? - existingTracker := existingTrackers[key] - if existingTracker == nil { - newList.items = append(newList.items, objectTracker{ - desired: obj, - lastApplied: nil, - desiredIsApplied: false, - isHealthy: false, - }) - } else if reflect.DeepEqual(existingTracker.desired, obj) { - newList.items = append(newList.items, objectTracker{ - desired: obj, - lastApplied: existingTracker.lastApplied, - desiredIsApplied: existingTracker.desiredIsApplied, - isHealthy: existingTracker.isHealthy, - }) - } else { - newList.items = append(newList.items, objectTracker{ - desired: obj, - lastApplied: existingTracker.lastApplied, - desiredIsApplied: false, - isHealthy: existingTracker.isHealthy, - }) - } - } - - return newList -} diff --git a/porch/controllers/remoterootsyncsets/pkg/controllers/remoterootsyncset/remoterootsync_controller.go b/porch/controllers/remoterootsyncsets/pkg/controllers/remoterootsyncset/remoterootsync_controller.go deleted file mode 100644 index afc7c436c5..0000000000 --- a/porch/controllers/remoterootsyncsets/pkg/controllers/remoterootsyncset/remoterootsync_controller.go +++ /dev/null @@ -1,536 +0,0 @@ -// Copyright 2022 The kpt 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. - -package remoterootsyncset - -import ( - "context" - "flag" - "fmt" - "strconv" - "strings" - - kptoci "github.com/GoogleContainerTools/kpt/pkg/oci" - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - api "github.com/GoogleContainerTools/kpt/porch/controllers/remoterootsyncsets/api/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/controllers/remoterootsyncsets/pkg/applyset" - "github.com/GoogleContainerTools/kpt/porch/controllers/remoterootsyncsets/pkg/remoteclient" - "github.com/GoogleContainerTools/kpt/porch/pkg/objects" - "github.com/GoogleContainerTools/kpt/porch/pkg/oci" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/rest" - "k8s.io/klog/v2" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" -) - -var ( - RootSyncNamespace = "config-management-system" - RootSyncApiVersion = "configsync.gke.io/v1beta1" - RootSyncName = "root-sync" - RootSyncKind = "RootSync" -) - -type Options struct { -} - -func (o *Options) InitDefaults() { -} - -func (o *Options) BindFlags(prefix string, flags *flag.FlagSet) { -} - -// RemoteRootSyncSetReconciler reconciles RemoteRootSyncSet objects -type RemoteRootSyncSetReconciler struct { - Options - - remoteClientGetter remoteclient.RemoteClientGetter - - client client.Client - - // uncachedClient queries the apiserver without using a watch cache. - // This is useful for PackageRevisionResources, which are large - // and would consume a lot of memory, and so we deliberately don't - // support watching them. - uncachedClient client.Client - - ociStorage *kptoci.Storage - - // localRESTConfig stores the local RESTConfig from the manager - // This is currently (only) used in "development" mode, for loopback configuration - localRESTConfig *rest.Config -} - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 rbac:roleName=porch-controllers-remoterootsyncsets webhook paths="." output:rbac:artifacts:config=../../../config/rbac - -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=remoterootsyncsets,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=remoterootsyncsets/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=remoterootsyncsets/finalizers,verbs=update -//+kubebuilder:rbac:groups=porch.kpt.dev,resources=packagerevisions;packagerevisionresources,verbs=get;list;watch - -//+kubebuilder:rbac:groups=configcontroller.cnrm.cloud.google.com,resources=configcontrollerinstances,verbs=get;list;watch -//+kubebuilder:rbac:groups=container.cnrm.cloud.google.com,resources=containerclusters,verbs=get;list;watch -//+kubebuilder:rbac:groups=gkehub.cnrm.cloud.google.com,resources=gkehubmemberships,verbs=get;list;watch - -//+kubebuilder:rbac:groups=core.cnrm.cloud.google.com,resources=configconnectors;configconnectorcontexts,verbs=get;list;watch - -// Reconcile implements the main kubernetes reconciliation loop. -func (r *RemoteRootSyncSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - var subject api.RemoteRootSyncSet - if err := r.client.Get(ctx, req.NamespacedName, &subject); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - myFinalizerName := "config.porch.kpt.dev/finalizer" - if subject.ObjectMeta.DeletionTimestamp.IsZero() { - // The object is not being deleted, so if it does not have our finalizer, - // then lets add the finalizer and update the object. This is equivalent - // registering our finalizer. - if !controllerutil.ContainsFinalizer(&subject, myFinalizerName) { - controllerutil.AddFinalizer(&subject, myFinalizerName) - if err := r.client.Update(ctx, &subject); err != nil { - return ctrl.Result{}, err - } - } - } else { - // The object is being deleted - if controllerutil.ContainsFinalizer(&subject, myFinalizerName) { - // our finalizer is present, so lets handle any external dependency - if err := r.deleteExternalResources(ctx, &subject); err != nil { - // if fail to delete the external dependency here, return with error - // so that it can be retried - return ctrl.Result{}, fmt.Errorf("have problem to delete external resource: %w", err) - } - // remove our finalizer from the list and update it. - controllerutil.RemoveFinalizer(&subject, myFinalizerName) - if err := r.client.Update(ctx, &subject); err != nil { - return ctrl.Result{}, fmt.Errorf("failed to update %s after delete finalizer: %w", req.Name, err) - } - } - // Stop reconciliation as the item is being deleted - return ctrl.Result{}, nil - } - - var result ctrl.Result - - var applyErrors []error - for _, clusterRef := range subject.Spec.ClusterRefs { - results, err := r.applyToClusterRef(ctx, &subject, clusterRef) - if err != nil { - klog.Errorf("error applying to ref %v: %v", clusterRef, err) - applyErrors = append(applyErrors, err) - } - - updateTargetStatus(&subject, clusterRef, results, err) - - // TODO: Do we ever want to do a partial flush of results? Should we exit the loop and re-reconcile? - - if results != nil && !(results.AllApplied() && results.AllHealthy()) { - result.Requeue = true - } - } - - specTargets := make(map[api.ClusterRef]bool) - for _, ref := range subject.Spec.ClusterRefs { - specTargets[*ref] = true - } - - // Remove any old target statuses - var keepTargets []api.TargetStatus - for i := range subject.Status.Targets { - target := &subject.Status.Targets[i] - if specTargets[target.Ref] { - keepTargets = append(keepTargets, *target) - } - } - subject.Status.Targets = keepTargets - - updateAggregateStatus(&subject) - - // TODO: Do this in a lazy way? - if err := r.client.Status().Update(ctx, &subject); err != nil { - return result, fmt.Errorf("error updating status: %w", err) - } - - if len(applyErrors) != 0 { - return result, applyErrors[0] - } - return result, nil -} - -func updateTargetStatus(subject *api.RemoteRootSyncSet, ref *api.ClusterRef, applyResults *applyset.ApplyResults, err error) { - var found *api.TargetStatus - for i := range subject.Status.Targets { - target := &subject.Status.Targets[i] - if target.Ref == *ref { - found = target - break - } - } - if found == nil { - subject.Status.Targets = append(subject.Status.Targets, api.TargetStatus{ - Ref: *ref, - }) - found = &subject.Status.Targets[len(subject.Status.Targets)-1] - } - - if err != nil { - meta.SetStatusCondition(&found.Conditions, metav1.Condition{Type: "Applied", Status: metav1.ConditionFalse, Reason: "Error", Message: err.Error()}) - meta.SetStatusCondition(&found.Conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionFalse, Reason: "UpdateInProgress"}) - } else { - if applyResults == nil { - meta.SetStatusCondition(&found.Conditions, metav1.Condition{Type: "Applied", Status: metav1.ConditionFalse, Reason: "UnknownStatus"}) - meta.SetStatusCondition(&found.Conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionFalse, Reason: "UnknownStatus"}) - } else if !applyResults.AllApplied() { - meta.SetStatusCondition(&found.Conditions, metav1.Condition{Type: "Applied", Status: metav1.ConditionFalse, Reason: "UpdateInProgress"}) - meta.SetStatusCondition(&found.Conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionFalse, Reason: "UpdateInProgress"}) - } else if !applyResults.AllHealthy() { - meta.SetStatusCondition(&found.Conditions, metav1.Condition{Type: "Applied", Status: metav1.ConditionTrue, Reason: "Applied"}) - meta.SetStatusCondition(&found.Conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionFalse, Reason: "WaitingForReady"}) - } else { - meta.SetStatusCondition(&found.Conditions, metav1.Condition{Type: "Applied", Status: metav1.ConditionTrue, Reason: "Applied"}) - meta.SetStatusCondition(&found.Conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionTrue, Reason: "Ready"}) - } - } -} - -func updateAggregateStatus(subject *api.RemoteRootSyncSet) bool { - // TODO: Verify that all targets are accounted for - - applied := make(map[string]int32) - ready := make(map[string]int32) - - targetCount := int32(0) - for _, status := range subject.Status.Targets { - targetCount++ - appliedCondition := meta.FindStatusCondition(status.Conditions, "Applied") - if appliedCondition == nil { - applied["UnknownStatus"]++ - } else { - applied[appliedCondition.Reason]++ - } - readyCondition := meta.FindStatusCondition(status.Conditions, "Ready") - if appliedCondition == nil { - ready["UnknownStatus"]++ - } else { - ready[readyCondition.Reason]++ - } - } - - conditions := &subject.Status.AggregatedStatus.Conditions - if applied["UpdateInProgress"] > 0 { - meta.SetStatusCondition(conditions, metav1.Condition{Type: "Applied", Status: metav1.ConditionTrue, Reason: "UpdateInProgress"}) - } else if applied["Error"] > 0 { - meta.SetStatusCondition(conditions, metav1.Condition{Type: "Applied", Status: metav1.ConditionTrue, Reason: "Error"}) - } else if applied["Applied"] >= targetCount { - meta.SetStatusCondition(conditions, metav1.Condition{Type: "Applied", Status: metav1.ConditionTrue, Reason: "Applied"}) - } else { - meta.SetStatusCondition(conditions, metav1.Condition{Type: "Applied", Status: metav1.ConditionTrue, Reason: "UnknownStatus"}) - } - - if ready["UpdateInProgress"] > 0 { - meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionTrue, Reason: "UpdateInProgress"}) - } else if ready["WaitingForReady"] > 0 { - meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionTrue, Reason: "WaitingForReady"}) - } else if ready["Ready"] >= targetCount { - meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionTrue, Reason: "Ready"}) - } else { - meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionTrue, Reason: "UnknownStatus"}) - } - - subject.Status.AggregatedStatus.Targets = targetCount - subject.Status.AggregatedStatus.Applied = applied["Applied"] - subject.Status.AggregatedStatus.Ready = ready["Ready"] - - return true -} - -func (r *RemoteRootSyncSetReconciler) applyToClusterRef(ctx context.Context, subject *api.RemoteRootSyncSet, clusterRef *api.ClusterRef) (*applyset.ApplyResults, error) { - remoteClient, err := r.remoteClientGetter.GetRemoteClient(ctx, clusterRef, subject.Namespace) - if err != nil { - return nil, err - } - - restMapper, err := remoteClient.RESTMapper() - if err != nil { - return nil, err - } - - dynamicClient, err := remoteClient.DynamicClient() - if err != nil { - return nil, err - } - - objects, err := r.BuildObjectsToApply(ctx, subject) - if err != nil { - return nil, err - } - - // TODO: Cache applyset - patchOptions := metav1.PatchOptions{ - FieldManager: "remoterootsync-" + subject.GetNamespace() + "-" + subject.GetName(), - } - - // We force to overcome errors like: Apply failed with 1 conflict: conflict with "kubectl-client-side-apply" using apps/v1: .spec.template.spec.containers[name="porch-server"].image - // TODO: How to handle this better - force := true - patchOptions.Force = &force - - applyset, err := applyset.New(applyset.Options{ - RESTMapper: restMapper, - Client: dynamicClient, - PatchOptions: patchOptions, - }) - if err != nil { - return nil, err - } - - if err := applyset.ReplaceAllObjects(objects); err != nil { - return nil, err - } - - results, err := applyset.ApplyOnce(ctx) - if err != nil { - return nil, fmt.Errorf("failed to apply to cluster %v: %w", clusterRef, err) - } - - // TODO: Implement pruning - - return results, nil -} - -// BuildObjectsToApply config root sync -func (r *RemoteRootSyncSetReconciler) BuildObjectsToApply(ctx context.Context, subject *api.RemoteRootSyncSet) ([]applyset.ApplyableObject, error) { - sourceFormat := subject.GetSpec().GetTemplate().GetSourceFormat() - switch sourceFormat { - case "oci": - return r.buildObjectsToApplyFromOci(ctx, subject) - case "package": - return r.buildObjectsToApplyFromPackage(ctx, subject) - default: - return nil, fmt.Errorf("unknown sourceFormat %q", sourceFormat) - } -} - -func (r *RemoteRootSyncSetReconciler) buildObjectsToApplyFromOci(ctx context.Context, subject *api.RemoteRootSyncSet) ([]applyset.ApplyableObject, error) { - repository := subject.GetSpec().GetTemplate().GetOCI().GetRepository() - if repository == "" { - return nil, fmt.Errorf("spec.template.oci.repository is not set") - } - imageName, err := kptoci.ParseImageTagName(repository) - if err != nil { - return nil, fmt.Errorf("unable to parse image %q: %w", repository, err) - } - klog.Infof("image name %s -> %#v", repository, *imageName) - - digest, err := oci.LookupImageTag(ctx, r.ociStorage, *imageName) - if err != nil { - return nil, err - } - - resources, err := oci.LoadResources(ctx, r.ociStorage, digest) - if err != nil { - return nil, err - } - - unstructureds, err := objects.Parser{}.AsUnstructureds(resources.Contents) - if err != nil { - return nil, err - } - - var applyables []applyset.ApplyableObject - for _, u := range unstructureds { - applyables = append(applyables, u) - } - return applyables, nil -} - -func (r *RemoteRootSyncSetReconciler) buildObjectsToApplyFromPackage(ctx context.Context, subject *api.RemoteRootSyncSet) ([]applyset.ApplyableObject, error) { - packageName := subject.GetSpec().GetTemplate().GetPackageRef().GetName() - if packageName == "" { - return nil, fmt.Errorf("spec.template.packageRef.name is not set") - } - - ns := subject.GetNamespace() - - var packageRevisions porchapi.PackageRevisionList - // Note that latest revision is planned for removal: #3672 - - // TODO: publish package name as label? - // TODO: Make package a first class concept? - // TODO: Have some indicator of latest revision? - if err := r.client.List(ctx, &packageRevisions, client.InNamespace(ns)); err != nil { - // Not found here is unexpected - return nil, fmt.Errorf("error listing package revisions: %w", err) - } - - var latestPackageRevision *porchapi.PackageRevision - for i := range packageRevisions.Items { - candidate := &packageRevisions.Items[i] - if candidate.Spec.PackageName != packageName { - continue - } - if !strings.Contains(candidate.Spec.RepositoryName, "deployment") { - // TODO: How can we only pick up deployment packages? Probably labels... - klog.Warningf("HACK: ignoring package that does not appear to be a deployment package") - continue - } - - candidateRevision := candidate.Spec.Revision - if !strings.HasPrefix(candidateRevision, "v") { - klog.Warningf("ignoring revision %q with unexpected format %q", candidate.Name, candidateRevision) - continue - } - - if latestPackageRevision == nil { - latestPackageRevision = candidate - } else { - latestRevision := latestPackageRevision.Spec.Revision - - if !strings.HasPrefix(latestRevision, "v") { - return nil, fmt.Errorf("unexpected revision format %q", latestRevision) - } - latestRevision = strings.TrimPrefix(latestRevision, "v") - - if !strings.HasPrefix(candidateRevision, "v") { - return nil, fmt.Errorf("unexpected revision format %q", candidateRevision) - } - candidateRevision = strings.TrimPrefix(candidateRevision, "v") - - latestRevisionInt, err := strconv.Atoi(latestRevision) - if err != nil { - return nil, fmt.Errorf("unexpected revision format %q", latestRevision) - } - - candidateRevisionInt, err := strconv.Atoi(candidateRevision) - if err != nil { - return nil, fmt.Errorf("unexpected revision format %q", candidateRevision) - } - - if candidateRevisionInt == latestRevisionInt { - return nil, fmt.Errorf("found two package revision with same revision: %q and %q", candidate.Name, latestPackageRevision.Name) - } - - if candidateRevisionInt > latestRevisionInt { - latestPackageRevision = candidate - } - } - } - if latestPackageRevision == nil { - return nil, fmt.Errorf("cannot find latest version of package %q in namespace %q", packageName, ns) - } - - id := types.NamespacedName{ - Namespace: latestPackageRevision.Namespace, - Name: latestPackageRevision.Name, - } - klog.Infof("found latest package %q", id) - latestPackageRevisionResources := &porchapi.PackageRevisionResources{} - if err := r.uncachedClient.Get(ctx, id, latestPackageRevisionResources); err != nil { - // Not found here is unexpected - return nil, fmt.Errorf("error getting package revision resources for %v: %w", id, err) - } - - unstructureds, err := objects.Parser{}.AsUnstructureds(latestPackageRevisionResources.Spec.Resources) - if err != nil { - return nil, err - } - - var applyables []applyset.ApplyableObject - for _, u := range unstructureds { - applyables = append(applyables, u) - } - return applyables, nil -} - -// SetupWithManager sets up the controller with the Manager. -func (r *RemoteRootSyncSetReconciler) SetupWithManager(mgr ctrl.Manager) error { - if err := api.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - if err := porchapi.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - - if err := r.remoteClientGetter.Init(mgr); err != nil { - return err - } - - r.client = mgr.GetClient() - - // We need an uncachedClient to query objects directly. - // In particular we don't want to watch PackageRevisionResources, - // they are large so would have a large memory footprint, - // and we don't want to support watch on them anyway. - // If you need to watch PackageRevisionResources, you can watch PackageRevisions instead. - uncachedClient, err := client.New(mgr.GetConfig(), client.Options{ - Scheme: mgr.GetScheme(), - Mapper: mgr.GetRESTMapper(), - }) - if err != nil { - return fmt.Errorf("creating uncached client: %w", err) - } - r.uncachedClient = uncachedClient - - if err := ctrl.NewControllerManagedBy(mgr). - For(&api.RemoteRootSyncSet{}). - Complete(r); err != nil { - return err - } - - cacheDir := "./.cache" - - ociStorage, err := kptoci.NewStorage(cacheDir) - if err != nil { - return err - } - - r.ociStorage = ociStorage - - r.localRESTConfig = mgr.GetConfig() - - return nil -} - -func (r *RemoteRootSyncSetReconciler) deleteExternalResources(ctx context.Context, rootsyncset *api.RemoteRootSyncSet) error { - var deleteErrs []error - // for _, clusterRef := range rootsyncset.Spec.ClusterRefs { - // myClient, err := remoteclient.GetRemoteClient(ctx, r.Client, clusterRef, rootsyncset.Namespace) - // if err != nil { - // deleteErrs = append(deleteErrs, fmt.Errorf("failed to get client when delete resource: %w", err)) - // continue - // } - // klog.Infof("deleting external resource %s ...", rootSyncName) - // gv, err := schema.ParseGroupVersion(rootSyncApiVersion) - // if err != nil { - // deleteErrs = append(deleteErrs, fmt.Errorf("failed to parse group version when deleting external resrouces: %w", err)) - // continue - // } - // rootSyncRes := schema.GroupVersionResource{Group: gv.Group, Version: gv.Version, Resource: "rootsyncs"} - // err = myClient.Resource(rootSyncRes).Namespace("config-management-system").Delete(ctx, rootSyncName, metav1.DeleteOptions{}) - // if err != nil && !apierrors.IsNotFound(err) { - // deleteErrs = append(deleteErrs, fmt.Errorf("failed to delete external resource : %w", err)) - // } - // } - if len(deleteErrs) != 0 { - for _, deleteErr := range deleteErrs { - klog.Errorf("%v", deleteErr) - } - return deleteErrs[0] - } - klog.Infof("external resource %s delete Done!", RootSyncName) - return nil -} diff --git a/porch/controllers/remoterootsyncsets/pkg/remoteclient/getremoteclient.go b/porch/controllers/remoterootsyncsets/pkg/remoteclient/getremoteclient.go deleted file mode 100644 index a151e87165..0000000000 --- a/porch/controllers/remoterootsyncsets/pkg/remoteclient/getremoteclient.go +++ /dev/null @@ -1,438 +0,0 @@ -// Copyright 2022 The kpt 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. - -package remoteclient - -import ( - "context" - "encoding/base64" - "fmt" - "os" - - container "cloud.google.com/go/container/apiv1" - "github.com/GoogleContainerTools/kpt/porch/pkg/googleurl" - "golang.org/x/oauth2" - "golang.org/x/oauth2/google" - "google.golang.org/api/option" - containerpb "google.golang.org/genproto/googleapis/container/v1" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/discovery" - memory "k8s.io/client-go/discovery/cached" - "k8s.io/client-go/dynamic" - "k8s.io/client-go/rest" - "k8s.io/client-go/restmapper" - "k8s.io/klog/v2" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - containerClusterKind = "ContainerCluster" - containerClusterApiVersion = "container.cnrm.cloud.google.com/v1beta1" - - configControllerKind = "ConfigControllerInstance" - configControllerApiVersion = "configcontroller.cnrm.cloud.google.com/v1beta1" -) - -var hubMembershipGVK = schema.GroupVersionKind{ - Kind: "GKEHubMembership", - Group: "gkehub.cnrm.cloud.google.com", - Version: "v1beta1", -} - -type RemoteClientGetter struct { - client.Client - - workloadIdentity WorkloadIdentityHelper - - projectCache ProjectCache -} - -// Init performs one-off initialization of the object. -func (r *RemoteClientGetter) Init(mgr ctrl.Manager) error { - r.Client = mgr.GetClient() - - if err := r.projectCache.Init(mgr); err != nil { - return err - } - - return r.workloadIdentity.Init(mgr.GetConfig()) -} - -// getCCRESTConfig builds a rest.Config for accessing the config controller cluster. -func (r *RemoteClientGetter) getCCRESTConfig(ctx context.Context, cluster *unstructured.Unstructured) (*rest.Config, error) { - gkeResourceLink, _, err := unstructured.NestedString(cluster.Object, "status", "gkeResourceLink") - if err != nil { - return nil, fmt.Errorf("failed to get status.gkeResourceLink field: %w", err) - } - if gkeResourceLink == "" { - return nil, fmt.Errorf("status.gkeResourceLink not set in object") - } - googleURL, err := googleurl.ParseUnversioned(gkeResourceLink) - if err != nil { - return nil, fmt.Errorf("error parsing gkeResourceLink %q: %w", gkeResourceLink, err) - } - projectID := googleURL.Project - location := googleURL.Location - clusterName := googleURL.Extra["clusters"] - klog.Infof("cluster name is %s", clusterName) - - tokenSource, err := r.getConfigConnectorTokenSource(ctx, cluster.GetNamespace()) - if err != nil { - return nil, err - } - - // Temporary workaround for getting the cluster certificate, update after ACP add new fields - gkeClient, err := container.NewClusterManagerClient(ctx, option.WithTokenSource(tokenSource), option.WithQuotaProject(projectID)) - if err != nil { - return nil, fmt.Errorf("failed to create new cluster manager client: %w", err) - } - defer gkeClient.Close() - - clusterSelfLink := "projects/" + projectID + "/locations/" + location + "/clusters/" + clusterName - klog.Infof("cluster path is %s", clusterSelfLink) - req := &containerpb.GetClusterRequest{ - Name: clusterSelfLink, - } - - resp, err := gkeClient.GetCluster(ctx, req) - if err != nil { - return nil, fmt.Errorf("failed to get target cluster info: %w", err) - } - - restConfig := &rest.Config{} - caData, err := base64.StdEncoding.DecodeString(resp.MasterAuth.ClusterCaCertificate) - if err != nil { - return nil, fmt.Errorf("error decoding ca certificate: %w", err) - } - restConfig.CAData = caData - - restConfig.Host = "https://" + resp.Endpoint - klog.Infof("Host endpoint is %s", restConfig.Host) - - token, err := tokenSource.Token() - if err != nil { - return nil, fmt.Errorf("error getting token: %w", err) - } - - restConfig.BearerToken = token.AccessToken - return restConfig, nil -} - -// getConfigConnectorTokenSource gets and returns the token source to authenticate as KCC in the given namespace. -func (r *RemoteClientGetter) getConfigConnectorTokenSource(ctx context.Context, ns string) (oauth2.TokenSource, error) { - if os.Getenv("USE_DEV_AUTH") != "" { - klog.Warningf("using default authentication, intended for local development only") - accessTokenSource, err := GetDefaultAccessTokenSource(ctx) - if err != nil { - return nil, err - } - return accessTokenSource, nil - } - - gvr := schema.GroupVersionResource{ - Group: "core.cnrm.cloud.google.com", - Version: "v1beta1", - Resource: "configconnectors", - } - - id := types.NamespacedName{ - Name: "configconnector.core.cnrm.cloud.google.com", - } - cr, err := r.workloadIdentity.dynamicClient.Resource(gvr).Get(ctx, id.Name, metav1.GetOptions{}) - if err != nil { - return nil, fmt.Errorf("unable to get ConfigConnector resource %v: %w", id, err) - } - - mode, _, err := unstructured.NestedString(cr.Object, "spec", "mode") - if err != nil { - return nil, fmt.Errorf("error reading spec.mode from ConfigConnector resource: %w", err) - } - - // Default is namespaced - if mode == "" { - mode = "namespaced" - } - - switch mode { - case "namespaced": - return r.getConfigConnectorTokenSourceNamespaced(ctx, ns) - case "cluster": - // ok - default: - return nil, fmt.Errorf("unknown spec.mode %q in ConfigConnector resource", mode) - } - - googleServiceAccount, _, err := unstructured.NestedString(cr.Object, "spec", "googleServiceAccount") - if err != nil { - return nil, fmt.Errorf("error reading spec.googleServiceAccount from ConfigConnector resource: %w", err) - } - - if googleServiceAccount == "" { - return nil, fmt.Errorf("could not find spec.googleServiceAccount from ConfigConnector resource") - } - - kubeServiceAccount := types.NamespacedName{ - Namespace: "cnrm-system", - Name: "cnrm-controller-manager", - } - return r.workloadIdentity.GetGcloudAccessTokenSource(ctx, kubeServiceAccount, googleServiceAccount) -} - -// getConfigConnectorTokenSourceNamespaced gets and returns the ConfigConnectorContext for the given namespace, -// when running in namespace mode. -func (r *RemoteClientGetter) getConfigConnectorTokenSourceNamespaced(ctx context.Context, ns string) (oauth2.TokenSource, error) { - gvr := schema.GroupVersionResource{ - Group: "core.cnrm.cloud.google.com", - Version: "v1beta1", - Resource: "configconnectorcontexts", - } - - id := types.NamespacedName{ - Namespace: ns, - Name: "configconnectorcontext.core.cnrm.cloud.google.com", - } - cr, err := r.workloadIdentity.dynamicClient.Resource(gvr).Namespace(id.Namespace).Get(ctx, id.Name, metav1.GetOptions{}) - if err != nil { - return nil, fmt.Errorf("unable to get ConfigConnectorContext resource %v: %w", id, err) - } - - googleServiceAccount, _, err := unstructured.NestedString(cr.Object, "spec", "googleServiceAccount") - if err != nil { - return nil, fmt.Errorf("error reading spec.googleServiceAccount from ConfigConnectorContext in %q: %w", ns, err) - } - - if googleServiceAccount == "" { - return nil, fmt.Errorf("could not find spec.googleServiceAccount from ConfigConnectorContext in %q", ns) - } - - kubeServiceAccount := types.NamespacedName{ - Namespace: "cnrm-system", - Name: "cnrm-controller-manager-" + ns, - } - return r.workloadIdentity.GetGcloudAccessTokenSource(ctx, kubeServiceAccount, googleServiceAccount) -} - -type completedReference struct { - APIVersion string - Kind string - Name string - Namespace string -} - -type Reference interface { - GetAPIVersion() string - GetKind() string - GetName() string - GetNamespace() string -} - -func toCompletedReference(in Reference, defaultNamespace string) (completedReference, error) { - ref := completedReference{ - Name: in.GetName(), - Namespace: in.GetNamespace(), - APIVersion: in.GetAPIVersion(), - Kind: in.GetKind(), - } - - if ref.Namespace == "" { - ref.Namespace = defaultNamespace - } - - if ref.APIVersion == "" { - switch ref.Kind { - case containerClusterKind: - ref.APIVersion = containerClusterApiVersion - case hubMembershipGVK.Kind: - ref.APIVersion = hubMembershipGVK.GroupVersion().Identifier() - case configControllerKind: - ref.APIVersion = configControllerApiVersion - default: - return completedReference{}, fmt.Errorf("clusterRef references unknown kind %q", ref.Kind) - } - } - - return ref, nil -} - -type RemoteClient struct { - restConfig *rest.Config -} - -func (r *RemoteClient) DynamicClient() (dynamic.Interface, error) { - dynamicClient, err := dynamic.NewForConfig(r.restConfig) - if err != nil { - return nil, fmt.Errorf("failed to create a new dynamic client: %w", err) - } - return dynamicClient, nil -} - -func (r *RemoteClient) RESTMapper() (meta.RESTMapper, error) { - // TODO: Use a better discovery client - discovery, err := discovery.NewDiscoveryClientForConfig(r.restConfig) - if err != nil { - return nil, fmt.Errorf("error building discovery client: %w", err) - } - - cached := memory.NewMemCacheClient(discovery) - - restMapper := restmapper.NewDeferredDiscoveryRESTMapper(cached) - return restMapper, nil -} - -func (r *RemoteClientGetter) GetRemoteClient(ctx context.Context, clusterRef Reference, defaultNamespace string) (*RemoteClient, error) { - ref, err := toCompletedReference(clusterRef, defaultNamespace) - if err != nil { - return nil, err - } - key := types.NamespacedName{Namespace: ref.Namespace, Name: ref.Name} - - u := &unstructured.Unstructured{} - - gv, err := schema.ParseGroupVersion(ref.APIVersion) - if err != nil { - return nil, fmt.Errorf("failed to parse group version when building object: %w", err) - } - - u.SetGroupVersionKind(schema.GroupVersionKind{ - Group: gv.Group, - Version: gv.Version, - Kind: ref.Kind, - }) - if err := r.Get(ctx, key, u); err != nil { - return nil, fmt.Errorf("failed to get target cluster: %w", err) - } - - var restConfig *rest.Config - if ref.Kind == containerClusterKind { - restConfig, err = r.getGKERESTConfig(ctx, u) - } else if ref.Kind == configControllerKind { - restConfig, err = r.getCCRESTConfig(ctx, u) - } else if ref.Kind == hubMembershipGVK.Kind { - restConfig, err = r.getHubMembershipRESTConfig(ctx, u) - } else { - return nil, fmt.Errorf("failed to find target cluster, cluster kind has to be ContainerCluster or ConfigControllerInstance") - } - if err != nil { - return nil, err - } - - remoteClient := &RemoteClient{ - restConfig: restConfig, - } - return remoteClient, nil -} - -// getGKERESTConfig builds a rest.Config for accessing the specified cluster, -// without assuming that kubeconfig is correctly configured / mapped. -func (r *RemoteClientGetter) getGKERESTConfig(ctx context.Context, cluster *unstructured.Unstructured) (*rest.Config, error) { - restConfig := &rest.Config{} - - clusterCaCertificate, exist, err := unstructured.NestedString(cluster.Object, "spec", "masterAuth", "clusterCaCertificate") - if err != nil { - return nil, fmt.Errorf("failed to get spec.masterAuth.clusterCaCertificate: %w", err) - } - if !exist { - return nil, fmt.Errorf("spec.masterAuth.clusterCaCertificate field does not exist") - } - caData, err := base64.StdEncoding.DecodeString(clusterCaCertificate) - if err != nil { - return nil, fmt.Errorf("error decoding ca certificate: %w", err) - } - restConfig.CAData = caData - - endpoint, exist, err := unstructured.NestedString(cluster.Object, "status", "endpoint") - if err != nil { - return nil, fmt.Errorf("failed to get status.endpoint: %w", err) - } - if !exist { - return nil, fmt.Errorf("status.endpoint field does not exist") - } - restConfig.Host = "https://" + endpoint - klog.Infof("Host endpoint is %s", restConfig.Host) - - tokenSource, err := r.getConfigConnectorTokenSource(ctx, cluster.GetNamespace()) - if err != nil { - return nil, fmt.Errorf("error building authentication token provider: %w", err) - } - token, err := tokenSource.Token() - if err != nil { - return nil, fmt.Errorf("error getting authentication token: %w", err) - } - restConfig.BearerToken = token.AccessToken - - return restConfig, nil -} - -// getHubMembershipRESTConfig builds a rest.Config for accessing the specified cluster through connect gateway. -func (r *RemoteClientGetter) getHubMembershipRESTConfig(ctx context.Context, cluster *unstructured.Unstructured) (*rest.Config, error) { - restConfig := &rest.Config{} - - // TODO: We could really use a selfLink field here! - - projectID := cluster.GetAnnotations()["cnrm.cloud.google.com/project-id"] - if projectID == "" { - return nil, fmt.Errorf("cannot determine project-id for object") - } - - membershipName, _, err := unstructured.NestedString(cluster.Object, "spec", "resourceID") - if err != nil { - return nil, fmt.Errorf("failed to get spec.resourceID: %w", err) - } - if membershipName == "" { - return nil, fmt.Errorf("spec.resourceID field was not set") - } - - tokenSource, err := r.getConfigConnectorTokenSource(ctx, cluster.GetNamespace()) - if err != nil { - return nil, fmt.Errorf("error building authentication token provider: %w", err) - } - - projectInfo, err := r.projectCache.LookupByProjectID(ctx, projectID, tokenSource) - if err != nil { - return nil, err - } - - host := fmt.Sprintf("https://connectgateway.googleapis.com/v1/projects/%d/locations/global/memberships/%s", projectInfo.ProjectNumber, membershipName) - restConfig.Host = host - klog.Infof("Host endpoint is %s", restConfig.Host) - - token, err := tokenSource.Token() - if err != nil { - return nil, fmt.Errorf("error getting authentication token: %w", err) - } - - restConfig.BearerToken = token.AccessToken - - return restConfig, nil -} - -// GetDefaultAccessTokenSource gets the default gcloud access token, -// assuming the user has logged in with gcloud (the application-default context). -// This is intended for local development. -func GetDefaultAccessTokenSource(ctx context.Context) (oauth2.TokenSource, error) { - // Note: Not all tools support specifying the access token, so - // the user still needs to log in with ADC. e.g. terraform - // https://github.com/hashicorp/terraform/issues/21680 - - defaultTokenSource, err := google.DefaultTokenSource(ctx, "https://www.googleapis.com/auth/cloud-platform") - if err != nil { - return nil, fmt.Errorf("unable to get default access-token from gcloud: %w", err) - } - return defaultTokenSource, nil -} diff --git a/porch/controllers/remoterootsyncsets/pkg/remoteclient/projectcache.go b/porch/controllers/remoterootsyncsets/pkg/remoteclient/projectcache.go deleted file mode 100644 index 2eed2dfda7..0000000000 --- a/porch/controllers/remoterootsyncsets/pkg/remoteclient/projectcache.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2022 The kpt 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. - -package remoteclient - -import ( - "context" - "fmt" - - "golang.org/x/oauth2" - cloudresourcemanagerv1 "google.golang.org/api/cloudresourcemanager/v1" - "google.golang.org/api/option" - ctrl "sigs.k8s.io/controller-runtime" -) - -type ProjectCache struct { -} - -type ProjectInfo struct { - ProjectID string - ProjectNumber int64 -} - -// Init performs one-off initialization of the object. -func (r *ProjectCache) Init(mgr ctrl.Manager) error { - return nil -} - -func (r *ProjectCache) LookupByProjectID(ctx context.Context, projectID string, tokenSource oauth2.TokenSource) (*ProjectInfo, error) { - // TODO: Cache - - crmClient, err := cloudresourcemanagerv1.NewService(ctx, option.WithTokenSource(tokenSource)) - if err != nil { - return nil, fmt.Errorf("failed to create new cloudresourcemanager client: %w", err) - } - - project, err := crmClient.Projects.Get(projectID).Context(ctx).Do() - if err != nil { - return nil, fmt.Errorf("error querying project %q: %w", projectID, err) - } - - return &ProjectInfo{ - ProjectID: project.ProjectId, - ProjectNumber: project.ProjectNumber, - }, nil -} diff --git a/porch/controllers/remoterootsyncsets/pkg/remoteclient/tokens.go b/porch/controllers/remoterootsyncsets/pkg/remoteclient/tokens.go deleted file mode 100644 index f471b2ad5e..0000000000 --- a/porch/controllers/remoterootsyncsets/pkg/remoteclient/tokens.go +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2022 The kpt 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. - -package remoteclient - -import ( - "context" - "fmt" - "io/ioutil" - "os" - "strings" - "sync" - - "github.com/GoogleContainerTools/kpt/porch/pkg/tokenexchange/gcptokensource" - "github.com/GoogleContainerTools/kpt/porch/pkg/tokenexchange/ksaimpersonationtokensource" - "github.com/GoogleContainerTools/kpt/porch/pkg/tokenexchange/ksatokensource" - "github.com/GoogleContainerTools/kpt/porch/pkg/tokenexchange/membership" - "golang.org/x/oauth2" - "google.golang.org/api/option" - "google.golang.org/api/sts/v1" - stsv1 "google.golang.org/api/sts/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/dynamic" - corev1client "k8s.io/client-go/kubernetes/typed/core/v1" - "k8s.io/client-go/rest" - "k8s.io/klog/v2" -) - -// WorkloadIdentityHelper is a helper class that does the exchanges needed for workload identity. -type WorkloadIdentityHelper struct { - // stsClient holds a client for querying STS - stsClient *stsv1.Service - - // corev1Client is used for kubernetes impersonation - corev1Client corev1client.CoreV1Interface - - // dynamicClient is used to check for the membership resource - dynamicClient dynamic.Interface - - restConfig *rest.Config - - mutex sync.Mutex - tokenCache map[tokenCacheKey]oauth2.TokenSource -} - -type tokenCacheKey struct { - kubeServiceAccount types.NamespacedName - gcpServiceAccount string -} - -// Init should be called before using a WorkloadIdentityHelper -func (r *WorkloadIdentityHelper) Init(restConfig *rest.Config) error { - r.restConfig = restConfig - - // If we want to debug RBAC/Token Exchange locally... - // restConfigImpersonate := *restConfig - // restConfigImpersonate.Impersonate.UserName = "system:serviceaccount:configcontroller-system:rootsyncset-impersonate" - // restConfig = &restConfigImpersonate - - corev1Client, err := corev1client.NewForConfig(restConfig) - if err != nil { - return fmt.Errorf("error building corev1 client: %w", err) - } - r.corev1Client = corev1Client - - dynamicClient, err := dynamic.NewForConfig(restConfig) - if err != nil { - return fmt.Errorf("error building dynamic client: %w", err) - } - r.dynamicClient = dynamicClient - - // option.WithoutAuthentication because we don't want to use our credentials for the exchange - // STS actually gives an error: googleapi: "Error 400: Request contains an invalid argument., badRequest" - stsClient, err := sts.NewService(context.Background(), option.WithoutAuthentication()) - if err != nil { - return fmt.Errorf("error building sts client: %w", err) - } - r.stsClient = stsClient - - r.tokenCache = make(map[tokenCacheKey]oauth2.TokenSource) - - return nil -} - -// GetGcloudAccessTokenSource does the exchange to get a token for the specified GCP ServiceAccount. -func (r *WorkloadIdentityHelper) GetGcloudAccessTokenSource(ctx context.Context, kubeServiceAccount types.NamespacedName, gcpServiceAccount string) (oauth2.TokenSource, error) { - key := tokenCacheKey{ - kubeServiceAccount: kubeServiceAccount, - gcpServiceAccount: gcpServiceAccount, - } - - r.mutex.Lock() - cachedTokenSource := r.tokenCache[key] - r.mutex.Unlock() - - if cachedTokenSource != nil { - return cachedTokenSource, nil - } - - var workloadIdentityPool string - var identityProvider string - - membershipConfig, err := membership.Get(ctx, r.dynamicClient) - if err != nil { - if apierrors.IsNotFound(err) { - // TODO: Cache this? - workloadIdentityPool, identityProvider, err = r.findWorkloadIdentityPool(ctx, kubeServiceAccount) - if err != nil { - return nil, err - } - } else { - return nil, fmt.Errorf("error fetching membership: %w", err) - } - } else { - workloadIdentityPool = membershipConfig.Spec.WorkloadIdentityPool - identityProvider = membershipConfig.Spec.IdentityProvider - } - - impersonated := ksaimpersonationtokensource.New(r.corev1Client, kubeServiceAccount, []string{workloadIdentityPool}) - - ksaToken := ksatokensource.New(r.stsClient, impersonated, workloadIdentityPool, identityProvider) - - var scopes []string - gcpTokenSource := gcptokensource.New(gcpServiceAccount, scopes, ksaToken) - - tokenSource := oauth2.ReuseTokenSource(nil, gcpTokenSource) - - r.mutex.Lock() - r.tokenCache[key] = tokenSource - r.mutex.Unlock() - - return tokenSource, nil -} - -func (r *WorkloadIdentityHelper) findWorkloadIdentityPool(ctx context.Context, kubeServiceAccount types.NamespacedName) (string, string, error) { - accessToken := "" - - // First, see if we have a valid token mounted locally in our pod - { - const tokenFilePath = "/var/run/secrets/kubernetes.io/serviceaccount/token" - - tokenBytes, err := ioutil.ReadFile(tokenFilePath) - if err != nil { - if os.IsNotExist(err) { - klog.V(2).Infof("token file not found at %q", tokenFilePath) - } else { - klog.Warningf("error reading token file from %q: %v", tokenFilePath, err) - } - } else { - klog.Infof("found token at %q", tokenFilePath) - accessToken = string(tokenBytes) - } - } - - // We could also query the kube apiserver at /.well-known/openid-configuration - // kubectl get --raw /.well-known/openid-configuration - // {"issuer":"https://container.googleapis.com/v1/projects/example-project-id/locations/us-central1/clusters/krmapihost-control","jwks_uri":"https://172.16.0.130:443/openid/v1/jwks","response_types_supported":["id_token"],"subject_types_supported":["public"],"id_token_signing_alg_values_supported":["RS256"]} - - if accessToken == "" { - // We get a token for our own service account, so we can extract the issuer - klog.Infof("token not found at well-known path, requesting token from apiserver") - impersonated := ksaimpersonationtokensource.New(r.corev1Client, kubeServiceAccount, nil /* unspecified/default audience */) - - token, err := impersonated.Token() - if err != nil { - return "", "", fmt.Errorf("failed to get kube token for %s: %w", kubeServiceAccount, err) - } else { - accessToken = token.AccessToken - } - } - - issuer, err := ksatokensource.ExtractIssuer(accessToken) - if err != nil { - return "", "", err - } - - if strings.HasPrefix(issuer, "https://container.googleapis.com/") { - path := strings.TrimPrefix(issuer, "https://container.googleapis.com/") - tokens := strings.Split(path, "/") - for i := 0; i+1 < len(tokens); i++ { - if tokens[i] == "projects" { - workloadIdentityPool := tokens[i+1] + ".svc.id.goog" - klog.Infof("inferred workloadIdentityPool as %q", workloadIdentityPool) - return workloadIdentityPool, issuer, nil - } - } - return "", "", fmt.Errorf("could not extract project from issue %q", issuer) - } else { - return "", "", fmt.Errorf("unknown issuer %q", issuer) - } -} diff --git a/porch/controllers/rootsyncdeployments/api/v1alpha1/groupversion_info.go b/porch/controllers/rootsyncdeployments/api/v1alpha1/groupversion_info.go deleted file mode 100644 index b0010b886f..0000000000 --- a/porch/controllers/rootsyncdeployments/api/v1alpha1/groupversion_info.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2022 The kpt 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. - -// Package v1alpha1 contains API Schema definitions for the config.porch.kpt.dev v1alpha1 API group -// +kubebuilder:object:generate=true -// +groupName=config.porch.kpt.dev -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/scheme" -) - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 object:headerFile="../../../../scripts/boilerplate.go.txt" paths="./..." - -var ( - // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "config.porch.kpt.dev", Version: "v1alpha1"} - - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} - - // AddToScheme adds the types in this group-version to the given scheme. - AddToScheme = SchemeBuilder.AddToScheme -) diff --git a/porch/controllers/rootsyncdeployments/api/v1alpha1/rootsyncdeployments_types.go b/porch/controllers/rootsyncdeployments/api/v1alpha1/rootsyncdeployments_types.go deleted file mode 100644 index d1b022e345..0000000000 --- a/porch/controllers/rootsyncdeployments/api/v1alpha1/rootsyncdeployments_types.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2022 The kpt 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. - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// RootSyncDeploymentSpec defines the desired state of RootSyncDeployment -type RootSyncDeploymentSpec struct { - Targets ClusterTargetSelector `json:"targets,omitempty"` - PackageRevision PackageRevisionRef `json:"packageRevision,omitempty"` -} - -type ClusterTargetSelector struct { - Selector *metav1.LabelSelector `json:"selector,omitempty"` -} - -type PackageRevisionRef struct { - Name string `json:"name,omitempty"` - Namespace string `json:"namespace,omitempty"` -} - -// RootSyncDeploymentStatus defines the observed state of RootSyncDeployment -type RootSyncDeploymentStatus struct { - ObservedGeneration int64 `json:"observedGeneration,omitempty"` - - // Conditions describes the reconciliation state of the object. - Conditions []metav1.Condition `json:"conditions,omitempty"` - - ClusterRefStatuses []ClusterRefStatus `json:"clusterRefStatuses,omitempty"` -} - -type ClusterRefStatus struct { - ApiVersion string `json:"apiVersion,omitempty"` - Kind string `json:"kind,omitempty"` - Name string `json:"name,omitempty"` - Namespace string `json:"namespace,omitempty"` - Revision string `json:"revision,omitempty"` - Synced bool `json:"synced"` -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// RootSyncDeployment is the Schema for the rootsyncdeployments API -type RootSyncDeployment struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec RootSyncDeploymentSpec `json:"spec,omitempty"` - Status RootSyncDeploymentStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// RootSyncDeploymentList contains a list of RootSyncDeployment -type RootSyncDeploymentList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []RootSyncDeployment `json:"items"` -} - -func init() { - SchemeBuilder.Register(&RootSyncDeployment{}, &RootSyncDeploymentList{}) -} diff --git a/porch/controllers/rootsyncdeployments/api/v1alpha1/zz_generated.deepcopy.go b/porch/controllers/rootsyncdeployments/api/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index 55e13626a4..0000000000 --- a/porch/controllers/rootsyncdeployments/api/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,178 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// Copyright 2023 The kpt 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 controller-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ClusterRefStatus) DeepCopyInto(out *ClusterRefStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterRefStatus. -func (in *ClusterRefStatus) DeepCopy() *ClusterRefStatus { - if in == nil { - return nil - } - out := new(ClusterRefStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ClusterTargetSelector) DeepCopyInto(out *ClusterTargetSelector) { - *out = *in - if in.Selector != nil { - in, out := &in.Selector, &out.Selector - *out = new(v1.LabelSelector) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTargetSelector. -func (in *ClusterTargetSelector) DeepCopy() *ClusterTargetSelector { - if in == nil { - return nil - } - out := new(ClusterTargetSelector) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevisionRef) DeepCopyInto(out *PackageRevisionRef) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevisionRef. -func (in *PackageRevisionRef) DeepCopy() *PackageRevisionRef { - if in == nil { - return nil - } - out := new(PackageRevisionRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RootSyncDeployment) DeepCopyInto(out *RootSyncDeployment) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RootSyncDeployment. -func (in *RootSyncDeployment) DeepCopy() *RootSyncDeployment { - if in == nil { - return nil - } - out := new(RootSyncDeployment) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RootSyncDeployment) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RootSyncDeploymentList) DeepCopyInto(out *RootSyncDeploymentList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]RootSyncDeployment, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RootSyncDeploymentList. -func (in *RootSyncDeploymentList) DeepCopy() *RootSyncDeploymentList { - if in == nil { - return nil - } - out := new(RootSyncDeploymentList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RootSyncDeploymentList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RootSyncDeploymentSpec) DeepCopyInto(out *RootSyncDeploymentSpec) { - *out = *in - in.Targets.DeepCopyInto(&out.Targets) - out.PackageRevision = in.PackageRevision -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RootSyncDeploymentSpec. -func (in *RootSyncDeploymentSpec) DeepCopy() *RootSyncDeploymentSpec { - if in == nil { - return nil - } - out := new(RootSyncDeploymentSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RootSyncDeploymentStatus) DeepCopyInto(out *RootSyncDeploymentStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.ClusterRefStatuses != nil { - in, out := &in.ClusterRefStatuses, &out.ClusterRefStatuses - *out = make([]ClusterRefStatus, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RootSyncDeploymentStatus. -func (in *RootSyncDeploymentStatus) DeepCopy() *RootSyncDeploymentStatus { - if in == nil { - return nil - } - out := new(RootSyncDeploymentStatus) - in.DeepCopyInto(out) - return out -} diff --git a/porch/controllers/rootsyncdeployments/config/rbac/role.yaml b/porch/controllers/rootsyncdeployments/config/rbac/role.yaml deleted file mode 100644 index 822bc351e0..0000000000 --- a/porch/controllers/rootsyncdeployments/config/rbac/role.yaml +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - name: porch-controllers-rootsyncdeployments -rules: -- apiGroups: - - config.porch.kpt.dev - resources: - - repositories - verbs: - - get - - list - - watch -- apiGroups: - - config.porch.kpt.dev - resources: - - rootsyncdeployments - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - config.porch.kpt.dev - resources: - - rootsyncdeployments/finalizers - verbs: - - update -- apiGroups: - - config.porch.kpt.dev - resources: - - rootsyncdeployments/status - verbs: - - get - - patch - - update -- apiGroups: - - configcontroller.cnrm.cloud.google.com - resources: - - configcontrollerinstances - verbs: - - get - - list - - watch -- apiGroups: - - container.cnrm.cloud.google.com - resources: - - containerclusters - verbs: - - get - - list - - watch -- apiGroups: - - core.cnrm.cloud.google.com - resources: - - configconnectorcontexts - - configconnectors - verbs: - - get - - list - - watch -- apiGroups: - - gkehub.cnrm.cloud.google.com - resources: - - gkehubmemberships - verbs: - - get - - list - - watch -- apiGroups: - - porch.kpt.dev - resources: - - packagerevisions - verbs: - - get - - list - - watch diff --git a/porch/controllers/rootsyncdeployments/config/rbac/rolebinding.yaml b/porch/controllers/rootsyncdeployments/config/rbac/rolebinding.yaml deleted file mode 100644 index 120ba9ebb5..0000000000 --- a/porch/controllers/rootsyncdeployments/config/rbac/rolebinding.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: porch-system:porch-controllers-rootsyncdeployments -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: porch-controllers-rootsyncdeployments -subjects: -- kind: ServiceAccount - name: porch-controllers - namespace: porch-system \ No newline at end of file diff --git a/porch/controllers/rootsyncdeployments/config/samples/README.md b/porch/controllers/rootsyncdeployments/config/samples/README.md deleted file mode 100644 index 9b2d1f1cbb..0000000000 --- a/porch/controllers/rootsyncdeployments/config/samples/README.md +++ /dev/null @@ -1,118 +0,0 @@ -# Simple example - -This example adds a RootSyncDeployment with name `simple` that will deploy the referenced -PackageRevision to all GKE or Config Controller clusters with the `foo: bar` label. When the -version of the PackageRevision is changed, the clusters will be updated progressively. - -## Setup - -### Clusters -Create clusters with Config Connector using the following two manifests: -``` -apiVersion: container.cnrm.cloud.google.com/v1beta1 -kind: ContainerCluster -metadata: - name: gke-one - namespace: config-control -spec: - location: us-central1 - initialNodeCount: 1 - workloadIdentityConfig: - workloadPool: ${PROJECT-ID}.svc.id.goog -``` - -``` -apiVersion: container.cnrm.cloud.google.com/v1beta1 -kind: ContainerCluster -metadata: - name: gke-two - namespace: config-control -spec: - location: us-central1 - initialNodeCount: 1 - workloadIdentityConfig: - workloadPool: ${PROJECT-ID}.svc.id.goog -``` - -Install Config Management through the Google Cloud console to make sure -Config Sync is available in the cluster. - -### Porch package -Make sure you have a repository registered with Porch (this example assumes the repository is named `blueprint`). Create a new package `foo`, add a ConfigMap to the package, and publish it: -``` -kpt alpha rpkg init foo --repository=blueprint -n default --workspace=foo -kpt alpha rpkg pull blueprint-16f93511a8fd4774c928e09a7e135f9852161f74 -n default ./pull -cat <>./pull/cm.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: foo - namespace: default -data: - cm: foo -EOF -kpt alpha rpkg push blueprint-16f93511a8fd4774c928e09a7e135f9852161f74 -n default ./pull -kpt alpha rpkg propose blueprint-16f93511a8fd4774c928e09a7e135f9852161f74 -n default -kpt alpha rpkg approve blueprint-16f93511a8fd4774c928e09a7e135f9852161f74 -n default -rm -fr ./pull -``` - -Then create a new revision of the package and publish it. -``` -kpt alpha rpkg edit blueprint-16f93511a8fd4774c928e09a7e135f9852161f74 -n default --workspace foo2 -kpt alpha rpkg pull blueprint-93dabbfa9de63b507d13d366185a70ee2ed087f7 -n default ./pull -cat <./pull/cm.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: foo2 - namespace: default -data: - cm: foo2 -EOF -kpt alpha rpkg push blueprint-93dabbfa9de63b507d13d366185a70ee2ed087f7 -n default ./pull -kpt alpha rpkg propose blueprint-93dabbfa9de63b507d13d366185a70ee2ed087f7 -n default -kpt alpha rpkg approve blueprint-93dabbfa9de63b507d13d366185a70ee2ed087f7 -n default -rm -fr ./pull -``` - -## Running the example -Update the name of the PackageRevision in the `simple.yaml` file to point to the PackageRevision -you want to deploy (if you ended up with different names than the example) - -Label the first GKE cluster with the required labels: -``` -kubectl -n config-control label containerclusters.container.cnrm.cloud.google.com gke-one foo=bar -``` - -Apply the RootSyncDeployment to install the PackageRevision in the gke-one cluster: -``` -kubectl apply -f simple.yaml -``` - -Watch the progress: -``` -k get rootsyncdeployments.config.porch.kpt.dev simple -oyaml -w -``` - -Label the second cluster as well: -``` -kubectl -n config-control label containerclusters.container.cnrm.cloud.google.com gke-two foo=bar -``` - -Update the RootSyncDeployment spec to point to the next revision of the Package: -``` -spec: - packageRevision: - name: blueprint-93dabbfa9de63b507d13d366185a70ee2ed087f7 -``` - -Apply it again: -``` -kubectl apply -f simple.yaml -``` - -Watch the progress: -``` -k get rootsyncdeployments.config.porch.kpt.dev simple -oyaml -w -``` diff --git a/porch/controllers/rootsyncdeployments/config/samples/simple.yaml b/porch/controllers/rootsyncdeployments/config/samples/simple.yaml deleted file mode 100644 index 553d8cde1b..0000000000 --- a/porch/controllers/rootsyncdeployments/config/samples/simple.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: RootSyncDeployment -metadata: - name: simple - namespace: default -spec: - targets: - selector: - matchLabels: - foo: bar - packageRevision: - name: blueprint-16f93511a8fd4774c928e09a7e135f9852161f74 - namespace: default \ No newline at end of file diff --git a/porch/controllers/rootsyncdeployments/pkg/controllers/rootsyncdeployment/controller.go b/porch/controllers/rootsyncdeployments/pkg/controllers/rootsyncdeployment/controller.go deleted file mode 100644 index 1741659f21..0000000000 --- a/porch/controllers/rootsyncdeployments/pkg/controllers/rootsyncdeployment/controller.go +++ /dev/null @@ -1,522 +0,0 @@ -// Copyright 2022 The kpt 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. - -package rootsyncdeployment - -import ( - "context" - "flag" - "fmt" - "sync" - - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/controllers/rootsyncdeployments/api/v1alpha1" - rssapi "github.com/GoogleContainerTools/kpt/porch/controllers/rootsyncsets/api/v1alpha1" - "k8s.io/apimachinery/pkg/api/equality" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "k8s.io/klog/v2" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" -) - -const ( - rootSyncSetLabel = "config.porch.kpt.dev/rootsyncdeployment" -) - -var ( - configConnectorContainerClusterGVK = schema.GroupVersionKind{ - Group: "container.cnrm.cloud.google.com", - Version: "v1beta1", - Kind: "ContainerCluster", - } - configConnectorConfigControllerClusterGVK = schema.GroupVersionKind{ - Group: "configcontroller.cnrm.cloud.google.com", - Version: "v1beta1", - Kind: "ConfigControllerInstance", - } - rootSyncSetGVK = schema.GroupVersionKind{ - Group: "config.porch.kpt.dev", - Version: "v1alpha1", - Kind: "RootSyncSet", - } -) - -type Options struct { -} - -func (o *Options) InitDefaults() { -} - -func (o *Options) BindFlags(prefix string, flags *flag.FlagSet) { -} - -func NewRootSyncDeploymentReconciler() *RootSyncDeploymentReconciler { - return &RootSyncDeploymentReconciler{ - clusterTargetCache: make(map[types.NamespacedName]labels.Selector), - } -} - -// RootSyncDeploymentReconciler reconciles a RootSyncDeployment object -type RootSyncDeploymentReconciler struct { - Options - - client.Client - - mutex sync.Mutex - clusterTargetCache map[types.NamespacedName]labels.Selector -} - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 rbac:roleName=porch-controllers-rootsyncdeployments webhook paths="." output:rbac:artifacts:config=../../../config/rbac - -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=rootsyncdeployments,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=rootsyncdeployments/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=rootsyncdeployments/finalizers,verbs=update -//+kubebuilder:rbac:groups=porch.kpt.dev,resources=packagerevisions,verbs=get;list;watch -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=repositories,verbs=get;list;watch - -//+kubebuilder:rbac:groups=configcontroller.cnrm.cloud.google.com,resources=configcontrollerinstances,verbs=get;list;watch -//+kubebuilder:rbac:groups=container.cnrm.cloud.google.com,resources=containerclusters,verbs=get;list;watch -//+kubebuilder:rbac:groups=gkehub.cnrm.cloud.google.com,resources=gkehubmemberships,verbs=get;list;watch - -//+kubebuilder:rbac:groups=core.cnrm.cloud.google.com,resources=configconnectors;configconnectorcontexts,verbs=get;list;watch - -func (r *RootSyncDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - var rootsyncdeployment v1alpha1.RootSyncDeployment - if err := r.Get(ctx, req.NamespacedName, &rootsyncdeployment); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - - myFinalizerName := "config.porch.kpt.dev/rootsyncdeployments" - if rootsyncdeployment.ObjectMeta.DeletionTimestamp.IsZero() { - // Update the cache with mapping from rollouts to ClusterTargets. It allows the controller - // to determine which Rollouts needs to be reconciled based on an event about a cluster. - selector, err := metav1.LabelSelectorAsSelector(rootsyncdeployment.Spec.Targets.Selector) - if err != nil { - return ctrl.Result{}, fmt.Errorf("error converting targets selector to labels.Selector: %v", err) - } - func() { - r.mutex.Lock() - defer r.mutex.Unlock() - r.clusterTargetCache[req.NamespacedName] = selector - }() - - // The object is not being deleted, so if it does not have our finalizer, - // then lets add the finalizer and update the object. This is equivalent - // registering our finalizer. - if !controllerutil.ContainsFinalizer(&rootsyncdeployment, myFinalizerName) { - controllerutil.AddFinalizer(&rootsyncdeployment, myFinalizerName) - if err := r.Update(ctx, &rootsyncdeployment); err != nil { - return ctrl.Result{}, fmt.Errorf("error adding finalizer: %w", err) - } - } - } else { - // Clean up the cache. - func() { - r.mutex.Lock() - defer r.mutex.Unlock() - delete(r.clusterTargetCache, req.NamespacedName) - }() - - // The object is being deleted - if controllerutil.ContainsFinalizer(&rootsyncdeployment, myFinalizerName) { - // remove our finalizer from the list and update it. - controllerutil.RemoveFinalizer(&rootsyncdeployment, myFinalizerName) - if err := r.Update(ctx, &rootsyncdeployment); err != nil { - return ctrl.Result{}, fmt.Errorf("failed to update %s after delete finalizer: %w", req.Name, err) - } - } - // Stop reconciliation as the item is being deleted - return ctrl.Result{}, nil - } - - res, err := r.syncRootSyncDeployment(ctx, &rootsyncdeployment) - if err != nil { - return ctrl.Result{}, err - } - - if err := r.updateStatus(ctx, &rootsyncdeployment, res); err != nil { - return ctrl.Result{}, err - } - - return ctrl.Result{}, nil -} - -func (r *RootSyncDeploymentReconciler) updateStatus(ctx context.Context, rsd *v1alpha1.RootSyncDeployment, clusterRefStatuses []v1alpha1.ClusterRefStatus) error { - if equality.Semantic.DeepEqual(rsd.Status.ClusterRefStatuses, clusterRefStatuses) { - klog.Infof("Status has not changed, update not needed.") - return nil - } - rsd.Status.ObservedGeneration = rsd.Generation - rsd.Status.ClusterRefStatuses = clusterRefStatuses - return r.Status().Update(ctx, rsd) -} - -func (r *RootSyncDeploymentReconciler) syncRootSyncDeployment(ctx context.Context, rsd *v1alpha1.RootSyncDeployment) ([]v1alpha1.ClusterRefStatus, error) { - var clusterRefStatuses []v1alpha1.ClusterRefStatus - namespace := rsd.Spec.PackageRevision.Namespace - if namespace == "" { - namespace = rsd.Namespace - } - nn := types.NamespacedName{ - Name: rsd.Spec.PackageRevision.Name, - Namespace: namespace, - } - - pkgRev, err := r.getPackageRevision(ctx, nn) - if err != nil { - return clusterRefStatuses, err - } - - repo, err := r.getRepository(ctx, types.NamespacedName{ - Name: pkgRev.Spec.RepositoryName, - Namespace: pkgRev.Namespace, - }) - if err != nil { - return clusterRefStatuses, err - } - - rootSyncSetSpec := toRootSyncSpec(pkgRev, repo) - - clusters, err := r.getClusters(ctx, rsd.Spec.Targets.Selector) - if err != nil { - return clusterRefStatuses, err - } - klog.Infof("Found clusters: %s", toClusterNames(clusters)) - - rootsyncsets, err := r.listRootSyncSets(ctx, rsd.Name, rsd.Namespace) - if err != nil { - return clusterRefStatuses, err - } - klog.Infof("Found RootSyncSets: %s", toRootSyncSetNames(rootsyncsets)) - - var clustersMissingRootSync []rssapi.ClusterRef - var clustersToDeleteRootSync []*rssapi.RootSyncSet - var clustersNeedingUpdate []*rssapi.RootSyncSet - var clustersBeingUpdated []*rssapi.RootSyncSet - var upToDateClusters []*rssapi.RootSyncSet - - for i := range rootsyncsets { - rss := rootsyncsets[i] - - // TODO: See if we can remove this constraint. But it make things easier for now. - // First remove RootSyncSets for clusters where it should no longer exist. - if l := len(rss.Spec.ClusterRefs); l != 1 { - return clusterRefStatuses, - fmt.Errorf("RootSyncSet %s contains %d ClusterRefs, but it should be 1", rss.Name, l) - } - - // If the RootSyncSet references a cluster that is no longer matches by the target selector, - // we need to delete the RootSyncSet. - clusterRef := rss.Spec.ClusterRefs[0] - if !contains(clusters, clusterRef) { - clustersToDeleteRootSync = append(clustersToDeleteRootSync, rss) - continue - } - - // If the RootSync template in the RootSyncSet doesn't match the spec from the - // PackageRevision, it needs to be updated. - if !equality.Semantic.DeepEqual(rootSyncSetSpec, rss.Spec.Template.Spec) { - clustersNeedingUpdate = append(clustersNeedingUpdate, rss) - continue - } - - // If the RootSyncSet is not synced, we treat them as being the process of being updated. - // This might not be correct in all situations. - if !isRssSynced(rss) { - clustersBeingUpdated = append(clustersBeingUpdated, rss) - continue - } - upToDateClusters = append(upToDateClusters, rss) - } - - // Find any clusters that are targeted by the label selector, but - // where we don't have a RootSyncSet referencing the cluster. - for i := range clusters { - cluster := clusters[i] - ref := rssapi.ClusterRef{ - Name: cluster.GetName(), - Namespace: cluster.GetNamespace(), - ApiVersion: cluster.GetAPIVersion(), - Kind: cluster.GetKind(), - } - var found bool - for _, rss := range rootsyncsets { - rssClusterRef := *rss.Spec.ClusterRefs[0] - if equality.Semantic.DeepEqual(rssClusterRef, ref) { - found = true - } - } - if !found { - clustersMissingRootSync = append(clustersMissingRootSync, ref) - } - } - - // TODO: We should keep track of the clusters and status until we know they have been removed - // from the cluster. - for _, rss := range clustersToDeleteRootSync { - if err := r.Delete(ctx, rss); err != nil { - klog.Warningf("Error removing RootSyncSet %s: %v", rss.Name, err) - } - } - - // If we have clusters that doesn't already have the package installed, we just - // update them all. The limit to the number of clusters being updated - // concurrently (currently that is 1) does not apply here. - if len(clustersMissingRootSync) > 0 { - for _, cr := range clustersMissingRootSync { - rss := newRootSyncSet(rsd, cr, rootSyncSetSpec, pkgRev.Spec.PackageName) - if err := r.Create(ctx, rss); err != nil { - klog.Warningf("Error creating RootSyncSet %s: %v", rss.Name, err) - } - clustersBeingUpdated = append(clustersBeingUpdated, rss) - } - } - - // If no clusters are in the process of being updated and we have clusters - // that needs to be updated, just update the corresponding RootSyncSet. - if len(clustersBeingUpdated) == 0 && len(clustersNeedingUpdate) > 0 { - rss := clustersNeedingUpdate[0] - rss.Spec.Template.Spec = rootSyncSetSpec - if err := r.Update(ctx, rss); err != nil { - klog.Warningf("Error updating RootSyncSet %s: %v", rss.Name, err) - } - clustersNeedingUpdate = clustersNeedingUpdate[1:] - clustersBeingUpdated = append(clustersBeingUpdated, rss) - } - - for _, c := range upToDateClusters { - clusterRefStatuses = append(clusterRefStatuses, newClusterRefStatus(c, true)) - } - for _, c := range clustersBeingUpdated { - clusterRefStatuses = append(clusterRefStatuses, newClusterRefStatus(c, false)) - } - for _, c := range clustersNeedingUpdate { - clusterRefStatuses = append(clusterRefStatuses, newClusterRefStatus(c, isRssSynced(c))) - } - - return clusterRefStatuses, nil -} - -func newClusterRefStatus(rss *rssapi.RootSyncSet, synced bool) v1alpha1.ClusterRefStatus { - clusterRef := rss.Spec.ClusterRefs[0] - return v1alpha1.ClusterRefStatus{ - ApiVersion: clusterRef.ApiVersion, - Kind: clusterRef.Kind, - Name: clusterRef.Name, - Namespace: clusterRef.Namespace, - Revision: rss.Spec.Template.Spec.Git.Revision, - Synced: synced, - } -} - -func (r *RootSyncDeploymentReconciler) getPackageRevision(ctx context.Context, nn types.NamespacedName) (*porchapi.PackageRevision, error) { - var packageRevision porchapi.PackageRevision - if err := r.Get(ctx, nn, &packageRevision); err != nil { - return nil, err - } - return &packageRevision, nil -} - -func (r *RootSyncDeploymentReconciler) getRepository(ctx context.Context, nn types.NamespacedName) (*configapi.Repository, error) { - var repository configapi.Repository - if err := r.Get(ctx, nn, &repository); err != nil { - return nil, err - } - return &repository, nil -} - -func newRootSyncSet(rsd *v1alpha1.RootSyncDeployment, clusterRef rssapi.ClusterRef, rssSpec *rssapi.RootSyncSpec, pkgName string) *rssapi.RootSyncSet { - t := true - rootsyncset := &rssapi.RootSyncSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("%s-%s", pkgName, clusterRef.Name), - Namespace: rsd.Namespace, - Labels: map[string]string{ - rootSyncSetLabel: rsd.Name, - }, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: rsd.APIVersion, - Kind: rsd.Kind, - Name: rsd.Name, - UID: rsd.UID, - Controller: &t, - }, - }, - }, - Spec: rssapi.RootSyncSetSpec{ - ClusterRefs: []*rssapi.ClusterRef{ - &clusterRef, - }, - Template: &rssapi.RootSyncInfo{ - Spec: rssSpec, - }, - }, - } - return rootsyncset -} - -func toRootSyncSpec(pkgRev *porchapi.PackageRevision, repo *configapi.Repository) *rssapi.RootSyncSpec { - return &rssapi.RootSyncSpec{ - SourceFormat: "unstructured", - Git: &rssapi.GitInfo{ - Repo: repo.Spec.Git.Repo, - Revision: fmt.Sprintf("%s/%s", pkgRev.Spec.PackageName, pkgRev.Spec.Revision), - Dir: pkgRev.Spec.PackageName, - Branch: repo.Spec.Git.Branch, - Auth: "none", - }, - } -} - -func isRssSynced(rss *rssapi.RootSyncSet) bool { - if rss.Generation != rss.Status.ObservedGeneration { - return false - } - - for _, crs := range rss.Status.ClusterRefStatuses { - if crs.SyncStatus == "Synced" { - return true - } - } - return false -} - -func contains(clusters []*unstructured.Unstructured, clusterRef *rssapi.ClusterRef) bool { - for _, cr := range clusters { - if clusterRef.ApiVersion == cr.GetAPIVersion() && - clusterRef.Kind == cr.GetKind() && - clusterRef.Name == cr.GetName() && - clusterRef.Namespace == cr.GetNamespace() { - return true - } - } - return false -} - -func (r *RootSyncDeploymentReconciler) listRootSyncSets(ctx context.Context, rsdName, rsdNamespace string) ([]*rssapi.RootSyncSet, error) { - var list rssapi.RootSyncSetList - if err := r.List(ctx, &list, client.MatchingLabels{rootSyncSetLabel: rsdName}, client.InNamespace(rsdNamespace)); err != nil { - return nil, err - } - var rootsyncsets []*rssapi.RootSyncSet - for i := range list.Items { - item := &list.Items[i] - rootsyncsets = append(rootsyncsets, item) - } - return rootsyncsets, nil -} - -func (r *RootSyncDeploymentReconciler) getClusters(ctx context.Context, sel *metav1.LabelSelector) ([]*unstructured.Unstructured, error) { - var clusters []*unstructured.Unstructured - for _, gvk := range []schema.GroupVersionKind{configConnectorConfigControllerClusterGVK, configConnectorContainerClusterGVK} { - c, err := r.getClustersByGVK(ctx, gvk, sel) - if err != nil { - return nil, err - } - clusters = append(clusters, c...) - } - return clusters, nil -} - -func (r *RootSyncDeploymentReconciler) getClustersByGVK(ctx context.Context, gvk schema.GroupVersionKind, sel *metav1.LabelSelector) ([]*unstructured.Unstructured, error) { - selector, err := metav1.LabelSelectorAsSelector(sel) - if err != nil { - return nil, err - } - var list unstructured.UnstructuredList - list.SetGroupVersionKind(gvk) - if err := r.List(ctx, &list, client.MatchingLabelsSelector{Selector: selector}); err != nil { - return nil, err - } - - var clusters []*unstructured.Unstructured - for i := range list.Items { - c := list.Items[i] - clusters = append(clusters, &c) - } - return clusters, nil -} - -func toRootSyncSetNames(rsss []*rssapi.RootSyncSet) []string { - var names []string - for _, rss := range rsss { - names = append(names, rss.Name) - } - return names -} - -func toClusterNames(clusters []*unstructured.Unstructured) []string { - var names []string - for _, c := range clusters { - names = append(names, c.GetName()) - } - return names -} - -// SetupWithManager sets up the controller with the Manager. -func (r *RootSyncDeploymentReconciler) SetupWithManager(mgr ctrl.Manager) error { - if err := v1alpha1.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - if err := porchapi.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - if err := configapi.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - - r.Client = mgr.GetClient() - - var containerCluster unstructured.Unstructured - containerCluster.SetGroupVersionKind(configConnectorContainerClusterGVK) - var configController unstructured.Unstructured - configController.SetGroupVersionKind(configConnectorConfigControllerClusterGVK) - - return ctrl.NewControllerManagedBy(mgr). - For(&v1alpha1.RootSyncDeployment{}). - Owns(&rssapi.RootSyncSet{}). - Watches( - &source.Kind{Type: &containerCluster}, - handler.EnqueueRequestsFromMapFunc(r.requestsFromMapFunc), - ). - Watches( - &source.Kind{Type: &configController}, - handler.EnqueueRequestsFromMapFunc(r.requestsFromMapFunc), - ). - Complete(r) -} - -func (r *RootSyncDeploymentReconciler) requestsFromMapFunc(cluster client.Object) []reconcile.Request { - r.mutex.Lock() - defer r.mutex.Unlock() - - var requests []reconcile.Request - l := cluster.GetLabels() - for nn, clusterTargetSelector := range r.clusterTargetCache { - if clusterTargetSelector.Matches(labels.Set(l)) { - requests = append(requests, reconcile.Request{NamespacedName: nn}) - } - } - return requests -} diff --git a/porch/controllers/rootsyncrollouts/api/v1alpha1/groupversion_info.go b/porch/controllers/rootsyncrollouts/api/v1alpha1/groupversion_info.go deleted file mode 100644 index b0010b886f..0000000000 --- a/porch/controllers/rootsyncrollouts/api/v1alpha1/groupversion_info.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2022 The kpt 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. - -// Package v1alpha1 contains API Schema definitions for the config.porch.kpt.dev v1alpha1 API group -// +kubebuilder:object:generate=true -// +groupName=config.porch.kpt.dev -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/scheme" -) - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 object:headerFile="../../../../scripts/boilerplate.go.txt" paths="./..." - -var ( - // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "config.porch.kpt.dev", Version: "v1alpha1"} - - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} - - // AddToScheme adds the types in this group-version to the given scheme. - AddToScheme = SchemeBuilder.AddToScheme -) diff --git a/porch/controllers/rootsyncrollouts/api/v1alpha1/rootsyncrollout_types.go b/porch/controllers/rootsyncrollouts/api/v1alpha1/rootsyncrollout_types.go deleted file mode 100644 index c73d25d99d..0000000000 --- a/porch/controllers/rootsyncrollouts/api/v1alpha1/rootsyncrollout_types.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2022 The kpt 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. - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// RootSyncRolloutSpec -type RootSyncRolloutSpec struct { - Targets ClusterTargetSelector `json:"targets,omitempty"` - - Packages PackageSelector `json:"packages,omitempty"` -} - -type ClusterTargetSelector struct { - Selector *metav1.LabelSelector `json:"selector,omitempty"` -} - -type PackageSelector struct { - Namespace string `json:"namespace,omitempty"` - - Selector *metav1.LabelSelector `json:"selector,omitempty"` -} - -// RootSyncRolloutStatus defines the observed state of RootSyncRollout -type RootSyncRolloutStatus struct { - // Conditions describes the reconciliation state of the object. - Conditions []metav1.Condition `json:"conditions,omitempty"` - - PackageStatuses []PackageStatus `json:"packageStatus,omitempty"` -} - -type PackageStatus struct { - Package string `json:"package"` - - Revisions []Revision `json:"revision"` -} - -type Revision struct { - Revision string `json:"revision"` - - Count int `json:"count"` - - SyncedCount int `json:"syncedCount"` -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// RootSyncRollout is the Schema for the rootsyncrollouts API -type RootSyncRollout struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec RootSyncRolloutSpec `json:"spec,omitempty"` - Status RootSyncRolloutStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// RootSyncRolloutList contains a list of RootSyncRollout -type RootSyncRolloutList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []RootSyncRollout `json:"items"` -} - -func init() { - SchemeBuilder.Register(&RootSyncRollout{}, &RootSyncRolloutList{}) -} diff --git a/porch/controllers/rootsyncrollouts/api/v1alpha1/zz_generated.deepcopy.go b/porch/controllers/rootsyncrollouts/api/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index cf9f6b713d..0000000000 --- a/porch/controllers/rootsyncrollouts/api/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,205 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// Copyright 2023 The kpt 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 controller-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ClusterTargetSelector) DeepCopyInto(out *ClusterTargetSelector) { - *out = *in - if in.Selector != nil { - in, out := &in.Selector, &out.Selector - *out = new(v1.LabelSelector) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTargetSelector. -func (in *ClusterTargetSelector) DeepCopy() *ClusterTargetSelector { - if in == nil { - return nil - } - out := new(ClusterTargetSelector) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageSelector) DeepCopyInto(out *PackageSelector) { - *out = *in - if in.Selector != nil { - in, out := &in.Selector, &out.Selector - *out = new(v1.LabelSelector) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageSelector. -func (in *PackageSelector) DeepCopy() *PackageSelector { - if in == nil { - return nil - } - out := new(PackageSelector) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageStatus) DeepCopyInto(out *PackageStatus) { - *out = *in - if in.Revisions != nil { - in, out := &in.Revisions, &out.Revisions - *out = make([]Revision, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageStatus. -func (in *PackageStatus) DeepCopy() *PackageStatus { - if in == nil { - return nil - } - out := new(PackageStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Revision) DeepCopyInto(out *Revision) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Revision. -func (in *Revision) DeepCopy() *Revision { - if in == nil { - return nil - } - out := new(Revision) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RootSyncRollout) DeepCopyInto(out *RootSyncRollout) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RootSyncRollout. -func (in *RootSyncRollout) DeepCopy() *RootSyncRollout { - if in == nil { - return nil - } - out := new(RootSyncRollout) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RootSyncRollout) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RootSyncRolloutList) DeepCopyInto(out *RootSyncRolloutList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]RootSyncRollout, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RootSyncRolloutList. -func (in *RootSyncRolloutList) DeepCopy() *RootSyncRolloutList { - if in == nil { - return nil - } - out := new(RootSyncRolloutList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RootSyncRolloutList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RootSyncRolloutSpec) DeepCopyInto(out *RootSyncRolloutSpec) { - *out = *in - in.Targets.DeepCopyInto(&out.Targets) - in.Packages.DeepCopyInto(&out.Packages) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RootSyncRolloutSpec. -func (in *RootSyncRolloutSpec) DeepCopy() *RootSyncRolloutSpec { - if in == nil { - return nil - } - out := new(RootSyncRolloutSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RootSyncRolloutStatus) DeepCopyInto(out *RootSyncRolloutStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.PackageStatuses != nil { - in, out := &in.PackageStatuses, &out.PackageStatuses - *out = make([]PackageStatus, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RootSyncRolloutStatus. -func (in *RootSyncRolloutStatus) DeepCopy() *RootSyncRolloutStatus { - if in == nil { - return nil - } - out := new(RootSyncRolloutStatus) - in.DeepCopyInto(out) - return out -} diff --git a/porch/controllers/rootsyncrollouts/config/rbac/role.yaml b/porch/controllers/rootsyncrollouts/config/rbac/role.yaml deleted file mode 100644 index 6e7fd08493..0000000000 --- a/porch/controllers/rootsyncrollouts/config/rbac/role.yaml +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - name: porch-controllers-rootsyncrollouts -rules: -- apiGroups: - - config.porch.kpt.dev - resources: - - rootsyncdeployments - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - config.porch.kpt.dev - resources: - - rootsyncrollouts - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - config.porch.kpt.dev - resources: - - rootsyncrollouts/finalizers - verbs: - - update -- apiGroups: - - config.porch.kpt.dev - resources: - - rootsyncrollouts/status - verbs: - - get - - patch - - update -- apiGroups: - - porch.kpt.dev - resources: - - packagerevisions - verbs: - - get - - list - - watch diff --git a/porch/controllers/rootsyncrollouts/config/rbac/rolebinding.yaml b/porch/controllers/rootsyncrollouts/config/rbac/rolebinding.yaml deleted file mode 100644 index 9b3c38f338..0000000000 --- a/porch/controllers/rootsyncrollouts/config/rbac/rolebinding.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: porch-system:porch-controllers-rootrollouts -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: porch-controllers-rootsyncrollouts -subjects: -- kind: ServiceAccount - name: porch-controllers - namespace: porch-system \ No newline at end of file diff --git a/porch/controllers/rootsyncrollouts/config/samples/simple.yaml b/porch/controllers/rootsyncrollouts/config/samples/simple.yaml deleted file mode 100644 index 6f911e3b1c..0000000000 --- a/porch/controllers/rootsyncrollouts/config/samples/simple.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: RootSyncRollout -metadata: - name: simple - namespace: default -spec: - targets: - selector: - matchLabels: - foo: bar - packages: - namespace: default \ No newline at end of file diff --git a/porch/controllers/rootsyncrollouts/pkg/controllers/rootsyncrollout/controller.go b/porch/controllers/rootsyncrollouts/pkg/controllers/rootsyncrollout/controller.go deleted file mode 100644 index c368b6aaa0..0000000000 --- a/porch/controllers/rootsyncrollouts/pkg/controllers/rootsyncrollout/controller.go +++ /dev/null @@ -1,384 +0,0 @@ -// Copyright 2022 The kpt 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. - -package rootsyncrollout - -import ( - "context" - "flag" - "fmt" - "sync" - - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - rsdapi "github.com/GoogleContainerTools/kpt/porch/controllers/rootsyncdeployments/api/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/controllers/rootsyncrollouts/api/v1alpha1" - "k8s.io/apimachinery/pkg/api/equality" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/types" - "k8s.io/klog/v2" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" -) - -const ( - rootSyncRolloutLabel = "config.porch.kpt.dev/rollout" -) - -type Options struct { -} - -func (o *Options) InitDefaults() { -} - -func (o *Options) BindFlags(prefix string, flags *flag.FlagSet) { -} - -func NewRootSyncRolloutReconciler() *RootSyncRolloutReconciler { - return &RootSyncRolloutReconciler{ - packageTargetCache: make(map[types.NamespacedName]v1alpha1.PackageSelector), - } -} - -// RootSyncRolloutReconciler reconciles a RootSyncRollout object -type RootSyncRolloutReconciler struct { - Options - - client.Client - - mutex sync.Mutex - packageTargetCache map[types.NamespacedName]v1alpha1.PackageSelector -} - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 rbac:roleName=porch-controllers-rootsyncrollouts webhook paths="." output:rbac:artifacts:config=../../../config/rbac - -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=rootsyncrollouts,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=rootsyncrollouts/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=rootsyncrollouts/finalizers,verbs=update -//+kubebuilder:rbac:groups=porch.kpt.dev,resources=packagerevisions,verbs=get;list;watch -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=rootsyncdeployments,verbs=get;list;watch;create;update;patch;delete - -// For more details, check Reconcile and its Result here: -// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.10.0/pkg/reconcile -func (r *RootSyncRolloutReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - logger := log.FromContext(ctx) - - logger.Info("Running reconcile") - var rootsyncrollout v1alpha1.RootSyncRollout - if err := r.Get(ctx, req.NamespacedName, &rootsyncrollout); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - myFinalizerName := "config.porch.kpt.dev/rootsyncrollouts" - if rootsyncrollout.ObjectMeta.DeletionTimestamp.IsZero() { - // Update the cache with mapping from rollouts to PackageRevision targets. It allows the controller - // to determine which Rollouts needs to be reconciled based on an event about a cluster. - func() { - r.mutex.Lock() - defer r.mutex.Unlock() - r.packageTargetCache[req.NamespacedName] = rootsyncrollout.Spec.Packages - }() - - // The object is not being deleted, so if it does not have our finalizer, - // then lets add the finalizer and update the object. This is equivalent - // registering our finalizer. - if !controllerutil.ContainsFinalizer(&rootsyncrollout, myFinalizerName) { - controllerutil.AddFinalizer(&rootsyncrollout, myFinalizerName) - if err := r.Update(ctx, &rootsyncrollout); err != nil { - return ctrl.Result{}, fmt.Errorf("error adding finalizer: %w", err) - } - } - } else { - // Clean up the cache. - func() { - r.mutex.Lock() - defer r.mutex.Unlock() - delete(r.packageTargetCache, req.NamespacedName) - }() - - // The object is being deleted - if controllerutil.ContainsFinalizer(&rootsyncrollout, myFinalizerName) { - // remove our finalizer from the list and update it. - controllerutil.RemoveFinalizer(&rootsyncrollout, myFinalizerName) - if err := r.Update(ctx, &rootsyncrollout); err != nil { - return ctrl.Result{}, fmt.Errorf("failed to update %s after delete finalizer: %w", req.Name, err) - } - } - // Stop reconciliation as the item is being deleted - return ctrl.Result{}, nil - } - - // Get all packages targeted by the Package selector - packageMap, err := r.getPackages(ctx, &rootsyncrollout) - if err != nil { - return ctrl.Result{}, err - } - logger.Info("Looked up packages", "count", len(packageMap)) - - rootSyncDeployments, err := r.listRootSyncDeployments(ctx, rootsyncrollout.Name, rootsyncrollout.Namespace) - if err != nil { - return ctrl.Result{}, err - } - logger.Info("Looked up RootSyncDeployments", "count", len(rootSyncDeployments)) - - currentRsds := make(map[string][]*rsdapi.RootSyncDeployment) - for i := range rootSyncDeployments { - rsd := rootSyncDeployments[i] - - pkgName, found := usesPackage(rsd, packageMap) - if !found { - logger.Info("Package not found, deleting RootSyncDeployment", "rsd", rsd.Name) - if r.Delete(ctx, rsd); err != nil { - return ctrl.Result{}, err - } - continue - } - logger.Info("Found package", "pkg", pkgName) - - latestPkgRev, found := findLatest(packageMap[pkgName]) - if !found { - return ctrl.Result{}, fmt.Errorf("no PackageRevision tagged with `latest` found for package %s", pkgName) - } - logger.Info("Found latest packagerevision", "pkgRev", latestPkgRev.Name) - newRsd := newRootSyncDeployment(&rootsyncrollout, pkgName, latestPkgRev.Name) - if !equality.Semantic.DeepEqual(rsd.Spec, newRsd.Spec) { - rsd.Spec = newRsd.Spec - if err := r.Update(ctx, rsd); err != nil { - return ctrl.Result{}, err - } - } - currentRsds[pkgName] = append(currentRsds[pkgName], rsd) - } - - for pkgName, pkgRevs := range packageMap { - var found bool - for _, rsd := range rootSyncDeployments { - rsdPkgRevNamespace := rsd.Spec.PackageRevision.Namespace - rsdPkgRevName := rsd.Spec.PackageRevision.Name - if rsdPkgRevNamespace == "" { - rsdPkgRevNamespace = rsd.Namespace - } - for _, pkgRev := range pkgRevs { - if pkgRev.Name == rsdPkgRevName && pkgRev.Namespace == rsdPkgRevNamespace { - found = true - } - } - } - if !found { - logger.Info("No RootSyncDeployment found for package", "pkg", pkgName) - pkgRev, found := findLatest(pkgRevs) - if !found { - return ctrl.Result{}, fmt.Errorf("no PackageRevision tagged with `latest` found for package %s", pkgName) - } - rsd := newRootSyncDeployment(&rootsyncrollout, pkgName, pkgRev.Name) - if err := r.Create(ctx, rsd); err != nil { - return ctrl.Result{}, fmt.Errorf("error creating new RootSyncDeployment %s: %v", rsd.Name, err) - } - currentRsds[pkgName] = append(currentRsds[pkgName], rsd) - } - } - - if err := r.updateStatus(ctx, &rootsyncrollout, currentRsds); err != nil { - return ctrl.Result{}, err - } - - return ctrl.Result{}, nil -} - -func (r *RootSyncRolloutReconciler) updateStatus(ctx context.Context, rsr *v1alpha1.RootSyncRollout, rsdsMap map[string][]*rsdapi.RootSyncDeployment) error { - var packageStatuses []v1alpha1.PackageStatus - - for pkgName, rsds := range rsdsMap { - pkgStatus := v1alpha1.PackageStatus{ - Package: pkgName, - } - - revisionMap := make(map[string][]rsdapi.ClusterRefStatus) - for i := range rsds { - rsd := rsds[i] - for j := range rsd.Status.ClusterRefStatuses { - crs := rsd.Status.ClusterRefStatuses[j] - revision := crs.Revision - revisionMap[revision] = append(revisionMap[revision], crs) - } - } - - for rev, crss := range revisionMap { - revision := v1alpha1.Revision{ - Revision: rev, - } - - var count int - var syncedCount int - for _, crs := range crss { - count += 1 - if crs.Synced { - syncedCount += 1 - } - } - revision.Count = count - revision.SyncedCount = syncedCount - pkgStatus.Revisions = append(pkgStatus.Revisions, revision) - } - - packageStatuses = append(packageStatuses, pkgStatus) - } - - if equality.Semantic.DeepEqual(rsr.Status.PackageStatuses, packageStatuses) { - klog.Infof("Status has not changed, update not needed.") - return nil - } - rsr.Status.PackageStatuses = packageStatuses - return r.Status().Update(ctx, rsr) -} - -func usesPackage(rsd *rsdapi.RootSyncDeployment, packageMap map[string][]*porchapi.PackageRevision) (string, bool) { - for pkgName, pkgRevs := range packageMap { - for _, pkgRev := range pkgRevs { - if pkgRev.Name == rsd.Spec.PackageRevision.Name { - return pkgName, true - } - } - } - return "", false -} - -func findLatest(pkgRevs []*porchapi.PackageRevision) (*porchapi.PackageRevision, bool) { - for _, pr := range pkgRevs { - if pr.Labels[porchapi.LatestPackageRevisionKey] == porchapi.LatestPackageRevisionValue { - return pr, true - } - } - return nil, false -} - -func newRootSyncDeployment(rsr *v1alpha1.RootSyncRollout, pkgName, pkgRevision string) *rsdapi.RootSyncDeployment { - t := true - return &rsdapi.RootSyncDeployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: pkgName, - Namespace: rsr.Namespace, - Labels: map[string]string{ - rootSyncRolloutLabel: rsr.Name, - }, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: rsr.APIVersion, - Kind: rsr.Kind, - Name: rsr.Name, - UID: rsr.UID, - Controller: &t, - }, - }, - }, - Spec: rsdapi.RootSyncDeploymentSpec{ - Targets: rsdapi.ClusterTargetSelector{ - Selector: rsr.Spec.Targets.Selector, - }, - PackageRevision: rsdapi.PackageRevisionRef{ - Name: pkgRevision, - Namespace: rsr.Namespace, - }, - }, - } -} - -func (r *RootSyncRolloutReconciler) getPackages(ctx context.Context, rollout *v1alpha1.RootSyncRollout) (map[string][]*porchapi.PackageRevision, error) { - var packageRevisionList porchapi.PackageRevisionList - var opts []client.ListOption - if rollout.Spec.Packages.Namespace != "" { - opts = append(opts, client.InNamespace(rollout.Spec.Packages.Namespace)) - } - if rollout.Spec.Packages.Selector != nil { - selector, err := metav1.LabelSelectorAsSelector(rollout.Spec.Packages.Selector) - if err != nil { - return nil, err - } - opts = append(opts, client.MatchingLabelsSelector{Selector: selector}) - } - if err := r.List(ctx, &packageRevisionList, opts...); err != nil { - return nil, err - } - - packageMap := make(map[string][]*porchapi.PackageRevision) - for i := range packageRevisionList.Items { - packageRevision := packageRevisionList.Items[i] - packageName := packageRevision.Spec.PackageName - // TODO: See if we can handle this with a FieldSelector on packagerevisions. - if !porchapi.LifecycleIsPublished(packageRevision.Spec.Lifecycle) { - continue - } - if _, found := packageMap[packageName]; !found { - packageMap[packageName] = make([]*porchapi.PackageRevision, 0) - } - packageMap[packageName] = append(packageMap[packageName], &packageRevision) - } - - return packageMap, nil -} - -func (r *RootSyncRolloutReconciler) listRootSyncDeployments(ctx context.Context, rsrName, rsrNamespace string) ([]*rsdapi.RootSyncDeployment, error) { - var list rsdapi.RootSyncDeploymentList - if err := r.List(ctx, &list, client.MatchingLabels{rootSyncRolloutLabel: rsrName}, client.InNamespace(rsrNamespace)); err != nil { - return nil, err - } - var rsds []*rsdapi.RootSyncDeployment - for i := range list.Items { - item := &list.Items[i] - rsds = append(rsds, item) - } - return rsds, nil -} - -// SetupWithManager sets up the controller with the Manager. -func (r *RootSyncRolloutReconciler) SetupWithManager(mgr ctrl.Manager) error { - if err := v1alpha1.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - - var pkgRev porchapi.PackageRevision - - r.Client = mgr.GetClient() - - return ctrl.NewControllerManagedBy(mgr). - For(&v1alpha1.RootSyncRollout{}). - Owns(&rsdapi.RootSyncDeployment{}). - Watches( - &source.Kind{Type: &pkgRev}, - handler.EnqueueRequestsFromMapFunc(r.findRolloutsForPackageRevision), - ). - Complete(r) -} - -func (r *RootSyncRolloutReconciler) findRolloutsForPackageRevision(pkgRev client.Object) []reconcile.Request { - // There is not support for reverse lookup by label: https://github.com/kubernetes/kubernetes/issues/1348 - var requests []reconcile.Request - l := pkgRev.GetLabels() - for nn, packageTargetSelector := range r.packageTargetCache { - selector, _ := metav1.LabelSelectorAsSelector(packageTargetSelector.Selector) - if !(packageTargetSelector.Selector == nil || selector.Empty() || selector.Matches(labels.Set(l))) { - continue - } - if !(packageTargetSelector.Namespace == "" || packageTargetSelector.Namespace == pkgRev.GetNamespace()) { - continue - } - - requests = append(requests, reconcile.Request{NamespacedName: nn}) - } - return requests -} diff --git a/porch/controllers/rootsyncsets/api/v1alpha1/groupversion_info.go b/porch/controllers/rootsyncsets/api/v1alpha1/groupversion_info.go deleted file mode 100644 index b0010b886f..0000000000 --- a/porch/controllers/rootsyncsets/api/v1alpha1/groupversion_info.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2022 The kpt 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. - -// Package v1alpha1 contains API Schema definitions for the config.porch.kpt.dev v1alpha1 API group -// +kubebuilder:object:generate=true -// +groupName=config.porch.kpt.dev -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/scheme" -) - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 object:headerFile="../../../../scripts/boilerplate.go.txt" paths="./..." - -var ( - // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "config.porch.kpt.dev", Version: "v1alpha1"} - - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} - - // AddToScheme adds the types in this group-version to the given scheme. - AddToScheme = SchemeBuilder.AddToScheme -) diff --git a/porch/controllers/rootsyncsets/api/v1alpha1/rootsyncset_types.go b/porch/controllers/rootsyncsets/api/v1alpha1/rootsyncset_types.go deleted file mode 100644 index df3e5b8e45..0000000000 --- a/porch/controllers/rootsyncsets/api/v1alpha1/rootsyncset_types.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2022 The kpt 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. - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// RootSyncSetSpec defines the desired state of RootSyncSet -type RootSyncSetSpec struct { - ClusterRefs []*ClusterRef `json:"clusterRefs,omitempty"` - Template *RootSyncInfo `json:"template,omitempty"` -} - -type ClusterRef struct { - ApiVersion string `json:"apiVersion,omitempty"` - Kind string `json:"kind,omitempty"` - Name string `json:"name,omitempty"` - Namespace string `json:"namespace,omitempty"` -} - -func (r *ClusterRef) GetKind() string { - return r.Kind -} - -func (r *ClusterRef) GetName() string { - return r.Name -} - -func (r *ClusterRef) GetNamespace() string { - return r.Namespace -} - -func (r *ClusterRef) GetAPIVersion() string { - return r.ApiVersion -} - -type RootSyncInfo struct { - Spec *RootSyncSpec `json:"spec,omitempty"` -} - -type RootSyncSpec struct { - SourceFormat string `json:"sourceFormat,omitempty"` - Git *GitInfo `json:"git,omitempty"` -} - -type GitInfo struct { - Repo string `json:"repo"` - Branch string `json:"branch,omitempty"` - Revision string `json:"revision,omitempty"` - Dir string `json:"dir,omitempty"` - Period metav1.Duration `json:"period,omitempty"` - Auth string `json:"auth"` - GCPServiceAccountEmail string `json:"gcpServiceAccountEmail,omitempty"` - Proxy string `json:"proxy,omitempty"` - SecretRef SecretReference `json:"secretRef,omitempty"` - NoSSLVerify bool `json:"noSSLVerify,omitempty"` -} - -// SecretReference contains the reference to the secret used to connect to -// Git source of truth. -type SecretReference struct { - // Name represents the secret name. - // +optional - Name string `json:"name,omitempty"` -} - -// RootSyncSetStatus defines the observed state of RootSyncSet -type RootSyncSetStatus struct { - ObservedGeneration int64 `json:"observedGeneration,omitempty"` - - // Conditions describes the reconciliation state of the object. - Conditions []metav1.Condition `json:"conditions,omitempty"` - - ClusterRefStatuses []ClusterRefStatus `json:"clusterRefStatuses,omitempty"` -} - -type ClusterRefStatus struct { - ApiVersion string `json:"apiVersion,omitempty"` - Kind string `json:"kind,omitempty"` - Name string `json:"name,omitempty"` - Namespace string `json:"namespace,omitempty"` - SyncStatus string `json:"syncStatus,omitempty"` -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// RootSyncSet is the Schema for the rootsyncsets API -type RootSyncSet struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec RootSyncSetSpec `json:"spec,omitempty"` - Status RootSyncSetStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// RootSyncSetList contains a list of RootSyncSet -type RootSyncSetList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []RootSyncSet `json:"items"` -} - -func init() { - SchemeBuilder.Register(&RootSyncSet{}, &RootSyncSetList{}) -} diff --git a/porch/controllers/rootsyncsets/api/v1alpha1/zz_generated.deepcopy.go b/porch/controllers/rootsyncsets/api/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index e7bbfb0c1c..0000000000 --- a/porch/controllers/rootsyncsets/api/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,244 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// Copyright 2023 The kpt 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 controller-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ClusterRef) DeepCopyInto(out *ClusterRef) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterRef. -func (in *ClusterRef) DeepCopy() *ClusterRef { - if in == nil { - return nil - } - out := new(ClusterRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ClusterRefStatus) DeepCopyInto(out *ClusterRefStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterRefStatus. -func (in *ClusterRefStatus) DeepCopy() *ClusterRefStatus { - if in == nil { - return nil - } - out := new(ClusterRefStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GitInfo) DeepCopyInto(out *GitInfo) { - *out = *in - out.Period = in.Period - out.SecretRef = in.SecretRef -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitInfo. -func (in *GitInfo) DeepCopy() *GitInfo { - if in == nil { - return nil - } - out := new(GitInfo) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RootSyncInfo) DeepCopyInto(out *RootSyncInfo) { - *out = *in - if in.Spec != nil { - in, out := &in.Spec, &out.Spec - *out = new(RootSyncSpec) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RootSyncInfo. -func (in *RootSyncInfo) DeepCopy() *RootSyncInfo { - if in == nil { - return nil - } - out := new(RootSyncInfo) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RootSyncSet) DeepCopyInto(out *RootSyncSet) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RootSyncSet. -func (in *RootSyncSet) DeepCopy() *RootSyncSet { - if in == nil { - return nil - } - out := new(RootSyncSet) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RootSyncSet) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RootSyncSetList) DeepCopyInto(out *RootSyncSetList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]RootSyncSet, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RootSyncSetList. -func (in *RootSyncSetList) DeepCopy() *RootSyncSetList { - if in == nil { - return nil - } - out := new(RootSyncSetList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RootSyncSetList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RootSyncSetSpec) DeepCopyInto(out *RootSyncSetSpec) { - *out = *in - if in.ClusterRefs != nil { - in, out := &in.ClusterRefs, &out.ClusterRefs - *out = make([]*ClusterRef, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(ClusterRef) - **out = **in - } - } - } - if in.Template != nil { - in, out := &in.Template, &out.Template - *out = new(RootSyncInfo) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RootSyncSetSpec. -func (in *RootSyncSetSpec) DeepCopy() *RootSyncSetSpec { - if in == nil { - return nil - } - out := new(RootSyncSetSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RootSyncSetStatus) DeepCopyInto(out *RootSyncSetStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.ClusterRefStatuses != nil { - in, out := &in.ClusterRefStatuses, &out.ClusterRefStatuses - *out = make([]ClusterRefStatus, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RootSyncSetStatus. -func (in *RootSyncSetStatus) DeepCopy() *RootSyncSetStatus { - if in == nil { - return nil - } - out := new(RootSyncSetStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RootSyncSpec) DeepCopyInto(out *RootSyncSpec) { - *out = *in - if in.Git != nil { - in, out := &in.Git, &out.Git - *out = new(GitInfo) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RootSyncSpec. -func (in *RootSyncSpec) DeepCopy() *RootSyncSpec { - if in == nil { - return nil - } - out := new(RootSyncSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecretReference) DeepCopyInto(out *SecretReference) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretReference. -func (in *SecretReference) DeepCopy() *SecretReference { - if in == nil { - return nil - } - out := new(SecretReference) - in.DeepCopyInto(out) - return out -} diff --git a/porch/controllers/rootsyncsets/config/rbac/role.yaml b/porch/controllers/rootsyncsets/config/rbac/role.yaml deleted file mode 100644 index 3a3b0f6477..0000000000 --- a/porch/controllers/rootsyncsets/config/rbac/role.yaml +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - name: porch-controllers-rootsyncsets -rules: -- apiGroups: - - "" - resources: - - serviceaccounts/token - verbs: - - create -- apiGroups: - - config.porch.kpt.dev - resources: - - rootsyncsets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - config.porch.kpt.dev - resources: - - rootsyncsets/finalizers - verbs: - - update -- apiGroups: - - config.porch.kpt.dev - resources: - - rootsyncsets/status - verbs: - - get - - patch - - update -- apiGroups: - - configcontroller.cnrm.cloud.google.com - resources: - - configcontrollerinstances - verbs: - - get - - list - - watch -- apiGroups: - - container.cnrm.cloud.google.com - resources: - - containerclusters - verbs: - - get - - list - - watch -- apiGroups: - - core.cnrm.cloud.google.com - resources: - - configconnectorcontexts - verbs: - - get - - list - - watch -- apiGroups: - - hub.gke.io - resources: - - memberships - verbs: - - get - - list - - watch diff --git a/porch/controllers/rootsyncsets/config/rbac/rolebinding.yaml b/porch/controllers/rootsyncsets/config/rbac/rolebinding.yaml deleted file mode 100644 index d02cdd8579..0000000000 --- a/porch/controllers/rootsyncsets/config/rbac/rolebinding.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: porch-system:porch-controllers-rootsyncsets -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: porch-controllers-rootsyncsets -subjects: -- kind: ServiceAccount - name: porch-controllers - namespace: porch-system \ No newline at end of file diff --git a/porch/controllers/rootsyncsets/config/samples/README.md b/porch/controllers/rootsyncsets/config/samples/README.md deleted file mode 100644 index b5827afd33..0000000000 --- a/porch/controllers/rootsyncsets/config/samples/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Simple example - -This example adds a RootSync with name `simple` to two GKE clusters -created with Config Connector. - -## Setup -Create clusters with Config Connector using the following two manifests: -``` -apiVersion: container.cnrm.cloud.google.com/v1beta1 -kind: ContainerCluster -metadata: - name: gke-one - namespace: config-control -spec: - location: us-central1 - initialNodeCount: 1 - workloadIdentityConfig: - workloadPool: ${PROJECT-ID}.svc.id.goog -``` - -``` -apiVersion: container.cnrm.cloud.google.com/v1beta1 -kind: ContainerCluster -metadata: - name: gke-two - namespace: config-control -spec: - location: us-central1 - initialNodeCount: 1 - workloadIdentityConfig: - workloadPool: ${PROJECT-ID}.svc.id.goog -``` - -Install Config Management through the Google Cloud console to make sure -Config Sync is available in the cluster. - -Apply the `simple.yaml` manifest: -``` -k apply -f simple.yaml -``` \ No newline at end of file diff --git a/porch/controllers/rootsyncsets/config/samples/simple.yaml b/porch/controllers/rootsyncsets/config/samples/simple.yaml deleted file mode 100644 index 62f4498f47..0000000000 --- a/porch/controllers/rootsyncsets/config/samples/simple.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: RootSyncSet -metadata: - name: simple - namespace: default -spec: - clusterRefs: - - apiVersion: container.cnrm.cloud.google.com/v1beta1 - kind: ContainerCluster - name: gke-one - namespace: config-control - - apiVersion: container.cnrm.cloud.google.com/v1beta1 - kind: ContainerCluster - name: gke-two - namespace: config-control - template: - spec: - sourceFormat: unstructured - git: - repo: https://github.com/mortent/csmr-examples.git - branch: main - dir: "multirepo/root" - auth: none \ No newline at end of file diff --git a/porch/controllers/rootsyncsets/pkg/controllers/rootsyncset/controller.go b/porch/controllers/rootsyncsets/pkg/controllers/rootsyncset/controller.go deleted file mode 100644 index 2bbd922e42..0000000000 --- a/porch/controllers/rootsyncsets/pkg/controllers/rootsyncset/controller.go +++ /dev/null @@ -1,438 +0,0 @@ -// Copyright 2022 The kpt 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. - -package rootsyncset - -import ( - "context" - "encoding/json" - "flag" - "fmt" - "strings" - "sync" - - "github.com/GoogleContainerTools/kpt/porch/controllers/remoterootsyncsets/pkg/remoteclient" - "github.com/GoogleContainerTools/kpt/porch/controllers/rootsyncsets/api/v1alpha1" - "k8s.io/apimachinery/pkg/api/equality" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/dynamic" - "k8s.io/klog/v2" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" -) - -var ( - rootSyncNamespace = "config-management-system" - rootSyncGVK = schema.GroupVersionKind{ - Group: "configsync.gke.io", - Version: "v1beta1", - Kind: "RootSync", - } - rootSyncGVR = schema.GroupVersionResource{ - Group: "configsync.gke.io", - Version: "v1beta1", - Resource: "rootsyncs", - } - rootSyncSetNameLabel = "config.porch.kpt.dev/rootsyncset-name" - rootSyncSetNamespaceLabel = "config.porch.kpt.dev/rootsyncset-namespace" -) - -type Options struct { -} - -func (o *Options) InitDefaults() { -} - -func (o *Options) BindFlags(prefix string, flags *flag.FlagSet) { -} - -// RootSyncSetReconciler reconciles a RootSyncSet object -type RootSyncSetReconciler struct { - Options - - remoteclient.RemoteClientGetter - - client.Client - - // channel is where watchers put events to trigger new reconcilations based - // on watch events from target clusters. - channel chan event.GenericEvent - - mutex sync.Mutex - watchers map[v1alpha1.ClusterRef]*watcher -} - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 rbac:roleName=porch-controllers-rootsyncsets webhook paths="." output:rbac:artifacts:config=../../../config/rbac - -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=rootsyncsets,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=rootsyncsets/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=rootsyncsets/finalizers,verbs=update -//+kubebuilder:rbac:groups=configcontroller.cnrm.cloud.google.com,resources=configcontrollerinstances,verbs=get;list;watch -//+kubebuilder:rbac:groups=container.cnrm.cloud.google.com,resources=containerclusters,verbs=get;list;watch -//+kubebuilder:rbac:groups=core.cnrm.cloud.google.com,resources=configconnectorcontexts,verbs=get;list;watch -//+kubebuilder:rbac:groups=hub.gke.io,resources=memberships,verbs=get;list;watch -//+kubebuilder:rbac:groups="",resources=serviceaccounts/token,verbs=create - -// Reconcile is part of the main kubernetes reconciliation loop which aims to -// move the current state of the cluster closer to the desired state. -// Reconcile function compares the state specified by -// the RootSyncSet object against the actual cluster state, and then -// perform operations to make the cluster state reflect the state specified by -// the user. -// - -// For more details, check Reconcile and its Result here: -// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.10.0/pkg/reconcile -func (r *RootSyncSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - var rootsyncset v1alpha1.RootSyncSet - if err := r.Get(ctx, req.NamespacedName, &rootsyncset); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - - myFinalizerName := "config.porch.kpt.dev/finalizer" - if rootsyncset.ObjectMeta.DeletionTimestamp.IsZero() { - // The object is not being deleted, so if it does not have our finalizer, - // then lets add the finalizer and update the object. This is equivalent - // registering our finalizer. - if !controllerutil.ContainsFinalizer(&rootsyncset, myFinalizerName) { - controllerutil.AddFinalizer(&rootsyncset, myFinalizerName) - if err := r.Update(ctx, &rootsyncset); err != nil { - return ctrl.Result{}, fmt.Errorf("error adding finalizer: %w", err) - } - } - } else { - // The object is being deleted - if controllerutil.ContainsFinalizer(&rootsyncset, myFinalizerName) { - // our finalizer is present, so lets handle any external dependency - if err := r.deleteExternalResources(ctx, &rootsyncset); err != nil { - // if fail to delete the external dependency here, return with error - // so that it can be retried - return ctrl.Result{}, fmt.Errorf("have problem to delete external resource: %w", err) - } - // Make sure we stop any watches that are no longer needed. - r.pruneWatches(req.NamespacedName, []*v1alpha1.ClusterRef{}) - // remove our finalizer from the list and update it. - controllerutil.RemoveFinalizer(&rootsyncset, myFinalizerName) - if err := r.Update(ctx, &rootsyncset); err != nil { - return ctrl.Result{}, fmt.Errorf("failed to update %s after delete finalizer: %w", req.Name, err) - } - } - // Stop reconciliation as the item is being deleted - return ctrl.Result{}, nil - } - - results := make(reconcileResult) - for _, clusterRef := range rootsyncset.Spec.ClusterRefs { - result := clusterRefResult{} - clusterRefName := clusterRef.Kind + ":" + clusterRef.Name - - remoteClient, err := r.GetRemoteClient(ctx, clusterRef, rootsyncset.Namespace) - if err != nil { - result.clientError = err - results[clusterRefName] = result - continue - } - dynamicClient, err := remoteClient.DynamicClient() - if err != nil { - result.clientError = err - results[clusterRefName] = result - continue - } - r.setupWatches(ctx, dynamicClient, rootsyncset.Name, rootsyncset.Namespace, *clusterRef) - - if err := r.patchRootSync(ctx, dynamicClient, req.Name, &rootsyncset); err != nil { - result.patchError = err - } - - s, err := checkSyncStatus(ctx, dynamicClient, req.Name) - if err != nil { - result.statusError = err - result.status = "Unknown" - } else { - result.status = s - } - - results[clusterRefName] = result - } - - r.pruneWatches(req.NamespacedName, rootsyncset.Spec.ClusterRefs) - - if err := r.updateStatus(ctx, &rootsyncset, results); err != nil { - klog.Errorf("failed to update status: %w", err) - return ctrl.Result{}, err - } - - if errs := results.Errors(); len(errs) > 0 { - klog.Warningf("Errors: %s", results.Error()) - return ctrl.Result{}, results - } - - return ctrl.Result{}, nil -} - -func (r *RootSyncSetReconciler) updateStatus(ctx context.Context, rss *v1alpha1.RootSyncSet, results reconcileResult) error { - crss := make([]v1alpha1.ClusterRefStatus, 0) - - for _, clusterRef := range rss.Spec.ClusterRefs { - clusterRefName := clusterRef.Kind + ":" + clusterRef.Name - res := results[clusterRefName] - crss = append(crss, v1alpha1.ClusterRefStatus{ - ApiVersion: clusterRef.ApiVersion, - Kind: clusterRef.Kind, - Name: clusterRef.Name, - Namespace: clusterRef.Namespace, - SyncStatus: res.status, - }) - } - - // Don't update if there are no changes. - if equality.Semantic.DeepEqual(rss.Status.ClusterRefStatuses, crss) && - rss.Generation == rss.Status.ObservedGeneration { - return nil - } - - rss.Status.ClusterRefStatuses = crss - rss.Status.ObservedGeneration = rss.Generation - return r.Client.Status().Update(ctx, rss) -} - -type reconcileResult map[string]clusterRefResult - -func (r reconcileResult) Errors() []error { - var errs []error - for _, crr := range r { - if crr.clientError != nil { - errs = append(errs, crr.clientError) - } - if crr.patchError != nil { - errs = append(errs, crr.patchError) - } - if crr.statusError != nil { - errs = append(errs, crr.statusError) - } - } - return errs -} - -// TODO: Improve the formatting of the printed errors here. -func (r reconcileResult) Error() string { - var sb strings.Builder - for clusterRef, res := range r { - if res.clientError != nil { - sb.WriteString(fmt.Sprintf("failed to create client for %s: %v\n", clusterRef, res.clientError)) - } - if res.patchError != nil { - sb.WriteString(fmt.Sprintf("failed to patch %s: %v\n", clusterRef, res.patchError)) - } - if res.statusError != nil { - sb.WriteString(fmt.Sprintf("failed to check status for %s: %v\n", clusterRef, res.statusError)) - } - } - return sb.String() -} - -type clusterRefResult struct { - clientError error - patchError error - statusError error - status string -} - -// patchRootSync patches the RootSync in the remote clusters targeted by -// the clusterRefs based on the latest revision of the template in the RootSyncSet. -func (r *RootSyncSetReconciler) patchRootSync(ctx context.Context, client dynamic.Interface, name string, rss *v1alpha1.RootSyncSet) error { - newRootSync, err := BuildObjectsToApply(rss) - if err != nil { - return err - } - data, err := json.Marshal(newRootSync) - if err != nil { - return fmt.Errorf("failed to encode root sync to JSON: %w", err) - } - rs, err := client.Resource(rootSyncGVR).Namespace(rootSyncNamespace).Patch(ctx, name, types.ApplyPatchType, data, metav1.PatchOptions{FieldManager: name}) - if err != nil { - return fmt.Errorf("failed to patch RootSync: %w", err) - } - klog.Infof("Create/Update resource %s as %v", name, rs) - return nil -} - -// setupWatches makes sure we have the necessary watches running against -// the remote clusters we care about. -func (r *RootSyncSetReconciler) setupWatches(ctx context.Context, client dynamic.Interface, rssName, ns string, clusterRef v1alpha1.ClusterRef) { - r.mutex.Lock() - defer r.mutex.Unlock() - nn := types.NamespacedName{ - Namespace: ns, - Name: rssName, - } - - // If we already have a watch running, make sure we have the current RootSyncSet - // listed in the liens map. - if w, found := r.watchers[clusterRef]; found { - w.liens[nn] = struct{}{} - return - } - - // Since we don't currently have a watch running, create a new watcher - // and add it to the map of watchers. - watcherCtx, cancelFunc := context.WithCancel(context.Background()) - w := &watcher{ - clusterRef: clusterRef, - ctx: watcherCtx, - cancelFunc: cancelFunc, - client: client, - channel: r.channel, - liens: map[types.NamespacedName]struct{}{ - nn: {}, - }, - } - klog.Infof("Creating watcher for %v", clusterRef) - go w.watch() - r.watchers[clusterRef] = w -} - -// pruneWatches removes the current RootSyncSet from the liens map of all watchers -// that it no longer needs. If any of the watchers are no longer used by any RootSyncSets, -// they are shut down. -func (r *RootSyncSetReconciler) pruneWatches(rssnn types.NamespacedName, clusterRefs []*v1alpha1.ClusterRef) { - r.mutex.Lock() - defer r.mutex.Unlock() - klog.Infof("Pruning watches for %s which has %v clusterRefs", rssnn.String(), clusterRefs) - - // Look through all watchers to check if it used to be needed by the RootSyncSet - // but is no longer. - for clusterRef, w := range r.watchers { - // If the watcher is still needed, we don't need to do anything. - var found bool - for _, cr := range clusterRefs { - if clusterRef == *cr { - found = true - } - } - if found { - continue - } - - // Delete the current RootSyncSet from the list of liens (it it exists) - delete(w.liens, rssnn) - // If no other RootSyncSets need the watch, stop it and remove the watcher from the map. - if len(w.liens) == 0 { - w.cancelFunc() - delete(r.watchers, clusterRef) - } - } -} - -// BuildObjectsToApply config root sync -func BuildObjectsToApply(rootsyncset *v1alpha1.RootSyncSet) (*unstructured.Unstructured, error) { - newRootSync, err := runtime.DefaultUnstructuredConverter.ToUnstructured(rootsyncset.Spec.Template) - if err != nil { - return nil, err - } - u := unstructured.Unstructured{Object: newRootSync} - u.SetGroupVersionKind(rootSyncGVK) - u.SetName(rootsyncset.Name) - u.SetNamespace(rootSyncNamespace) - u.SetLabels(map[string]string{ - rootSyncSetNameLabel: rootsyncset.Name, - rootSyncSetNamespaceLabel: rootsyncset.Namespace, - }) - if err != nil { - return nil, fmt.Errorf("failed to convert to unstructured type: %w", err) - } - return &u, nil -} - -// SetupWithManager sets up the controller with the Manager. -func (r *RootSyncSetReconciler) SetupWithManager(mgr ctrl.Manager) error { - if err := r.RemoteClientGetter.Init(mgr); err != nil { - return err - } - - r.channel = make(chan event.GenericEvent, 10) - r.watchers = make(map[v1alpha1.ClusterRef]*watcher) - - if err := v1alpha1.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - - r.Client = mgr.GetClient() - - return ctrl.NewControllerManagedBy(mgr). - For(&v1alpha1.RootSyncSet{}). - Watches( - &source.Channel{Source: r.channel}, - handler.EnqueueRequestsFromMapFunc(func(o client.Object) []reconcile.Request { - var rssName string - var rssNamespace string - if o.GetLabels() != nil { - rssName = o.GetLabels()[rootSyncSetNameLabel] - rssNamespace = o.GetLabels()[rootSyncSetNamespaceLabel] - } - if rssName == "" || rssNamespace == "" { - return []reconcile.Request{} - } - klog.Infof("Resource %s contains a label for %s", o.GetName(), rssName) - return []reconcile.Request{ - { - NamespacedName: types.NamespacedName{ - Namespace: rssNamespace, - Name: rssName, - }, - }, - } - }), - ). - Complete(r) -} - -func (r *RootSyncSetReconciler) deleteExternalResources(ctx context.Context, rootsyncset *v1alpha1.RootSyncSet) error { - var deleteErrs []error - for _, clusterRef := range rootsyncset.Spec.ClusterRefs { - remoteClient, err := r.GetRemoteClient(ctx, clusterRef, rootsyncset.Namespace) - if err != nil { - deleteErrs = append(deleteErrs, fmt.Errorf("failed to get client when deleting resource: %w", err)) - continue - } - dynamicClient, err := remoteClient.DynamicClient() - if err != nil { - deleteErrs = append(deleteErrs, fmt.Errorf("failed to get client when deleting resource: %w", err)) - continue - } - klog.Infof("deleting external resource %s ...", rootsyncset.Name) - err = dynamicClient.Resource(rootSyncGVR).Namespace("config-management-system").Delete(ctx, rootsyncset.Name, metav1.DeleteOptions{}) - if err != nil && !apierrors.IsNotFound(err) { - deleteErrs = append(deleteErrs, fmt.Errorf("failed to delete external resource : %w", err)) - } - } - if len(deleteErrs) != 0 { - for _, deleteErr := range deleteErrs { - klog.Errorf("%v", deleteErr) - } - return deleteErrs[0] - } - klog.Infof("external resource %s delete Done!", rootsyncset.Name) - return nil -} diff --git a/porch/controllers/rootsyncsets/pkg/controllers/rootsyncset/status.go b/porch/controllers/rootsyncsets/pkg/controllers/rootsyncset/status.go deleted file mode 100644 index d7ae45afa5..0000000000 --- a/porch/controllers/rootsyncsets/pkg/controllers/rootsyncset/status.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2022 The kpt 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. - -package rootsyncset - -import ( - "context" - "fmt" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/client-go/dynamic" -) - -// checkSyncStatus fetches the RootSync using the provided client and computes the sync status. The rules -// for computing status here mirrors the one used in the status command in the nomos cli. -func checkSyncStatus(ctx context.Context, client dynamic.Interface, rssName string) (string, error) { - // TODO: Change this to use the RootSync type instead of Unstructured. - rs, err := client.Resource(rootSyncGVR).Namespace(rootSyncNamespace).Get(ctx, rssName, metav1.GetOptions{}) - if err != nil { - return "", fmt.Errorf("failed to get RootSync: %w", err) - } - - generation, _, err := unstructured.NestedInt64(rs.Object, "metadata", "generation") - if err != nil { - return "", fmt.Errorf("failed to read generation from RootSync: %w", err) - } - - observedGeneration, _, err := unstructured.NestedInt64(rs.Object, "status", "observedGeneration") - if err != nil { - return "", fmt.Errorf("failed to read observedGeneration from RootSync: %w", err) - } - - if generation != observedGeneration { - return "Pending", nil - } - - conditions, _, err := unstructured.NestedSlice(rs.Object, "status", "conditions") - if err != nil { - return "", fmt.Errorf("failed to extract conditions from RootSync: %w", err) - } - - val, found, err := getConditionStatus(conditions, "Stalled") - if err != nil { - return "", fmt.Errorf("error fetching condition 'Stalled' from conditions slice: %w", err) - } - if found && val == "True" { - return "Stalled", nil - } - - val, found, err = getConditionStatus(conditions, "Reconciling") - if err != nil { - return "", fmt.Errorf("error fetching condition 'Reconciling' from conditions slice: %w", err) - } - if found && val == "True" { - return "Reconciling", nil - } - - cond, found, err := getCondition(conditions, "Syncing") - if err != nil { - return "", fmt.Errorf("error fetching condition 'Syncing' from conditions slice: %w", err) - } - if !found { - return "Reconciling", nil - } - - errCount, err := extractErrorCount(cond) - if err != nil { - return "", fmt.Errorf("error extracting error count from 'Syncing' condition: %w", err) - } - if errCount > 0 { - return "Error", nil - } - - val, err = extractStringField(cond, "status") - if err != nil { - return "", fmt.Errorf("error extracting status of 'Syncing' condition: %w", err) - } - if val == "True" { - return "Pending", nil - } - - return "Synced", nil -} - -func getConditionStatus(conditions []interface{}, condType string) (string, bool, error) { - cond, found, err := getCondition(conditions, condType) - if err != nil { - return "", false, err - } - if !found { - return "", false, nil - } - s, err := extractStringField(cond, "status") - if err != nil { - return "", false, err - } - return s, true, nil -} - -func getCondition(conditions []interface{}, condType string) (map[string]interface{}, bool, error) { - for i := range conditions { - cond, ok := conditions[i].(map[string]interface{}) - if !ok { - return map[string]interface{}{}, false, fmt.Errorf("failed to extract condition %d from slice", i) - } - t, err := extractStringField(cond, "type") - if err != nil { - return map[string]interface{}{}, false, err - } - - if t != condType { - continue - } - return cond, true, nil - } - return map[string]interface{}{}, false, nil -} - -func extractStringField(condition map[string]interface{}, field string) (string, error) { - t, ok := condition[field] - if !ok { - return "", fmt.Errorf("condition does not have a type field") - } - condVal, ok := t.(string) - if !ok { - return "", fmt.Errorf("value of '%s' condition is not of type 'string'", field) - } - return condVal, nil -} - -func extractErrorCount(cond map[string]interface{}) (int64, error) { - count, found, err := unstructured.NestedInt64(cond, "errorSummary", "totalCount") - if err != nil || !found { - return 0, err - } - return count, nil -} diff --git a/porch/controllers/rootsyncsets/pkg/controllers/rootsyncset/watcher.go b/porch/controllers/rootsyncsets/pkg/controllers/rootsyncset/watcher.go deleted file mode 100644 index fd893923d4..0000000000 --- a/porch/controllers/rootsyncsets/pkg/controllers/rootsyncset/watcher.go +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2022 The kpt 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. - -package rootsyncset - -import ( - "context" - "fmt" - "time" - - "github.com/GoogleContainerTools/kpt/porch/controllers/rootsyncsets/api/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/dynamic" - "k8s.io/klog/v2" - "sigs.k8s.io/controller-runtime/pkg/event" -) - -const ( - minReconnectDelay = 1 * time.Second - maxReconnectDelay = 30 * time.Second -) - -type watcher struct { - clusterRef v1alpha1.ClusterRef - - ctx context.Context - - cancelFunc context.CancelFunc - - client dynamic.Interface - - channel chan event.GenericEvent - - liens map[types.NamespacedName]struct{} -} - -func (w watcher) watch() { - clusterRefName := fmt.Sprintf("%s:%s", w.clusterRef.Kind, w.clusterRef.Name) - var events <-chan watch.Event - var watcher watch.Interface - var bookmark string - defer func() { - if watcher != nil { - watcher.Stop() - } - }() - - reconnect := newBackoffTimer(minReconnectDelay, maxReconnectDelay) - defer reconnect.Stop() - -loop: - for { - select { - case <-reconnect.channel(): - var err error - klog.Infof("Starting watch for %s... ", clusterRefName) - watcher, err = w.client.Resource(rootSyncGVR).Watch(w.ctx, v1.ListOptions{}) - if err != nil { - klog.Errorf("Cannot start watch for %s: %v; will retry", clusterRefName, err) - reconnect.backoff() - } else { - klog.Infof("Watch successfully started for %s.", clusterRefName) - events = watcher.ResultChan() - } - case e, ok := <-events: - if !ok { - klog.Errorf("Watch event stream closed for cluster %s. Will restart watch from bookmark %q", clusterRefName, bookmark) - watcher.Stop() - events = nil - watcher = nil - - // Initiate reconnect - reconnect.reset() - } else if obj, ok := e.Object.(*unstructured.Unstructured); ok { - if e.Type == watch.Bookmark { - bookmark = obj.GetResourceVersion() - klog.Infof("Watch bookmark for %s: %q", clusterRefName, bookmark) - } else { - w.channel <- event.GenericEvent{ - Object: obj, - } - } - } else { - klog.V(5).Infof("Received unexpected watch event Object from %s: %T", e.Object, clusterRefName) - } - case <-w.ctx.Done(): - if w.ctx.Err() != nil { - klog.V(2).Infof("exiting watcher for %s, because context is done: %v", clusterRefName, w.ctx.Err()) - } else { - klog.Infof("Watch background routine exiting for %s; context done", clusterRefName) - } - break loop - } - } -} - -// TODO: This comes from Porch. Find a place to put code that can be shared. -type backoffTimer struct { - min, max, curr time.Duration - timer *time.Timer -} - -func newBackoffTimer(min, max time.Duration) *backoffTimer { - return &backoffTimer{ - min: min, - max: max, - timer: time.NewTimer(min), - } -} - -func (t *backoffTimer) Stop() bool { - return t.timer.Stop() -} - -func (t *backoffTimer) channel() <-chan time.Time { - return t.timer.C -} - -func (t *backoffTimer) reset() bool { - t.curr = t.min - return t.timer.Reset(t.curr) -} - -func (t *backoffTimer) backoff() bool { - curr := t.curr * 2 - if curr > t.max { - curr = t.max - } - t.curr = curr - return t.timer.Reset(curr) -} diff --git a/porch/controllers/workloadidentitybindings/api/v1alpha1/groupversion_info.go b/porch/controllers/workloadidentitybindings/api/v1alpha1/groupversion_info.go deleted file mode 100644 index b0010b886f..0000000000 --- a/porch/controllers/workloadidentitybindings/api/v1alpha1/groupversion_info.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2022 The kpt 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. - -// Package v1alpha1 contains API Schema definitions for the config.porch.kpt.dev v1alpha1 API group -// +kubebuilder:object:generate=true -// +groupName=config.porch.kpt.dev -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/scheme" -) - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 object:headerFile="../../../../scripts/boilerplate.go.txt" paths="./..." - -var ( - // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "config.porch.kpt.dev", Version: "v1alpha1"} - - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} - - // AddToScheme adds the types in this group-version to the given scheme. - AddToScheme = SchemeBuilder.AddToScheme -) diff --git a/porch/controllers/workloadidentitybindings/api/v1alpha1/workloadidentitybinding_types.go b/porch/controllers/workloadidentitybindings/api/v1alpha1/workloadidentitybinding_types.go deleted file mode 100644 index 11bdd40e49..0000000000 --- a/porch/controllers/workloadidentitybindings/api/v1alpha1/workloadidentitybinding_types.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2022 The kpt 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. - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=='Ready')].reason` - -// WorkloadIdentityBinding -type WorkloadIdentityBinding struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec WorkloadIdentityBindingSpec `json:"spec,omitempty"` - Status WorkloadIdentityBindingStatus `json:"status,omitempty"` -} - -// WorkloadIdentityBindingSpec defines the desired state of WorkloadIdentityBinding -type WorkloadIdentityBindingSpec struct { - KubernetesServiceAccountRef KubernetesServiceAccountRef `json:"kubernetesServiceAccountRef,omitempty"` - GcpServiceAccountRef GcpServiceAccountRef `json:"gcpServiceAccountRef,omitempty"` -} - -type KubernetesServiceAccountRef struct { - Name string `json:"name,omitempty"` - Namespace string `json:"namespace,omitempty"` -} - -type GcpServiceAccountRef struct { - Name string `json:"name,omitempty"` - Namespace string `json:"namespace,omitempty"` - External string `json:"external,omitempty"` -} - -// WorkloadIdentityBindingStatus defines the observed state of WorkloadIdentityBinding -type WorkloadIdentityBindingStatus struct { - // Conditions describes the reconciliation state of the object. - Conditions []metav1.Condition `json:"conditions,omitempty"` -} - -//+kubebuilder:object:root=true - -// WorkloadIdentityBindingList contains a list of WorkloadIdentityBinding -type WorkloadIdentityBindingList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []WorkloadIdentityBinding `json:"items"` -} - -func init() { - SchemeBuilder.Register(&WorkloadIdentityBinding{}, &WorkloadIdentityBindingList{}) -} diff --git a/porch/controllers/workloadidentitybindings/api/v1alpha1/zz_generated.deepcopy.go b/porch/controllers/workloadidentitybindings/api/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index f1680f3ef6..0000000000 --- a/porch/controllers/workloadidentitybindings/api/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,153 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// Copyright 2023 The kpt 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 controller-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GcpServiceAccountRef) DeepCopyInto(out *GcpServiceAccountRef) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GcpServiceAccountRef. -func (in *GcpServiceAccountRef) DeepCopy() *GcpServiceAccountRef { - if in == nil { - return nil - } - out := new(GcpServiceAccountRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *KubernetesServiceAccountRef) DeepCopyInto(out *KubernetesServiceAccountRef) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesServiceAccountRef. -func (in *KubernetesServiceAccountRef) DeepCopy() *KubernetesServiceAccountRef { - if in == nil { - return nil - } - out := new(KubernetesServiceAccountRef) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *WorkloadIdentityBinding) DeepCopyInto(out *WorkloadIdentityBinding) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkloadIdentityBinding. -func (in *WorkloadIdentityBinding) DeepCopy() *WorkloadIdentityBinding { - if in == nil { - return nil - } - out := new(WorkloadIdentityBinding) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *WorkloadIdentityBinding) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *WorkloadIdentityBindingList) DeepCopyInto(out *WorkloadIdentityBindingList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]WorkloadIdentityBinding, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkloadIdentityBindingList. -func (in *WorkloadIdentityBindingList) DeepCopy() *WorkloadIdentityBindingList { - if in == nil { - return nil - } - out := new(WorkloadIdentityBindingList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *WorkloadIdentityBindingList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *WorkloadIdentityBindingSpec) DeepCopyInto(out *WorkloadIdentityBindingSpec) { - *out = *in - out.KubernetesServiceAccountRef = in.KubernetesServiceAccountRef - out.GcpServiceAccountRef = in.GcpServiceAccountRef -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkloadIdentityBindingSpec. -func (in *WorkloadIdentityBindingSpec) DeepCopy() *WorkloadIdentityBindingSpec { - if in == nil { - return nil - } - out := new(WorkloadIdentityBindingSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *WorkloadIdentityBindingStatus) DeepCopyInto(out *WorkloadIdentityBindingStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkloadIdentityBindingStatus. -func (in *WorkloadIdentityBindingStatus) DeepCopy() *WorkloadIdentityBindingStatus { - if in == nil { - return nil - } - out := new(WorkloadIdentityBindingStatus) - in.DeepCopyInto(out) - return out -} diff --git a/porch/controllers/workloadidentitybindings/config/rbac/role.yaml b/porch/controllers/workloadidentitybindings/config/rbac/role.yaml deleted file mode 100644 index 1634a386f2..0000000000 --- a/porch/controllers/workloadidentitybindings/config/rbac/role.yaml +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright 2023 The kpt 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. - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - name: porch-controllers-workloadidentitybinding -rules: -- apiGroups: - - "" - resources: - - namespaces - verbs: - - get - - list - - watch -- apiGroups: - - "" - resources: - - serviceaccounts - verbs: - - get - - list - - patch - - watch -- apiGroups: - - config.porch.kpt.dev - resources: - - workloadidentitybindings - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - config.porch.kpt.dev - resources: - - workloadidentitybindings/finalizers - verbs: - - update -- apiGroups: - - config.porch.kpt.dev - resources: - - workloadidentitybindings/status - verbs: - - get - - patch - - update -- apiGroups: - - iam.cnrm.cloud.google.com - resources: - - iampolicymembers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - iam.cnrm.cloud.google.com - resources: - - iamserviceaccounts - verbs: - - get - - list - - watch diff --git a/porch/controllers/workloadidentitybindings/config/rbac/rolebinding.yaml b/porch/controllers/workloadidentitybindings/config/rbac/rolebinding.yaml deleted file mode 100644 index 819556eccd..0000000000 --- a/porch/controllers/workloadidentitybindings/config/rbac/rolebinding.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: porch-system:porch-controllers-workloadidentitybinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: porch-controllers-workloadidentitybinding -subjects: -- kind: ServiceAccount - name: porch-controllers - namespace: porch-system \ No newline at end of file diff --git a/porch/controllers/workloadidentitybindings/config/samples/README.md b/porch/controllers/workloadidentitybindings/config/samples/README.md deleted file mode 100644 index 1fd9e9629f..0000000000 --- a/porch/controllers/workloadidentitybindings/config/samples/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Simple example - -This example creates an IAMPolicyMember so that the reference Kubernetes Service Account can access GCP services using the referenced GCP Service Account. -It also annotates the KSA with the `iam.gke.io/gcp-service-account` annotation. - -## Setup -Create a Kubernetes Service Account (KSA) in the default namespace: - -``` -kubectl -n default create sa my-example-ksa -``` - -Use Config Connector to create a GCP Service Account (GSA): - -``` -cat <.iam.gserviceaccount.com -``` - -And see that the KSA have been annotated: -``` -kubectl get sa my-example-ksa -oyaml -``` \ No newline at end of file diff --git a/porch/controllers/workloadidentitybindings/config/samples/simple.yaml b/porch/controllers/workloadidentitybindings/config/samples/simple.yaml deleted file mode 100644 index 8eca0ed02d..0000000000 --- a/porch/controllers/workloadidentitybindings/config/samples/simple.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: WorkloadIdentityBinding -metadata: - name: sample-workloadidentitybinding - namespace: config-control -spec: - gcpServiceAccountRef: - name: my-example-gsa - kubernetesServiceAccountRef: - name: my-example-ksa - namespace: default - diff --git a/porch/controllers/workloadidentitybindings/pkg/controllers/workloadidentitybinding/controller.go b/porch/controllers/workloadidentitybindings/pkg/controllers/workloadidentitybinding/controller.go deleted file mode 100644 index 9881775610..0000000000 --- a/porch/controllers/workloadidentitybindings/pkg/controllers/workloadidentitybinding/controller.go +++ /dev/null @@ -1,393 +0,0 @@ -// Copyright 2022 The kpt 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. - -package workloadidentitybinding - -import ( - "context" - "encoding/json" - "flag" - "fmt" - - "github.com/GoogleContainerTools/kpt/porch/controllers/remoterootsyncsets/pkg/applyset" - api "github.com/GoogleContainerTools/kpt/porch/controllers/workloadidentitybindings/api/v1alpha1" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/dynamic" - "k8s.io/klog/v2" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" -) - -const ( - finalizerName = "config.porch.kpt.dev/workloadidentitybindings" -) - -type Options struct { -} - -func (o *Options) InitDefaults() { -} - -func (o *Options) BindFlags(prefix string, flags *flag.FlagSet) { -} - -// WorkloadIdentityBindingReconciler reconciles WorkloadIdentityBinding objects -type WorkloadIdentityBindingReconciler struct { - Options - - client.Client - - dynamicClient dynamic.Interface - restMapper meta.RESTMapper -} - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 rbac:roleName=porch-controllers-workloadidentitybinding webhook paths="." output:rbac:artifacts:config=../../../config/rbac - -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=workloadidentitybindings,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=workloadidentitybindings/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=workloadidentitybindings/finalizers,verbs=update -//+kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch -//+kubebuilder:rbac:groups=iam.cnrm.cloud.google.com,resources=iampolicymembers,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=iam.cnrm.cloud.google.com,resources=iamserviceaccounts,verbs=get;list;watch -//+kubebuilder:rbac:groups="",resources=serviceaccounts,verbs=get;list;watch;patch - -// Reconcile implements the main kubernetes reconciliation loop. -func (r *WorkloadIdentityBindingReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - var subject api.WorkloadIdentityBinding - if err := r.Get(ctx, req.NamespacedName, &subject); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - if subject.ObjectMeta.DeletionTimestamp.IsZero() { - // The object is not being deleted, so if it does not have our finalizer, - // then lets add the finalizer and update the object. This is equivalent - // registering our finalizer. - if !controllerutil.ContainsFinalizer(&subject, finalizerName) { - controllerutil.AddFinalizer(&subject, finalizerName) - if err := r.Update(ctx, &subject); err != nil { - klog.Warningf("failed to update %s after adding finalizer: %v", req.Name, err) - return ctrl.Result{}, err - } - } - } else { - // The object is being deleted - if controllerutil.ContainsFinalizer(&subject, finalizerName) { - // // our finalizer is present, so lets remove the annotation from the SA - if err := r.removeWiAnnotation(ctx, &subject); err != nil { - // failed to remove the annotation, so return the error so it can be retried. - klog.Warningf("failed to remove SA annotation from %s: %v", req.Name, err) - return ctrl.Result{}, err - } - // remove our finalizer from the list and update it. - controllerutil.RemoveFinalizer(&subject, finalizerName) - if err := r.Update(ctx, &subject); err != nil { - klog.Warningf("failed to update %s after removing finalizer: %v", req.Name, err) - return ctrl.Result{}, err - } - } - // Stop reconciliation as the item is being deleted - return ctrl.Result{}, nil - } - - var result ctrl.Result - - projectID, err := r.findProjectID(ctx, &subject) - if err != nil { - return result, err - } - - results, err := r.applyToClusterRef(ctx, projectID, &subject) - if err == nil && results.AllApplied() && results.AllHealthy() { - // If the IAMPolicyMember has been installed and reconciled, we add the annotation. - err = r.addWiAnnotation(ctx, projectID, &subject) - } - if updateStatus(&subject, results, err) { - if updateErr := r.Status().Update(ctx, &subject); updateErr != nil { - if err == nil { - return result, updateErr - } - } - } - - if err != nil { - klog.Warningf("error during apply: %v", err) - // TODO: Post event - return result, err - } - if results != nil && !(results.AllApplied() && results.AllHealthy()) { - result.Requeue = true - } - - return result, nil -} - -func updateStatus(subject *api.WorkloadIdentityBinding, results *applyset.ApplyResults, err error) bool { - conditions := &subject.Status.Conditions - if err != nil { - meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionFalse, Reason: "Error"}) - } else if !results.AllApplied() { - meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionFalse, Reason: "ApplyInProgress"}) - } else if !results.AllHealthy() { - meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionFalse, Reason: "NotHealthy"}) - } else { - meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionTrue, Reason: "Ready"}) - } - - // TODO: Check apply results and think about status conditions - - return true -} - -func (r *WorkloadIdentityBindingReconciler) findProjectID(ctx context.Context, subject *api.WorkloadIdentityBinding) (string, error) { - ns := &corev1.Namespace{} - if err := r.Get(ctx, types.NamespacedName{Name: subject.GetNamespace()}, ns); err != nil { - return "", fmt.Errorf("error getting namespace %q: %w", subject.GetNamespace(), err) - } - - parentProjectID := ns.GetAnnotations()["cnrm.cloud.google.com/project-id"] - if parentProjectID == "" { - return "", fmt.Errorf("project-id not found for namespace %q", ns.GetName()) - } - return parentProjectID, nil -} - -func (r *WorkloadIdentityBindingReconciler) applyToClusterRef(ctx context.Context, projectID string, subject *api.WorkloadIdentityBinding) (*applyset.ApplyResults, error) { - objects, err := r.BuildObjectsToApply(ctx, projectID, subject) - if err != nil { - return nil, err - } - - // TODO: Cache applyset? - patchOptions := metav1.PatchOptions{ - FieldManager: fieldManager(subject), - } - - // We force to overcome errors like: Apply failed with 1 conflict: conflict with "kubectl-client-side-apply" using apps/v1: .spec.template.spec.containers[name="porch-server"].image - // TODO: How to handle this better - force := true - patchOptions.Force = &force - - applyset, err := applyset.New(applyset.Options{ - RESTMapper: r.restMapper, - Client: r.dynamicClient, - PatchOptions: patchOptions, - }) - if err != nil { - return nil, err - } - - if err := applyset.ReplaceAllObjects(objects); err != nil { - return nil, err - } - - results, err := applyset.ApplyOnce(ctx) - if err != nil { - return nil, fmt.Errorf("failed to apply: %w", err) - } - - return results, nil -} - -func (r *WorkloadIdentityBindingReconciler) BuildObjectsToApply(ctx context.Context, projectID string, subject *api.WorkloadIdentityBinding) ([]applyset.ApplyableObject, error) { - var objects []applyset.ApplyableObject - - { - u := &unstructured.Unstructured{} - u.SetAPIVersion("iam.cnrm.cloud.google.com/v1beta1") - u.SetKind("IAMPolicyMember") - u.SetName("workloadidentitybinding-" + subject.GetName()) - u.SetNamespace(subject.GetNamespace()) - - saRef := subject.Spec.KubernetesServiceAccountRef - - saNamespace := saRef.Namespace - saName := saRef.Name - if saNamespace == "" { - saNamespace = subject.GetNamespace() - } - - member := "serviceAccount:" + projectID + ".svc.id.goog[" + saNamespace + "/" + saName + "]" - - resourceRef := map[string]string{ - "apiVersion": "iam.cnrm.cloud.google.com/v1beta1", - "kind": "IAMServiceAccount", - "name": subject.Spec.GcpServiceAccountRef.Name, - } - if ns := subject.Spec.GcpServiceAccountRef.Namespace; ns != "" { - resourceRef["namespace"] = ns - } - if ext := subject.Spec.GcpServiceAccountRef.External; ext != "" { - resourceRef["external"] = ext - } - u.Object["spec"] = map[string]interface{}{ - "member": member, - "role": "roles/iam.workloadIdentityUser", - "resourceRef": resourceRef, - } - - objects = append(objects, u) - } - - for _, obj := range objects { - ownerRefs := obj.GetOwnerReferences() - - controller := true - ownerRefs = append(ownerRefs, metav1.OwnerReference{ - APIVersion: subject.APIVersion, - Kind: subject.Kind, - Name: subject.GetName(), - UID: subject.GetUID(), - Controller: &controller, - }) - obj.SetOwnerReferences(ownerRefs) - } - - return objects, nil -} - -func (r *WorkloadIdentityBindingReconciler) addWiAnnotation(ctx context.Context, projectID string, subject *api.WorkloadIdentityBinding) error { - // TODO: We should have a watch here so we can annotate the ServiceAccount even if it is - // applied later. - ksa, err := r.getKubernetesServiceAccount(ctx, subject) - if err != nil { - return client.IgnoreNotFound(err) - } - - // TODO: Same as above, we should have a watch here so we can annotate the ksa when - // the gsa is created and reconciled (i.e. have the status.email field set) - gsa, err := r.getGcpServiceAccount(ctx, subject) - if err != nil { - return client.IgnoreNotFound(err) - } - - gsaEmail, found, err := unstructured.NestedString(gsa.Object, "status", "email") - if err != nil { - return err - } - if !found || gsaEmail == "" { - return nil - } - - u := &unstructured.Unstructured{} - u.SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("ServiceAccount")) - u.SetName(ksa.GetName()) - u.SetNamespace(ksa.GetNamespace()) - u.SetAnnotations(map[string]string{ - "iam.gke.io/gcp-service-account": gsaEmail, - }) - - return r.updateServiceAccount(ctx, u, subject) -} - -func (r *WorkloadIdentityBindingReconciler) removeWiAnnotation(ctx context.Context, subject *api.WorkloadIdentityBinding) error { - sa, err := r.getKubernetesServiceAccount(ctx, subject) - if err != nil { - return client.IgnoreNotFound(err) - } - - u := &unstructured.Unstructured{} - u.SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("ServiceAccount")) - u.SetName(sa.GetName()) - u.SetNamespace(sa.GetNamespace()) - u.SetAnnotations(make(map[string]string)) - - return r.updateServiceAccount(ctx, u, subject) -} - -func (r *WorkloadIdentityBindingReconciler) getKubernetesServiceAccount(ctx context.Context, subject *api.WorkloadIdentityBinding) (*unstructured.Unstructured, error) { - saRef := subject.Spec.KubernetesServiceAccountRef - - saName := saRef.Name - saNamespace := saRef.Namespace - if saNamespace == "" { - saNamespace = subject.GetNamespace() - } - - var sa unstructured.Unstructured - sa.SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("ServiceAccount")) - if err := r.Get(ctx, types.NamespacedName{Name: saName, Namespace: saNamespace}, &sa); err != nil { - return nil, err - } - - return &sa, nil -} - -func (r *WorkloadIdentityBindingReconciler) getGcpServiceAccount(ctx context.Context, subject *api.WorkloadIdentityBinding) (*unstructured.Unstructured, error) { - gsaRef := subject.Spec.GcpServiceAccountRef - - gsaName := gsaRef.Name - gsaNamespace := gsaRef.Namespace - if gsaNamespace == "" { - gsaNamespace = subject.GetNamespace() - } - - u := &unstructured.Unstructured{} - u.SetAPIVersion("iam.cnrm.cloud.google.com/v1beta1") - u.SetKind("IAMServiceAccount") - - err := r.Get(ctx, types.NamespacedName{Name: gsaName, Namespace: gsaNamespace}, u) - return u, err -} - -func (r *WorkloadIdentityBindingReconciler) updateServiceAccount(ctx context.Context, sa *unstructured.Unstructured, subject *api.WorkloadIdentityBinding) error { - data, err := json.Marshal(sa) - if err != nil { - return err - } - - mapping, err := r.restMapper.RESTMapping(corev1.SchemeGroupVersion.WithKind("ServiceAccount").GroupKind(), corev1.SchemeGroupVersion.Version) - if err != nil { - return err - } - dr := r.dynamicClient.Resource(mapping.Resource) - _, err = dr.Namespace(sa.GetNamespace()).Patch(ctx, sa.GetName(), types.ApplyPatchType, data, metav1.PatchOptions{ - FieldManager: fieldManager(subject), - }) - return client.IgnoreNotFound(err) -} - -func fieldManager(subject *api.WorkloadIdentityBinding) string { - return subject.GetObjectKind().GroupVersionKind().Kind + "-" + subject.GetNamespace() + "-" + subject.GetName() -} - -// SetupWithManager sets up the controller with the Manager. -func (r *WorkloadIdentityBindingReconciler) SetupWithManager(mgr ctrl.Manager) error { - if err := api.AddToScheme(mgr.GetScheme()); err != nil { - return err - } - - r.Client = mgr.GetClient() - - if err := ctrl.NewControllerManagedBy(mgr). - For(&api.WorkloadIdentityBinding{}). - Complete(r); err != nil { - return err - } - - restConfig := mgr.GetConfig() - - client, err := dynamic.NewForConfig(restConfig) - if err != nil { - return fmt.Errorf("failed to create a new dynamic client: %w", err) - } - r.dynamicClient = client - - r.restMapper = mgr.GetRESTMapper() - - return nil -} diff --git a/porch/deployments/local/kubeconfig b/porch/deployments/local/kubeconfig deleted file mode 100644 index eae532546a..0000000000 --- a/porch/deployments/local/kubeconfig +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: v1 -clusters: -- cluster: - insecure-skip-tls-verify: true - # IP Address statically assigned when Docker container is started (see Makefile) - server: https://192.168.8.201:9444 - name: apiserver -contexts: -- context: - cluster: apiserver - user: apiserver - name: apiserver -current-context: apiserver -kind: Config -preferences: {} -users: -- name: apiserver - user: - client-key: ../../.build/pki/admin.key - client-certificate: ../../.build/pki/admin.crt - diff --git a/porch/deployments/local/kubeconfig.direct b/porch/deployments/local/kubeconfig.direct deleted file mode 100644 index f461a6f256..0000000000 --- a/porch/deployments/local/kubeconfig.direct +++ /dev/null @@ -1,19 +0,0 @@ - -apiVersion: v1 -clusters: -- cluster: - insecure-skip-tls-verify: true - server: https://localhost:9443 - name: apiserver -contexts: -- context: - cluster: apiserver - user: apiserver - name: apiserver -current-context: apiserver -kind: Config -preferences: {} -users: -- name: apiserver - user: - username: apiserver diff --git a/porch/deployments/local/localconfig.yaml b/porch/deployments/local/localconfig.yaml deleted file mode 100644 index 74c9fcfb81..0000000000 --- a/porch/deployments/local/localconfig.yaml +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: v1 -kind: Namespace -metadata: - name: porch-system -spec: {} - ---- - -apiVersion: apiregistration.k8s.io/v1 -kind: APIService -metadata: - name: v1alpha1.porch.kpt.dev -spec: - insecureSkipTLSVerify: true - group: porch.kpt.dev - groupPriorityMinimum: 1000 - versionPriority: 15 - service: - name: api - namespace: porch-system - port: 9443 - version: v1alpha1 - ---- - -apiVersion: v1 -kind: Service -metadata: - name: api - namespace: porch-system -spec: - type: ExternalName - # We use Docker DNS to reach the host. See Makefile for how the containers are started on porch network - # with `--add-host host.docker.internal:host-gateway` flag. - externalName: host.docker.internal diff --git a/porch/deployments/local/makekeys.sh b/porch/deployments/local/makekeys.sh deleted file mode 100755 index 7eba69122b..0000000000 --- a/porch/deployments/local/makekeys.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/bin/bash -# Copyright 2022 The kpt 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. - -# Build keys for running kube-apiserver -# Based on https://kubernetes.io/docs/tasks/administer-cluster/certificates/ - -DIR=.build/pki -mkdir -p ${DIR} -cd ${DIR} - - -if [[ ! -f service-account.pub ]]; then - openssl genrsa -out service-account.key 2048 - openssl rsa -in service-account.key -pubout -out service-account.pub -fi - - -cat > csr.conf < -#ST = -#L = -#O = -#OU = -CN = 127.0.0.1 - -[ req_ext ] -subjectAltName = @alt_names - -[ alt_names ] -DNS.1 = kubernetes -DNS.2 = kubernetes.default -DNS.3 = kubernetes.default.svc -DNS.4 = kubernetes.default.svc.cluster -DNS.5 = kubernetes.default.svc.cluster.local -IP.1 = 127.0.0.1 -#IP.2 = - -[ v3_ext ] -authorityKeyIdentifier=keyid,issuer:always -basicConstraints=CA:FALSE -keyUsage=keyEncipherment,dataEncipherment -extendedKeyUsage=serverAuth,clientAuth -subjectAltName=@alt_names -EOF - -if [[ ! -f ca.crt ]]; then - openssl genrsa -out ca.key 2048 - openssl req -x509 -new -nodes -key ca.key -subj "/CN=127.0.0.1" -days 10000 -out ca.crt -fi - -if [[ ! -f apiserver.crt ]]; then - openssl genrsa -out apiserver.key 2048 - openssl req -new -key apiserver.key -out apiserver.csr -config csr.conf - - openssl x509 -req -in apiserver.csr -CA ca.crt -CAkey ca.key \ - -CAcreateserial -out apiserver.crt -days 10000 \ - -extensions v3_ext -extfile csr.conf -fi - -if [[ ! -f admin.crt ]]; then - openssl genrsa -out admin.key 2048 - openssl req -new -key admin.key -out admin.csr -subj "/CN=admin/O=system:masters" -days 10000 - - openssl x509 -req -in admin.csr -CA ca.crt -CAkey ca.key \ - -CAcreateserial -out admin.crt -days 10000 \ - -extensions v3_ext -extfile csr.conf -fi diff --git a/porch/deployments/porch/1-namespace.yaml b/porch/deployments/porch/1-namespace.yaml deleted file mode 100644 index c04891e34e..0000000000 --- a/porch/deployments/porch/1-namespace.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: v1 -kind: Namespace -metadata: - name: porch-system - ---- -apiVersion: v1 -kind: Namespace -metadata: - name: porch-fn-system diff --git a/porch/deployments/porch/2-function-runner.yaml b/porch/deployments/porch/2-function-runner.yaml deleted file mode 100644 index beda1cba3e..0000000000 --- a/porch/deployments/porch/2-function-runner.yaml +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright 2022 The kpt 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. - -kind: ServiceAccount -apiVersion: v1 -metadata: - name: porch-fn-runner - namespace: porch-system - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: function-runner - namespace: porch-system -spec: - replicas: 2 - selector: - matchLabels: - app: function-runner - template: - metadata: - labels: - app: function-runner - spec: - serviceAccountName: porch-fn-runner - containers: - - name: function-runner - image: gcr.io/example-google-project-id/porch-function-runner:latest - imagePullPolicy: IfNotPresent - command: - - /server - - --config=/config.yaml - - --functions=/functions - - --pod-namespace=porch-fn-system - env: - - name: WRAPPER_SERVER_IMAGE - value: gcr.io/example-google-project-id/porch-wrapper-server:latest - ports: - - containerPort: 9445 - # Add grpc readiness probe to ensure the cache is ready - readinessProbe: - exec: - command: - - /grpc-health-probe - - -addr - - localhost:9445 - resources: - requests: - memory: "64Mi" - cpu: "125m" - volumeMounts: - - mountPath: /pod-cache-config - name: pod-cache-config-volume - volumes: - - name: pod-cache-config-volume - configMap: - name: pod-cache-config - ---- -apiVersion: v1 -kind: Service -metadata: - name: function-runner - namespace: porch-system -spec: - selector: - app: function-runner - ports: - - port: 9445 - protocol: TCP - targetPort: 9445 - ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: pod-cache-config - namespace: porch-system -data: - pod-cache-config.yaml: | - gcr.io/kpt-fn/apply-replacements:v0.1.1: 30m - gcr.io/kpt-fn/apply-setters:v0.2.0: 30m - gcr.io/kpt-fn/create-setters:v0.1.0: 30m - gcr.io/kpt-fn/ensure-name-substring:v0.2.0: 30m - gcr.io/kpt-fn/gatekeeper:v0.2.1: 30m - gcr.io/kpt-fn/kubeval:v0.2.0: 30m - gcr.io/kpt-fn/search-replace:v0.2.0: 30m - gcr.io/kpt-fn/set-annotations:v0.1.4: 30m - gcr.io/kpt-fn/set-enforcement-action:v0.1.0: 30m - gcr.io/kpt-fn/set-image:v0.1.1: 30m - gcr.io/kpt-fn/set-labels:v0.1.5: 30m - gcr.io/kpt-fn/set-namespace:v0.4.1: 30m - gcr.io/kpt-fn/starlark:v0.4.3: 30m - gcr.io/kpt-fn/upsert-resource:v0.2.0: 30m - gcr.io/kpt-fn/enable-gcp-services:v0.1.0: 30m - gcr.io/kpt-fn/export-terraform:v0.1.0: 30m - gcr.io/kpt-fn/generate-folders:v0.1.1: 30m - gcr.io/kpt-fn/remove-local-config-resources:v0.1.0: 30m - gcr.io/kpt-fn/set-project-id:v0.2.0: 30m diff --git a/porch/deployments/porch/3-porch-server.yaml b/porch/deployments/porch/3-porch-server.yaml deleted file mode 100644 index 87b88bbfae..0000000000 --- a/porch/deployments/porch/3-porch-server.yaml +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright 2022 The kpt 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. - -kind: ServiceAccount -apiVersion: v1 -metadata: - name: porch-server - namespace: porch-system - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: porch-server - namespace: porch-system -spec: - replicas: 1 - selector: - matchLabels: - app: porch-server - template: - metadata: - labels: - app: porch-server - spec: - serviceAccountName: porch-server - volumes: - - name: cache-volume - emptyDir: {} - - name: webhook-certs - emptyDir: {} - - name: api-server-certs - emptyDir: {} - containers: - - name: porch-server - # Update image to the image of your porch apiserver build. - image: gcr.io/example-google-project-id/porch-server:latest - imagePullPolicy: IfNotPresent - resources: - requests: - memory: "256Mi" - cpu: "250m" - limits: - memory: "512Mi" - volumeMounts: - - mountPath: /cache - name: cache-volume - - mountPath: /etc/webhook/certs - name: webhook-certs - - name: api-server-certs - mountPath: /tmp/certs - env: - # Uncomment to enable trace-reporting to jaeger - #- name: OTEL - # value: otel://jaeger-oltp:4317 - - name: OTEL_SERVICE_NAME - value: porch-server - - name: CERT_STORAGE_DIR - value: "/etc/webhook/certs" - args: - - --function-runner=function-runner:9445 - - --cache-directory=/cache - - --cert-dir=/tmp/certs - - --secure-port=4443 - - --repo-sync-frequency=60s - ---- -apiVersion: v1 -kind: Service -metadata: - name: api - namespace: porch-system -spec: - ports: - - port: 443 - protocol: TCP - targetPort: 4443 - name: api - - port: 8443 - protocol: TCP - targetPort: 8443 - name: webhooks - selector: - app: porch-server diff --git a/porch/deployments/porch/4-apiservice.yaml b/porch/deployments/porch/4-apiservice.yaml deleted file mode 100644 index d9b6843429..0000000000 --- a/porch/deployments/porch/4-apiservice.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: apiregistration.k8s.io/v1 -kind: APIService -metadata: - name: v1alpha1.porch.kpt.dev -spec: - insecureSkipTLSVerify: true - group: porch.kpt.dev - groupPriorityMinimum: 1000 - versionPriority: 15 - service: - name: api - namespace: porch-system - version: v1alpha1 diff --git a/porch/deployments/porch/5-rbac.yaml b/porch/deployments/porch/5-rbac.yaml deleted file mode 100644 index bb4721e479..0000000000 --- a/porch/deployments/porch/5-rbac.yaml +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright 2022 The kpt 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. - -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: aggregated-apiserver-clusterrole -rules: - - apiGroups: [""] - resources: ["namespaces", "secrets"] - verbs: ["get", "watch", "list"] - - apiGroups: ["admissionregistration.k8s.io"] - resources: - ["mutatingwebhookconfigurations", "validatingwebhookconfigurations"] - verbs: ["get", "watch", "list", "create", "patch", "delete"] - - apiGroups: ["porch.kpt.dev"] - resources: ["functions"] - verbs: ["get", "list", "watch", "create", "update", "patch"] - - apiGroups: ["config.porch.kpt.dev"] - resources: ["repositories", "repositories/status"] - verbs: ["get", "list", "watch", "create", "update", "patch"] - - apiGroups: ["porch.kpt.dev"] - resources: ["packagerevisions", "packagerevisions/status"] - verbs: ["get", "list"] - - apiGroups: ["config.porch.kpt.dev"] - resources: ["packagerevs", "packagerevs/status"] - verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] - # Needed for priority and fairness - - apiGroups: ["flowcontrol.apiserver.k8s.io"] - resources: ["flowschemas", "prioritylevelconfigurations"] - verbs: ["get", "watch", "list"] ---- -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: aggregated-apiserver-role - namespace: porch-system -rules: - # Needed for workload identity - - apiGroups: [""] - resources: ["serviceaccounts"] - verbs: ["get"] - - apiGroups: [""] - resources: ["serviceaccounts/token"] - verbs: ["create"] ---- -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: porch-function-executor - namespace: porch-fn-system -rules: - # Needed to launch / read function executor pods - - apiGroups: [""] - resources: ["pods"] - verbs: ["create", "delete", "patch", "get", "watch", "list"] diff --git a/porch/deployments/porch/6-rbac-bind.yaml b/porch/deployments/porch/6-rbac-bind.yaml deleted file mode 100644 index 906dbed7f1..0000000000 --- a/porch/deployments/porch/6-rbac-bind.yaml +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: sample-apiserver-clusterrolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: aggregated-apiserver-clusterrole -subjects: - - kind: ServiceAccount - name: porch-server - namespace: porch-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: sample-apiserver-rolebinding - namespace: porch-system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: aggregated-apiserver-role -subjects: - - kind: ServiceAccount - name: porch-server - namespace: porch-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: porch-function-executor - namespace: porch-fn-system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: porch-function-executor -subjects: - - kind: ServiceAccount - name: porch-fn-runner - namespace: porch-system diff --git a/porch/deployments/porch/7-auth-reader.yaml b/porch/deployments/porch/7-auth-reader.yaml deleted file mode 100644 index 1d310230b2..0000000000 --- a/porch/deployments/porch/7-auth-reader.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: porch-auth-reader - namespace: kube-system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: extension-apiserver-authentication-reader -subjects: -- kind: ServiceAccount - name: porch-server - namespace: porch-system diff --git a/porch/deployments/porch/8-auth-delegator.yaml b/porch/deployments/porch/8-auth-delegator.yaml deleted file mode 100644 index 0a1ccad998..0000000000 --- a/porch/deployments/porch/8-auth-delegator.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: porch:system:auth-delegator -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:auth-delegator -subjects: -- kind: ServiceAccount - name: porch-server - namespace: porch-system diff --git a/porch/deployments/porch/9-controllers.yaml b/porch/deployments/porch/9-controllers.yaml deleted file mode 100644 index 509eb3d380..0000000000 --- a/porch/deployments/porch/9-controllers.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2022 The kpt 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. - -kind: ServiceAccount -apiVersion: v1 -metadata: - name: porch-controllers - namespace: porch-system - ---- - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: porch-controllers - namespace: porch-system - labels: - k8s-app: "porch-controllers" -spec: - replicas: 1 - selector: - matchLabels: - k8s-app: "porch-controllers" - template: - metadata: - labels: - k8s-app: "porch-controllers" - spec: - serviceAccountName: porch-controllers - containers: - - name: porch-controllers - # Update to the image of your porch-controllers build. - image: gcr.io/example-google-project-id/porch-controllers:latest - env: - - name: GCP_PROJECT_ID - value: example-google-project-id diff --git a/porch/deployments/porch/Kptfile b/porch/deployments/porch/Kptfile deleted file mode 100644 index 26f914b0de..0000000000 --- a/porch/deployments/porch/Kptfile +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: porch -info: - description: porch diff --git a/porch/deployments/tracing/README.md b/porch/deployments/tracing/README.md deleted file mode 100644 index 9e7065ec24..0000000000 --- a/porch/deployments/tracing/README.md +++ /dev/null @@ -1,30 +0,0 @@ -### How to enable jaeger tracing - -If you want to enable jaeger tracing of the porch-server: - -* Apply the [deployment.yaml manifest](deployment.yaml) from this directory - -``` -kubectl apply -f deployment.yaml -``` - -* Add the commented out env var OTEL to the porch-server manifest: - -``` -kubectl edit deployment -n porch-system porch-server -``` - -``` - env: - # Uncomment to enable trace-reporting to jaeger - #- name: OTEL - # value: otel://jaeger-oltp:4317 -``` - -* Port-forward the jaeger http port to your local machine: - -``` -kubectl port-forward -n porch-system service/jaeger-http 16686 -``` - -* Open your browser to the UI on http://localhost:16686 \ No newline at end of file diff --git a/porch/deployments/tracing/deployment.yaml b/porch/deployments/tracing/deployment.yaml deleted file mode 100644 index f14b2869af..0000000000 --- a/porch/deployments/tracing/deployment.yaml +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2022 The kpt 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. - -kind: ServiceAccount -apiVersion: v1 -metadata: - name: jaeger - namespace: porch-system - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: jaeger - namespace: porch-system -spec: - replicas: 1 - selector: - matchLabels: - app: jaeger - template: - metadata: - labels: - app: jaeger - spec: - serviceAccountName: jaeger - containers: - - name: jaeger - image: jaegertracing/opentelemetry-all-in-one:latest - imagePullPolicy: IfNotPresent - resources: - requests: - memory: "1024Mi" - cpu: "250m" - limits: - memory: "1024Mi" - ---- -apiVersion: v1 -kind: Service -metadata: - name: jaeger-oltp - namespace: porch-system -spec: - ports: - - port: 4317 - protocol: TCP - targetPort: 55680 - selector: - app: jaeger ---- -apiVersion: v1 -kind: Service -metadata: - name: jaeger-http - namespace: porch-system -spec: - ports: - - port: 16686 - protocol: TCP - targetPort: 16686 - selector: - app: jaeger diff --git a/porch/docs/development.md b/porch/docs/development.md deleted file mode 100644 index 3efe63a972..0000000000 --- a/porch/docs/development.md +++ /dev/null @@ -1,107 +0,0 @@ -# Development - -## Changing Porch API - -If you change the API resources, in `api/porch/.../*.go`, update the generated code by running: - -```sh -make generate -``` - -## Components - -Porch comprises of several software components: - -* [api](../api): Definition of the KRM API supported by the Porch extension apiserver -* [apiserver](../pkg/apiserver/): The Porch apiserver implementation, REST handlers, Porch `main` function -* [engine](../pkg/engine/): Core logic of Package Orchestration - operations on package contents -* [func](../func): KRM function evaluator microservice; exposes gRPC API -* [repository](../pkg/repository/): Repository integration packge -* [git](../pkg/git/): Integration with Git repository. -* [oci](../pkg/oci/): Integration with OCI repository. -* [cache](../pkg/cache/): Package caching. -* [controllers](../controllers): `Repository` CRD. No controller; - Porch apiserver watches these resources for changes as repositories are (un-)registered. -* [remoterootsync](../controllers/remoterootsync): CRD and controller for deploying packages -* [test](../test): Test Git Server for Porch e2e testing, and - [e2e](../test/e2e/) tests. - -## Running Porch - -See dedicated documentation on running Porch: - -* [locally](running-locally.md) -* [on GKE](../../site/guides/porch-installation.md) - -## Build the Container Images - -Build Docker images of Porch components: - -```sh -# Build Images -make build-images - -# Push Images to Docker Registry -make push-images - -# Supported make variables: -# IMAGE_TAG - image tag, i.e. 'latest' (defaults to 'latest') -# GCP_PROJECT_ID - GCP project hosting gcr.io repository (will translate to gcr.io/${GCP_PROJECT_ID}) -# IMAGE_REPO - overwrites the default image repository - -# Example: -IMAGE_TAG=$(git rev-parse --short HEAD) make push-images -``` - -## Running Locally - -Follow [running-locally.md](./running-locally.md) to run Porch locally. - -## Debugging - -To debug Porch, run Porch locally [running-locally.md](./running-locally.md), exit porch server running in the shell, -and launch Porch under the debugger. VSCode debug session is preconfigured in [launch.json](../.vscode/launch.json). - -Update the launch arguments to your needs. - -## Code Pointers - -Some useful code pointers: - -* Porch REST API handlers in [registry/porch](../pkg/registry/porch/), for example - [packagerevision.go](../pkg/registry/porch/packagerevision.go) -* Background task handling cache updates in [background.go](../pkg/registry/porch/background.go) -* Git repository integration in [pkg/git](../pkg/git) -* OCI repository integration in [pkg/oci](../pkg/oci) -* CaD Engine in [engine](../pkg/engine) -* e2e tests in [e2e](../test/e2e/). See below more on testing. - -## Running Tests - -All tests can be run using `make test`. Individual tests can be run using `go test`. -End-to-End tests assume that Porch instance is running and `KUBECONFIG` is configured -with the instance. The tests will automatically detect whether they are running against -Porch running on local machien or k8s cluster and will start Git server appropriately, -then run test suite against the Porch instance. - -## Makefile Targets - -* `make generate`: generate code based on Porch API definitions (runs k8s code generators) -* `make tidy`: tidies all Porch modules -* `make fmt`: formats golang sources -* `make build-images`: builds Porch Docker images -* `make push-images`: builds and pushes Porch Docker images -* `make deployment-config`: customizes configuration which installs Porch - in k8s cluster with correct image names, annotations, service accounts. - The deployment-ready configuration is copied into `./.build/deploy` -* `make deploy`: deploys Porch in the k8s cluster configured with current kubectl context -* `make push-and-deploy`: builds, pushes Porch Docker images, creates deployment configuration, and deploys Porch -* `make` or `make all`: builds and runs Porch [locally](./running-locally.md) -* `make test`: runs tests - -## VSCode - -[VSCode](https://code.visualstudio.com/) works really well for editing and debugging. -Because Porch is comprises of multiple go modules, there is a pre-configured -multi-folder workspace in [porch.code-workspace](../porch.code-workspace). -Open it in VSCode (File / Open Workspace from File) to use Workspace Folders. diff --git a/porch/docs/porch-roadmap.md b/porch/docs/porch-roadmap.md deleted file mode 100644 index 278112745a..0000000000 --- a/porch/docs/porch-roadmap.md +++ /dev/null @@ -1,157 +0,0 @@ -# Porch Roadmap - -Last updated: February 9th, 2023 - -This document outlines next steps for Porch in several areas. This is a living -document outlining future direction and work in different Porch subsystems. - -## API Changes - -* Expression kpt function type 'signature', including: - * types of resources the function acts on - * schema of the function config - * types of resources the function _produces_ (if the function introduces new - resources into the configuration package) -* Add `Package` resource to encapsulate all `PackageRevision`s of the same - package, link to the latest `PackageRevision`. Possibly the `Package` resource - can allow mutation of the package or its contents, and automatically create - new (_Draft_) `PackageRevision` resources on mutations. -* Implement support for API-level filtering (field and label selectors) for all - `list` operations. -* Make sure that all errors translate to the appropriate API-level HTTP status - with clear, actionable messages. -* Cross-namespace cloning to make it possible to better leverage Kubernetes RBAC - for controlling access to repositories. -* Move long-running operations to asynchronous operations by controllers rather than - synchronous operations by the aggregated apiserver. This means exposing results - in the status object of resources rather than return errors. -* Support non-KRM content as part of `ResourceList` to allow lossless package - transformations, or compensate for lack of this support in general by enabling - in Porch partial package revision `pull` and `push`. - -## Repository Management - -* Support for specifying repository-wide, default _upstream_ repository which - would become the default upstream repository for cloned packages -* Repository-wide guardrails - functions registered with the repository that - then are evaluated on packages in that repository whenever those packages - change. -* Support updating repository registration, for example when `Repository` - resource is modified to point to a different repository, or even a different - type of a repository (Git --> OCI). -* Support read only repositories. Porch will allow package discovery in a read - only repository but attempt to create/modify package in read only repository - will result in an error. Consider supporting via RBAC so different principals - can have different level of access to the same repository. -* Implement repository cache eviction policy -* Support `ObjectMeta.GenerateName` for `PackageRevision` creation. Currently - package names are computed as -. Ideally Porch would accept - name prefix (constrained for example to the last segment of the package name) - as `GenerateName` value, for example `istions` and Porch would append the SHA. - This will require creating an inverse mapping from package name to its owning - repository. Currently the inverse mapping is encoded in the package name, - whose format is `-`. -* Error-resilient repository ingestion (some erroneous packages in the - repository should not prevent repository from successfully loading). -* Make the background repository routine a controller to leverage functionality - in the common controller libraries, such as maintaining reliable `Watch` - connection (`background.go`). -* Enable OCI repositories with heterogeneous contents (containing both - `Package` and `Function` resources)? -* Improve synchronization of repository actions to avoid simultaneous repository - fetches and repository access that requires synchronization. - -### Git - -* Support authentication for cloning packages from unregistered repositories. -* Porch will need to store more information associated with a package revision, - for example: - * information about the package's error status (to populate the `status` - section of the PackageRevision API resource)) - * rationale for rejection proposal to publish a package - - We will need to utilize Git repository or some auxiliary storage (git is - preferred because it also propagates information across Porch instances) - and we can consider: - * storing the information in a HEAD draft commit. When draft is updated, - Porch would drop this HEAD commit, stack more mutation commits and then - add a new HEAD commit with additional meta information - * using separate 'meta' branches - * Git notes (though these are attached to object ) -* Implement appropriate caching when cloning packages from unregistered - repositories (currently, those repositories are fetched and immediately - deleted)) - -## OCI - -* Complete the OCI support (current implementation is partial, missing package - lifecycle support, cloning from OCI repository is not supported, etc.) -* Support for authentication methods as required by integration with specific - OCI repository providers. Currently Porch authenticates as the workload - identity GCP service account which works well with Google Container Registry - and Artifact Registry; different methods will likely be needed for other - providers. - -## Engine - -* Create a unified representation of a package and its contents in the system. - Porch Engine currently stores package contents as `map[string]string` (file - name --> file contents, see `PackageResources` type) and kpt intrinsic - algorithms work with `kyaml filesys.FileSys` interface, necessitating - translation. Ideal representation would help minimize the need to not only - translate the representation at the macro level but also reduce need for - repeated parsing and serialization of YAML. -* Support package contents that are not text -* Revisit package update mutation to avoid using local file system and integrate - better with CaD library (`updatePackageMutation.Apply`). -* Migrate the PackageRevision resource to a CRD rather than using the - aggregated APIServer. - -## Package Lifecycle - -* Ensure that all operations can be performed only on package revision in the - appropriate lifecycle state (example: only _Published_ packages can be cloned, - deployed, etc.) -* Support detection of new version of upstream package and downstream package - update -* Support sub-packages -* Handling of merge conflicts, assistance with manual conflict resolution -* Bulk package operations (bulk upgrade from updated upstream package) -* Permission model to enable admins more fine-grained control over repository - access than what it supported by underlying Git or other providers - -## CLI Integration - -* Support for registering repository-wide guardrails - mutators or validators. -* Support for updating repository registration (currently only `register`, - `unregister`, and `get` are implemented) -* On repository unregistration, the CLI can check all other registered - repositories and suggest to the user to keep or delete the secret containing - credentials depending on whether other repository registrations use it or - the last one is being deleted; today, a `--keep-auth-secret` flag is used. -* Registration of _function_ repositories (only _package_ repositories are - currently supported in the CLI). -* Function discovery via in registered function repositories. -* Consider revising the structure of the `kpt alpha` command groups. `kubectl` - organizes the groups by action, for example `kpt get ` whereas - `kpt` by resource: `kpt alpha rpkg get`. Consider `kpt alpha get rpkg` or - `kpt alpha get repo` for consistency with `kubectl` experience. -* Implement richer support for referencing to packages by URLs with proper - parsing, reduce number of command line flags required. For example, support: - `https://github.com/org/repo.git/packge/patch@reference`; Make the parsing - code reusable with the rest of kpt CLI. - -## Testing - -* Enable the e2e tests to run against a specified Git repository -* Accept Git test image as an argument to avoid requiring the Porch server - image and Git test server image to share the same tag - (see `InferGitServerImage` function and `suite.go` file) -* Set up infrastructure for better testing of the controllers. - -## Deployment and integration with syncers -* Support bulk management of variants of packages based on deployment targets. -* Rollout engine for progressive rollout of packages into clusters. - - - diff --git a/porch/docs/running-locally.md b/porch/docs/running-locally.md deleted file mode 100644 index c0aff3883a..0000000000 --- a/porch/docs/running-locally.md +++ /dev/null @@ -1,115 +0,0 @@ -# Running Porch Locally - -## Prerequisites - -To run Porch locally, you will need: - -* Linux machine (technically it is possible to run Porch locally on a Mac but - due to differences in Docker between Linux and Mac, the Porch scripts are - confirmed to work on Linux) -* [go 1.21](https://go.dev/dl/) or newer -* [docker](https://docs.docker.com/get-docker/) -* [git](https://git-scm.com/) -* [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/) -* `make` - -## Getting Started - -Clone this repository into `${GOPATH}/src/github.com/GoogleContainerTools/kpt`. - -```sh -git clone https://github.com/GoogleContainerTools/kpt.git "${GOPATH}/src/github.com/GoogleContainerTools/kpt" -``` - -Download dependencies: - -```sh -make tidy -``` - -## Running Porch - -Porch consists of: -* k8s extension apiserver [porch](../pkg/apiserver/) -* kpt function evaluator [func](../func/) -* k8s [controllers](../controllers) - -In addition, to run Porch locally, we need to run the main k8s apiserver and its backing storage, etcd. - -To build and run Porch locally in one command, run: - -```sh -# Go into the porch directory: -cd "${GOPATH}/src/github.com/GoogleContainerTools/kpt/porch" - -# Start Porch in one command: -make -``` - -This will: - -* create Docker network named `porch` -* build and start `etcd` Docker container -* build and start main k8s apiserver Docker container -* build and start the kpt function evaluator microservice [func](../porch/func) Docker container -* build Porch binary and run it locally -* configure Porch as the extension apiserver - -**Note:** this command does not build and start the Porch k8s controllers. Those -are not required for basic package orchestration but are required for deploying packages. - -You can also run the commands individually which can be useful when developing, -in particular building and running Porch extension apiserver. - -```sh -# Create Porch network -make network - -# Build and start etcd container -make start-etcd - -# Build and start main apiserver container -make start-kube-apiserver - -# Build and start kpt function evaluator microservice Docker container -make start-function-runner - -# Build and start Porch on your local machine. -make run-local -``` - -Porch will run directly on your local machine and API requests will be forwarded to it from the -main apiserver. Configure `kubectl` context to interact with the main k8s apiserver running as -Docker container: - -```sh -export KUBECONFIG=${PWD}/deployments/local/kubeconfig - -# Confirm Porch is running -kubectl api-resources | grep porch - -repositories config.porch.kpt.dev/v1alpha1 true Repository -functions porch.kpt.dev/v1alpha1 true Function -packagerevisionresources porch.kpt.dev/v1alpha1 true PackageRevisionResources -packagerevisions porch.kpt.dev/v1alpha1 true PackageRevision -``` - -## Restarting Porch - -If you make code changes, an expedient way to rebuild and restart porch is: - -* Stop Porch running in the shell session (Ctrl+C) -* Run `make run-local` again to rebuild and restart Porch - -## Stopping Porch - -To stop Porch and all associated Docker containers, including the Docker network, run: - -```sh -make stop -``` - -## Troubleshooting - -If you run into issues that look like `git: authentication required`, make sure you have SSH -keys set up on your local machine. diff --git a/porch/examples/apps/hello-server/Dockerfile b/porch/examples/apps/hello-server/Dockerfile deleted file mode 100644 index 894c29f3ea..0000000000 --- a/porch/examples/apps/hello-server/Dockerfile +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2022 The kpt 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. - -FROM golang:1.21.6-bookworm as builder - -WORKDIR /src -COPY go.mod go.sum ./ - -WORKDIR /src -COPY *.go . - -RUN CGO_ENABLED=0 go build -o /hello-server -v . - -FROM gcr.io/distroless/static -WORKDIR / -COPY --from=builder /hello-server /hello-server - -ENTRYPOINT ["/hello-server"] diff --git a/porch/examples/apps/hello-server/Makefile b/porch/examples/apps/hello-server/Makefile deleted file mode 100644 index 8dbc65b791..0000000000 --- a/porch/examples/apps/hello-server/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2022 The kpt 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. - -# GCP project to use for development -GCP_PROJECT_ID ?= $(shell gcloud config get-value project) -IMAGE_TAG ?= latest -IMAGE_REPO ?= gcr.io/$(GCP_PROJECT_ID) -IMAGE_NAME ?= hello-server - -.PHONY: push-image -push-image: - docker buildx build --push --tag $(IMAGE_REPO)/$(IMAGE_NAME):$(IMAGE_TAG) . - -.PHONY: build-image -build-image: - docker buildx build --load --tag $(IMAGE_REPO)/$(IMAGE_NAME):$(IMAGE_TAG) . diff --git a/porch/examples/apps/hello-server/go.mod b/porch/examples/apps/hello-server/go.mod deleted file mode 100644 index 52376fb9a2..0000000000 --- a/porch/examples/apps/hello-server/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/GoogleContainerTools/kpt/porch/config/samples/apps/hello - -go 1.21 diff --git a/porch/examples/apps/hello-server/go.sum b/porch/examples/apps/hello-server/go.sum deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/porch/examples/apps/hello-server/k8s/Kptfile b/porch/examples/apps/hello-server/k8s/Kptfile deleted file mode 100644 index e99bae3694..0000000000 --- a/porch/examples/apps/hello-server/k8s/Kptfile +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: hello-server -info: - emails: - - kpt-team@google.com - description: This is an example package. -# pipeline: -# validators: -# - image: gcr.io/kpt-fn/kubeval:v0.1 -# configMap: -# strict: "true" diff --git a/porch/examples/apps/hello-server/k8s/deployment.yaml b/porch/examples/apps/hello-server/k8s/deployment.yaml deleted file mode 100644 index 72c5da4dbf..0000000000 --- a/porch/examples/apps/hello-server/k8s/deployment.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2021 The kpt 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. - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: hello-server - namespace: hello-server -spec: - replicas: 2 - selector: - matchLabels: - app: hello-server - template: - metadata: - labels: - app: hello-server - spec: - containers: - - name: hello-server - image: "gcr.io/example-google-project-id/hello-server:latest" diff --git a/porch/examples/apps/hello-server/k8s/ns.yaml b/porch/examples/apps/hello-server/k8s/ns.yaml deleted file mode 100644 index 1c43894e60..0000000000 --- a/porch/examples/apps/hello-server/k8s/ns.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2021 The kpt 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. - -apiVersion: v1 -kind: Namespace -metadata: - name: hello-server diff --git a/porch/examples/apps/hello-server/k8s/svc.yaml b/porch/examples/apps/hello-server/k8s/svc.yaml deleted file mode 100644 index 782bf6284e..0000000000 --- a/porch/examples/apps/hello-server/k8s/svc.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2021 The kpt 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. - -apiVersion: v1 -kind: Service -metadata: - name: hello-server - namespace: hello-server -spec: - type: LoadBalancer - selector: - app: hello-server - ports: - - protocol: TCP - port: 80 - targetPort: 8080 diff --git a/porch/examples/apps/hello-server/main.go b/porch/examples/apps/hello-server/main.go deleted file mode 100644 index 838eb7faeb..0000000000 --- a/porch/examples/apps/hello-server/main.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2022 The kpt 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. - -package main - -import ( - "context" - "fmt" - "net/http" - "os" -) - -func main() { - if err := run(context.Background()); err != nil { - fmt.Fprintf(os.Stderr, "%v\n", err) - os.Exit(1) - } -} - -func run(ctx context.Context) error { - http.HandleFunc("/", HelloHandler) - - listen := ":8080" - if err := http.ListenAndServe(listen, nil); err != nil { - return fmt.Errorf("error listening on %q: %w", listen, err) - } - - // This is documented not to happen - return fmt.Errorf("error: ListenAndServe returned nil error") -} - -func HelloHandler(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, "Hello world\n") -} diff --git a/porch/examples/config/bucket-label.yaml b/porch/examples/config/bucket-label.yaml deleted file mode 100644 index 4c01cfa6b3..0000000000 --- a/porch/examples/config/bucket-label.yaml +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: porch.kpt.dev/v1alpha1 -kind: PackageRevision -metadata: - namespace: default - name: blueprints:bucket-eval:v0 -spec: - packageName: bucket-eval - revision: v0 - repository: blueprints - tasks: - - type: clone - clone: - upstreamRef: - type: git - git: - repo: https://github.com/GoogleCloudPlatform/blueprints.git - ref: main - directory: catalog/bucket - - type: eval - eval: - image: gcr.io/kpt-fn/set-labels:v0.1.5 - configMap: - bucket-label: bucket-label-value - another-label: another-label-value diff --git a/porch/examples/config/config-management.yaml b/porch/examples/config/config-management.yaml deleted file mode 100644 index d1e3562684..0000000000 --- a/porch/examples/config/config-management.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: configmanagement.gke.io/v1 -kind: ConfigManagement -metadata: - name: config-management -spec: - enableMultiRepo: true diff --git a/porch/examples/config/deployment-repository.yaml b/porch/examples/config/deployment-repository.yaml deleted file mode 100644 index af9fd7c96b..0000000000 --- a/porch/examples/config/deployment-repository.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Repository -metadata: - name: deployment - namespace: default -spec: - deployment: true - description: Deployment Repository for testing Porch. - content: PackageRevision # TODO: Deployment or similar? - type: oci - oci: - # Replace with your OCI repository. - registry: us-west1-docker.pkg.dev/example-google-project-id/deployment diff --git a/porch/examples/config/function-repository.yaml b/porch/examples/config/function-repository.yaml deleted file mode 100644 index a737ef01a0..0000000000 --- a/porch/examples/config/function-repository.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Repository -metadata: - name: kpt-functions - namespace: default -spec: - description: Standard library of core kpt functions to manipulate KRM blueprints. - content: Function - type: oci - oci: - registry: gcr.io/kpt-fn diff --git a/porch/examples/config/git-repository.yaml b/porch/examples/config/git-repository.yaml deleted file mode 100644 index 03eaee76ba..0000000000 --- a/porch/examples/config/git-repository.yaml +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Repository -metadata: - name: blueprints - namespace: default -spec: - description: Blueprints Git Repository - content: PackageRevision - type: git - git: - repo: UPDATE_ME # URL of the repository, - branch: main - directory: "" - secretRef: - # Create the secret via: - # - # kubectl create secret generic git-repository-auth \ - # --namespace=default \ - # --type=kubernetes.io/basic-auth \ - # --from-literal=username= \ - # --from-literal=password= - name: git-repository-auth diff --git a/porch/examples/config/new-package.yaml b/porch/examples/config/new-package.yaml deleted file mode 100644 index f6b79195ad..0000000000 --- a/porch/examples/config/new-package.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: porch.kpt.dev/v1alpha1 -kind: PackageRevision -metadata: - namespace: default - name: blueprints:new-package:v0 -spec: - packageName: new-package - revision: v0 - repository: blueprints - tasks: - - type: init - init: - description: New Package Description - keywords: - - example - - package - site: https://kpt.dev diff --git a/porch/examples/config/oci-repository.yaml b/porch/examples/config/oci-repository.yaml deleted file mode 100644 index 4a96614c66..0000000000 --- a/porch/examples/config/oci-repository.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: config.porch.kpt.dev/v1alpha1 -kind: Repository -metadata: - name: blueprints - namespace: default -spec: - description: OCI Blueprints Repository for testing Porch. - content: PackageRevision - type: oci - oci: - # Replace with your OCI repository. - registry: us-west1-docker.pkg.dev/example-google-project-id/packages diff --git a/porch/examples/config/packagerevision.yaml b/porch/examples/config/packagerevision.yaml deleted file mode 100644 index 278336d56a..0000000000 --- a/porch/examples/config/packagerevision.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: porch.kpt.dev/v1alpha1 -kind: PackageRevision -metadata: - namespace: kube-system -spec: - packageName: justin - revision: dec30-1212 - repository: blueprints - tasks: - - type: clone - clone: - upstreamRef: - type: git - git: - repo: https://github.com/GoogleContainerTools/kpt - ref: v0.7 - directory: package-examples/wordpress diff --git a/porch/func/Dockerfile b/porch/func/Dockerfile deleted file mode 100644 index c227f7519a..0000000000 --- a/porch/func/Dockerfile +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2022 The kpt 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. - -FROM gcr.io/kpt-fn/apply-setters:v0.2.0 as apply-setters -FROM gcr.io/kpt-fn/apply-setters:v0.1.1 as apply-setters-v1 -FROM gcr.io/kpt-fn/ensure-name-substring:v0.1.1 as ensure-name-substring -FROM gcr.io/kpt-fn/search-replace:v0.2.0 as search-replace -FROM gcr.io/kpt-fn/set-annotations:v0.1.4 as set-annotations -FROM gcr.io/kpt-fn/set-image:v0.1.0 as set-image -FROM gcr.io/kpt-fn/set-labels:v0.1.5 as set-labels -FROM gcr.io/kpt-fn/set-namespace:v0.2.0 as set-namespace -FROM gcr.io/kpt-fn/set-namespace:v0.3.4 as set-namespace-v3 -FROM gcr.io/kpt-fn/set-project-id:v0.2.0 as set-project-id -FROM gcr.io/kpt-fn/starlark:v0.3.0 as starlark -FROM gcr.io/kpt-fn/upsert-resource:v0.2.0 as upsert-resource - -FROM golang:1.21.6-alpine3.18 as builder -WORKDIR /go/src/github.com/GoogleContainerTools/kpt - -RUN go install github.com/grpc-ecosystem/grpc-health-probe@v0.4.11 -RUN cp $GOPATH/bin/grpc-health-probe /grpc-health-probe - -COPY go.mod go.sum ./ -COPY porch/go.mod porch/go.sum porch/ -COPY porch/api/go.mod porch/api/go.sum porch/api/ - -RUN cd porch ; go build -v google.golang.org/grpc k8s.io/klog/v2 - -COPY pkg pkg -COPY internal internal -COPY porch/func/ porch/func/ -RUN cd porch/func ; go build -v -o /server ./server -COPY porch/func/config.yaml /config.yaml - -FROM alpine:3.18 - -COPY --from=apply-setters /usr/local/bin/function /functions/apply-setters -COPY --from=apply-setters-v1 /usr/local/bin/function /functions/apply-setters-v1 -COPY --from=ensure-name-substring /usr/local/bin/function /functions/ensure-name-substring -COPY --from=search-replace /usr/local/bin/function /functions/search-replace -COPY --from=set-annotations /usr/local/bin/function /functions/set-annotations -COPY --from=set-image /usr/local/bin/function /functions/set-image -COPY --from=set-labels /usr/local/bin/function /functions/set-labels -COPY --from=set-namespace /usr/local/bin/function /functions/set-namespace -COPY --from=set-namespace-v3 /usr/local/bin/function /functions/set-namespace-v3 -COPY --from=set-project-id /usr/local/bin/function /functions/set-project-id -COPY --from=starlark /usr/local/bin/star /functions/starlark -COPY --from=upsert-resource /usr/local/bin/function /functions/upsert-resource -COPY --from=builder /server /grpc-health-probe /config.yaml / - -EXPOSE 9445/tcp -ENTRYPOINT [ "/server", "--config=/config.yaml", "--functions=/functions" ] diff --git a/porch/func/Dockerfile-wrapperserver b/porch/func/Dockerfile-wrapperserver deleted file mode 100644 index ef60940f2d..0000000000 --- a/porch/func/Dockerfile-wrapperserver +++ /dev/null @@ -1,19 +0,0 @@ -FROM golang:1.21.6-alpine3.18 as builder - -WORKDIR /go/src/github.com/GoogleContainerTools/kpt - -# Ensure the wrapper server and grpc-health-probe is statically linked so that they works in distroless-based images. -ENV CGO_ENABLED=0 - -COPY go.mod go.sum ./ -COPY porch/go.mod porch/go.sum porch/ -COPY porch/api/go.mod porch/api/go.sum porch/api/ - -RUN go install github.com/grpc-ecosystem/grpc-health-probe@v0.4.11 -COPY porch/func/ porch/func/ -RUN cd porch/func ; go build -v -o /wrapper-server/wrapper-server ./wrapper-server -RUN cp $GOPATH/bin/grpc-health-probe /wrapper-server/ - -FROM alpine:3.18 - -COPY --from=builder /wrapper-server/* /wrapper-server/ diff --git a/porch/func/Makefile b/porch/func/Makefile deleted file mode 100644 index 60cdd753cd..0000000000 --- a/porch/func/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2019 The kpt 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. - -GCP_PROJECT_ID ?= $(shell gcloud config get-value project) -IMAGE_TAG ?= latest -IMAGE_REPO ?= gcr.io/$(GCP_PROJECT_ID) -IMAGE_NAME ?= function-runner -WRAPPER_SERVER_IMAGE_NAME ?= wrapper-server -COMPILED_PROTO=evaluator/evaluator_grpc.pb.go evaluator/evaluator.pb.go - -KPTDIR = $(abspath $(CURDIR)/../..) - -all: $(COMPILED_PROTO) - -$(COMPILED_PROTO): evaluator/evaluator.proto - protoc \ - -I /usr/local/include/google/protobuf \ - -I ./evaluator \ - --go_out=./evaluator --go_opt=paths=source_relative \ - --go-grpc_out=./evaluator --go-grpc_opt=paths=source_relative \ - ./evaluator/evaluator.proto - -.PHONY: build-image -build-image: - docker buildx build --load --tag $(IMAGE_REPO)/$(IMAGE_NAME):$(IMAGE_TAG) -f ./Dockerfile "$(KPTDIR)" - docker buildx build --load --tag $(IMAGE_REPO)/$(WRAPPER_SERVER_IMAGE_NAME):$(IMAGE_TAG) -f ./Dockerfile-wrapperserver "$(KPTDIR)" - -.PHONY: push-image -push-image: - docker buildx build --push --tag $(IMAGE_REPO)/$(IMAGE_NAME):$(IMAGE_TAG) -f ./Dockerfile "$(KPTDIR)" - docker buildx build --push --tag $(IMAGE_REPO)/$(WRAPPER_SERVER_IMAGE_NAME):$(IMAGE_TAG) -f ./Dockerfile-wrapperserver "$(KPTDIR)" diff --git a/porch/func/client/main.go b/porch/func/client/main.go deleted file mode 100644 index 0891212c37..0000000000 --- a/porch/func/client/main.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2022 The kpt 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. - -package main - -import ( - "bytes" - "context" - "flag" - "fmt" - "os" - "strings" - "time" - - pb "github.com/GoogleContainerTools/kpt/porch/func/evaluator" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -var ( - addressFlag = flag.String("address", "localhost:9445", "FunctionEvaluator server address") - packageFlag = flag.String("package", "", "Source package") - imageFlag = flag.String("image", "", "Image of the function to evaluate") -) - -func main() { - flag.Parse() - - if err := run(flag.Args()); err != nil { - fmt.Fprintf(os.Stderr, "unexpected error: %v\n", err) - os.Exit(1) - } -} - -func run(args []string) error { - rl, err := createResourceList(args) - if err != nil { - return err - } - - fmt.Printf("Request:\n\n%s\n", string(rl)) - - res, err := call(rl) - if err != nil { - return err - } - - fmt.Printf("Response:\n\n%s\n\nLog:\n%s\n", string(res.ResourceList), string(res.Log)) - return nil -} - -func createResourceList(args []string) ([]byte, error) { - r := kio.LocalPackageReader{ - PackagePath: *packageFlag, - IncludeSubpackages: true, - WrapBareSeqNode: true, - } - - cfg, err := configmap(args) - if err != nil { - return nil, fmt.Errorf("failed to create function config: %w", err) - } - - var b bytes.Buffer - w := kio.ByteWriter{ - Writer: &b, - KeepReaderAnnotations: true, - Style: 0, - FunctionConfig: cfg, - WrappingKind: kio.ResourceListKind, - WrappingAPIVersion: kio.ResourceListAPIVersion, - } - - if err := (kio.Pipeline{Inputs: []kio.Reader{r}, Outputs: []kio.Writer{w}}).Execute(); err != nil { - return nil, fmt.Errorf("failed to create serialized ResourceList: %w", err) - } - - return b.Bytes(), nil -} - -func call(rl []byte) (*pb.EvaluateFunctionResponse, error) { - cc, err := grpc.Dial(*addressFlag, grpc.WithTransportCredentials(insecure.NewCredentials())) - if err != nil { - return nil, fmt.Errorf("failed to connect to %s: %w", *addressFlag, err) - } - defer cc.Close() - - evaluator := pb.NewFunctionEvaluatorClient(cc) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - defer cancel() - - in := &pb.EvaluateFunctionRequest{ - ResourceList: rl, - Image: *imageFlag, - } - - r, err := evaluator.EvaluateFunction(ctx, in) - if err != nil { - return nil, fmt.Errorf("function evaluation failed: %w", err) - } else { - return r, nil - } -} - -func configmap(args []string) (*yaml.RNode, error) { - if len(args) == 0 { - return nil, nil - } - - data := map[string]string{} - for _, a := range args { - split := strings.SplitN(a, "=", 2) - if len(split) != 2 { - return nil, fmt.Errorf("invalid config value: %q", a) - } - data[split[0]] = split[1] - } - node := yaml.NewMapRNode(&data) - if node == nil { - return nil, nil - } - - // create ConfigMap resource to contain function config - configMap := yaml.MustParse(` -apiVersion: v1 -kind: ConfigMap -metadata: - name: function-input -data: {} -`) - if err := configMap.PipeE(yaml.SetField("data", node)); err != nil { - return nil, err - } - return configMap, nil -} diff --git a/porch/func/config.yaml b/porch/func/config.yaml deleted file mode 100644 index 7be58bf7b9..0000000000 --- a/porch/func/config.yaml +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2022 The kpt 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. - -functions: - - function: set-image - images: - - gcr.io/kpt-fn/set-image@sha256:d07677591e5b39a56d44bafaba0d881e4f2ae25ed020dfa2ad002fb9e62d1508 - - gcr.io/kpt-fn/set-image:v0.1.0 - - function: set-namespace - images: - - gcr.io/kpt-fn/set-namespace@sha256:7adc23986f97572d75af9aec6a7f74d60f7b9976227f43a75486633e7c539e6f - - gcr.io/kpt-fn/set-namespace:v0.2.0 - - function: set-namespace-v3 - images: - - gcr.io/kpt-fn/set-namespace@sha256:0ec0fb2380be42142a87a7c9815f0d30415e2da07468591dd9345c7c81d6c93e - - gcr.io/kpt-fn/set-namespace:v0.3.4 - - function: upsert-resource - images: - - gcr.io/kpt-fn/upsert-resource@sha256:77196bdb9e33e4259d530ee1996a05c40bbefe39b80d52dcb66c32f7b85a62f1 - - gcr.io/kpt-fn/upsert-resource:v0.2.0 - - function: set-project-id - images: - - gcr.io/kpt-fn/set-project-id@sha256:966c9e51163bce52274dfa0406ae580283712cb38625660cd2f66e9f13d2c01b - - gcr.io/kpt-fn/set-project-id:v0.2.0 - - function: apply-setters - images: - - gcr.io/kpt-fn/apply-setters@sha256:4d4295727183396f0c3c6a75d2560254c2f9041a39e95dc1e5beffeb49cc1a12 - - gcr.io/kpt-fn/apply-setters:v0.2.0 - - function: apply-setters-v1 - images: - - gcr.io/kpt-fn/apply-setters@sha256:d2a0219b24a47ebb4bf568d3ccf5bb0e7be2f3f94b28b0c3b1bed011a51d7c35 - - gcr.io/kpt-fn/apply-setters:v0.1 - - gcr.io/kpt-fn/apply-setters:v0.1.1 - - function: search-replace - images: - - gcr.io/kpt-fn/search-replace@sha256:6864b06bf654fbdff3efb666a0a75fa14da2ba405f33187b60648e0b74bc2272 - - gcr.io/kpt-fn/search-replace:v0.2.0 - - function: ensure-name-substring - images: - - gcr.io/kpt-fn/ensure-name-substring@sha256:3105ac150f86dcafa2d656e30feb5c51b83a43f5bb9b84458cdde620c9757227 - - gcr.io/kpt-fn/ensure-name-substring:v0.1.1 - - function: set-annotations - images: - - gcr.io/kpt-fn/set-annotations@sha256:76d65ebddf6ce9c2c00bbcb3c0e963a2d856685bdcf2f1072386f41ca9b563e5 - - gcr.io/kpt-fn/set-annotations:v0.1.4 - - function: set-labels - images: - - gcr.io/kpt-fn/set-labels@sha256:0dfc3c8aba8b791d0c45fe7eafbc8cf3c5920a09f69848f46dcc270ae3423641 - - gcr.io/kpt-fn/set-labels:v0.1.5 - - function: starlark - images: - - gcr.io/kpt-fn/starlark@sha256:c347e28606fa1a608e8e02e03541a5a46e4a0152005df4a11e44f6c4ab1edd9a - - gcr.io/kpt-fn/starlark:v0.3.0 diff --git a/porch/func/config/sample/Kptfile b/porch/func/config/sample/Kptfile deleted file mode 100644 index 783d9a5756..0000000000 --- a/porch/func/config/sample/Kptfile +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: config -info: - description: sample package diff --git a/porch/func/config/sample/README.md b/porch/func/config/sample/README.md deleted file mode 100644 index 223a8be44e..0000000000 --- a/porch/func/config/sample/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# config - -Sample package for experimentation. \ No newline at end of file diff --git a/porch/func/config/sample/configmap.yaml b/porch/func/config/sample/configmap.yaml deleted file mode 100644 index e332430472..0000000000 --- a/porch/func/config/sample/configmap.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: v1 -kind: ConfigMap -metadata: - name: test -data: - value: hello \ No newline at end of file diff --git a/porch/func/evaluator/evaluator.pb.go b/porch/func/evaluator/evaluator.pb.go deleted file mode 100644 index a21b18e978..0000000000 --- a/porch/func/evaluator/evaluator.pb.go +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright 2022 The kpt 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 protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.27.1 -// protoc v3.19.4 -// source: evaluator.proto - -package evaluator - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - _ "google.golang.org/protobuf/types/known/structpb" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type EvaluateFunctionRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Serialized ResourceList (https://kpt.dev/reference/schema/resource-list/) - ResourceList []byte `protobuf:"bytes,1,opt,name=resource_list,json=resourceList,proto3" json:"resource_list,omitempty"` - // kpt image identifying the function to evaluate - Image string `protobuf:"bytes,2,opt,name=image,proto3" json:"image,omitempty"` -} - -func (x *EvaluateFunctionRequest) Reset() { - *x = EvaluateFunctionRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_evaluator_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *EvaluateFunctionRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*EvaluateFunctionRequest) ProtoMessage() {} - -func (x *EvaluateFunctionRequest) ProtoReflect() protoreflect.Message { - mi := &file_evaluator_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use EvaluateFunctionRequest.ProtoReflect.Descriptor instead. -func (*EvaluateFunctionRequest) Descriptor() ([]byte, []int) { - return file_evaluator_proto_rawDescGZIP(), []int{0} -} - -func (x *EvaluateFunctionRequest) GetResourceList() []byte { - if x != nil { - return x.ResourceList - } - return nil -} - -func (x *EvaluateFunctionRequest) GetImage() string { - if x != nil { - return x.Image - } - return "" -} - -// ConfigMap wraps a map for use in oneof clause. -type ConfigMap struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Data map[string]string `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` -} - -func (x *ConfigMap) Reset() { - *x = ConfigMap{} - if protoimpl.UnsafeEnabled { - mi := &file_evaluator_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ConfigMap) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ConfigMap) ProtoMessage() {} - -func (x *ConfigMap) ProtoReflect() protoreflect.Message { - mi := &file_evaluator_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ConfigMap.ProtoReflect.Descriptor instead. -func (*ConfigMap) Descriptor() ([]byte, []int) { - return file_evaluator_proto_rawDescGZIP(), []int{1} -} - -func (x *ConfigMap) GetData() map[string]string { - if x != nil { - return x.Data - } - return nil -} - -type EvaluateFunctionResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Serialized ResourceList (https://kpt.dev/reference/schema/resource-list/), - // including structured function results. - ResourceList []byte `protobuf:"bytes,1,opt,name=resource_list,json=resourceList,proto3" json:"resource_list,omitempty"` - // Additional log produced by the function (if any). - Log []byte `protobuf:"bytes,2,opt,name=log,proto3" json:"log,omitempty"` -} - -func (x *EvaluateFunctionResponse) Reset() { - *x = EvaluateFunctionResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_evaluator_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *EvaluateFunctionResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*EvaluateFunctionResponse) ProtoMessage() {} - -func (x *EvaluateFunctionResponse) ProtoReflect() protoreflect.Message { - mi := &file_evaluator_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use EvaluateFunctionResponse.ProtoReflect.Descriptor instead. -func (*EvaluateFunctionResponse) Descriptor() ([]byte, []int) { - return file_evaluator_proto_rawDescGZIP(), []int{2} -} - -func (x *EvaluateFunctionResponse) GetResourceList() []byte { - if x != nil { - return x.ResourceList - } - return nil -} - -func (x *EvaluateFunctionResponse) GetLog() []byte { - if x != nil { - return x.Log - } - return nil -} - -var File_evaluator_proto protoreflect.FileDescriptor - -var file_evaluator_proto_rawDesc = []byte{ - 0x0a, 0x0f, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x12, 0x09, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x6f, 0x72, 0x1a, 0x0c, 0x73, 0x74, - 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x54, 0x0a, 0x17, 0x45, 0x76, - 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, - 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, - 0x22, 0x78, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x12, 0x32, 0x0a, - 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x65, 0x76, - 0x61, 0x6c, 0x75, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, - 0x70, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, - 0x61, 0x1a, 0x37, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x51, 0x0a, 0x18, 0x45, 0x76, - 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6c, - 0x6f, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x32, 0x72, 0x0a, - 0x11, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, - 0x6f, 0x72, 0x12, 0x5d, 0x0a, 0x10, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x46, 0x75, - 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, - 0x6f, 0x72, 0x2e, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x46, 0x75, 0x6e, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x65, 0x76, 0x61, - 0x6c, 0x75, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x46, - 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x54, - 0x6f, 0x6f, 0x6c, 0x73, 0x2f, 0x6b, 0x70, 0x74, 0x2f, 0x70, 0x6f, 0x72, 0x63, 0x68, 0x2f, 0x66, - 0x75, 0x6e, 0x63, 0x2f, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x6f, 0x72, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_evaluator_proto_rawDescOnce sync.Once - file_evaluator_proto_rawDescData = file_evaluator_proto_rawDesc -) - -func file_evaluator_proto_rawDescGZIP() []byte { - file_evaluator_proto_rawDescOnce.Do(func() { - file_evaluator_proto_rawDescData = protoimpl.X.CompressGZIP(file_evaluator_proto_rawDescData) - }) - return file_evaluator_proto_rawDescData -} - -var file_evaluator_proto_msgTypes = make([]protoimpl.MessageInfo, 4) -var file_evaluator_proto_goTypes = []interface{}{ - (*EvaluateFunctionRequest)(nil), // 0: evaluator.EvaluateFunctionRequest - (*ConfigMap)(nil), // 1: evaluator.ConfigMap - (*EvaluateFunctionResponse)(nil), // 2: evaluator.EvaluateFunctionResponse - nil, // 3: evaluator.ConfigMap.DataEntry -} -var file_evaluator_proto_depIdxs = []int32{ - 3, // 0: evaluator.ConfigMap.data:type_name -> evaluator.ConfigMap.DataEntry - 0, // 1: evaluator.FunctionEvaluator.EvaluateFunction:input_type -> evaluator.EvaluateFunctionRequest - 2, // 2: evaluator.FunctionEvaluator.EvaluateFunction:output_type -> evaluator.EvaluateFunctionResponse - 2, // [2:3] is the sub-list for method output_type - 1, // [1:2] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name -} - -func init() { file_evaluator_proto_init() } -func file_evaluator_proto_init() { - if File_evaluator_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_evaluator_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EvaluateFunctionRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_evaluator_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ConfigMap); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_evaluator_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EvaluateFunctionResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_evaluator_proto_rawDesc, - NumEnums: 0, - NumMessages: 4, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_evaluator_proto_goTypes, - DependencyIndexes: file_evaluator_proto_depIdxs, - MessageInfos: file_evaluator_proto_msgTypes, - }.Build() - File_evaluator_proto = out.File - file_evaluator_proto_rawDesc = nil - file_evaluator_proto_goTypes = nil - file_evaluator_proto_depIdxs = nil -} diff --git a/porch/func/evaluator/evaluator.proto b/porch/func/evaluator/evaluator.proto deleted file mode 100644 index 03efd8ccd0..0000000000 --- a/porch/func/evaluator/evaluator.proto +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2022 The kpt 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. - -syntax = "proto3"; - -package evaluator; - -import "struct.proto"; - -option go_package = "github.com/GoogleContainerTools/kpt/porch/func/evaluator"; - -// Evaluator of kpt functions -service FunctionEvaluator { - // Evaluates a kpt function on the provided package - rpc EvaluateFunction(EvaluateFunctionRequest) - returns (EvaluateFunctionResponse) {} -} - -message EvaluateFunctionRequest { - // Serialized ResourceList (https://kpt.dev/reference/schema/resource-list/) - bytes resource_list = 1; - - // kpt image identifying the function to evaluate - string image = 2; -} - -// ConfigMap wraps a map for use in oneof clause. -message ConfigMap { - map data = 1; -} - -message EvaluateFunctionResponse { - // Serialized ResourceList (https://kpt.dev/reference/schema/resource-list/), - // including structured function results. - bytes resource_list = 1; - - // Additional log produced by the function (if any). - bytes log = 2; -} diff --git a/porch/func/evaluator/evaluator_grpc.pb.go b/porch/func/evaluator/evaluator_grpc.pb.go deleted file mode 100644 index 56a77dc9af..0000000000 --- a/porch/func/evaluator/evaluator_grpc.pb.go +++ /dev/null @@ -1,107 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.2.0 -// - protoc v3.19.4 -// source: evaluator.proto - -package evaluator - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 - -// FunctionEvaluatorClient is the client API for FunctionEvaluator service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type FunctionEvaluatorClient interface { - // Evaluates a kpt function on the provided package - EvaluateFunction(ctx context.Context, in *EvaluateFunctionRequest, opts ...grpc.CallOption) (*EvaluateFunctionResponse, error) -} - -type functionEvaluatorClient struct { - cc grpc.ClientConnInterface -} - -func NewFunctionEvaluatorClient(cc grpc.ClientConnInterface) FunctionEvaluatorClient { - return &functionEvaluatorClient{cc} -} - -func (c *functionEvaluatorClient) EvaluateFunction(ctx context.Context, in *EvaluateFunctionRequest, opts ...grpc.CallOption) (*EvaluateFunctionResponse, error) { - out := new(EvaluateFunctionResponse) - err := c.cc.Invoke(ctx, "/evaluator.FunctionEvaluator/EvaluateFunction", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// FunctionEvaluatorServer is the server API for FunctionEvaluator service. -// All implementations must embed UnimplementedFunctionEvaluatorServer -// for forward compatibility -type FunctionEvaluatorServer interface { - // Evaluates a kpt function on the provided package - EvaluateFunction(context.Context, *EvaluateFunctionRequest) (*EvaluateFunctionResponse, error) - mustEmbedUnimplementedFunctionEvaluatorServer() -} - -// UnimplementedFunctionEvaluatorServer must be embedded to have forward compatible implementations. -type UnimplementedFunctionEvaluatorServer struct { -} - -func (UnimplementedFunctionEvaluatorServer) EvaluateFunction(context.Context, *EvaluateFunctionRequest) (*EvaluateFunctionResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method EvaluateFunction not implemented") -} -func (UnimplementedFunctionEvaluatorServer) mustEmbedUnimplementedFunctionEvaluatorServer() {} - -// UnsafeFunctionEvaluatorServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to FunctionEvaluatorServer will -// result in compilation errors. -type UnsafeFunctionEvaluatorServer interface { - mustEmbedUnimplementedFunctionEvaluatorServer() -} - -func RegisterFunctionEvaluatorServer(s grpc.ServiceRegistrar, srv FunctionEvaluatorServer) { - s.RegisterService(&FunctionEvaluator_ServiceDesc, srv) -} - -func _FunctionEvaluator_EvaluateFunction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(EvaluateFunctionRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(FunctionEvaluatorServer).EvaluateFunction(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/evaluator.FunctionEvaluator/EvaluateFunction", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(FunctionEvaluatorServer).EvaluateFunction(ctx, req.(*EvaluateFunctionRequest)) - } - return interceptor(ctx, in, info, handler) -} - -// FunctionEvaluator_ServiceDesc is the grpc.ServiceDesc for FunctionEvaluator service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var FunctionEvaluator_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "evaluator.FunctionEvaluator", - HandlerType: (*FunctionEvaluatorServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "EvaluateFunction", - Handler: _FunctionEvaluator_EvaluateFunction_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "evaluator.proto", -} diff --git a/porch/func/healthchecker/healthchecker.go b/porch/func/healthchecker/healthchecker.go deleted file mode 100644 index b7bd4c1e29..0000000000 --- a/porch/func/healthchecker/healthchecker.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2022 The kpt 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. - -package healthchecker - -import ( - "context" - - "google.golang.org/grpc/health/grpc_health_v1" - "k8s.io/klog/v2" -) - -// HealthChecker implements the GRPC Health Checking Protocol: -// https://github.com/grpc/grpc/blob/master/doc/health-checking.md -type HealthChecker struct{} - -func NewHealthChecker() *HealthChecker { - return &HealthChecker{} -} - -func (s *HealthChecker) Check(ctx context.Context, req *grpc_health_v1.HealthCheckRequest) (*grpc_health_v1.HealthCheckResponse, error) { - klog.Info("Serving the Check request for health check") - return &grpc_health_v1.HealthCheckResponse{ - Status: grpc_health_v1.HealthCheckResponse_SERVING, - }, nil -} - -func (s *HealthChecker) Watch(req *grpc_health_v1.HealthCheckRequest, server grpc_health_v1.Health_WatchServer) error { - klog.Info("Serving the Watch request for health check") - return server.Send(&grpc_health_v1.HealthCheckResponse{ - Status: grpc_health_v1.HealthCheckResponse_SERVING, - }) -} diff --git a/porch/func/internal/executableevaluator.go b/porch/func/internal/executableevaluator.go deleted file mode 100644 index 1f4fe2eeba..0000000000 --- a/porch/func/internal/executableevaluator.go +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2022 The kpt 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. - -package internal - -import ( - "bytes" - "context" - "fmt" - "os" - "os/exec" - "path/filepath" - - v1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/pkg/fn" - pb "github.com/GoogleContainerTools/kpt/porch/func/evaluator" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "gopkg.in/yaml.v2" - "k8s.io/klog/v2" -) - -type executableEvaluator struct { - // Fast-path function cache - cache map[string]string -} - -type configuration struct { - Functions []function `yaml:"functions"` -} - -type function struct { - Function string `yaml:"function"` - Images []string `yaml:"images"` -} - -var _ Evaluator = &executableEvaluator{} - -func NewExecutableEvaluator(functions string, config string) (Evaluator, error) { - cache := map[string]string{} - - if config != "" { - bytes, err := os.ReadFile(config) - if err != nil { - return nil, fmt.Errorf("failed to read configuration file %q: %w", config, err) - } - var cfg configuration - if err := yaml.Unmarshal(bytes, &cfg); err != nil { - return nil, fmt.Errorf("failed to parse configuration file %q: %w", config, err) - } - - for _, fn := range cfg.Functions { - for _, img := range fn.Images { - if _, exists := cache[img]; exists { - klog.Warningf("Ignoring duplicate image %q (%s)", img, fn.Function) - } else { - abs, err := filepath.Abs(filepath.Join(functions, fn.Function)) - if err != nil { - return nil, fmt.Errorf("failed to determine path to the cached function %q: %w", img, err) - } - klog.Infof("Caching %s as %s", img, abs) - cache[img] = abs - } - } - } - } - return &executableEvaluator{ - cache: cache, - }, nil -} - -func (e *executableEvaluator) EvaluateFunction(ctx context.Context, req *pb.EvaluateFunctionRequest) (*pb.EvaluateFunctionResponse, error) { - binary, cached := e.cache[req.Image] - if !cached { - return nil, &fn.NotFoundError{ - Function: v1.Function{Image: req.Image}, - } - } - - klog.Infof("Evaluating %q in executable mode", req.Image) - var stdout, stderr bytes.Buffer - cmd := exec.CommandContext(ctx, binary) - cmd.Stdin = bytes.NewReader(req.ResourceList) - cmd.Stdout = &stdout - cmd.Stderr = &stderr - - if err := cmd.Run(); err != nil { - return nil, status.Errorf(codes.Internal, "Failed to execute function %q: %s (%s)", req.Image, err, stderr.String()) - } - - outbytes := stdout.Bytes() - - klog.Infof("Evaluated %q: stdout %d bytes, stderr:\n%s", req.Image, len(outbytes), stderr.String()) - - // TODO: include stderr in the output? - return &pb.EvaluateFunctionResponse{ - ResourceList: outbytes, - Log: stderr.Bytes(), - }, nil -} diff --git a/porch/func/internal/multievaluator.go b/porch/func/internal/multievaluator.go deleted file mode 100644 index 2291ae820e..0000000000 --- a/porch/func/internal/multievaluator.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2022 The kpt 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. - -package internal - -import ( - "context" - "errors" - - "github.com/GoogleContainerTools/kpt/pkg/fn" - pb "github.com/GoogleContainerTools/kpt/porch/func/evaluator" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -type Evaluator interface { - EvaluateFunction(context.Context, *pb.EvaluateFunctionRequest) (*pb.EvaluateFunctionResponse, error) -} - -type multiEvaluator struct { - pb.UnimplementedFunctionEvaluatorServer - - evaluators []Evaluator -} - -func NewMultiEvaluator(evaluators ...Evaluator) pb.FunctionEvaluatorServer { - return &multiEvaluator{ - evaluators: evaluators, - } -} - -func (me *multiEvaluator) EvaluateFunction(ctx context.Context, req *pb.EvaluateFunctionRequest) (*pb.EvaluateFunctionResponse, error) { - var err error - var notFoundErr *fn.NotFoundError - var resp *pb.EvaluateFunctionResponse - for _, eval := range me.evaluators { - resp, err = eval.EvaluateFunction(ctx, req) - if err == nil { - return resp, nil - } else if !errors.As(err, ¬FoundErr) { - return nil, err - } - } - return nil, status.Error(codes.NotFound, err.Error()) -} diff --git a/porch/func/internal/podevaluator.go b/porch/func/internal/podevaluator.go deleted file mode 100644 index 14446419fe..0000000000 --- a/porch/func/internal/podevaluator.go +++ /dev/null @@ -1,663 +0,0 @@ -// Copyright 2022 The kpt 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. - -package internal - -import ( - "context" - "fmt" - "net" - "os" - "path/filepath" - "strconv" - "strings" - "sync" - "time" - - "github.com/GoogleContainerTools/kpt/porch/func/evaluator" - "github.com/google/go-containerregistry/pkg/gcrane" - "github.com/google/go-containerregistry/pkg/name" - "github.com/google/go-containerregistry/pkg/v1/remote" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - "gopkg.in/yaml.v2" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/klog/v2" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/config" -) - -const ( - defaultWrapperServerPort = "9446" - volumeName = "wrapper-server-tools" - volumeMountPath = "/wrapper-server-tools" - wrapperServerBin = "wrapper-server" - gRPCProbeBin = "grpc-health-probe" - krmFunctionLabel = "fn.kpt.dev/image" - reclaimAfterAnnotation = "fn.kpt.dev/reclaim-after" - fieldManagerName = "krm-function-runner" - - channelBufferSize = 128 -) - -type podEvaluator struct { - requestCh chan<- *clientConnRequest - - podCacheManager *podCacheManager -} - -var _ Evaluator = &podEvaluator{} - -func NewPodEvaluator(namespace, wrapperServerImage string, interval, ttl time.Duration, podTTLConfig string) (Evaluator, error) { - restCfg, err := config.GetConfig() - if err != nil { - return nil, fmt.Errorf("failed to get rest config: %w", err) - } - // Give it a slightly higher QPS to prevent unnecessary client-side throttling. - if restCfg.QPS < 30 { - restCfg.QPS = 30.0 - restCfg.Burst = 45 - } - - cl, err := client.New(restCfg, client.Options{}) - if err != nil { - return nil, fmt.Errorf("failed to create client: %w", err) - } - - reqCh := make(chan *clientConnRequest, channelBufferSize) - readyCh := make(chan *imagePodAndGRPCClient, channelBufferSize) - - pe := &podEvaluator{ - requestCh: reqCh, - podCacheManager: &podCacheManager{ - gcScanInternal: interval, - podTTL: ttl, - requestCh: reqCh, - podReadyCh: readyCh, - cache: map[string]*podAndGRPCClient{}, - waitlists: map[string][]chan<- *clientConnAndError{}, - - podManager: &podManager{ - kubeClient: cl, - namespace: namespace, - wrapperServerImage: wrapperServerImage, - podReadyCh: readyCh, - }, - }, - } - go pe.podCacheManager.podCacheManager() - - // TODO(mengqiy): add watcher that support reloading the cache when the config file was changed. - err = pe.podCacheManager.warmupCache(podTTLConfig) - // If we can't warm up the cache, we can still proceed without it. - if err != nil { - klog.Warningf("unable to warm up the pod cache: %w", err) - } - return pe, nil -} - -func (pe *podEvaluator) EvaluateFunction(ctx context.Context, req *evaluator.EvaluateFunctionRequest) (*evaluator.EvaluateFunctionResponse, error) { - starttime := time.Now() - defer func() { - klog.Infof("evaluating %v in pod took %v", req.Image, time.Now().Sub(starttime)) - }() - // make a buffer for the channel to prevent unnecessary blocking when the pod cache manager sends it to multiple waiting gorouthine in batch. - ccChan := make(chan *clientConnAndError, 1) - // Send a request to request a grpc client. - pe.requestCh <- &clientConnRequest{ - image: req.Image, - grpcClientCh: ccChan, - } - - // Waiting for the client from the channel. This step is blocking. - cc := <-ccChan - if cc.err != nil { - return nil, fmt.Errorf("unable to get the grpc client to the pod for %v: %w", req.Image, cc.err) - } - - resp, err := evaluator.NewFunctionEvaluatorClient(cc.grpcClient).EvaluateFunction(ctx, req) - if err != nil { - return nil, fmt.Errorf("unable to evaluate %v with pod evaluator: %w", req.Image, err) - } - // Log stderr when the function succeeded. If the function fails, stderr will be surfaced to the users. - if len(resp.Log) > 0 { - klog.Warningf("evaluating %v succeeded, but stderr is: %v", req.Image, string(resp.Log)) - } - return resp, nil -} - -// podCacheManager manages the cache of the pods and the corresponding GRPC clients. -// It also does the garbage collection after pods' TTL. -// It has 2 receive-only channels: requestCh and podReadyCh. -// It listens to the requestCh channel and receives clientConnRequest from the -// GRPC request handlers and add them in the waitlists. -// It also listens to the podReadyCh channel. If a pod is ready, it notifies the -// goroutines by sending back the GRPC client by lookup the waitlists mapping. -type podCacheManager struct { - gcScanInternal time.Duration - podTTL time.Duration - - // requestCh is a receive-only channel to receive - requestCh <-chan *clientConnRequest - // podReadyCh is a channel to receive the information when a pod is ready. - podReadyCh <-chan *imagePodAndGRPCClient - - // cache is a mapping from image name to . - cache map[string]*podAndGRPCClient - // waitlists is a mapping from image name to a list of channels that are - // waiting for the GPRC client connections. - waitlists map[string][]chan<- *clientConnAndError - - podManager *podManager -} - -type clientConnRequest struct { - image string - - // grpcConn is a channel that a grpc client should be sent back. - grpcClientCh chan<- *clientConnAndError -} - -type clientConnAndError struct { - grpcClient *grpc.ClientConn - err error -} - -type podAndGRPCClient struct { - grpcClient *grpc.ClientConn - pod client.ObjectKey -} - -type imagePodAndGRPCClient struct { - image string - *podAndGRPCClient - err error -} - -// warmupCache creates the pods and warms up the cache. -func (pcm *podCacheManager) warmupCache(podTTLConfig string) error { - start := time.Now() - defer func() { - klog.Infof("cache warning is completed and it took %v", time.Now().Sub(start)) - }() - content, err := os.ReadFile(podTTLConfig) - if err != nil { - return err - } - var podsTTL map[string]string - err = yaml.Unmarshal(content, &podsTTL) - if err != nil { - return err - } - - // We precreate the pods (concurrently) to speed it up. - forEachConcurrently(podsTTL, func(fnImage string, ttlStr string) { - klog.Infof("preloading pod cache for function %v with TTL %v", fnImage, ttlStr) - - ttl, err := time.ParseDuration(ttlStr) - if err != nil { - klog.Warningf("unable to parse duration from the config file for function %v: %w", fnImage, err) - ttl = pcm.podTTL - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - defer cancel() - - // We invoke the function with useGenerateName=false so that the pod name is fixed, - // since we want to ensure only one pod is created for each function. - pcm.podManager.getFuncEvalPodClient(ctx, fnImage, ttl, false) - klog.Infof("preloaded pod cache for function %v", fnImage) - }) - - return nil -} - -// forEachConcurrently runs fn for each entry in the map m, in parallel goroutines. -// It waits for each to finish before returning. -func forEachConcurrently(m map[string]string, fn func(k string, v string)) { - var wg sync.WaitGroup - for k, v := range m { - k := k - v := v - - wg.Add(1) - go func() { - defer wg.Done() - fn(k, v) - }() - } - // Wait for all the functions to complete. - wg.Wait() -} - -// podCacheManager responds to the requestCh and the podReadyCh and does the -// garbage collection synchronously. -// We must run this method in one single goroutine. Doing it this way simplify -// design around concurrency. -func (pcm *podCacheManager) podCacheManager() { - tick := time.Tick(pcm.gcScanInternal) - for { - select { - case req := <-pcm.requestCh: - podAndCl, found := pcm.cache[req.image] - if found && podAndCl != nil { - // Ensure the pod still exists and is not being deleted before sending the gprc client back to the channel. - // We can't simply return grpc client from the cache and let evaluator try to connect to the pod. - // If the pod is deleted by others, it will take ~10 seconds for the evaluator to fail. - // Wasting 10 second is so much, so we check if the pod still exist first. - pod := &corev1.Pod{} - err := pcm.podManager.kubeClient.Get(context.Background(), podAndCl.pod, pod) - deleteCacheEntry := false - if err == nil { - if pod.DeletionTimestamp == nil && net.JoinHostPort(pod.Status.PodIP, defaultWrapperServerPort) == podAndCl.grpcClient.Target() { - klog.Infof("reusing the connection to pod %v/%v to evaluate %v", pod.Namespace, pod.Name, req.image) - req.grpcClientCh <- &clientConnAndError{grpcClient: podAndCl.grpcClient} - go patchPodWithUnixTimeAnnotation(pcm.podManager.kubeClient, podAndCl.pod, pcm.podTTL) - break - } else { - deleteCacheEntry = true - } - } else if errors.IsNotFound(err) { - deleteCacheEntry = true - } - // We delete the cache entry if the pod has been deleted or being deleted. - if deleteCacheEntry { - delete(pcm.cache, req.image) - } - } - _, found = pcm.waitlists[req.image] - if !found { - pcm.waitlists[req.image] = []chan<- *clientConnAndError{} - } - list := pcm.waitlists[req.image] - pcm.waitlists[req.image] = append(list, req.grpcClientCh) - // We invoke the function with useGenerateName=true to avoid potential name collision, since if pod foo is - // being deleted and we can't use the same name. - go pcm.podManager.getFuncEvalPodClient(context.Background(), req.image, pcm.podTTL, true) - case resp := <-pcm.podReadyCh: - if resp.err != nil { - klog.Warningf("received error from the pod manager: %v", resp.err) - } else { - pcm.cache[resp.image] = resp.podAndGRPCClient - } - // notify all the goroutines that are waiting for the GRPC client. - channels := pcm.waitlists[resp.image] - delete(pcm.waitlists, resp.image) - for i := range channels { - cce := &clientConnAndError{err: resp.err} - if resp.podAndGRPCClient != nil { - cce.grpcClient = resp.podAndGRPCClient.grpcClient - } - // The channel has one buffer size, nothing will be blocking. - channels[i] <- cce - } - case <-tick: - // synchronous GC - pcm.garbageCollector() - } - } -} - -// TODO: We can use Watch + periodically reconciliation to manage the pods, -// the pod evaluator will become a controller. -func (pcm *podCacheManager) garbageCollector() { - var err error - podList := &corev1.PodList{} - err = pcm.podManager.kubeClient.List(context.Background(), podList, client.InNamespace(pcm.podManager.namespace)) - if err != nil { - klog.Warningf("unable to list pods in namespace %v: %w", pcm.podManager.namespace, err) - return - } - for i, pod := range podList.Items { - // If a pod is being deleted, skip it. - if pod.DeletionTimestamp != nil { - continue - } - reclaimAfterStr, found := pod.Annotations[reclaimAfterAnnotation] - // If a pod doesn't have a last-use annotation, we patch it. This should not happen, but if it happens, - // we give another TTL before deleting it. - if !found { - go patchPodWithUnixTimeAnnotation(pcm.podManager.kubeClient, client.ObjectKeyFromObject(&pod), pcm.podTTL) - continue - } else { - reclaimAfter, err := strconv.ParseInt(reclaimAfterStr, 10, 64) - // If the annotation is ill-formatted, we patch it with the current time and will try to GC it later. - // This should not happen, but if it happens, we give another TTL before deleting it. - if err != nil { - klog.Warningf("unable to convert the Unix time string to int64: %w", err) - go patchPodWithUnixTimeAnnotation(pcm.podManager.kubeClient, client.ObjectKeyFromObject(&pod), pcm.podTTL) - continue - } - // If the current time is after the reclaim-ater annotation in the pod, we delete the pod and remove the corresponding cache entry. - if time.Now().After(time.Unix(reclaimAfter, 0)) { - podIP := pod.Status.PodIP - go func(po corev1.Pod) { - klog.Infof("deleting pod %v/%v", po.Namespace, po.Name) - err := pcm.podManager.kubeClient.Delete(context.Background(), &po) - if err != nil { - klog.Warningf("unable to delete pod %v/%v: %w", po.Namespace, po.Name, err) - } - }(podList.Items[i]) - - image := pod.Spec.Containers[0].Image - podAndCl, found := pcm.cache[image] - if found { - host, _, err := net.SplitHostPort(podAndCl.grpcClient.Target()) - // If the client target in the cache points to a different pod IP, it means the matching pod is not the current pod. - // We will keep this cache entry. - if err == nil && host != podIP { - continue - } - // We delete the cache entry when the IP of the old pod match the client target in the cache - // or we can't split the host and port in the client target. - delete(pcm.cache, image) - } - } - } - } -} - -// podManager is responsible for: -// - creating a pod -// - retrieving an existing pod -// - waiting for the pod to be running and ready -// - caching the metadata (e.g. entrypoint) for the image. -type podManager struct { - // kubeClient is the kubernetes client - kubeClient client.Client - // namespace holds the namespace where the executors run - namespace string - // wrapperServerImage is the image name of the wrapper server - wrapperServerImage string - - // podReadyCh is a channel to receive requests to get GRPC client from each function evaluation request handler. - podReadyCh chan<- *imagePodAndGRPCClient - - // imageMetadataCache is a cache of image name to digestAndEntrypoint. - // Only podManager is allowed to touch this cache. - // Its underlying type is map[string]*digestAndEntrypoint. - imageMetadataCache sync.Map -} - -type digestAndEntrypoint struct { - // digest is a hex string - digest string - // entrypoint is the entrypoint of the image - entrypoint []string -} - -// getFuncEvalPodClient ensures there is a pod running and ready for the image. -// It will send it to the podReadyCh channel when the pod is ready. ttl is the -// time-to-live period for the pod. If useGenerateName is false, it will try to -// create a pod with a fixed name. Otherwise, it will create a pod and let the -// apiserver to generate the name from a template. -func (pm *podManager) getFuncEvalPodClient(ctx context.Context, image string, ttl time.Duration, useGenerateName bool) { - c, err := func() (*podAndGRPCClient, error) { - podKey, err := pm.retrieveOrCreatePod(ctx, image, ttl, useGenerateName) - if err != nil { - return nil, err - } - podIP, err := pm.podIpIfRunningAndReady(ctx, podKey) - if err != nil { - return nil, err - } - if podIP == "" { - return nil, fmt.Errorf("pod %s/%s did not have podIP", podKey.Namespace, podKey.Name) - } - address := net.JoinHostPort(podIP, defaultWrapperServerPort) - cc, err := grpc.Dial(address, grpc.WithTransportCredentials(insecure.NewCredentials())) - if err != nil { - return nil, fmt.Errorf("failed to dial grpc function evaluator on %q for pod %s/%s: %w", address, podKey.Namespace, podKey.Name, err) - } - return &podAndGRPCClient{ - pod: podKey, - grpcClient: cc, - }, err - }() - pm.podReadyCh <- &imagePodAndGRPCClient{ - image: image, - podAndGRPCClient: c, - err: err, - } -} - -// imageDigestAndEntrypoint gets the entrypoint of a container image by looking at its metadata. -func (pm *podManager) imageDigestAndEntrypoint(ctx context.Context, image string) (*digestAndEntrypoint, error) { - start := time.Now() - defer func() { - klog.Infof("getting image metadata for %v took %v", image, time.Now().Sub(start)) - }() - var entrypoint []string - ref, err := name.ParseReference(image) - if err != nil { - return nil, err - } - img, err := remote.Image(ref, remote.WithAuthFromKeychain(gcrane.Keychain), remote.WithContext(ctx)) - if err != nil { - return nil, err - } - hash, err := img.Digest() - if err != nil { - return nil, err - } - cf, err := img.ConfigFile() - if err != nil { - return nil, err - } - - cfg := cf.Config - // TODO: to handle all scenario, we should follow https://docs.docker.com/engine/reference/builder/#understand-how-cmd-and-entrypoint-interact. - if len(cfg.Entrypoint) != 0 { - entrypoint = cfg.Entrypoint - } else { - entrypoint = cfg.Cmd - } - de := &digestAndEntrypoint{ - digest: hash.Hex, - entrypoint: entrypoint, - } - pm.imageMetadataCache.Store(image, de) - return de, nil -} - -// retrieveOrCreatePod retrieves or creates a pod for an image. -func (pm *podManager) retrieveOrCreatePod(ctx context.Context, image string, ttl time.Duration, useGenerateName bool) (client.ObjectKey, error) { - var de *digestAndEntrypoint - var err error - val, found := pm.imageMetadataCache.Load(image) - if !found { - de, err = pm.imageDigestAndEntrypoint(ctx, image) - if err != nil { - return client.ObjectKey{}, fmt.Errorf("unable to get the entrypoint for %v: %w", image, err) - } - } else { - de = val.(*digestAndEntrypoint) - } - - podId, err := podID(image, de.digest) - if err != nil { - return client.ObjectKey{}, err - } - - // Try to retrieve the pod. Lookup the pod by label to see if there is a pod that can be reused. - // Looking it up locally may not work if there are more than one instance of the function runner, - // since the pod may be created by one the other instance and the current instance is not aware of it. - // TODO: It's possible to set up a Watch in the fn runner namespace, and always try to maintain a up-to-date local cache. - podList := &corev1.PodList{} - err = pm.kubeClient.List(ctx, podList, client.InNamespace(pm.namespace), client.MatchingLabels(map[string]string{krmFunctionLabel: podId})) - if err != nil { - klog.Warningf("error when listing pods for %q: %w", image, err) - } - if err == nil && len(podList.Items) > 0 { - // TODO: maybe we should randomly pick one that is no being deleted. - for _, pod := range podList.Items { - if pod.DeletionTimestamp == nil { - klog.Infof("retrieved function evaluator pod %v/%v for %q", pod.Namespace, pod.Name, image) - return client.ObjectKeyFromObject(&pod), nil - } - } - } - - cmd := append([]string{ - filepath.Join(volumeMountPath, wrapperServerBin), - "--port", defaultWrapperServerPort, "--", - }, de.entrypoint...) - - // Create a pod - pod := &corev1.Pod{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Pod", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: pm.namespace, - Annotations: map[string]string{ - reclaimAfterAnnotation: fmt.Sprintf("%v", time.Now().Add(ttl).Unix()), - // Add the following annotation to make it work well with the cluster autoscaler. - // https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#what-types-of-pods-can-prevent-ca-from-removing-a-node - "cluster-autoscaler.kubernetes.io/safe-to-evict": "true", - }, - // The function runner can use the label to retrieve the pod. Label is function name + part of its digest. - // If a function has more than one tags pointing to the same digest, we can reuse the same pod. - // TODO: controller-runtime provides field indexer, we can potentially use it to index spec.containers[*].image field. - Labels: map[string]string{ - krmFunctionLabel: podId, - }, - }, - Spec: corev1.PodSpec{ - // We use initContainer to copy the wrapper server binary into the KRM function image. - InitContainers: []corev1.Container{ - { - Name: "copy-wrapper-server", - Image: pm.wrapperServerImage, - Command: []string{ - "cp", - "-a", - "/wrapper-server/.", - volumeMountPath, - }, - VolumeMounts: []corev1.VolumeMount{ - { - Name: volumeName, - MountPath: volumeMountPath, - }, - }, - }, - }, - Containers: []corev1.Container{ - { - Name: "function", - Image: image, - Command: cmd, - ReadinessProbe: &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - // TODO: use the k8s native GRPC prober when it has been rolled out in GKE. - // https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-a-grpc-liveness-probe - Exec: &corev1.ExecAction{ - Command: []string{ - filepath.Join(volumeMountPath, gRPCProbeBin), - "-addr", net.JoinHostPort("localhost", defaultWrapperServerPort), - }, - }, - }, - }, - VolumeMounts: []corev1.VolumeMount{ - { - Name: volumeName, - MountPath: volumeMountPath, - }, - }, - }, - }, - Volumes: []corev1.Volume{ - { - Name: volumeName, - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{}, - }, - }, - }, - }, - } - // Server-side apply doesn't support name generation. We have to use Create - // if we need to use name generation. - if useGenerateName { - pod.GenerateName = podId + "-" - err = pm.kubeClient.Create(ctx, pod, client.FieldOwner(fieldManagerName)) - if err != nil { - return client.ObjectKey{}, fmt.Errorf("unable to apply the pod: %w", err) - } - } else { - pod.Name = podId - err = pm.kubeClient.Patch(ctx, pod, client.Apply, client.FieldOwner(fieldManagerName)) - if err != nil { - return client.ObjectKey{}, fmt.Errorf("unable to apply the pod: %w", err) - } - } - - klog.Infof("created KRM function evaluator pod %v/%v for %q", pod.Namespace, pod.Name, image) - return client.ObjectKeyFromObject(pod), nil -} - -// podIpIfRunningAndReady waits for the pod to be running and ready and returns the pod IP and a potential error. -func (pm *podManager) podIpIfRunningAndReady(ctx context.Context, podKey client.ObjectKey) (ip string, e error) { - var pod corev1.Pod - // Wait until the pod is Running - if e := wait.PollImmediate(100*time.Millisecond, 60*time.Second, func() (done bool, err error) { - err = pm.kubeClient.Get(ctx, podKey, &pod) - if err != nil { - return false, err - } - if pod.Status.Phase != "Running" { - return false, nil - } - for _, cond := range pod.Status.Conditions { - if cond.Type == corev1.PodReady && cond.Status == corev1.ConditionTrue { - return true, nil - } - } - return false, nil - }); e != nil { - return "", fmt.Errorf("error occured when waiting the pod to be ready. If the error is caused by timeout, you may want to examine the pods in namespace %q. Error: %w", pm.namespace, e) - } - return pod.Status.PodIP, nil -} - -// patchPodWithUnixTimeAnnotation patches the pod with the new updated TTL annotation. -func patchPodWithUnixTimeAnnotation(cl client.Client, podKey client.ObjectKey, ttl time.Duration) { - patch := []byte(fmt.Sprintf(`{"metadata":{"annotations":{"%v": "%v"}}}`, reclaimAfterAnnotation, time.Now().Add(ttl).Unix())) - pod := &corev1.Pod{} - pod.Namespace = podKey.Namespace - pod.Name = podKey.Name - if err := cl.Patch(context.Background(), pod, client.RawPatch(types.MergePatchType, patch)); err != nil { - klog.Warningf("unable to patch last-use annotation for pod %v/%v: %w", podKey.Namespace, podKey.Name, err) - } -} - -func podID(image, hash string) (string, error) { - ref, err := name.ParseReference(image) - if err != nil { - return "", fmt.Errorf("unable to parse image reference %v: %w", image, err) - } - - // repoName will be something like gcr.io/kpt-fn/set-namespace - repoName := ref.Context().Name() - parts := strings.Split(repoName, "/") - name := strings.ReplaceAll(parts[len(parts)-1], "_", "-") - return fmt.Sprintf("%v-%v", name, hash[:8]), nil -} diff --git a/porch/func/server/server.go b/porch/func/server/server.go deleted file mode 100644 index b5b340c4b8..0000000000 --- a/porch/func/server/server.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2022 The kpt 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. - -package main - -import ( - "flag" - "fmt" - "net" - "os" - "strings" - "time" - - pb "github.com/GoogleContainerTools/kpt/porch/func/evaluator" - "github.com/GoogleContainerTools/kpt/porch/func/healthchecker" - "github.com/GoogleContainerTools/kpt/porch/func/internal" - "google.golang.org/grpc" - "google.golang.org/grpc/health/grpc_health_v1" - "k8s.io/klog/v2" -) - -const ( - execRuntime = "exec" - podRuntime = "pod" - - wrapperServerImageEnv = "WRAPPER_SERVER_IMAGE" -) - -var ( - port = flag.Int("port", 9445, "The server port") - functions = flag.String("functions", "./functions", "Path to cached functions.") - config = flag.String("config", "./config.yaml", "Path to the config file.") - podCacheConfig = flag.String("pod-cache-config", "/pod-cache-config/pod-cache-config.yaml", "Path to the pod cache config file. The file is map of function name to TTL.") - podNamespace = flag.String("pod-namespace", "porch-fn-system", "Namespace to run KRM functions pods.") - podTTL = flag.Duration("pod-ttl", 30*time.Minute, "TTL for pods before GC.") - scanInterval = flag.Duration("scan-interval", time.Minute, "The interval of GC between scans.") - disableRuntimes = flag.String("disable-runtimes", "", fmt.Sprintf("The runtime(s) to disable. Multiple runtimes should separated by `,`. Available runtimes: `%v`, `%v`.", execRuntime, podRuntime)) -) - -func main() { - flag.Parse() - - if err := run(); err != nil { - fmt.Fprintf(os.Stderr, "unexpected error: %v\n", err) - os.Exit(1) - } -} - -func run() error { - address := fmt.Sprintf(":%d", *port) - lis, err := net.Listen("tcp", address) - if err != nil { - return fmt.Errorf("failed to listen: %w", err) - } - - availableRuntimes := map[string]struct{}{ - execRuntime: {}, - podRuntime: {}, - } - if disableRuntimes != nil { - runtimesFromFlag := strings.Split(*disableRuntimes, ",") - for _, rt := range runtimesFromFlag { - delete(availableRuntimes, rt) - } - } - runtimes := []internal.Evaluator{} - for rt := range availableRuntimes { - switch rt { - case execRuntime: - execEval, err := internal.NewExecutableEvaluator(*functions, *config) - if err != nil { - return fmt.Errorf("failed to initialize executable evaluator: %w", err) - } - runtimes = append(runtimes, execEval) - case podRuntime: - wrapperServerImage := os.Getenv(wrapperServerImageEnv) - if wrapperServerImage == "" { - return fmt.Errorf("environment variable %v must be set to use pod function evaluator runtime", wrapperServerImageEnv) - } - podEval, err := internal.NewPodEvaluator(*podNamespace, wrapperServerImage, *scanInterval, *podTTL, *podCacheConfig) - if err != nil { - return fmt.Errorf("failed to initialize pod evaluator: %w", err) - } - runtimes = append(runtimes, podEval) - } - } - if len(runtimes) == 0 { - klog.Warning("no runtime is enabled in function-runner") - } - evaluator := internal.NewMultiEvaluator(runtimes...) - - klog.Infof("Listening on %s", address) - - // Start the gRPC server - server := grpc.NewServer() - pb.RegisterFunctionEvaluatorServer(server, evaluator) - healthService := healthchecker.NewHealthChecker() - grpc_health_v1.RegisterHealthServer(server, healthService) - if err := server.Serve(lis); err != nil { - return fmt.Errorf("server failed: %w", err) - } - return nil -} diff --git a/porch/func/wrapper-server/main.go b/porch/func/wrapper-server/main.go deleted file mode 100644 index d56ad941e3..0000000000 --- a/porch/func/wrapper-server/main.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2022 The kpt 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. - -package main - -import ( - "bytes" - "context" - "errors" - "fmt" - "net" - "os" - "os/exec" - - "github.com/GoogleContainerTools/kpt-functions-sdk/go/fn" - pb "github.com/GoogleContainerTools/kpt/porch/func/evaluator" - "github.com/GoogleContainerTools/kpt/porch/func/healthchecker" - "github.com/spf13/cobra" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/health/grpc_health_v1" - "google.golang.org/grpc/status" - "k8s.io/klog/v2" -) - -func main() { - op := &options{} - cmd := &cobra.Command{ - Use: "wrapper-server", - Short: "wrapper-server is a gRPC server that fronts a KRM function", - RunE: func(cmd *cobra.Command, args []string) error { - argsLenAtDash := cmd.ArgsLenAtDash() - if argsLenAtDash > -1 { - op.entrypoint = args[argsLenAtDash:] - } - return op.run() - }, - } - cmd.Flags().IntVar(&op.port, "port", 9446, "The server port") - if err := cmd.Execute(); err != nil { - fmt.Fprintf(os.Stderr, "unexpected error: %v\n", err) - os.Exit(1) - } -} - -type options struct { - port int - entrypoint []string -} - -func (o *options) run() error { - address := fmt.Sprintf(":%d", o.port) - lis, err := net.Listen("tcp", address) - if err != nil { - return fmt.Errorf("failed to listen: %w", err) - } - - evaluator := &singleFunctionEvaluator{ - entrypoint: o.entrypoint, - } - - klog.Infof("Listening on %s", address) - - // Start the gRPC server - server := grpc.NewServer() - pb.RegisterFunctionEvaluatorServer(server, evaluator) - healthService := healthchecker.NewHealthChecker() - grpc_health_v1.RegisterHealthServer(server, healthService) - - if err := server.Serve(lis); err != nil { - return fmt.Errorf("server failed: %w", err) - } - return nil -} - -type singleFunctionEvaluator struct { - pb.UnimplementedFunctionEvaluatorServer - - entrypoint []string -} - -func (e *singleFunctionEvaluator) EvaluateFunction(ctx context.Context, req *pb.EvaluateFunctionRequest) (*pb.EvaluateFunctionResponse, error) { - var stdout, stderr bytes.Buffer - cmd := exec.CommandContext(ctx, e.entrypoint[0], e.entrypoint[1:]...) - cmd.Stdin = bytes.NewReader(req.ResourceList) - cmd.Stdout = &stdout - cmd.Stderr = &stderr - - err := cmd.Run() - var exitErr *exec.ExitError - outbytes := stdout.Bytes() - stderrStr := stderr.String() - if err != nil { - if errors.As(err, &exitErr) { - // If the exit code is non-zero, we will try to embed the structured results and content from stderr into the error message. - rl, pe := fn.ParseResourceList(outbytes) - if pe != nil { - // If we can't parse the output resource list, we only surface the content in stderr. - return nil, status.Errorf(codes.Internal, "failed to evaluate function %q with stderr %v", req.Image, stderrStr) - } - return nil, status.Errorf(codes.Internal, "failed to evaluate function %q with structured results: %v and stderr: %v", req.Image, rl.Results.Error(), stderrStr) - } else { - return nil, status.Errorf(codes.Internal, "Failed to execute function %q: %s (%s)", req.Image, err, stderrStr) - } - } - - klog.Infof("Evaluated %q: stdout length: %d\nstderr:\n%v", req.Image, len(outbytes), stderrStr) - - return &pb.EvaluateFunctionResponse{ - ResourceList: outbytes, - Log: []byte(stderrStr), - }, nil -} diff --git a/porch/go.mod b/porch/go.mod deleted file mode 100644 index 3a9b77e8eb..0000000000 --- a/porch/go.mod +++ /dev/null @@ -1,193 +0,0 @@ -module github.com/GoogleContainerTools/kpt/porch - -go 1.21 - -replace ( - github.com/GoogleContainerTools/kpt => ../ - github.com/GoogleContainerTools/kpt/porch/api => ./api - github.com/go-git/go-git/v5 v5.4.3-0.20220408232334-4f916225cb2f => github.com/platkrm/go-git/v5 v5.4.3-0.20220410165046-c76b262044ce -) - -require ( - cloud.google.com/go/iam v1.1.1 - github.com/GoogleContainerTools/kpt v0.0.0-00010101000000-000000000000 - github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/apply-replacements v0.1.1 - github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/apply-setters v0.2.0 - github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/set-namespace v0.4.1 - github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/starlark v0.4.3 - github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220506190241-f85503febd54 - github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20230121152246-dc44dbd18a33 - github.com/bluekeyes/go-gitdiff v0.6.1 - github.com/go-git/go-billy/v5 v5.3.1 - github.com/go-git/go-git/v5 v5.4.3-0.20220408232334-4f916225cb2f - github.com/golang/protobuf v1.5.3 - github.com/google/go-cmp v0.5.9 - github.com/google/go-containerregistry v0.14.0 - github.com/google/uuid v1.3.1 - github.com/hexops/gotextdiff v1.0.3 - github.com/spf13/cobra v1.6.1 - github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.8.3 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 - go.opentelemetry.io/otel v1.16.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 - go.opentelemetry.io/otel/sdk v1.16.0 - go.opentelemetry.io/otel/trace v1.16.0 - golang.org/x/mod v0.9.0 - golang.org/x/oauth2 v0.11.0 - golang.org/x/tools v0.7.0 - google.golang.org/api v0.126.0 - google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d - google.golang.org/grpc v1.59.0 - google.golang.org/protobuf v1.33.0 - gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.26.9 - k8s.io/apimachinery v0.26.9 - k8s.io/apiserver v0.26.9 - k8s.io/client-go v0.26.9 - k8s.io/component-base v0.26.9 - k8s.io/klog/v2 v2.90.1 - k8s.io/kube-aggregator v0.24.0-beta.0 - k8s.io/utils v0.0.0-20230115233650-391b47cb4029 - sigs.k8s.io/controller-runtime v0.14.1 - sigs.k8s.io/kustomize/kyaml v0.13.9 - sigs.k8s.io/yaml v1.3.0 -) - -require ( - cloud.google.com/go/compute v1.23.0 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect - github.com/360EntSecGroup-Skylar/excelize v1.4.1 // indirect - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect - github.com/MakeNowJust/heredoc v1.0.0 // indirect - github.com/Microsoft/go-winio v0.6.0 // indirect - github.com/NYTimes/gziphandler v1.1.1 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect - github.com/PuerkitoBio/goquery v1.5.1 // indirect - github.com/acomagu/bufpipe v1.0.4-0.20210605013841-cd7a5f79d3c4 // indirect - github.com/andybalholm/cascadia v1.1.0 // indirect - github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect - github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/blang/semver/v4 v4.0.0 // indirect - github.com/bytecodealliance/wasmtime-go v0.39.0 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/chai2010/gettext-go v1.0.2 // indirect - github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect - github.com/coreos/go-semver v0.3.0 // indirect - github.com/coreos/go-systemd/v22 v22.3.2 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/docker/cli v23.0.1+incompatible // indirect - github.com/docker/distribution v2.8.2+incompatible // indirect - github.com/docker/docker v24.0.9+incompatible // indirect - github.com/docker/docker-credential-helpers v0.7.0 // indirect - github.com/dustmop/soup v1.1.2-0.20190516214245-38228baa104e // indirect - github.com/emicklei/go-restful/v3 v3.9.0 // indirect - github.com/emirpasic/gods v1.12.0 // indirect - github.com/evanphx/json-patch v4.12.0+incompatible // indirect - github.com/evanphx/json-patch/v5 v5.6.0 // indirect - github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect - github.com/felixge/httpsnoop v1.0.3 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-errors/errors v1.4.2 // indirect - github.com/go-git/gcfg v1.5.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect - github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.1 // indirect - github.com/go-openapi/swag v0.22.3 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/google/btree v1.1.2 // indirect - github.com/google/cel-go v0.12.7 // indirect - github.com/google/gnostic v0.6.9 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/google/s2a-go v0.1.4 // indirect - github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.11.0 // indirect - github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect - github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect - github.com/imdario/mergo v0.3.12 // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect - github.com/klauspost/compress v1.16.0 // indirect - github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/go-wordwrap v1.0.0 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/moby/spdystream v0.2.0 // indirect - github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc2 // indirect - github.com/otiai10/copy v1.7.0 // indirect - github.com/paulmach/orb v0.1.5 // indirect - github.com/peterbourgon/diskv v2.0.1+incompatible // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prep/wasmexec v0.0.0-20220807105708-6554945c1dec // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect - github.com/qri-io/starlib v0.5.0 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/sergi/go-diff v1.2.0 // indirect - github.com/sirupsen/logrus v1.9.0 // indirect - github.com/stoewer/go-strcase v1.2.0 // indirect - github.com/vbatts/tar-split v0.11.2 // indirect - github.com/xanzy/ssh-agent v0.3.1 // indirect - github.com/xlab/treeprint v1.1.0 // indirect - go.etcd.io/etcd/api/v3 v3.5.5 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.5 // indirect - go.etcd.io/etcd/client/v3 v3.5.5 // indirect - go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.35.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect - go.opentelemetry.io/otel/metric v1.16.0 // indirect - go.opentelemetry.io/proto/otlp v0.19.0 // indirect - go.starlark.net v0.0.0-20210901212718-87f333178d59 // indirect - go.uber.org/atomic v1.7.0 // indirect - go.uber.org/multierr v1.6.0 // indirect - go.uber.org/zap v1.24.0 // indirect - golang.org/x/crypto v0.21.0 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/term v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.3.0 // indirect - gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect - gopkg.in/warnings.v0 v0.1.2 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.26.9 // indirect - k8s.io/cli-runtime v0.26.9 // indirect - k8s.io/kms v0.26.9 // indirect - k8s.io/kube-openapi v0.0.0-20230109183929-3758b55a6596 // indirect - k8s.io/kubectl v0.26.9 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.37 // indirect - sigs.k8s.io/cli-utils v0.35.0 // indirect - sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect - sigs.k8s.io/kustomize/api v0.12.1 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect -) diff --git a/porch/go.sum b/porch/go.sum deleted file mode 100644 index 8e7599b9a0..0000000000 --- a/porch/go.sum +++ /dev/null @@ -1,1324 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -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= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= -cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -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/360EntSecGroup-Skylar/excelize v1.4.1 h1:l55mJb6rkkaUzOpSsgEeKYtS6/0gHwBYyfo5Jcjv/Ks= -github.com/360EntSecGroup-Skylar/excelize v1.4.1/go.mod h1:vnax29X2usfl7HHkBrX5EvSCJcmH3dT9luvxzu8iGAE= -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-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= -github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= -github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/logger v0.2.1/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/GoogleContainerTools/kpt-functions-catalog/functions/go/apply-replacements v0.1.1 h1:fg4LOWPoFYsMzV6h29la7egu4LSAWgJjHN1dkSdmx/A= -github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/apply-replacements v0.1.1/go.mod h1:8xnZ/1TxSoomhm/jqWHX9BIBhFUuRWifmmz469dcox0= -github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/apply-setters v0.2.0 h1:GhM9JLR+vW4/jPuL7bGVAEUsIIp5xhJKhm17wSyQZLY= -github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/apply-setters v0.2.0/go.mod h1:D+1CuvT4BecI7ZokGUVPdjnhT+z0z1/9NB6HGH4cTSI= -github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/set-namespace v0.4.1 h1:4/PW8UQST7f6oBIA+vEOHeFFQYkX+FOWYwQyS7lZAVI= -github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/set-namespace v0.4.1/go.mod h1:5XWywBvOyBmuIoD9waCvtL2jXaZBYAY6QH+s9UunlVY= -github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/starlark v0.4.3 h1:fipXlh4qYf5vkpUEA8wmK6YLIC1mgPMsHUpF7gIYamU= -github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/starlark v0.4.3/go.mod h1:V11NRqrqOFy43O35azz012xtNBU/px2b8qclZn3Ohpg= -github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220506190241-f85503febd54 h1:z5iYiugZJiTzQ6ggU0Cae/T+LkrDwcqZyebh8SbmQ0E= -github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220506190241-f85503febd54/go.mod h1:vl3iiwgrqdDgvGi5ckt3O9IoyaHUgFkfxE4RjQIqgwk= -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.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -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/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= -github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ= -github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= -github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE= -github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= -github.com/acomagu/bufpipe v1.0.4-0.20210605013841-cd7a5f79d3c4 h1:LLzKXLcKO8rAXpUHeNI5FkJKivErqhBKdeMzrpBFqS4= -github.com/acomagu/bufpipe v1.0.4-0.20210605013841-cd7a5f79d3c4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= -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/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo= -github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= -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 v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves= -github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= -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= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= -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= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -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/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -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/bluekeyes/go-gitdiff v0.6.1 h1:VPpQZanEVwFid0IoAIyiJLD+SMWM/AXZXYFc+3E9CS4= -github.com/bluekeyes/go-gitdiff v0.6.1/go.mod h1:QpfYYO1E0fTVHVZAZKiRjtSGY9823iCdvGXBcEzHGbM= -github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/bytecodealliance/wasmtime-go v0.39.0 h1:35AXy5+py5ZXRSpfoxqh+dWJ7nJnIrW1avjDfaJinxU= -github.com/bytecodealliance/wasmtime-go v0.39.0/go.mod h1:q320gUxqyI8yB+ZqRuaJOEnGkAnHh6WtJjMaT2CW4wI= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= -github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/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/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= -github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= -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/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-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -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/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= -github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= -github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= -github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= -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-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 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -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.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -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.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= -github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -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/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/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.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 v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0= -github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= -github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= -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/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustmop/soup v1.1.2-0.20190516214245-38228baa104e h1:44fmjqDtdCiUNlSjJVp+w1AOs6na3Y6Ai0aIeseFjkI= -github.com/dustmop/soup v1.1.2-0.20190516214245-38228baa104e/go.mod h1:CgNC6SGbT+Xb8wGGvzilttZL1mc5sQ/5KkcxsZttMIk= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= -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.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= -github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= -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= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= -github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= -github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= -github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= -github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= -github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -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/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= -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/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= -github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -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/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= -github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= -github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= -github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= -github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-git-fixtures/v4 v4.3.1 h1:y5z6dd3qi8Hl+stezc8p3JxDkoTRqMAlKnXHuzrfjTQ= -github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -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-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -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-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -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.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro= -github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= -github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5/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.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= -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/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -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.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= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= -github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= -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= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -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/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -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= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -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/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.12.7 h1:jM6p55R0MKBg79hZjn1zs2OlrywZ1Vk00rxVvad1/O0= -github.com/google/cel-go v0.12.7/go.mod h1:Jk7ljRzLBhkmiAwBoUxB1sZSCVBAzkqPF25olK/iRDw= -github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= -github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= -github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -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.14.0 h1:z58vMqHxuwvAsVwvKEkmVBz2TlgBgH5k6koEXBtlYkw= -github.com/google/go-containerregistry v0.14.0/go.mod h1:aiJ2fp/SXvkWgmYHioXnbMdlgB8eXiiYOY55gfN91Wk= -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= -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/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= -github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -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.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4= -github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= -github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= -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/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= -github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/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.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= -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.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -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= -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= -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 v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= -github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= -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.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.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -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= -github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= -github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -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/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= -github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -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.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.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -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= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -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/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -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-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.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= -github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= -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/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.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM= -github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -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 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -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/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= -github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI= -github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= -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= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -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/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= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -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/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.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo/v2 v2.7.0 h1:/XxtEV3I3Eif/HobnVx9YmJgk8ENdRsuUmM+fLCFNow= -github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.24.2 h1:J/tulyYK6JwBldPViHJReihxxZ+22FHs0piGjQAvoUE= -github.com/onsi/gomega v1.24.2/go.mod h1:gs3J10IS7Z7r7eXRoNJIrNqU4ToQukCJhFtKrWgHWnk= -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.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= -github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE= -github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U= -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.3 h1:7JgpsBaN0uMkyju4tbYHu0mnM55hNKVYLsXmwr15NQI= -github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/paulmach/orb v0.1.5 h1:GUcATabvxciqEzGd+c01/9ek3B6pUp9OdcIHFSDDSSg= -github.com/paulmach/orb v0.1.5/go.mod h1:pPwxxs3zoAyosNSbNKn1jiXV2+oovRDObDKfTvRegDI= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -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/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f h1:WyCn68lTiytVSkk7W1K9nBiSGTSRlUOdyTnSjwrIlok= -github.com/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f/go.mod h1:/iRjX3DdSK956SzsUdV55J+wIsQ+2IBWmBrB4RvZfk4= -github.com/pkg/errors v0.8.0/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/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/platkrm/go-git/v5 v5.4.3-0.20220410165046-c76b262044ce h1:HuO44EsG+4+mGBkomtK/tTEiegvrN2mROsWDenSLF0Y= -github.com/platkrm/go-git/v5 v5.4.3-0.20220410165046-c76b262044ce/go.mod h1:U7oc8MDRtQhVD6StooNkBMVsh/Y4J/2Vl36Mo4IclvM= -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/prep/wasmexec v0.0.0-20220807105708-6554945c1dec h1:Yz85KaIsPzF0YRrznNaD35o4GEk65/3mqio3m9sgqi4= -github.com/prep/wasmexec v0.0.0-20220807105708-6554945c1dec/go.mod h1:/AG7CoBOwtk42jdCTLbd280PA4h50oaFK88jee+BaVA= -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.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -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.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -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.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -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.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/qri-io/starlib v0.5.0 h1:NlveoBAhO6mNgM7+JpM9QlHh3/3pOtOiH6iXaqSdVK0= -github.com/qri-io/starlib v0.5.0/go.mod h1:FpVumyB2CMrKIrjf39fAi4uydYWVvnWEvXEOwfzZRHY= -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= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -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/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= -github.com/sergi/go-diff v1.2.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.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -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.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= -github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -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/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= -github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= -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.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= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -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.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 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/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= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -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/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA= -github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME= -github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI= -github.com/xanzy/ssh-agent v0.3.1 h1:AmzO1SSWxw73zxFZPRwaMN1MohDw8UyHnmuxyceTEGo= -github.com/xanzy/ssh-agent v0.3.1/go.mod h1:QIE4lCeL7nkC25x+yA3LBIYfwCc1TFziCtG7cBAac6w= -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 v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= -github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= -github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= -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= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -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.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/api/v3 v3.5.5 h1:BX4JIbQ7hl7+jL+g+2j5UAr0o1bctCm6/Ct+ArBGkf0= -go.etcd.io/etcd/api/v3 v3.5.5/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.5 h1:9S0JUVvmrVl7wCF39iTQthdaaNIiAaQbmK75ogO6GU8= -go.etcd.io/etcd/client/pkg/v3 v3.5.5/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.etcd.io/etcd/client/v2 v2.305.5 h1:DktRP60//JJpnPC0VBymAN/7V71GHMdjDCBt4ZPXDjI= -go.etcd.io/etcd/client/v2 v2.305.5/go.mod h1:zQjKllfqfBVyVStbt4FaosoX2iYd8fV/GRy/PbowgP4= -go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= -go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q= -go.etcd.io/etcd/client/v3 v3.5.5 h1:q++2WTJbUgpQu4B6hCuT7VkdwaTP7Qz6Daak3WzbrlI= -go.etcd.io/etcd/client/v3 v3.5.5/go.mod h1:aApjR4WGlSumpnJ2kloS75h6aHUmAyaPLjHMxpc7E7c= -go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= -go.etcd.io/etcd/pkg/v3 v3.5.5 h1:Ablg7T7OkR+AeeeU32kdVhw/AGDsitkKPl7aW73ssjU= -go.etcd.io/etcd/pkg/v3 v3.5.5/go.mod h1:6ksYFxttiUGzC2uxyqiyOEvhAiD0tuIqSZkX3TyPdaE= -go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= -go.etcd.io/etcd/raft/v3 v3.5.5 h1:Ibz6XyZ60OYyRopu73lLM/P+qco3YtlZMOhnXNS051I= -go.etcd.io/etcd/raft/v3 v3.5.5/go.mod h1:76TA48q03g1y1VpTue92jZLr9lIHKUNcYdZOOGyx8rI= -go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= -go.etcd.io/etcd/server/v3 v3.5.5 h1:jNjYm/9s+f9A9r6+SC4RvNaz6AqixpOvhrFdT0PvIj0= -go.etcd.io/etcd/server/v3 v3.5.5/go.mod h1:rZ95vDw/jrvsbj9XpTqPrTAB9/kzchVdhRirySPkUBc= -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= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.35.0 h1:xFSRQBbXF6VvYRf2lqMJXxoB72XI1K/azav8TekHHSw= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.35.0/go.mod h1:h8TWwRAhQpOd0aM5nYsRD8+flnkj+526GEIVlarH7eY= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 h1:pginetY7+onl4qN1vl0xW/V/v6OBZ0vVdH+esuJgvmM= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0/go.mod h1:XiYsayHc36K3EByOO6nbAXnAWbrUxdjUROCEeeROOH8= -go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= -go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= -go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 h1:t4ZwRPU+emrcvM2e9DHd0Fsf0JTPVcbfa/BhTDF03d0= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0/go.mod h1:vLarbg68dH2Wa77g71zmKQqlQ8+8Rq3GRG31uc0WcWI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 h1:cbsD4cUcviQGXdw8+bo5x2wazq10SKz8hEbtCRPcU78= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0/go.mod h1:JgXSGah17croqhJfhByOLVY719k1emAXC8MVhCIJlRs= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 h1:TVQp/bboR4mhZSav+MdgXB8FaRho1RC8UwVn3T0vjVc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0/go.mod h1:I33vtIe0sR96wfrUcilIzLoA3mLHhRmz9S9Te0S3gDo= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= -go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= -go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= -go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= -go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= -go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= -go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= -go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= -go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= -go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= -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.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= -go.starlark.net v0.0.0-20210406145628-7a1108eaa012/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= -go.starlark.net v0.0.0-20210901212718-87f333178d59 h1:F8ArBy9n1l7HE1JjzOIYqweEqoUlywy5+L3bR0tIa9g= -go.starlark.net v0.0.0-20210901212718-87f333178d59/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= -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/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= -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/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -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.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -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-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= -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-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -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/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-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -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-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= -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-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-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= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -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-20190827160401-ba9fcec4b297/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= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/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-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -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-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/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-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= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= -golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -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-20190215142949-d0b11bdaac8a/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-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-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/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-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-20200122134326-e047566fdf82/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-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= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -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-20200519105757-fe76b779f299/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-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/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-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-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/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-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/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-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/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.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -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.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -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-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/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-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= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -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-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= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -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-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-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= -gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= -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= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -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.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o= -google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -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= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -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-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-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= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -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-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= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -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-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-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/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-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q= -google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -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.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= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -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-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -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 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -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/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -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= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -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 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 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= -gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= -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= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -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.24.0-beta.0/go.mod h1:D7w5dDA57yCeRJnl0vPuRj6KBAwWYxea4Dwo5kgJGIY= -k8s.io/api v0.26.9 h1:s8Y+G1u2JM55b90+Yo2RVb3PGT/hkWNVPN4idPERxJg= -k8s.io/api v0.26.9/go.mod h1:W/W4fEWRVzPD36820LlVUQfNBiSbiq0VPWRFJKwzmUg= -k8s.io/apiextensions-apiserver v0.26.9 h1:aJqWRuBj9i9J6tIDniqUDYM5QCRajTKXK/GO+zEccGQ= -k8s.io/apiextensions-apiserver v0.26.9/go.mod h1:L1uysxOP2kC1vkZTlHGUlUl5WSpa7e4GHJmGEZY7yLg= -k8s.io/apimachinery v0.24.0-beta.0/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= -k8s.io/apimachinery v0.26.9 h1:5yAV9cFR7Z4gIorKcAjWnx4uxtxiFsERwq4Pvmx0CCg= -k8s.io/apimachinery v0.26.9/go.mod h1:qYzLkrQ9lhrZRh0jNKo2cfvf/R1/kQONnSiyB7NUJU0= -k8s.io/apiserver v0.24.0-beta.0/go.mod h1:pPF5/dEQukQjwauSxjW8IHKn8W1r8u2nERGojwFFlj4= -k8s.io/apiserver v0.26.9 h1:G8D5XIXbhLzqdRY3FajzkKE2lt8hnAW5Vjq67mzEeR8= -k8s.io/apiserver v0.26.9/go.mod h1:HY2TzNkDgq71jsNLyk61ZoDrpiyvujdY6kHyT9DwvtU= -k8s.io/cli-runtime v0.26.9 h1:Iv095J30ieAvYvQabW/ds3BPwC8n7RvFN+mLRWNcTB8= -k8s.io/cli-runtime v0.26.9/go.mod h1:fnnTrhjj3dZz4ULolimyUrBiChVSBKgoyPnJT1WV1GE= -k8s.io/client-go v0.24.0-beta.0/go.mod h1:D4rgRqnNPdFCFMMrcCqCOAouzIwJkPuKXr3zWThEExM= -k8s.io/client-go v0.26.9 h1:TGWi/6guEjIgT0Hg871Gsmx0qFuoGyGFjlFedrk7It0= -k8s.io/client-go v0.26.9/go.mod h1:tU1FZS0bwAmAFyPYpZycUQrQnUMzQ5MHloop7EbX6ow= -k8s.io/code-generator v0.24.0-beta.0/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w= -k8s.io/component-base v0.24.0-beta.0/go.mod h1:UrgHIn7am00FE1rRmr0GHCiNZg7oZO+Oh6iXROJt2oU= -k8s.io/component-base v0.26.9 h1:qQVdQgyEIUe8EUkB3EEuQ9l5sgVlG2KgOB519yWEBGw= -k8s.io/component-base v0.26.9/go.mod h1:3WmW9lH9tbjpuvpAc22cPF/6C3VxCjMxkOU1j2mpzr8= -k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/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.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= -k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kms v0.26.9 h1:3pGaRcG2jaBHzOMcq5zTYp5lWjZrAv7U3k+XiG8jncg= -k8s.io/kms v0.26.9/go.mod h1:AYuV9ZebRhr6cb1eT9L6kZVxvgIUxmE1Fe6kPhqYvuc= -k8s.io/kube-aggregator v0.24.0-beta.0 h1:pRl/qwCw2XBuWrMzkTiWOFfONZtClgHWdbKmIZdDY8o= -k8s.io/kube-aggregator v0.24.0-beta.0/go.mod h1:i9SRRGwxhXwuNuArHlkfy/EuWSrrbUEsIah/7OROTZU= -k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= -k8s.io/kube-openapi v0.0.0-20230109183929-3758b55a6596 h1:8cNCQs+WqqnSpZ7y0LMQPKD+RZUHU17VqLPMW3qxnxc= -k8s.io/kube-openapi v0.0.0-20230109183929-3758b55a6596/go.mod h1:/BYxry62FuDzmI+i9B+X2pqfySRmSOW2ARmj5Zbqhj0= -k8s.io/kubectl v0.26.9 h1:0Z8wEFQoXqWbWfT7G9si5EKVjYf5KG4hocSB7B8Jkbc= -k8s.io/kubectl v0.26.9/go.mod h1:Rl9W561iyUZtzwgstHcKChzUo2xMaGqb7Za6jUDMKP4= -k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20230115233650-391b47cb4029 h1:L8zDtT4jrxj+TaQYD0k8KNlr556WaVQylDXswKmX+dE= -k8s.io/utils v0.0.0-20230115233650-391b47cb4029/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.30/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.37 h1:fAPTNEpzQMOLMGwOHNbUkR2xXTQwMJOZYNx+/mLlOh0= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.37/go.mod h1:vfnxT4FXNT8eGvO+xi/DsyC/qHmdujqwrUa1WSspCsk= -sigs.k8s.io/cli-utils v0.35.0 h1:dfSJaF1W0frW74PtjwiyoB4cwdRygbHnC7qe7HF0g/Y= -sigs.k8s.io/cli-utils v0.35.0/go.mod h1:ITitykCJxP1vaj1Cew/FZEaVJ2YsTN9Q71m02jebkoE= -sigs.k8s.io/controller-runtime v0.14.1 h1:vThDes9pzg0Y+UbCPY3Wj34CGIYPgdmspPm2GIpxpzM= -sigs.k8s.io/controller-runtime v0.14.1/go.mod h1:GaRkrY8a7UZF0kqFFbUKG7n9ICiTY5T55P1RiE3UZlU= -sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= -sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= -sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM= -sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s= -sigs.k8s.io/kustomize/kyaml v0.10.21/go.mod h1:TYWhGwW9vjoRh3rWqBwB/ZOXyEGRVWe7Ggc3+KZIO+c= -sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk= -sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= -sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= -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.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/porch/internal/api/porchinternal/v1alpha1/config.porch.kpt.dev_packagerevs.yaml b/porch/internal/api/porchinternal/v1alpha1/config.porch.kpt.dev_packagerevs.yaml deleted file mode 100644 index 80f0045498..0000000000 --- a/porch/internal/api/porchinternal/v1alpha1/config.porch.kpt.dev_packagerevs.yaml +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2024 The kpt 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. - ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.14.0 - name: packagerevs.config.porch.kpt.dev -spec: - group: config.porch.kpt.dev - names: - kind: PackageRev - listKind: PackageRevList - plural: packagerevs - singular: packagerev - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: PackageRev - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: PackageRevSpec defines the desired state of PackageRev - type: object - status: - description: PackageRevStatus defines the observed state of PackageRev - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/porch/internal/api/porchinternal/v1alpha1/groupversion_info.go b/porch/internal/api/porchinternal/v1alpha1/groupversion_info.go deleted file mode 100644 index 323d277d38..0000000000 --- a/porch/internal/api/porchinternal/v1alpha1/groupversion_info.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2022 The kpt 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. - -// Package v1alpha1 contains API Schema definitions for the v1alpha1 API group -// +kubebuilder:object:generate=true -// +groupName=config.porch.kpt.dev -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 object:headerFile="../../../../scripts/boilerplate.go.txt" crd:crdVersions=v1 output:crd:artifacts:config=. paths=./... - -var ( - // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "config.porch.kpt.dev", Version: "v1alpha1"} - - // We removed SchemeBuilder to keep our dependencies small - - KindRepository = KindInfo{ - Resource: GroupVersion.WithResource("packagerev"), - objects: []runtime.Object{&PackageRev{}, &PackageRevList{}}, - } - - AllKinds = []KindInfo{KindRepository} -) - -//+kubebuilder:object:generate=false - -// KindInfo holds type meta-information -type KindInfo struct { - Resource schema.GroupVersionResource - objects []runtime.Object -} - -// GroupResource returns the GroupResource for the kind -func (k *KindInfo) GroupResource() schema.GroupResource { - return k.Resource.GroupResource() -} - -func AddToScheme(scheme *runtime.Scheme) error { - for _, kind := range AllKinds { - scheme.AddKnownTypes(GroupVersion, kind.objects...) - } - metav1.AddToGroupVersion(scheme, GroupVersion) - return nil -} diff --git a/porch/internal/api/porchinternal/v1alpha1/types.go b/porch/internal/api/porchinternal/v1alpha1/types.go deleted file mode 100644 index 7e823493da..0000000000 --- a/porch/internal/api/porchinternal/v1alpha1/types.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2022 The kpt 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. - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:resource:path=packagerevs,singular=packagerev - -// PackageRev -type PackageRev struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec PackageRevSpec `json:"spec,omitempty"` - Status PackageRevStatus `json:"status,omitempty"` -} - -// PackageRevSpec defines the desired state of PackageRev -type PackageRevSpec struct { -} - -// PackageRevStatus defines the observed state of PackageRev -type PackageRevStatus struct { -} - -//+kubebuilder:object:root=true - -// PackageRevList contains a list of PackageRev -type PackageRevList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []PackageRev `json:"items"` -} diff --git a/porch/internal/api/porchinternal/v1alpha1/zz_generated.deepcopy.go b/porch/internal/api/porchinternal/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index bff9376714..0000000000 --- a/porch/internal/api/porchinternal/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,112 +0,0 @@ -//go:build !ignore_autogenerated - -// Copyright 2023 The kpt 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 controller-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRev) DeepCopyInto(out *PackageRev) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - out.Status = in.Status -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRev. -func (in *PackageRev) DeepCopy() *PackageRev { - if in == nil { - return nil - } - out := new(PackageRev) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackageRev) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevList) DeepCopyInto(out *PackageRevList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]PackageRev, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevList. -func (in *PackageRevList) DeepCopy() *PackageRevList { - if in == nil { - return nil - } - out := new(PackageRevList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PackageRevList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevSpec) DeepCopyInto(out *PackageRevSpec) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevSpec. -func (in *PackageRevSpec) DeepCopy() *PackageRevSpec { - if in == nil { - return nil - } - out := new(PackageRevSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PackageRevStatus) DeepCopyInto(out *PackageRevStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageRevStatus. -func (in *PackageRevStatus) DeepCopy() *PackageRevStatus { - if in == nil { - return nil - } - out := new(PackageRevStatus) - in.DeepCopyInto(out) - return out -} diff --git a/porch/internal/tools/tools.go b/porch/internal/tools/tools.go deleted file mode 100644 index 4e35cd8a1a..0000000000 --- a/porch/internal/tools/tools.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2022 The kpt 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. - -//go:build tools -// +build tools - -package tools - -import ( - _ "golang.org/x/tools/cmd/stringer" -) diff --git a/porch/pkg/apiserver/apiserver.go b/porch/pkg/apiserver/apiserver.go deleted file mode 100644 index 72c44d0109..0000000000 --- a/porch/pkg/apiserver/apiserver.go +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright 2022 The kpt 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. - -package apiserver - -import ( - "context" - "fmt" - "os" - "time" - - "github.com/GoogleContainerTools/kpt/internal/fnruntime" - "github.com/GoogleContainerTools/kpt/porch/api/porch/install" - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - internalapi "github.com/GoogleContainerTools/kpt/porch/internal/api/porchinternal/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/cache" - "github.com/GoogleContainerTools/kpt/porch/pkg/engine" - "github.com/GoogleContainerTools/kpt/porch/pkg/meta" - "github.com/GoogleContainerTools/kpt/porch/pkg/registry/porch" - "google.golang.org/api/option" - "google.golang.org/api/sts/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/runtime/serializer" - "k8s.io/apimachinery/pkg/version" - genericapiserver "k8s.io/apiserver/pkg/server" - corev1client "k8s.io/client-go/kubernetes/typed/core/v1" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" - "k8s.io/klog/v2" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -var ( - // Scheme defines methods for serializing and deserializing API objects. - Scheme = runtime.NewScheme() - // Codecs provides methods for retrieving codecs and serializers for specific - // versions and content types. - Codecs = serializer.NewCodecFactory(Scheme) -) - -func init() { - install.Install(Scheme) - - // we need to add the options to empty v1 - // TODO fix the server code to avoid this - metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) - - // TODO: keep the generic API server from wanting this - unversioned := schema.GroupVersion{Group: "", Version: "v1"} - Scheme.AddUnversionedTypes(unversioned, - &metav1.Status{}, - &metav1.APIVersions{}, - &metav1.APIGroupList{}, - &metav1.APIGroup{}, - &metav1.APIResourceList{}, - ) -} - -// ExtraConfig holds custom apiserver config -type ExtraConfig struct { - CoreAPIKubeconfigPath string - CacheDirectory string - FunctionRunnerAddress string - DefaultImagePrefix string - RepoSyncFrequency time.Duration -} - -// Config defines the config for the apiserver -type Config struct { - GenericConfig *genericapiserver.RecommendedConfig - ExtraConfig ExtraConfig -} - -// PorchServer contains state for a Kubernetes cluster master/api server. -type PorchServer struct { - GenericAPIServer *genericapiserver.GenericAPIServer - coreClient client.WithWatch - cache *cache.Cache -} - -type completedConfig struct { - GenericConfig genericapiserver.CompletedConfig - ExtraConfig *ExtraConfig -} - -// CompletedConfig embeds a private pointer that cannot be instantiated outside of this package. -type CompletedConfig struct { - *completedConfig -} - -// Complete fills in any fields not set that are required to have valid data. It's mutating the receiver. -func (cfg *Config) Complete() CompletedConfig { - c := completedConfig{ - cfg.GenericConfig.Complete(), - &cfg.ExtraConfig, - } - - c.GenericConfig.Version = &version.Info{ - Major: "1", - Minor: "0", - } - - return CompletedConfig{&c} -} - -func (c completedConfig) getRestConfig() (*rest.Config, error) { - kubeconfig := c.ExtraConfig.CoreAPIKubeconfigPath - if kubeconfig == "" { - icc, err := rest.InClusterConfig() - if err != nil { - return nil, fmt.Errorf("failed to load in-cluster config (specify --kubeconfig if not running in-cluster): %w", err) - } - return icc, nil - } else { - loadingRules := &clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeconfig} - loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{}) - - cc, err := loader.ClientConfig() - if err != nil { - return nil, fmt.Errorf("failed to load config %q: %w", kubeconfig, err) - } - return cc, nil - } -} - -func (c completedConfig) getCoreClient() (client.WithWatch, error) { - restConfig, err := c.getRestConfig() - if err != nil { - return nil, err - } - - // set high qps/burst limits since this will effectively limit API server responsiveness - restConfig.QPS = 200 - restConfig.Burst = 400 - - scheme := runtime.NewScheme() - if err := configapi.AddToScheme(scheme); err != nil { - return nil, fmt.Errorf("error building scheme: %w", err) - } - - if err := porchapi.AddToScheme(scheme); err != nil { - return nil, fmt.Errorf("error building scheme: %w", err) - } - - if err := corev1.AddToScheme(scheme); err != nil { - return nil, fmt.Errorf("error building scheme: %w", err) - } - if err := internalapi.AddToScheme(scheme); err != nil { - return nil, fmt.Errorf("error building scheme: %w", err) - } - - coreClient, err := client.NewWithWatch(restConfig, client.Options{ - Scheme: scheme, - }) - if err != nil { - return nil, fmt.Errorf("error building client for core apiserver: %w", err) - } - - return coreClient, nil -} - -func (c completedConfig) getCoreV1Client() (*corev1client.CoreV1Client, error) { - restConfig, err := c.getRestConfig() - if err != nil { - return nil, err - } - - corev1Client, err := corev1client.NewForConfig(restConfig) - if err != nil { - return nil, fmt.Errorf("error building corev1 client: %w", err) - } - return corev1Client, nil -} - -// New returns a new instance of PorchServer from the given config. -func (c completedConfig) New() (*PorchServer, error) { - genericServer, err := c.GenericConfig.New("porch-apiserver", genericapiserver.NewEmptyDelegate()) - if err != nil { - return nil, err - } - - coreClient, err := c.getCoreClient() - if err != nil { - return nil, fmt.Errorf("failed to build client for core apiserver: %w", err) - } - - coreV1Client, err := c.getCoreV1Client() - if err != nil { - return nil, err - } - - stsClient, err := sts.NewService(context.Background(), option.WithoutAuthentication()) - if err != nil { - return nil, fmt.Errorf("failed to build sts client: %w", err) - } - - resolverChain := []porch.Resolver{ - porch.NewBasicAuthResolver(), - porch.NewGcloudWIResolver(coreV1Client, stsClient), - } - - metadataStore := meta.NewCrdMetadataStore(coreClient) - - credentialResolver := porch.NewCredentialResolver(coreClient, resolverChain) - referenceResolver := porch.NewReferenceResolver(coreClient) - userInfoProvider := &porch.ApiserverUserInfoProvider{} - - watcherMgr := engine.NewWatcherManager() - - cache := cache.NewCache(c.ExtraConfig.CacheDirectory, c.ExtraConfig.RepoSyncFrequency, cache.CacheOptions{ - CredentialResolver: credentialResolver, - UserInfoProvider: userInfoProvider, - MetadataStore: metadataStore, - ObjectNotifier: watcherMgr, - }) - - runnerOptionsResolver := func(namespace string) fnruntime.RunnerOptions { - runnerOptions := fnruntime.RunnerOptions{} - runnerOptions.InitDefaults() - r := &KubeFunctionResolver{ - client: coreClient, - defaultImagePrefix: c.ExtraConfig.DefaultImagePrefix, - namespace: namespace, - } - runnerOptions.ResolveToImage = r.resolveToImagePorch - - return runnerOptions - } - - cad, err := engine.NewCaDEngine( - engine.WithCache(cache), - // The order of registering the function runtimes matters here. When - // evaluating a function, the runtimes will be tried in the same - // order as they are registered. - engine.WithBuiltinFunctionRuntime(), - engine.WithGRPCFunctionRuntime(c.ExtraConfig.FunctionRunnerAddress), - engine.WithCredentialResolver(credentialResolver), - engine.WithRunnerOptionsResolver(runnerOptionsResolver), - engine.WithReferenceResolver(referenceResolver), - engine.WithUserInfoProvider(userInfoProvider), - engine.WithMetadataStore(metadataStore), - engine.WithWatcherManager(watcherMgr), - ) - if err != nil { - return nil, err - } - - porchGroup, err := porch.NewRESTStorage(Scheme, Codecs, cad, coreClient) - if err != nil { - return nil, err - } - - s := &PorchServer{ - GenericAPIServer: genericServer, - coreClient: coreClient, - cache: cache, - } - - // Install the groups. - if err := s.GenericAPIServer.InstallAPIGroups(&porchGroup); err != nil { - return nil, err - } - - return s, nil -} - -func (s *PorchServer) Run(ctx context.Context) error { - porch.RunBackground(ctx, s.coreClient, s.cache) - certStorageDir, found := os.LookupEnv("CERT_STORAGE_DIR") - if found && certStorageDir != "" { - if err := setupWebhooks(ctx, certStorageDir); err != nil { - klog.Errorf("%v\n", err) - return err - } - } else { - klog.Infoln("Cert storage dir not provided, skipping webhook setup") - } - return s.GenericAPIServer.PrepareRun().Run(ctx.Done()) -} diff --git a/porch/pkg/apiserver/resolvetoimage.go b/porch/pkg/apiserver/resolvetoimage.go deleted file mode 100644 index 7a14852322..0000000000 --- a/porch/pkg/apiserver/resolvetoimage.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2022 The kpt 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. - -package apiserver - -import ( - "context" - "fmt" - "strings" - - "github.com/GoogleContainerTools/kpt/internal/util/porch" - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -// KubeFunctionResolver resolves function names to full image paths -type KubeFunctionResolver struct { - client client.WithWatch - defaultImagePrefix string - // resolver *FunctionResolver - namespace string -} - -// resolveToImagePorch converts the function short path to the full image url. -// If the function is Catalog function, it adds "gcr.io/kpt-fn/".e.g. set-namespace:v0.1 --> gcr.io/kpt-fn/set-namespace:v0.1 -// If the function is porch function, it queries porch to get the function image by name and namespace. -// e.g. default:set-namespace:v0.1 --> us-west1-docker.pkg.dev/cpa-kit-dev/packages/set-namespace:v0.1 -func (r *KubeFunctionResolver) resolveToImagePorch(ctx context.Context, image string) (string, error) { - segments := strings.Split(image, ":") - if len(segments) == 4 { - // Porch function - // TODO: Remove this legacy configuration - functionName := strings.Join(segments[1:], ":") - function, err := porch.FunctionGetter{}.Get(ctx, functionName, segments[0]) - if err != nil { - return "", fmt.Errorf("failed to get image for function %q: %w", image, err) - } - return function.Spec.Image, nil - } - if !strings.Contains(image, "/") { - var function v1alpha1.Function - // TODO: Use fieldSelectors and better lookup - name := "functions:" + image + ":latest" - key := types.NamespacedName{ - Namespace: r.namespace, - Name: name, - } - // We query the apiserver for these types, even if we could query directly; this will then work with CRDs etc. - // TODO: We need to think about priority-and-fairness with loopback queries - if err := r.client.Get(ctx, key, &function); err != nil { - if !apierrors.IsNotFound(err) { - return "", fmt.Errorf("failed to get image for function %q: %w", image, err) - } - } else { - return function.Spec.Image, nil - } - // TODO: Fallback to cluster-scoped? - return r.defaultImagePrefix + image, nil - } - return image, nil -} diff --git a/porch/pkg/apiserver/scheme_test.go b/porch/pkg/apiserver/scheme_test.go deleted file mode 100644 index 6dfaca763e..0000000000 --- a/porch/pkg/apiserver/scheme_test.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2022 The kpt 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. - -package apiserver - -import ( - "testing" - - "github.com/GoogleContainerTools/kpt/porch/api/porch/fuzzer" - "k8s.io/apimachinery/pkg/api/apitesting/roundtrip" -) - -func TestRoundTripTypes(t *testing.T) { - roundtrip.RoundTripTestForScheme(t, Scheme, fuzzer.Funcs) -} diff --git a/porch/pkg/apiserver/webhooks.go b/porch/pkg/apiserver/webhooks.go deleted file mode 100644 index 00909e7685..0000000000 --- a/porch/pkg/apiserver/webhooks.go +++ /dev/null @@ -1,371 +0,0 @@ -// Copyright 2022 The kpt 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. - -package apiserver - -import ( - "bytes" - "context" - cryptorand "crypto/rand" - "crypto/rsa" - "crypto/tls" - "crypto/x509" - "crypto/x509/pkix" - "encoding/json" - "encoding/pem" - "fmt" - "io/ioutil" - "math/big" - "net/http" - "os" - "path/filepath" - "time" - - "github.com/GoogleContainerTools/kpt/internal/util/porch" - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - admissionv1 "k8s.io/api/admission/v1" - admissionregistrationv1 "k8s.io/api/admissionregistration/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/serializer" - "k8s.io/client-go/kubernetes" - "k8s.io/klog/v2" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/config" -) - -const ( - webhookServicePort = 8443 - serverEndpoint = "/validate-deletion" -) - -func setupWebhooks(ctx context.Context, certStorageDir string) error { - caBytes, err := createCerts(certStorageDir) - if err != nil { - return err - } - if err := createValidatingWebhook(ctx, caBytes); err != nil { - return err - } - if err := runWebhookServer(certStorageDir); err != nil { - return err - } - return nil -} - -func createCerts(certStorageDir string) ([]byte, error) { - klog.Infoln("creating self-signing TLS cert and key ") - dnsNames := []string{"api", - "api.porch-system", "api.porch-system.svc"} - commonName := "api.porch-system.svc" - - var caPEM, serverCertPEM, serverPrivateKeyPEM *bytes.Buffer - // CA config - ca := &x509.Certificate{ - SerialNumber: big.NewInt(2020), - Subject: pkix.Name{ - Organization: []string{"google.com"}, - }, - NotBefore: time.Now(), - NotAfter: time.Now().AddDate(1, 0, 0), - IsCA: true, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, - KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, - BasicConstraintsValid: true, - } - - privateKey, err := rsa.GenerateKey(cryptorand.Reader, 4096) - if err != nil { - return nil, err - } - caBytes, err := x509.CreateCertificate(cryptorand.Reader, ca, ca, &privateKey.PublicKey, privateKey) - if err != nil { - return nil, err - } - caPEM = new(bytes.Buffer) - _ = pem.Encode(caPEM, &pem.Block{ - Type: "CERTIFICATE", - Bytes: caBytes, - }) - - // server cert config - cert := &x509.Certificate{ - DNSNames: dnsNames, - SerialNumber: big.NewInt(1658), - Subject: pkix.Name{ - CommonName: commonName, - Organization: []string{"google.com"}, - }, - NotBefore: time.Now(), - NotAfter: time.Now().AddDate(1, 0, 0), - SubjectKeyId: []byte{1, 2, 3, 4, 6}, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, - KeyUsage: x509.KeyUsageDigitalSignature, - } - - serverPrivateKey, err := rsa.GenerateKey(cryptorand.Reader, 4096) - if err != nil { - return nil, err - } - serverCertBytes, err := x509.CreateCertificate(cryptorand.Reader, cert, ca, &serverPrivateKey.PublicKey, privateKey) - if err != nil { - return nil, err - } - serverCertPEM = new(bytes.Buffer) - _ = pem.Encode(serverCertPEM, &pem.Block{ - Type: "CERTIFICATE", - Bytes: serverCertBytes, - }) - serverPrivateKeyPEM = new(bytes.Buffer) - _ = pem.Encode(serverPrivateKeyPEM, &pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(serverPrivateKey), - }) - - err = os.MkdirAll(certStorageDir, 0666) - if err != nil { - return nil, err - } - err = WriteFile(filepath.Join(certStorageDir, "tls.crt"), serverCertPEM.Bytes()) - if err != nil { - return nil, err - } - err = WriteFile(filepath.Join(certStorageDir, "tls.key"), serverPrivateKeyPEM.Bytes()) - if err != nil { - return nil, err - } - - return caPEM.Bytes(), nil -} - -// WriteFile writes data in the file at the given path -func WriteFile(filepath string, c []byte) error { - f, err := os.Create(filepath) - if err != nil { - return err - } - defer f.Close() - - _, err = f.Write(c) - if err != nil { - return err - } - return nil -} - -func createValidatingWebhook(ctx context.Context, caCert []byte) error { - klog.Infoln("Creating validating webhook") - - cfg := ctrl.GetConfigOrDie() - kubeClient, err := kubernetes.NewForConfig(cfg) - if err != nil { - return fmt.Errorf("failed to setup kubeClient: %v", err) - } - - var ( - webhookNamespace = "porch-system" - validationCfgName = "packagerev-deletion-validating-webhook" - webhookService = "api" - path = serverEndpoint - fail = admissionregistrationv1.Fail - none = admissionregistrationv1.SideEffectClassNone - port = int32(webhookServicePort) - ) - - validateConfig := &admissionregistrationv1.ValidatingWebhookConfiguration{ - ObjectMeta: metav1.ObjectMeta{ - Name: validationCfgName, - }, - Webhooks: []admissionregistrationv1.ValidatingWebhook{{ - Name: "packagerevdeletion.google.com", - ClientConfig: admissionregistrationv1.WebhookClientConfig{ - CABundle: caCert, // CA bundle created earlier - Service: &admissionregistrationv1.ServiceReference{ - Name: webhookService, - Namespace: webhookNamespace, - Path: &path, - Port: &port, - }, - }, - Rules: []admissionregistrationv1.RuleWithOperations{{Operations: []admissionregistrationv1.OperationType{ - admissionregistrationv1.Delete}, - Rule: admissionregistrationv1.Rule{ - APIGroups: []string{"porch.kpt.dev"}, - APIVersions: []string{"v1alpha1"}, - Resources: []string{"packagerevisions"}, - }, - }}, - AdmissionReviewVersions: []string{"v1", "v1beta1"}, - SideEffects: &none, - FailurePolicy: &fail, - }}, - } - - if err := kubeClient.AdmissionregistrationV1().ValidatingWebhookConfigurations().Delete(ctx, validationCfgName, metav1.DeleteOptions{}); err != nil { - klog.Error("failed to delete existing webhook: %w", err) - } - - if _, err := kubeClient.AdmissionregistrationV1().ValidatingWebhookConfigurations().Create(ctx, validateConfig, - metav1.CreateOptions{}); err != nil { - klog.Infoln("failed to create validating webhook for package revision deletion: %s\n", err.Error()) - return err - } - - return nil -} - -func runWebhookServer(certStorageDir string) error { - certFile := filepath.Join(certStorageDir, "tls.crt") - keyFile := filepath.Join(certStorageDir, "tls.key") - - cert, err := tls.LoadX509KeyPair(certFile, keyFile) - if err != nil { - return err - } - klog.Infoln("Starting webhook server") - http.HandleFunc(serverEndpoint, validateDeletion) - server := http.Server{ - Addr: fmt.Sprintf(":%d", webhookServicePort), - TLSConfig: &tls.Config{ - Certificates: []tls.Certificate{cert}, - }, - } - go func() { - err = server.ListenAndServeTLS("", "") - if err != nil { - klog.Errorf("could not start server: %w", err) - } - }() - return err -} - -func validateDeletion(w http.ResponseWriter, r *http.Request) { - klog.Infoln("received request to validate deletion") - - admissionReviewRequest, err := decodeAdmissionReview(r) - if err != nil { - errMsg := fmt.Sprintf("error getting admission review from request: %v", err) - writeErr(errMsg, &w) - return - } - - // Verify that we have a PackageRevision resource - pkgRevGVK := metav1.GroupVersionResource{Group: "porch.kpt.dev", Version: "v1alpha1", Resource: "packagerevisions"} - if admissionReviewRequest.Request.Resource != pkgRevGVK { - errMsg := fmt.Sprintf("did not receive PackageRevision, got %s", admissionReviewRequest.Request.Resource.Resource) - writeErr(errMsg, &w) - return - } - - // Get the package revision using the name and namespace from the request. - porchClient, err := createPorchClient() - if err != nil { - errMsg := fmt.Sprintf("could not create porch client: %v", err) - writeErr(errMsg, &w) - return - } - pr := v1alpha1.PackageRevision{} - if err := porchClient.Get(context.Background(), client.ObjectKey{ - Namespace: admissionReviewRequest.Request.Namespace, - Name: admissionReviewRequest.Request.Name, - }, &pr); err != nil { - klog.Errorf("could not get package revision: %s", err.Error()) - } - - admissionResponse := &admissionv1.AdmissionResponse{} - if pr.Spec.Lifecycle == v1alpha1.PackageRevisionLifecyclePublished { - admissionResponse.Allowed = false - admissionResponse.Result = &metav1.Status{ - Status: "Failure", - Message: fmt.Sprintf("failed to delete package revision %q: published PackageRevisions must be proposed for deletion by setting spec.lifecycle to 'DeletionProposed' prior to deletion", pr.Name), - Reason: "Published PackageRevisions must be proposed for deletion by setting spec.lifecycle to 'DeletionProposed' prior to deletion.", - } - } else { - admissionResponse.Allowed = true - admissionResponse.Result = &metav1.Status{ - Status: "Success", - Message: fmt.Sprintf("Successfully deleted package revision %q", pr.Name), - } - } - - resp, err := constructResponse(admissionResponse, admissionReviewRequest) - if err != nil { - errMsg := fmt.Sprintf("error constructing response: %v", err) - writeErr(errMsg, &w) - return - } - - w.Header().Set("Content-Type", "application/json") - w.Write(resp) -} - -func decodeAdmissionReview(r *http.Request) (*admissionv1.AdmissionReview, error) { - if r.Header.Get("Content-Type") != "application/json" { - return nil, fmt.Errorf("expected Content-Type 'application/json'") - } - var requestData []byte - if r.Body != nil { - var err error - requestData, err = ioutil.ReadAll(r.Body) - if err != nil { - return nil, err - } - } - admissionReviewRequest := &admissionv1.AdmissionReview{} - deserializer := serializer.NewCodecFactory(runtime.NewScheme()).UniversalDeserializer() - if _, _, err := deserializer.Decode(requestData, nil, admissionReviewRequest); err != nil { - return nil, err - } - if admissionReviewRequest.Request == nil { - return nil, fmt.Errorf("admission review request is empty") - } - return admissionReviewRequest, nil -} - -func constructResponse(response *admissionv1.AdmissionResponse, - request *admissionv1.AdmissionReview) ([]byte, error) { - var admissionReviewResponse admissionv1.AdmissionReview - admissionReviewResponse.Response = response - admissionReviewResponse.SetGroupVersionKind(request.GroupVersionKind()) - admissionReviewResponse.Response.UID = request.Request.UID - - resp, err := json.Marshal(admissionReviewResponse) - if err != nil { - return nil, fmt.Errorf("error marshalling response json: %v", err) - } - return resp, nil -} - -func createPorchClient() (client.Client, error) { - cfg, err := config.GetConfig() - if err != nil { - klog.Errorf("could not get config: %s", err.Error()) - return nil, err - } - porchClient, err := porch.CreateClient(cfg) - if err != nil { - klog.Errorf("could not get porch client: %s", err.Error()) - return nil, err - } - return porchClient, nil -} - -func writeErr(errMsg string, w *http.ResponseWriter) { - klog.Errorf(errMsg) - (*w).WriteHeader(500) - if _, err := (*w).Write([]byte(errMsg)); err != nil { - klog.Errorf("could not write error message: %v", err) - } -} diff --git a/porch/pkg/apiserver/webhooks_test.go b/porch/pkg/apiserver/webhooks_test.go deleted file mode 100644 index a5a9290353..0000000000 --- a/porch/pkg/apiserver/webhooks_test.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2022 The kpt 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. - -package apiserver - -import ( - "bytes" - "encoding/json" - "io" - "net/http" - "net/http/httptest" - "os" - "path/filepath" - "strings" - "testing" - - "github.com/stretchr/testify/require" - admissionv1 "k8s.io/api/admission/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestCreateCerts(t *testing.T) { - dir := t.TempDir() - defer func() { - require.NoError(t, os.RemoveAll(dir)) - }() - - caCert, err := createCerts(dir) - require.NoError(t, err) - - caStr := strings.TrimSpace(string(caCert)) - require.True(t, strings.HasPrefix(caStr, "-----BEGIN CERTIFICATE-----\n")) - require.True(t, strings.HasSuffix(caStr, "\n-----END CERTIFICATE-----")) - - crt, err := os.ReadFile(filepath.Join(dir, "tls.crt")) - require.NoError(t, err) - - key, err := os.ReadFile(filepath.Join(dir, "tls.key")) - require.NoError(t, err) - - crtStr := strings.TrimSpace(string(crt)) - require.True(t, strings.HasPrefix(crtStr, "-----BEGIN CERTIFICATE-----\n")) - require.True(t, strings.HasSuffix(crtStr, "\n-----END CERTIFICATE-----")) - - keyStr := strings.TrimSpace(string(key)) - require.True(t, strings.HasPrefix(keyStr, "-----BEGIN RSA PRIVATE KEY-----\n")) - require.True(t, strings.HasSuffix(keyStr, "\n-----END RSA PRIVATE KEY-----")) -} - -func TestValidateDeletion(t *testing.T) { - t.Run("invalid content-type", func(t *testing.T) { - request, err := http.NewRequest(http.MethodPost, serverEndpoint, nil) - require.NoError(t, err) - request.Header.Set("Content-Type", "foo") - response := httptest.NewRecorder() - - validateDeletion(response, request) - require.Equal(t, - "error getting admission review from request: expected Content-Type 'application/json'", - response.Body.String()) - }) - t.Run("valid content-type, but no body", func(t *testing.T) { - request, err := http.NewRequest(http.MethodPost, serverEndpoint, nil) - require.NoError(t, err) - request.Header.Set("Content-Type", "application/json") - response := httptest.NewRecorder() - - validateDeletion(response, request) - require.Equal(t, - "error getting admission review from request: admission review request is empty", - response.Body.String()) - }) - t.Run("wrong GVK in request", func(t *testing.T) { - request, err := http.NewRequest(http.MethodPost, serverEndpoint, nil) - require.NoError(t, err) - - request.Header.Set("Content-Type", "application/json") - response := httptest.NewRecorder() - - admissionReviewRequest := admissionv1.AdmissionReview{ - TypeMeta: v1.TypeMeta{ - Kind: "AdmissionReview", - APIVersion: "admission.k8s.io/v1", - }, - Request: &admissionv1.AdmissionRequest{ - Resource: v1.GroupVersionResource{ - Group: "porch.kpt.dev", - Version: "v1alpha1", - Resource: "not-a-package-revision", - }, - }, - } - - body, err := json.Marshal(admissionReviewRequest) - require.NoError(t, err) - - request.Body = io.NopCloser(bytes.NewReader(body)) - validateDeletion(response, request) - require.Equal(t, - "did not receive PackageRevision, got not-a-package-revision", - response.Body.String()) - }) -} diff --git a/porch/pkg/cache/cache.go b/porch/pkg/cache/cache.go deleted file mode 100644 index 21d3a46a38..0000000000 --- a/porch/pkg/cache/cache.go +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2022 The kpt 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. - -package cache - -import ( - "context" - "errors" - "fmt" - "path/filepath" - "sync" - "time" - - kptoci "github.com/GoogleContainerTools/kpt/pkg/oci" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/git" - "github.com/GoogleContainerTools/kpt/porch/pkg/meta" - "github.com/GoogleContainerTools/kpt/porch/pkg/oci" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "go.opentelemetry.io/otel/trace" - "k8s.io/apimachinery/pkg/watch" -) - -// Cache allows us to keep state for repositories, rather than querying them every time. -// -// Cache Structure: -// /git/ -// * Caches bare git repositories in directories named based on the repository address. -// /oci/ -// * Caches oci images with further hierarchy underneath -// * We Cache image layers in /oci/layers/ (this might be obsolete with the flattened Cache) -// * We Cache flattened tar files in /oci/ (so we don't need to pull to read resources) -// * We poll the repositories (every minute) and Cache the discovered images in memory. -type Cache struct { - mutex sync.Mutex - repositories map[string]*cachedRepository - cacheDir string - credentialResolver repository.CredentialResolver - userInfoProvider repository.UserInfoProvider - metadataStore meta.MetadataStore - repoSyncFrequency time.Duration - objectNotifier objectNotifier -} - -type objectNotifier interface { - NotifyPackageRevisionChange(eventType watch.EventType, obj repository.PackageRevision, objMeta meta.PackageRevisionMeta) int -} - -type CacheOptions struct { - CredentialResolver repository.CredentialResolver - UserInfoProvider repository.UserInfoProvider - MetadataStore meta.MetadataStore - ObjectNotifier objectNotifier -} - -func NewCache(cacheDir string, repoSyncFrequency time.Duration, opts CacheOptions) *Cache { - return &Cache{ - repositories: make(map[string]*cachedRepository), - cacheDir: cacheDir, - credentialResolver: opts.CredentialResolver, - userInfoProvider: opts.UserInfoProvider, - metadataStore: opts.MetadataStore, - objectNotifier: opts.ObjectNotifier, - repoSyncFrequency: repoSyncFrequency, - } -} - -func (c *Cache) OpenRepository(ctx context.Context, repositorySpec *configapi.Repository) (*cachedRepository, error) { - ctx, span := tracer.Start(ctx, "Cache::OpenRepository", trace.WithAttributes()) - defer span.End() - - switch repositoryType := repositorySpec.Spec.Type; repositoryType { - case configapi.RepositoryTypeOCI: - ociSpec := repositorySpec.Spec.Oci - if ociSpec == nil { - return nil, fmt.Errorf("oci not configured") - } - key := "oci://" + ociSpec.Registry - c.mutex.Lock() - defer c.mutex.Unlock() - - cr := c.repositories[key] - - if cr == nil { - cacheDir := filepath.Join(c.cacheDir, "oci") - storage, err := kptoci.NewStorage(cacheDir) - if err != nil { - return nil, err - } - - r, err := oci.OpenRepository(repositorySpec.Name, repositorySpec.Namespace, repositorySpec.Spec.Content, ociSpec, repositorySpec.Spec.Deployment, storage) - if err != nil { - return nil, err - } - cr = newRepository(key, repositorySpec, r, c.objectNotifier, c.metadataStore, c.repoSyncFrequency) - c.repositories[key] = cr - } - return cr, nil - - case configapi.RepositoryTypeGit: - gitSpec := repositorySpec.Spec.Git - if gitSpec == nil { - return nil, errors.New("git property is required") - } - if gitSpec.Repo == "" { - return nil, errors.New("git.repo property is required") - } - if !isPackageContent(repositorySpec.Spec.Content) { - return nil, fmt.Errorf("git repository supports Package content only; got %q", string(repositorySpec.Spec.Content)) - } - key := "git://" + gitSpec.Repo + gitSpec.Directory - - c.mutex.Lock() - defer c.mutex.Unlock() - - cr := c.repositories[key] - if cr == nil { - var mbs git.MainBranchStrategy - if gitSpec.CreateBranch { - mbs = git.CreateIfMissing - } else { - mbs = git.ErrorIfMissing - } - if r, err := git.OpenRepository(ctx, repositorySpec.Name, repositorySpec.Namespace, gitSpec, repositorySpec.Spec.Deployment, filepath.Join(c.cacheDir, "git"), git.GitRepositoryOptions{ - CredentialResolver: c.credentialResolver, - UserInfoProvider: c.userInfoProvider, - MainBranchStrategy: mbs, - }); err != nil { - return nil, err - } else { - cr = newRepository(key, repositorySpec, r, c.objectNotifier, c.metadataStore, c.repoSyncFrequency) - c.repositories[key] = cr - } - } else { - // If there is an error from the background refresh goroutine, return it. - if err := cr.getRefreshError(); err != nil { - return nil, err - } - } - return cr, nil - - default: - return nil, fmt.Errorf("type %q not supported", repositoryType) - } -} - -func isPackageContent(content configapi.RepositoryContent) bool { - return content == configapi.RepositoryContentPackage -} - -func (c *Cache) CloseRepository(repositorySpec *configapi.Repository) error { - var key string - - switch repositorySpec.Spec.Type { - case configapi.RepositoryTypeOCI: - oci := repositorySpec.Spec.Oci - if oci == nil { - return fmt.Errorf("oci not configured for %s:%s", repositorySpec.ObjectMeta.Namespace, repositorySpec.ObjectMeta.Name) - } - key = "oci://" + oci.Registry - - case configapi.RepositoryTypeGit: - git := repositorySpec.Spec.Git - if git == nil { - return fmt.Errorf("git not configured for %s:%s", repositorySpec.ObjectMeta.Namespace, repositorySpec.ObjectMeta.Name) - } - key = "git://" + git.Repo + git.Directory - - default: - return fmt.Errorf("unknown repository type: %q", repositorySpec.Spec.Type) - } - - // TODO: Multiple Repository resources can point to the same underlying repository - // and therefore the same cache. Implement reference counting - - var repository *cachedRepository - { - c.mutex.Lock() - if r, ok := c.repositories[key]; ok { - delete(c.repositories, key) - repository = r - } - c.mutex.Unlock() - } - - if repository != nil { - return repository.Close() - } else { - return nil - } -} diff --git a/porch/pkg/cache/cache_test.go b/porch/pkg/cache/cache_test.go deleted file mode 100644 index a6e1a53307..0000000000 --- a/porch/pkg/cache/cache_test.go +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2022 The kpt 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. - -package cache - -import ( - "context" - "fmt" - "os" - "path/filepath" - "testing" - "time" - - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - fakecache "github.com/GoogleContainerTools/kpt/porch/pkg/cache/fake" - "github.com/GoogleContainerTools/kpt/porch/pkg/git" - "github.com/GoogleContainerTools/kpt/porch/pkg/meta" - fakemeta "github.com/GoogleContainerTools/kpt/porch/pkg/meta/fake" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - gogit "github.com/go-git/go-git/v5" - "github.com/google/go-cmp/cmp" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/yaml" -) - -func TestLatestPackages(t *testing.T) { - ctx := context.Background() - testPath := filepath.Join("..", "git", "testdata") - - _, cachedGit := openRepositoryFromArchive(t, ctx, testPath, "nested") - - wantLatest := map[string]string{ - "sample": "v2", - "catalog/empty": "v1", - "catalog/gcp/bucket": "v1", - "catalog/namespace/basens": "v3", - "catalog/namespace/istions": "v3", - } - revisions, err := cachedGit.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{}) - if err != nil { - t.Fatalf("ListPackageRevisions failed: %v", err) - } - - gotLatest := map[string]string{} - for _, pr := range revisions { - rev, err := pr.GetPackageRevision(ctx) - if err != nil { - t.Errorf("didn't expect error, but got %v", err) - } - - if latest, ok := rev.Labels[api.LatestPackageRevisionKey]; ok { - if got, want := latest, api.LatestPackageRevisionValue; got != want { - t.Errorf("%s label value: got %q, want %q", api.LatestPackageRevisionKey, got, want) - continue - } - - if existing, ok := gotLatest[rev.Spec.PackageName]; ok { - t.Errorf("Multiple latest package revisions for package %q: %q and %q", - rev.Spec.PackageName, rev.Spec.Revision, existing) - } - - // latest package - gotLatest[rev.Spec.PackageName] = rev.Spec.Revision - } - } - - if !cmp.Equal(wantLatest, gotLatest) { - t.Errorf("Latest package revisions differ (-want,+got): %s", cmp.Diff(wantLatest, gotLatest)) - } -} - -func TestPublishedLatest(t *testing.T) { - ctx := context.Background() - testPath := filepath.Join("..", "git", "testdata") - _, cached := openRepositoryFromArchive(t, ctx, testPath, "nested") - - revisions, err := cached.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{ - Package: "catalog/gcp/bucket", - WorkspaceName: "v2", - }) - if err != nil { - t.Fatalf("ListPackageRevisions failed: %v", err) - } - - // Expect a single result - if got, want := len(revisions), 1; got != want { - t.Fatalf("ListPackageRevisions returned %d packages; want %d", got, want) - } - - bucket := revisions[0] - // Expect draft package - if got, want := bucket.Lifecycle(), api.PackageRevisionLifecycleDraft; got != want { - t.Fatalf("Bucket package lifecycle: got %s, want %s", got, want) - } - - update, err := cached.UpdatePackageRevision(ctx, bucket) - if err != nil { - t.Fatalf("UpdatePackaeg(%s) failed: %v", bucket.Key(), err) - } - if err := update.UpdateLifecycle(ctx, api.PackageRevisionLifecyclePublished); err != nil { - t.Fatalf("UpdateLifecycle failed; %v", err) - } - closed, err := update.Close(ctx) - if err != nil { - t.Fatalf("Close failed: %v", err) - } - resource, err := closed.GetPackageRevision(ctx) - if err != nil { - t.Errorf("didn't expect error, but got %v", err) - } - if got, ok := resource.Labels[api.LatestPackageRevisionKey]; !ok { - t.Errorf("Label %s not found as expected", api.LatestPackageRevisionKey) - } else if want := api.LatestPackageRevisionValue; got != want { - t.Errorf("Latest label: got %s, want %s", got, want) - } -} - -func openRepositoryFromArchive(t *testing.T, ctx context.Context, testPath, name string) (*gogit.Repository, *cachedRepository) { - t.Helper() - - tempdir := t.TempDir() - tarfile := filepath.Join(testPath, fmt.Sprintf("%s-repository.tar", name)) - repo, address := git.ServeGitRepository(t, tarfile, tempdir) - metadataStore := createMetadataStoreFromArchive(t, "", "") - - cache := NewCache(t.TempDir(), 60*time.Second, CacheOptions{ - MetadataStore: metadataStore, - ObjectNotifier: &fakecache.ObjectNotifier{}, - }) - cachedGit, err := cache.OpenRepository(ctx, &v1alpha1.Repository{ - TypeMeta: metav1.TypeMeta{ - Kind: v1alpha1.TypeRepository.Kind, - APIVersion: v1alpha1.TypeRepository.APIVersion(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: "default", - }, - Spec: v1alpha1.RepositorySpec{ - Deployment: false, - Type: v1alpha1.RepositoryTypeGit, - Content: v1alpha1.RepositoryContentPackage, - Git: &v1alpha1.GitRepository{ - Repo: address, - }, - }, - }) - if err != nil { - t.Fatalf("OpenRepository(%q) of %q failed; %v", address, tarfile, err) - } - - return repo, cachedGit -} - -func createMetadataStoreFromArchive(t *testing.T, testPath, name string) meta.MetadataStore { - t.Helper() - - f := filepath.Join("..", "git", "testdata", "nested-metadata.yaml") - c, err := os.ReadFile(f) - if err != nil && !os.IsNotExist(err) { - t.Fatalf("Error reading metadata file found for repository %s", name) - } - if os.IsNotExist(err) { - return &fakemeta.MemoryMetadataStore{ - Metas: []meta.PackageRevisionMeta{}, - } - } - - var metas []meta.PackageRevisionMeta - if err := yaml.Unmarshal(c, &metas); err != nil { - t.Fatalf("Error unmarshalling metadata file for repository %s", name) - } - - return &fakemeta.MemoryMetadataStore{ - Metas: metas, - } -} diff --git a/porch/pkg/cache/draft.go b/porch/pkg/cache/draft.go deleted file mode 100644 index ddf8ca290f..0000000000 --- a/porch/pkg/cache/draft.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2022 The kpt 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. - -package cache - -import ( - "context" - "fmt" - - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" -) - -type cachedDraft struct { - repository.PackageDraft - cache *cachedRepository -} - -var _ repository.PackageDraft = &cachedDraft{} - -func (cd *cachedDraft) Close(ctx context.Context) (repository.PackageRevision, error) { - closed, err := cd.PackageDraft.Close(ctx) - if err != nil { - return nil, err - } - - err = cd.cache.reconcileCache(ctx, "close-draft") - if err != nil { - return nil, err - } - - cpr := cd.cache.getPackageRevision(closed.Key()) - if cpr == nil { - return nil, fmt.Errorf("closed draft not found") - } - - return cpr, nil -} diff --git a/porch/pkg/cache/fake/objectnotifier.go b/porch/pkg/cache/fake/objectnotifier.go deleted file mode 100644 index b766206edd..0000000000 --- a/porch/pkg/cache/fake/objectnotifier.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2022 The kpt 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. - -package fake - -import ( - "github.com/GoogleContainerTools/kpt/porch/pkg/meta" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "k8s.io/apimachinery/pkg/watch" -) - -type ObjectNotifier struct{} - -func (o *ObjectNotifier) NotifyPackageRevisionChange(watch.EventType, repository.PackageRevision, meta.PackageRevisionMeta) int { - return 0 -} diff --git a/porch/pkg/cache/package.go b/porch/pkg/cache/package.go deleted file mode 100644 index bb7d4c15fa..0000000000 --- a/porch/pkg/cache/package.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2022 The kpt 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. - -package cache - -import "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - -// We take advantage of the cache having a global view of all the packages -// in a repository and compute the latest package revision in the cache -// rather than add another level of caching in the repositories themselves. -// This also reuses the revision comparison code and ensures same behavior -// between Git and OCI. - -var _ repository.Package = &cachedPackage{} - -type cachedPackage struct { - repository.Package - latestPackageRevision string -} - -func (c *cachedPackage) GetLatestRevision() string { - if c.latestPackageRevision != "" { - return c.latestPackageRevision - } - return c.Package.GetLatestRevision() -} diff --git a/porch/pkg/cache/packagerevision.go b/porch/pkg/cache/packagerevision.go deleted file mode 100644 index 01d9c10134..0000000000 --- a/porch/pkg/cache/packagerevision.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2022 The kpt 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. - -package cache - -import ( - "context" - - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" -) - -// We take advantage of the cache having a global view of all the packages -// in a repository and compute the latest package revision in the cache -// rather than add another level of caching in the repositories themselves. -// This also reuses the revision comparison code and ensures same behavior -// between Git and OCI. - -var _ repository.PackageRevision = &cachedPackageRevision{} - -type cachedPackageRevision struct { - repository.PackageRevision - isLatestRevision bool -} - -func (c *cachedPackageRevision) GetPackageRevision(ctx context.Context) (*v1alpha1.PackageRevision, error) { - rev, err := c.PackageRevision.GetPackageRevision(ctx) - if err != nil { - return nil, err - } - if c.isLatestRevision { - // copy the labels in case the cached object is being read by another go routine - labels := make(map[string]string, len(rev.Labels)) - for k, v := range rev.Labels { - labels[k] = v - } - labels[v1alpha1.LatestPackageRevisionKey] = v1alpha1.LatestPackageRevisionValue - rev.Labels = labels - } - return rev, nil -} diff --git a/porch/pkg/cache/repository.go b/porch/pkg/cache/repository.go deleted file mode 100644 index f09ea310df..0000000000 --- a/porch/pkg/cache/repository.go +++ /dev/null @@ -1,542 +0,0 @@ -// Copyright 2022 The kpt 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. - -package cache - -import ( - "context" - "fmt" - "sync" - "time" - - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/git" - "github.com/GoogleContainerTools/kpt/porch/pkg/meta" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/trace" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/klog/v2" -) - -var tracer = otel.Tracer("cache") - -// We take advantage of the cache having a global view of all the packages -// in a repository and compute the latest package revision in the cache -// rather than add another level of caching in the repositories themselves. -// This also reuses the revision comparison code and ensures same behavior -// between Git and OCI. - -var _ repository.Repository = &cachedRepository{} -var _ repository.FunctionRepository = &cachedRepository{} - -type cachedRepository struct { - id string - // We need the kubernetes object so we can add the appropritate - // ownerreferences to PackageRevision resources. - repoSpec *configapi.Repository - repo repository.Repository - cancel context.CancelFunc - - lastVersion string - - // We use separate mutexes for cache map changes and for the overall - // reconcile process. We want update, delete, and reconcile - // to all block on the reconcileMutex, which could be held for a long time - // during reconcile. For much of that time (during reconcile) we do NOT - // want to block reads. There are a few protected areas where we touch map - // entries where we need to block reads, so those will also grab the general - // mutex. - // - // Any code that needs to hold both locks MUST get the reconcileMutex first, - // or we could end up with deadlocks - mutex sync.RWMutex - reconcileMutex sync.Mutex - cachedPackageRevisions map[repository.PackageRevisionKey]*cachedPackageRevision - - // not ideal but this is another cache, used by the underlying storage to avoid - // reloading. Would be best to combine these somehow, but not doing that now. - // Eventual CRD-based redesign should make this entire repo cache obsolete - packageRevisionCache repository.PackageRevisionCache - - // TODO: Currently we support repositories with homogenous content (only packages xor functions). Model this more optimally? - cachedFunctions []repository.Function - // Error encountered on repository refresh by the refresh goroutine. - // This is returned back by the cache to the background goroutine when it calls periodicall to resync repositories. - refreshRevisionsError error - - objectNotifier objectNotifier - - metadataStore meta.MetadataStore -} - -func newRepository(id string, repoSpec *configapi.Repository, repo repository.Repository, objectNotifier objectNotifier, metadataStore meta.MetadataStore, repoSyncFrequency time.Duration) *cachedRepository { - ctx, cancel := context.WithCancel(context.Background()) - r := &cachedRepository{ - id: id, - repoSpec: repoSpec, - repo: repo, - cancel: cancel, - objectNotifier: objectNotifier, - metadataStore: metadataStore, - } - - // TODO: Should we fetch the packages here? - - go r.pollForever(ctx, repoSyncFrequency) - - return r -} - -func (r *cachedRepository) nn() string { - return r.repoSpec.Namespace + "/" + r.repoSpec.Name -} - -func (r *cachedRepository) Version(ctx context.Context) (string, error) { - return r.repo.Version(ctx) -} - -func (r *cachedRepository) ListPackageRevisions(ctx context.Context, filter repository.ListPackageRevisionFilter) ([]repository.PackageRevision, error) { - packages, err := r.getPackageRevisions(ctx, filter) - if err != nil { - return nil, err - } - - return packages, nil -} - -func (r *cachedRepository) ListFunctions(ctx context.Context) ([]repository.Function, error) { - functions, err := r.getFunctions(ctx, false) - if err != nil { - return nil, err - } - return functions, nil -} - -func (r *cachedRepository) getPackageRevision(key repository.PackageRevisionKey) *cachedPackageRevision { - r.mutex.RLock() - defer r.mutex.RUnlock() - - cpr, _ := r.cachedPackageRevisions[key] - return cpr -} - -func (r *cachedRepository) getRefreshError() error { - r.mutex.RLock() - defer r.mutex.RUnlock() - - return r.refreshRevisionsError -} - -func (r *cachedRepository) getPackageRevisions(ctx context.Context, filter repository.ListPackageRevisionFilter) ([]repository.PackageRevision, error) { - packageRevisions, err := r.getCachedPackageRevisions(ctx) - if err != nil { - return nil, err - } - - return toPackageRevisionSlice(packageRevisions, filter), nil -} - -// getCachedPackageRevisions returns the cache contents, blocking until -// the cache is loaded -// caller must NOT hold the lock -// returned *map* is a copy and can be operated on without locks -// map entries are NOT copies and should not be modified -func (r *cachedRepository) getCachedPackageRevisions(ctx context.Context) (map[repository.PackageRevisionKey]*cachedPackageRevision, error) { - err := r.blockUntilLoaded(ctx) - if err != nil { - return nil, err - } - - r.mutex.RLock() - defer r.mutex.RUnlock() - - packageRevisions := make(map[repository.PackageRevisionKey]*cachedPackageRevision, len(r.cachedPackageRevisions)) - for k, v := range r.cachedPackageRevisions { - packageRevisions[k] = v - } - - return packageRevisions, r.refreshRevisionsError -} - -// blocks waiting until the cache is loaded -func (r *cachedRepository) blockUntilLoaded(ctx context.Context) error { - for { - select { - case <-ctx.Done(): - return fmt.Errorf("repo %s: stopped waiting for load because context is done: %v", r.nn(), ctx.Err()) - default: - r.mutex.RLock() - if r.cachedPackageRevisions != nil { - r.mutex.RUnlock() - return nil - } - r.mutex.RUnlock() - time.Sleep(1 * time.Second) - } - } -} - -func (r *cachedRepository) getFunctions(ctx context.Context, force bool) ([]repository.Function, error) { - var functions []repository.Function - - if !force { - r.mutex.Lock() - functions = r.cachedFunctions - r.mutex.Unlock() - } - - if functions == nil { - fr, ok := (r.repo).(repository.FunctionRepository) - if !ok { - return []repository.Function{}, nil - } - - if f, err := fr.ListFunctions(ctx); err != nil { - return nil, err - } else { - functions = f - } - - r.mutex.Lock() - r.cachedFunctions = functions - r.mutex.Unlock() - } - - return functions, nil -} - -func (r *cachedRepository) CreatePackageRevision(ctx context.Context, obj *v1alpha1.PackageRevision) (repository.PackageDraft, error) { - created, err := r.repo.CreatePackageRevision(ctx, obj) - if err != nil { - return nil, err - } - - // reconciliation is faster now, so force it immediately - if err := r.reconcileCache(ctx, "create"); err != nil { - klog.Warningf("error reconciling cache after creating %v in %s: %v", created, r.nn(), err) - } - - return &cachedDraft{ - PackageDraft: created, - cache: r, - }, nil -} - -func (r *cachedRepository) UpdatePackageRevision(ctx context.Context, old repository.PackageRevision) (repository.PackageDraft, error) { - // Unwrap - unwrapped := old.(*cachedPackageRevision).PackageRevision - created, err := r.repo.UpdatePackageRevision(ctx, unwrapped) - if err != nil { - return nil, err - } - - // reconciliation is faster now, so force it immediately - if err := r.reconcileCache(ctx, "update"); err != nil { - klog.Warningf("error reconciling cache after updating %v in %s: %v", unwrapped.Key(), r.nn(), err) - } - - return &cachedDraft{ - PackageDraft: created, - cache: r, - }, nil -} - -func (r *cachedRepository) DeletePackageRevision(ctx context.Context, old repository.PackageRevision) error { - // Unwrap - unwrapped := old.(*cachedPackageRevision).PackageRevision - if err := r.repo.DeletePackageRevision(ctx, unwrapped); err != nil { - return err - } - - // reconciliation is faster now, so force it immediately - if err := r.reconcileCache(ctx, "delete"); err != nil { - klog.Warningf("error reconciling cache after deleting %v in %s: %v", unwrapped.Key(), r.nn(), err) - } - - return nil -} - -func (r *cachedRepository) ListPackages(ctx context.Context, filter repository.ListPackageFilter) ([]repository.Package, error) { - return nil, fmt.Errorf("not implemented") -} - -func (r *cachedRepository) CreatePackage(ctx context.Context, obj *v1alpha1.Package) (repository.Package, error) { - return nil, fmt.Errorf("not implemented") -} - -func (r *cachedRepository) DeletePackage(ctx context.Context, old repository.Package) error { - return fmt.Errorf("not implemented") -} - -func (r *cachedRepository) Close() error { - r.cancel() - - r.reconcileMutex.Lock() - defer r.reconcileMutex.Unlock() - - r.mutex.Lock() - defer r.mutex.Unlock() - - // Make sure that watch events are sent for packagerevisions that are - // removed as part of closing the repository. - sent := 0 - for _, pr := range r.cachedPackageRevisions { - nn := types.NamespacedName{ - Name: pr.KubeObjectName(), - Namespace: pr.KubeObjectNamespace(), - } - // There isn't really any correct way to handle finalizers here. We are removing - // the repository, so we have to just delete the PackageRevision regardless of any - // finalizers. - klog.Infof("repo %s: deleting packagerev %s/%s because repository is closed", r.nn(), nn.Namespace, nn.Name) - pkgRevMeta, err := r.metadataStore.Delete(context.TODO(), nn, true) - if err != nil { - // There isn't much use in returning an error here, so we just log it - // and create a PackageRevisionMeta with just name and namespace. This - // makes sure that the Delete event is sent. - if !apierrors.IsNotFound(err) { - klog.Warningf("Error deleting PackageRev CR %s/%s: %s", nn.Namespace, nn.Name, err) - } - pkgRevMeta = meta.PackageRevisionMeta{ - Name: nn.Name, - Namespace: nn.Namespace, - } - } - sent += r.objectNotifier.NotifyPackageRevisionChange(watch.Deleted, pr, pkgRevMeta) - } - klog.Infof("repo %s: sent %d notifications for %d package revisions during close", r.nn(), sent, len(r.cachedPackageRevisions)) - return r.repo.Close() -} - -// pollForever will continue polling until signal channel is closed or ctx is done. -func (r *cachedRepository) pollForever(ctx context.Context, repoSyncFrequency time.Duration) { - r.pollOnce(ctx) - for { - select { - case <-ctx.Done(): - klog.V(2).Infof("repo %s: exiting repository poller, because context is done: %v", r.nn(), ctx.Err()) - return - default: - r.pollOnce(ctx) - time.Sleep(repoSyncFrequency) - } - } -} - -func (r *cachedRepository) pollOnce(ctx context.Context) { - ctx, span := tracer.Start(ctx, "Repository::pollOnce", trace.WithAttributes()) - defer span.End() - - if err := r.reconcileCache(ctx, "poll"); err != nil { - klog.Warningf("error polling repo packages %s: %v", r.nn(), err) - } - if _, err := r.getFunctions(ctx, true); err != nil { - klog.Warningf("error polling repo functions %s: %v", r.nn(), err) - } -} - -// reconcileCache updates the cached map for this repository -// it also triggers notifications for all package changes -// caller must NOT hold any locks -func (r *cachedRepository) reconcileCache(ctx context.Context, reason string) error { - // if this is not a package repo, just set the cache to "loaded" and return - if r.repoSpec.Spec.Content != configapi.RepositoryContentPackage { - r.mutex.Lock() - defer r.mutex.Unlock() - if r.cachedPackageRevisions != nil { - return nil - } - r.cachedPackageRevisions = make(map[repository.PackageRevisionKey]*cachedPackageRevision) - return nil - } - - start := time.Now() - defer func() { - klog.Infof("repo %s: reconcile for %s finished in %f secs", r.nn(), reason, time.Since(start).Seconds()) - }() - - curVer, err := r.Version(ctx) - if err != nil { - return err - } - - if curVer == r.lastVersion { - return nil - } - - // get the reconcile lock first, to block any repo-level mutations - r.reconcileMutex.Lock() - defer r.reconcileMutex.Unlock() - - if gitRepo, isGitRepo := r.repo.(git.GitRepository); isGitRepo { - // TODO: Figure out a way to do this without the cache layer - // needing to know what type of repo we are working with. - if err := gitRepo.UpdateDeletionProposedCache(); err != nil { - return err - } - } - - // Look up all existing PackageRevCRs so we can compare those to the - // actual PackageRevisions found in git/oci, and add/prune PackageRevCRs - // as necessary. - existingPkgRevCRs, err := r.metadataStore.List(ctx, r.repoSpec) - if err != nil { - return err - } - - // Create a map so we can quickly check if a specific PackageRevisionMeta exists. - pkgRevCRsMap := make(map[string]meta.PackageRevisionMeta) - for i := range existingPkgRevCRs { - pr := existingPkgRevCRs[i] - pkgRevCRsMap[pr.Name] = pr - } - - ctxWithCache := repository.ContextWithPackageRevisionCache(ctx, r.packageRevisionCache) - newPackageRevisions, err := r.repo.ListPackageRevisions(ctxWithCache, repository.ListPackageRevisionFilter{}) - if err != nil { - return fmt.Errorf("error listing packages: %w", err) - } - - // Build mapping from kubeObjectName to PackageRevisions for new PackageRevisions. - // and also recreate packageRevisionCache - prc := make(repository.PackageRevisionCache, len(newPackageRevisions)) - newPackageRevisionNames := make(map[string]*cachedPackageRevision, len(newPackageRevisions)) - for _, newPackage := range newPackageRevisions { - cid := newPackage.CachedIdentifier() - prc[cid.Key] = repository.PackageRevisionCacheEntry{Version: cid.Version, PackageRevision: newPackage} - - kname := newPackage.KubeObjectName() - if newPackageRevisionNames[kname] != nil { - klog.Warningf("repo %s: found duplicate packages with name %v", r.nn(), kname) - } - - pkgRev := &cachedPackageRevision{ - PackageRevision: newPackage, - isLatestRevision: false, - } - newPackageRevisionNames[newPackage.KubeObjectName()] = pkgRev - } - - // Build mapping from kubeObjectName to PackageRevisions for existing PackageRevisions - // Grab the RLock while we create this map - r.mutex.RLock() - oldPackageRevisionNames := make(map[string]*cachedPackageRevision, len(r.cachedPackageRevisions)) - for _, oldPackage := range r.cachedPackageRevisions { - oldPackageRevisionNames[oldPackage.KubeObjectName()] = oldPackage - } - r.mutex.RUnlock() - - addMeta := 0 - delMeta := 0 - - // We go through all PackageRev CRs that represents PackageRevisions - // in the current repo and make sure they all have a corresponding - // PackageRevision. The ones that doesn't is removed. - for _, prm := range existingPkgRevCRs { - if _, found := newPackageRevisionNames[prm.Name]; !found { - delMeta += 1 - if _, err := r.metadataStore.Delete(ctx, types.NamespacedName{ - Name: prm.Name, - Namespace: prm.Namespace, - }, true); err != nil { - if !apierrors.IsNotFound(err) { - // This will be retried the next time the sync runs. - klog.Warningf("repo %s: unable to delete PackageRev CR for %s/%s: %w", - r.nn(), prm.Name, prm.Namespace, err) - } - } - } - } - - // We go through all the PackageRevisions and make sure they have - // a corresponding PackageRev CR. - for pkgRevName, pkgRev := range newPackageRevisionNames { - if _, found := pkgRevCRsMap[pkgRevName]; !found { - pkgRevMeta := meta.PackageRevisionMeta{ - Name: pkgRevName, - Namespace: r.repoSpec.Namespace, - } - addMeta += 1 - if created, err := r.metadataStore.Create(ctx, pkgRevMeta, r.repoSpec.Name, pkgRev.UID()); err != nil { - // TODO: We should try to find a way to make these errors available through - // either the repository CR or the PackageRevision CR. This will be - // retried on the next sync. - klog.Warningf("unable to create PackageRev CR for %s/%s: %w", - r.repoSpec.Namespace, pkgRevName, err) - } else { - // add to the cache for notifications later - pkgRevCRsMap[pkgRevName] = created - } - } - } - - // fix up the isLatestRevision in the new maps - newPackageRevisionMap := make(map[repository.PackageRevisionKey]*cachedPackageRevision, len(newPackageRevisions)) - for _, newPackage := range newPackageRevisions { - k := newPackage.Key() - pkgRev := &cachedPackageRevision{ - PackageRevision: newPackage, - isLatestRevision: false, - } - newPackageRevisionMap[k] = pkgRev - } - - identifyLatestRevisions(newPackageRevisionMap) - - // hold the RW lock while swap in the new packages - // we do this now, *before* sending notifications, so that - // anyone responding to the notification will get the new values - r.mutex.Lock() - r.cachedPackageRevisions = newPackageRevisionMap - r.packageRevisionCache = prc - r.lastVersion = curVer - r.mutex.Unlock() - - // Send notification for packages that changed. - addSent := 0 - modSent := 0 - for kname, newPackage := range newPackageRevisionNames { - oldPackage := oldPackageRevisionNames[kname] - metaPackage, found := pkgRevCRsMap[newPackage.KubeObjectName()] - if !found { - // should never happen - klog.Warningf("no PackageRev CR found for PackageRevision %s", newPackage.KubeObjectName()) - } - if oldPackage == nil { - addSent += r.objectNotifier.NotifyPackageRevisionChange(watch.Added, newPackage, metaPackage) - } else { - if oldPackage.ResourceVersion() != newPackage.ResourceVersion() { - modSent += r.objectNotifier.NotifyPackageRevisionChange(watch.Modified, newPackage, metaPackage) - } - } - } - - delSent := 0 - // Send notifications for packages that were deleted in the SoT - for kname, oldPackage := range oldPackageRevisionNames { - if newPackageRevisionNames[kname] == nil { - metaPackage := meta.PackageRevisionMeta{ - Name: oldPackage.KubeObjectName(), - Namespace: oldPackage.KubeObjectNamespace(), - } - delSent += r.objectNotifier.NotifyPackageRevisionChange(watch.Deleted, oldPackage, metaPackage) - } - } - klog.Infof("repo %s: addMeta %d, delMeta %d, addSent %d, modSent %d, delSent %d for %d in-cache and %d in-storage package revisions", r.nn(), addMeta, delMeta, addSent, modSent, delSent, len(oldPackageRevisionNames), len(newPackageRevisionNames)) - return nil -} diff --git a/porch/pkg/cache/util.go b/porch/pkg/cache/util.go deleted file mode 100644 index 5f564a8228..0000000000 --- a/porch/pkg/cache/util.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2022 The kpt 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. - -package cache - -import ( - "sort" - "strings" - - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "golang.org/x/mod/semver" - "k8s.io/klog/v2" -) - -func identifyLatestRevisions(result map[repository.PackageRevisionKey]*cachedPackageRevision) { - // Compute the latest among the different revisions of the same package. - // The map is keyed by the package name; Values are the latest revision found so far. - - // TODO: Should map[string] be map[repository.PackageKey]? - latest := map[string]*cachedPackageRevision{} - for _, current := range result { - current.isLatestRevision = false // Clear all values - - // Check if the current package revision is more recent than the one seen so far. - // Only consider Published packages - if !v1alpha1.LifecycleIsPublished(current.Lifecycle()) { - continue - } - - currentKey := current.Key() - if previous, ok := latest[currentKey.Package]; ok { - previousKey := previous.Key() - switch cmp := semver.Compare(currentKey.Revision, previousKey.Revision); { - case cmp == 0: - // Same revision. - klog.Warningf("Encountered package revisions whose versions compare equal: %q, %q", currentKey, previousKey) - case cmp < 0: - // currentKey.Revision < previousKey.Revision; no change - case cmp > 0: - // currentKey.Revision > previousKey.Revision; update latest - latest[currentKey.Package] = current - } - } else if semver.IsValid(currentKey.Revision) { - // First revision of the specific package; candidate for the latest. - latest[currentKey.Package] = current - } - } - // Mark the winners as latest - for _, v := range latest { - v.isLatestRevision = true - } -} - -func toPackageRevisionSlice(cached map[repository.PackageRevisionKey]*cachedPackageRevision, filter repository.ListPackageRevisionFilter) []repository.PackageRevision { - result := make([]repository.PackageRevision, 0, len(cached)) - for _, p := range cached { - if filter.Matches(p) { - result = append(result, p) - } - } - sort.Slice(result, func(i, j int) bool { - ki, kl := result[i].Key(), result[j].Key() - switch res := strings.Compare(ki.Package, kl.Package); { - case res < 0: - return true - case res > 0: - return false - default: - // Equal. Compare next element - } - switch res := strings.Compare(ki.Revision, kl.Revision); { - case res < 0: - return true - case res > 0: - return false - default: - // Equal. Compare next element - } - switch res := strings.Compare(string(result[i].Lifecycle()), string(result[j].Lifecycle())); { - case res < 0: - return true - case res > 0: - return false - default: - // Equal. Compare next element - } - - return strings.Compare(result[i].KubeObjectName(), result[j].KubeObjectName()) < 0 - }) - return result -} - -func toPackageSlice(cached map[repository.PackageKey]*cachedPackage, filter repository.ListPackageFilter) []repository.Package { - result := make([]repository.Package, 0, len(cached)) - for _, p := range cached { - if filter.Matches(p) { - result = append(result, p) - } - } - sort.Slice(result, func(i, j int) bool { - ki, kj := result[i].Key(), result[j].Key() - // We assume they all have the same repository - return ki.Package < kj.Package - }) - - return result -} diff --git a/porch/pkg/cmd/server/start.go b/porch/pkg/cmd/server/start.go deleted file mode 100644 index 75fae5ab6a..0000000000 --- a/porch/pkg/cmd/server/start.go +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright 2022 The kpt 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. - -package server - -import ( - "context" - "fmt" - "io" - "net" - "os" - "time" - - "github.com/spf13/cobra" - "github.com/spf13/pflag" - - clientset "github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned" - informers "github.com/GoogleContainerTools/kpt/porch/api/generated/informers/externalversions" - sampleopenapi "github.com/GoogleContainerTools/kpt/porch/api/generated/openapi" - porchv1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/apiserver" - "k8s.io/apimachinery/pkg/runtime/schema" - utilerrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/apiserver/pkg/admission" - "k8s.io/apiserver/pkg/endpoints/openapi" - "k8s.io/apiserver/pkg/features" - genericapiserver "k8s.io/apiserver/pkg/server" - genericoptions "k8s.io/apiserver/pkg/server/options" - utilfeature "k8s.io/apiserver/pkg/util/feature" - "k8s.io/klog/v2" - netutils "k8s.io/utils/net" -) - -const defaultEtcdPathPrefix = "/registry/porch.kpt.dev" - -// PorchServerOptions contains state for master/api server -type PorchServerOptions struct { - RecommendedOptions *genericoptions.RecommendedOptions - LocalStandaloneDebugging bool // Enables local standalone running/debugging of the apiserver. - CacheDirectory string - CoreAPIKubeconfigPath string - FunctionRunnerAddress string - DefaultImagePrefix string - RepoSyncFrequency time.Duration - - SharedInformerFactory informers.SharedInformerFactory - StdOut io.Writer - StdErr io.Writer -} - -// NewPorchServerOptions returns a new PorchServerOptions -func NewPorchServerOptions(out, errOut io.Writer) *PorchServerOptions { - // - // GroupVersions served by this server - // - versions := schema.GroupVersions{ - porchv1alpha1.SchemeGroupVersion, - } - - o := &PorchServerOptions{ - RecommendedOptions: genericoptions.NewRecommendedOptions( - defaultEtcdPathPrefix, - apiserver.Codecs.LegacyCodec(versions...), - ), - - StdOut: out, - StdErr: errOut, - } - o.RecommendedOptions.Etcd.StorageConfig.EncodeVersioner = versions - o.RecommendedOptions.Etcd = nil - return o -} - -// NewCommandStartPorchServer provides a CLI handler for 'start master' command -// with a default PorchServerOptions. -func NewCommandStartPorchServer(ctx context.Context, defaults *PorchServerOptions) *cobra.Command { - o := *defaults - cmd := &cobra.Command{ - Short: "Launch a porch API server", - Long: "Launch a porch API server", - RunE: func(c *cobra.Command, args []string) error { - if err := o.Complete(); err != nil { - return err - } - if err := o.Validate(args); err != nil { - return err - } - if err := o.RunPorchServer(ctx); err != nil { - return err - } - return nil - }, - } - - flags := cmd.Flags() - o.AddFlags(flags) - - return cmd -} - -// Validate validates PorchServerOptions -func (o PorchServerOptions) Validate(args []string) error { - errors := []error{} - errors = append(errors, o.RecommendedOptions.Validate()...) - return utilerrors.NewAggregate(errors) -} - -// Complete fills in fields required to have valid data -func (o *PorchServerOptions) Complete() error { - o.CoreAPIKubeconfigPath = o.RecommendedOptions.CoreAPI.CoreAPIKubeconfigPath - - if o.LocalStandaloneDebugging { - if os.Getenv("KUBERNETES_SERVICE_HOST") != "" || os.Getenv("KUBERNETES_SERVICE_PORT") != "" { - klog.Fatalf("--standalone-debug-mode must not be used when running in k8s") - } else { - o.RecommendedOptions.Authorization = nil - o.RecommendedOptions.CoreAPI = nil - o.RecommendedOptions.Admission = nil - o.RecommendedOptions.Authentication.RemoteKubeConfigFileOptional = true - } - } - - if o.CacheDirectory == "" { - cache, err := os.UserCacheDir() - if err != nil { - cache = os.TempDir() - klog.Warningf("Cannot find user cache directory, using temporary directory %q", cache) - } - o.CacheDirectory = cache + "/porch" - } - - // if !o.LocalStandaloneDebugging { - // TODO: register admission plugins here ... - // add admission plugins to the RecommendedPluginOrder here ... - // } - - return nil -} - -// Config returns config for the api server given PorchServerOptions -func (o *PorchServerOptions) Config() (*apiserver.Config, error) { - // TODO have a "real" external address - if err := o.RecommendedOptions.SecureServing.MaybeDefaultWithSelfSignedCerts("localhost", nil, []net.IP{netutils.ParseIPSloppy("127.0.0.1")}); err != nil { - return nil, fmt.Errorf("error creating self-signed certificates: %w", err) - } - - if o.RecommendedOptions.Etcd != nil { - o.RecommendedOptions.Etcd.StorageConfig.Paging = utilfeature.DefaultFeatureGate.Enabled(features.APIListChunking) - } - - o.RecommendedOptions.ExtraAdmissionInitializers = func(c *genericapiserver.RecommendedConfig) ([]admission.PluginInitializer, error) { - client, err := clientset.NewForConfig(c.LoopbackClientConfig) - if err != nil { - return nil, err - } - informerFactory := informers.NewSharedInformerFactory(client, c.LoopbackClientConfig.Timeout) - o.SharedInformerFactory = informerFactory - return []admission.PluginInitializer{}, nil - } - - serverConfig := genericapiserver.NewRecommendedConfig(apiserver.Codecs) - - serverConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(sampleopenapi.GetOpenAPIDefinitions, openapi.NewDefinitionNamer(apiserver.Scheme)) - serverConfig.OpenAPIConfig.Info.Title = "Porch" - serverConfig.OpenAPIConfig.Info.Version = "0.1" - - if err := o.RecommendedOptions.ApplyTo(serverConfig); err != nil { - return nil, err - } - - config := &apiserver.Config{ - GenericConfig: serverConfig, - ExtraConfig: apiserver.ExtraConfig{ - CoreAPIKubeconfigPath: o.CoreAPIKubeconfigPath, - CacheDirectory: o.CacheDirectory, - RepoSyncFrequency: o.RepoSyncFrequency, - FunctionRunnerAddress: o.FunctionRunnerAddress, - DefaultImagePrefix: o.DefaultImagePrefix, - }, - } - return config, nil -} - -// RunPorchServer starts a new PorchServer given PorchServerOptions -func (o PorchServerOptions) RunPorchServer(ctx context.Context) error { - config, err := o.Config() - if err != nil { - return err - } - - server, err := config.Complete().New() - if err != nil { - return err - } - - if config.GenericConfig.SharedInformerFactory != nil { - server.GenericAPIServer.AddPostStartHookOrDie("start-sample-server-informers", func(context genericapiserver.PostStartHookContext) error { - config.GenericConfig.SharedInformerFactory.Start(context.StopCh) - o.SharedInformerFactory.Start(context.StopCh) - return nil - }) - } - - return server.Run(ctx) -} - -func (o *PorchServerOptions) AddFlags(fs *pflag.FlagSet) { - // Add base flags - o.RecommendedOptions.AddFlags(fs) - utilfeature.DefaultMutableFeatureGate.AddFlag(fs) - - // Add additional flags. - - if os.Getenv("KUBERNETES_SERVICE_HOST") == "" && os.Getenv("KUBERNETES_SERVICE_PORT") == "" { - // Add this flag only when not running in k8s cluster. - fs.BoolVar(&o.LocalStandaloneDebugging, "standalone-debug-mode", false, - "Under the local-debug mode the apiserver will allow all access to its resources without "+ - "authorizing the requests, this flag is only intended for debugging in your workstation.") - } - - fs.StringVar(&o.FunctionRunnerAddress, "function-runner", "", "Address of the function runner gRPC service.") - fs.StringVar(&o.DefaultImagePrefix, "default-image-prefix", "gcr.io/kpt-fn/", "Default prefix for unqualified function names") - fs.StringVar(&o.CacheDirectory, "cache-directory", "", "Directory where Porch server stores repository and package caches.") - fs.DurationVar(&o.RepoSyncFrequency, "repo-sync-frequency", 60*time.Second, "Frequency in seconds at which registered repositories will be synced.") -} diff --git a/porch/pkg/cmd/server/start_test.go b/porch/pkg/cmd/server/start_test.go deleted file mode 100644 index b70b40c011..0000000000 --- a/porch/pkg/cmd/server/start_test.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2023 The kpt 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. - -package server - -import ( - porchv1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/apiserver" - "github.com/spf13/pflag" - "k8s.io/apimachinery/pkg/runtime/schema" - genericoptions "k8s.io/apiserver/pkg/server/options" - "testing" - "time" -) - -func TestAddFlags(t *testing.T) { - versions := schema.GroupVersions{ - porchv1alpha1.SchemeGroupVersion, - } - o := PorchServerOptions{ - RecommendedOptions: genericoptions.NewRecommendedOptions( - defaultEtcdPathPrefix, - apiserver.Codecs.LegacyCodec(versions...), - ), - } - o.AddFlags(&pflag.FlagSet{}) - if o.RepoSyncFrequency < 30*time.Second { - t.Fatalf("AddFlags(): repo-sync-frequency cannot be less that 30 seconds.") - } -} diff --git a/porch/pkg/controllerrestmapper/caching.go b/porch/pkg/controllerrestmapper/caching.go deleted file mode 100644 index 2ab0735500..0000000000 --- a/porch/pkg/controllerrestmapper/caching.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2022 The kpt 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. - -package controllerrestmapper - -import ( - "fmt" - "strings" - "sync" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/discovery" - "k8s.io/klog/v2" - "sigs.k8s.io/controller-runtime/pkg/log" -) - -// cache is our cache of schema information. -type cache struct { - mutex sync.Mutex - groupVersions map[schema.GroupVersion]*cachedGroupVersion -} - -// newCache is the constructor for a cache. -func newCache() *cache { - return &cache{ - groupVersions: make(map[schema.GroupVersion]*cachedGroupVersion), - } -} - -// cachedGroupVersion caches (all) the resource information for a particular groupversion. -type cachedGroupVersion struct { - gv schema.GroupVersion - mutex sync.Mutex - kinds map[string]cachedGVR -} - -// cachedGVR caches the information for a particular resource. -type cachedGVR struct { - Resource string - Scope meta.RESTScope -} - -// findRESTMapping returns the RESTMapping for the specified GVK, querying discovery if not cached. -func (c *cache) findRESTMapping(discovery discovery.DiscoveryInterface, gv schema.GroupVersion, kind string) (*meta.RESTMapping, error) { - c.mutex.Lock() - cached := c.groupVersions[gv] - if cached == nil { - cached = &cachedGroupVersion{gv: gv} - c.groupVersions[gv] = cached - } - c.mutex.Unlock() - return cached.findRESTMapping(discovery, kind) -} - -// findRESTMapping returns the RESTMapping for the specified GVK, querying discovery if not cached. -func (c *cachedGroupVersion) findRESTMapping(discovery discovery.DiscoveryInterface, kind string) (*meta.RESTMapping, error) { - kinds, err := c.fetch(discovery) - if err != nil { - return nil, err - } - - cached, found := kinds[kind] - if !found { - return nil, nil - } - return &meta.RESTMapping{ - Resource: c.gv.WithResource(cached.Resource), - GroupVersionKind: c.gv.WithKind(kind), - Scope: cached.Scope, - }, nil -} - -// fetch returns the metadata, fetching it if not cached. -func (c *cachedGroupVersion) fetch(discovery discovery.DiscoveryInterface) (map[string]cachedGVR, error) { - log := log.Log - - c.mutex.Lock() - defer c.mutex.Unlock() - - if c.kinds != nil { - return c.kinds, nil - } - - log.Info("discovering server resources for group/version", "gv", c.gv.String()) - resourceList, err := discovery.ServerResourcesForGroupVersion(c.gv.String()) - if err != nil { - // We treat "no match" as an empty result, but any other error percolates back up - if meta.IsNoMatchError(err) || apierrors.IsNotFound(err) { - return nil, nil - } else { - klog.Infof("unexpected error from ServerResourcesForGroupVersion(%v): %v", c.gv, err) - return nil, fmt.Errorf("error from ServerResourcesForGroupVersion(%v): %w", c.gv, err) - } - } - - kinds := make(map[string]cachedGVR) - for i := range resourceList.APIResources { - resource := resourceList.APIResources[i] - - // if we have a slash, then this is a subresource and we shouldn't create mappings for those. - if strings.Contains(resource.Name, "/") { - continue - } - - scope := meta.RESTScopeRoot - if resource.Namespaced { - scope = meta.RESTScopeNamespace - } - kinds[resource.Kind] = cachedGVR{ - Resource: resource.Name, - Scope: scope, - } - } - c.kinds = kinds - return kinds, nil -} diff --git a/porch/pkg/controllerrestmapper/controllerrestmapper.go b/porch/pkg/controllerrestmapper/controllerrestmapper.go deleted file mode 100644 index fc4180d73c..0000000000 --- a/porch/pkg/controllerrestmapper/controllerrestmapper.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2022 The kpt 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. - -package controllerrestmapper - -import ( - "fmt" - - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/discovery" - "k8s.io/client-go/rest" -) - -// New is the constructor for a ControllerRESTMapper -func New(cfg *rest.Config) (meta.RESTMapper, error) { - discoveryClient, err := discovery.NewDiscoveryClientForConfig(cfg) - if err != nil { - return nil, err - } - - return &ControllerRESTMapper{ - uncached: discoveryClient, - cache: newCache(), - }, nil -} - -// ControllerRESTMapper is a meta.RESTMapper that is optimized for controllers. -// It caches results in memory, and minimizes discovery because we don't need shortnames etc in controllers. -// Controllers primarily need to map from GVK -> GVR. -type ControllerRESTMapper struct { - uncached discovery.DiscoveryInterface - cache *cache -} - -var _ meta.RESTMapper = &ControllerRESTMapper{} - -// KindFor takes a partial resource and returns the single match. Returns an error if there are multiple matches -func (m *ControllerRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) { - return schema.GroupVersionKind{}, fmt.Errorf("ControllerRESTMaper does not support KindFor operation") -} - -// KindsFor takes a partial resource and returns the list of potential kinds in priority order -func (m *ControllerRESTMapper) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) { - return nil, fmt.Errorf("ControllerRESTMaper does not support KindsFor operation") -} - -// ResourceFor takes a partial resource and returns the single match. Returns an error if there are multiple matches -func (m *ControllerRESTMapper) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) { - return schema.GroupVersionResource{}, fmt.Errorf("ControllerRESTMaper does not support ResourceFor operation") -} - -// ResourcesFor takes a partial resource and returns the list of potential resource in priority order -func (m *ControllerRESTMapper) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) { - return nil, fmt.Errorf("ControllerRESTMaper does not support ResourcesFor operation") -} - -// RESTMapping identifies a preferred resource mapping for the provided group kind. -func (m *ControllerRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) { - for _, version := range versions { - gv := schema.GroupVersion{Group: gk.Group, Version: version} - mapping, err := m.cache.findRESTMapping(m.uncached, gv, gk.Kind) - if err != nil { - return nil, err - } - if mapping != nil { - return mapping, nil - } - } - - return nil, &meta.NoKindMatchError{GroupKind: gk, SearchedVersions: versions} -} - -// RESTMappings returns all resource mappings for the provided group kind if no -// version search is provided. Otherwise identifies a preferred resource mapping for -// the provided version(s). -func (m *ControllerRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) { - return nil, fmt.Errorf("ControllerRESTMaper does not support RESTMappings operation") -} - -func (m *ControllerRESTMapper) ResourceSingularizer(resource string) (singular string, err error) { - return "", fmt.Errorf("ControllerRESTMaper does not support ResourceSingularizer operation") -} diff --git a/porch/pkg/engine/builtin.go b/porch/pkg/engine/builtin.go deleted file mode 100644 index f0bc8de05e..0000000000 --- a/porch/pkg/engine/builtin.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "fmt" - - "github.com/GoogleContainerTools/kpt/internal/builtins" - "github.com/GoogleContainerTools/kpt/internal/fnruntime" - "github.com/GoogleContainerTools/kpt/pkg/fn" - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil" - "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -type builtinEvalMutation struct { - function string - runner fn.FunctionRunner -} - -func newPackageContextGeneratorMutation(packageConfig *builtins.PackageConfig) (mutation, error) { - runner := &builtins.PackageContextGenerator{ - PackageConfig: packageConfig, - } - - return &builtinEvalMutation{ - function: fnruntime.FuncGenPkgContext, - runner: runner, - }, nil -} - -var _ mutation = &builtinEvalMutation{} - -func (m *builtinEvalMutation) Apply(ctx context.Context, resources repository.PackageResources) (repository.PackageResources, *api.TaskResult, error) { - ff := &runtimeutil.FunctionFilter{ - Run: m.runner.Run, - Results: &yaml.RNode{}, - } - - pr := &packageReader{ - input: resources, - extra: map[string]string{}, - } - - result := repository.PackageResources{ - Contents: map[string]string{}, - } - - pipeline := kio.Pipeline{ - Inputs: []kio.Reader{pr}, - Filters: []kio.Filter{ff}, - Outputs: []kio.Writer{&packageWriter{ - output: result, - }}, - } - - if err := pipeline.Execute(); err != nil { - return repository.PackageResources{}, nil, fmt.Errorf("failed to evaluate function %q: %w", m.function, err) - } - - for k, v := range pr.extra { - result.Contents[k] = v - } - - return result, &api.TaskResult{}, nil -} diff --git a/porch/pkg/engine/builtin_test.go b/porch/pkg/engine/builtin_test.go deleted file mode 100644 index a3019fe67e..0000000000 --- a/porch/pkg/engine/builtin_test.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "os" - "path/filepath" - "testing" - - "github.com/GoogleContainerTools/kpt/internal/builtins" - "github.com/google/go-cmp/cmp" -) - -const ( - updateGoldenFiles = "UPDATE_GOLDEN_FILES" -) - -func TestPackageContext(t *testing.T) { - testdata, err := filepath.Abs(filepath.Join(".", "testdata", "context")) - if err != nil { - t.Fatalf("Failed to find testdata: %v", err) - } - - input := readPackage(t, filepath.Join(testdata, "input")) - - packageConfig := &builtins.PackageConfig{ - PackagePath: "parent1/parent1.2/parent1.2.3/me", - } - m, err := newPackageContextGeneratorMutation(packageConfig) - if err != nil { - t.Fatalf("Failed to get builtin function mutation: %v", err) - } - - got, _, err := m.Apply(context.Background(), input) - if err != nil { - t.Fatalf("Failed to apply builtin function mutation: %v", err) - } - - expectedPackage := filepath.Join(testdata, "expected") - - if os.Getenv(updateGoldenFiles) != "" { - if err := os.RemoveAll(expectedPackage); err != nil { - t.Fatalf("Failed to update golden files: %v", err) - } - - writePackage(t, expectedPackage, got) - } - - want := readPackage(t, expectedPackage) - - if !cmp.Equal(want, got) { - t.Errorf("Unexpected result of builtin function mutation (-want, +got): %s", cmp.Diff(want, got)) - } -} diff --git a/porch/pkg/engine/builtinruntime.go b/porch/pkg/engine/builtinruntime.go deleted file mode 100644 index 63f0d05f05..0000000000 --- a/porch/pkg/engine/builtinruntime.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "io" - - "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/apply-replacements/replacements" - "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/set-namespace/transformer" - "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/starlark/starlark" - fnsdk "github.com/GoogleContainerTools/kpt-functions-sdk/go/fn" - v1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/pkg/fn" - "github.com/GoogleContainerTools/kpt/porch/pkg/kpt" -) - -// When updating the version for the builtin functions, please also update the image version -// in test TestBuiltinFunctionEvaluator in porch/test/e2e/e2e_test.go, if the versions mismatch -// the e2e test will fail in local deployment mode. -var ( - applyReplacementsImageAliases = []string{ - "gcr.io/kpt-fn/apply-replacements:v0.1.1", - "gcr.io/kpt-fn/apply-replacements:v0.1", - "gcr.io/kpt-fn/apply-replacements@sha256:85913d4ec8db62053eb060ff1b7e26d13ff8853b75cae4d0461b8a1c7ddd4947", - } - setNamespaceImageAliases = []string{ - "gcr.io/kpt-fn/set-namespace:v0.4.1", - "gcr.io/kpt-fn/set-namespace:v0.4", - "gcr.io/kpt-fn/set-namespace@sha256:f930d9248001fa763799cc81cf2d89bbf83954fc65de0db20ab038a21784f323", - } - starlarkImageAliases = []string{ - "gcr.io/kpt-fn/starlark:v0.4.3", - "gcr.io/kpt-fn/starlark:v0.4", - "gcr.io/kpt-fn/starlark@sha256:6ba3971c64abcd6c3d93039d45721bb5ab496c7fbbc9ac1e685b11577f368ce0", - } -) - -type builtinRuntime struct { - fnMapping map[string]fnsdk.ResourceListProcessor -} - -func newBuiltinRuntime() *builtinRuntime { - fnMap := map[string]fnsdk.ResourceListProcessor{} - for _, img := range applyReplacementsImageAliases { - fnMap[img] = fnsdk.ResourceListProcessorFunc(replacements.ApplyReplacements) - } - for _, img := range setNamespaceImageAliases { - fnMap[img] = fnsdk.ResourceListProcessorFunc(transformer.SetNamespace) - } - for _, img := range starlarkImageAliases { - fnMap[img] = fnsdk.ResourceListProcessorFunc(starlark.Process) - } - return &builtinRuntime{ - fnMapping: fnMap, - } -} - -var _ kpt.FunctionRuntime = &builtinRuntime{} - -func (br *builtinRuntime) GetRunner(ctx context.Context, funct *v1.Function) (fn.FunctionRunner, error) { - processor, found := br.fnMapping[funct.Image] - if !found { - return nil, &fn.NotFoundError{Function: *funct} - } - - return &builtinRunner{ - ctx: ctx, - processor: processor, - }, nil -} - -func (br *builtinRuntime) Close() error { - return nil -} - -type builtinRunner struct { - ctx context.Context - processor fnsdk.ResourceListProcessor -} - -var _ fn.FunctionRunner = &builtinRunner{} - -func (br *builtinRunner) Run(r io.Reader, w io.Writer) error { - return fnsdk.Execute(br.processor, r, w) -} diff --git a/porch/pkg/engine/builtinruntime_test.go b/porch/pkg/engine/builtinruntime_test.go deleted file mode 100644 index be403f8cde..0000000000 --- a/porch/pkg/engine/builtinruntime_test.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "bytes" - "context" - "errors" - "testing" - - fnsdk "github.com/GoogleContainerTools/kpt-functions-sdk/go/fn" - v1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/pkg/fn" -) - -func TestBuiltinRuntime(t *testing.T) { - br := newBuiltinRuntime() - fn := &v1.Function{ - Image: setNamespaceImageAliases[0], - } - fr, err := br.GetRunner(context.Background(), fn) - if err != nil { - t.Fatalf("unexpected error when getting the runner: %v", err) - } - reader := bytes.NewReader([]byte(`apiVersion: config.kubernetes.io/v1alpha1 -kind: ResourceList -items: - - apiVersion: v1 - kind: ConfigMap - metadata: - name: my-cm - namespace: old - data: - foo: bar -functionConfig: - apiVersion: v1 - kind: ConfigMap - data: - namespace: test-ns -`)) - var buf bytes.Buffer - err = fr.Run(reader, &buf) - if err != nil { - t.Fatalf("unexpected error when running the function runner: %v", err) - } - rl, err := fnsdk.ParseResourceList(buf.Bytes()) - if err != nil { - t.Fatalf("can't parse the updated resource list: %v", err) - } - if len(rl.Items) != 1 { - t.Fatalf("expect the updated resource list to have 1 object in items, but got %d", len(rl.Items)) - } - ns := rl.Items[0].GetNamespace() - if ns != "test-ns" { - t.Fatalf("expect the updated namespace to be %v, but got %v", "test-ns", "ns") - } -} - -func TestBuiltinRuntimeNotFound(t *testing.T) { - br := newBuiltinRuntime() - funct := &v1.Function{ - Image: "gcr.io/kpt-fn/not-exist:unstable", - } - _, err := br.GetRunner(context.Background(), funct) - var fnNotFoundErr *fn.NotFoundError - if !errors.As(err, &fnNotFoundErr) { - t.Fatalf("expect error to be %T, but got %T %v", fnNotFoundErr, err, err) - } -} diff --git a/porch/pkg/engine/clone.go b/porch/pkg/engine/clone.go deleted file mode 100644 index b4722dc0ff..0000000000 --- a/porch/pkg/engine/clone.go +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "errors" - "fmt" - "os" - "strings" - - "github.com/GoogleContainerTools/kpt/internal/builtins" - v1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/git" - "github.com/GoogleContainerTools/kpt/porch/pkg/kpt" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "go.opentelemetry.io/otel/trace" - "k8s.io/klog/v2" -) - -type clonePackageMutation struct { - task *api.Task - - // namespace is the namespace against which we resolve references. - // TODO: merge namespace into referenceResolver? - namespace string - - name string // package target name - isDeployment bool // is the package deployable instance - repoOpener RepositoryOpener - credentialResolver repository.CredentialResolver - referenceResolver ReferenceResolver - - // packageConfig contains the package configuration. - packageConfig *builtins.PackageConfig -} - -func (m *clonePackageMutation) Apply(ctx context.Context, resources repository.PackageResources) (repository.PackageResources, *api.TaskResult, error) { - ctx, span := tracer.Start(ctx, "clonePackageMutation::Apply", trace.WithAttributes()) - defer span.End() - - var cloned repository.PackageResources - var err error - - if ref := m.task.Clone.Upstream.UpstreamRef; ref != nil { - cloned, err = m.cloneFromRegisteredRepository(ctx, ref) - } else if git := m.task.Clone.Upstream.Git; git != nil { - cloned, err = m.cloneFromGit(ctx, git) - } else if oci := m.task.Clone.Upstream.Oci; oci != nil { - cloned, err = m.cloneFromOci(ctx, oci) - } else { - err = errors.New("invalid clone source (neither of git, oci, nor upstream were specified)") - } - - if err != nil { - return repository.PackageResources{}, nil, err - } - - // Add any pre-existing parts of the config that have not been overwritten by the clone operation. - for k, v := range resources.Contents { - if _, exists := cloned.Contents[k]; !exists { - cloned.Contents[k] = v - } - } - - if m.isDeployment { - // TODO(droot): executing this as mutation is not really needed, but can be - // refactored once we finalize the task/mutation/commit model. - genPkgContextMutation, err := newPackageContextGeneratorMutation(m.packageConfig) - if err != nil { - return repository.PackageResources{}, nil, err - } - cloned, _, err = genPkgContextMutation.Apply(ctx, cloned) - if err != nil { - return repository.PackageResources{}, nil, fmt.Errorf("failed to generate deployment context %w", err) - } - } - - // ensure merge-key comment is added to newly added resources. - // this operation is done on best effort basis because if upstream contains - // valid YAML but invalid KRM resources, merge-key operation will fail - // but shouldn't result in overall clone operation. - result, err := ensureMergeKey(ctx, cloned) - if err != nil { - klog.Infof("failed to add merge-key to resources %v", err) - } - - return result, &api.TaskResult{Task: m.task}, nil -} - -func (m *clonePackageMutation) cloneFromRegisteredRepository(ctx context.Context, ref *api.PackageRevisionRef) (repository.PackageResources, error) { - if ref.Name == "" { - return repository.PackageResources{}, fmt.Errorf("upstreamRef.name is required") - } - - upstreamRevision, err := (&PackageFetcher{ - repoOpener: m.repoOpener, - referenceResolver: m.referenceResolver, - }).FetchRevision(ctx, ref, m.namespace) - if err != nil { - return repository.PackageResources{}, fmt.Errorf("failed to fetch package revision %q: %w", ref.Name, err) - } - - resources, err := upstreamRevision.GetResources(ctx) - if err != nil { - return repository.PackageResources{}, fmt.Errorf("cannot read contents of package %q: %w", ref.Name, err) - } - - upstream, lock, err := upstreamRevision.GetLock() - if err != nil { - return repository.PackageResources{}, fmt.Errorf("cannot determine upstream lock for package %q: %w", ref.Name, err) - } - - // Update Kptfile - if err := kpt.UpdateKptfileUpstream(m.name, resources.Spec.Resources, upstream, lock); err != nil { - return repository.PackageResources{}, fmt.Errorf("failed to apply upstream lock to package %q: %w", ref.Name, err) - } - - return repository.PackageResources{ - Contents: resources.Spec.Resources, - }, nil -} - -func (m *clonePackageMutation) cloneFromGit(ctx context.Context, gitPackage *api.GitPackage) (repository.PackageResources, error) { - // TODO: Cache unregistered repositories with appropriate cache eviction policy. - // TODO: Separate low-level repository access from Repository abstraction? - - spec := configapi.GitRepository{ - Repo: gitPackage.Repo, - Directory: gitPackage.Directory, - SecretRef: configapi.SecretRef{ - Name: gitPackage.SecretRef.Name, - }, - } - - dir, err := os.MkdirTemp("", "clone-git-package-*") - if err != nil { - return repository.PackageResources{}, fmt.Errorf("cannot create temporary directory to clone Git repository: %w", err) - } - defer os.RemoveAll(dir) - - r, err := git.OpenRepository(ctx, "", "", &spec, false, dir, git.GitRepositoryOptions{ - CredentialResolver: m.credentialResolver, - MainBranchStrategy: git.SkipVerification, // We are only reading so we don't need the main branch to exist. - }) - if err != nil { - return repository.PackageResources{}, fmt.Errorf("cannot clone Git repository: %w", err) - } - - revision, lock, err := r.GetPackageRevision(ctx, gitPackage.Ref, gitPackage.Directory) - if err != nil { - return repository.PackageResources{}, fmt.Errorf("cannot find package %s@%s: %w", gitPackage.Directory, gitPackage.Ref, err) - } - - resources, err := revision.GetResources(ctx) - if err != nil { - return repository.PackageResources{}, fmt.Errorf("cannot read package resources: %w", err) - } - - contents := resources.Spec.Resources - - // Update Kptfile - if err := kpt.UpdateKptfileUpstream(m.name, contents, v1.Upstream{ - Type: v1.GitOrigin, - Git: &v1.Git{ - Repo: lock.Repo, - Directory: lock.Directory, - Ref: lock.Ref, - }, - }, v1.UpstreamLock{ - Type: v1.GitOrigin, - Git: &lock, - }); err != nil { - return repository.PackageResources{}, fmt.Errorf("failed to clone package %s@%s: %w", gitPackage.Directory, gitPackage.Ref, err) - } - - return repository.PackageResources{ - Contents: contents, - }, nil -} - -func (m *clonePackageMutation) cloneFromOci(ctx context.Context, ociPackage *api.OciPackage) (repository.PackageResources, error) { - return repository.PackageResources{}, errors.New("clone from OCI is not implemented") -} - -func parseUpstreamRepository(name string) (string, error) { - lastDash := strings.LastIndex(name, "-") - if lastDash < 0 { - return "", fmt.Errorf("malformed package revision name; expected at least one hyphen: %q", name) - } - return name[:lastDash], nil -} diff --git a/porch/pkg/engine/clone_test.go b/porch/pkg/engine/clone_test.go deleted file mode 100644 index d19dc0cd9f..0000000000 --- a/porch/pkg/engine/clone_test.go +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "fmt" - "io" - "io/fs" - "math/rand" - "net" - "net/http" - "os" - "path/filepath" - "sync" - "testing" - "time" - - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/git" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/go-git/go-billy/v5/memfs" - gogit "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/object" - "github.com/go-git/go-git/v5/plumbing/transport" - githttp "github.com/go-git/go-git/v5/plumbing/transport/http" - "github.com/go-git/go-git/v5/storage/memory" -) - -func createRepoWithContents(t *testing.T, contentDir string) *gogit.Repository { - repo, err := gogit.Init(memory.NewStorage(), memfs.New()) - if err != nil { - t.Fatalf("Failed to initialize in-memory git repository: %v", err) - } - wt, err := repo.Worktree() - if err != nil { - t.Fatalf("Failed to get git repository worktree: %v", err) - } - - if err := filepath.Walk(contentDir, func(path string, info fs.FileInfo, err error) error { - if err != nil { - return err - } - if info.IsDir() { - return nil - } else if !info.Mode().IsRegular() { - return fmt.Errorf("irregular file object detected: %q (%s)", path, info.Mode()) - } - rel, err := filepath.Rel(contentDir, path) - if err != nil { - return fmt.Errorf("failed to get relative path from %q to %q: %w", contentDir, path, err) - } - dir := filepath.Dir(rel) - if err := wt.Filesystem.MkdirAll(dir, 0777); err != nil { - return fmt.Errorf("failed to create directories for %q: %w", rel, err) - } - src, err := os.Open(path) - if err != nil { - return fmt.Errorf("failed to open the source file %q: %w", path, err) - } - defer src.Close() - dst, err := wt.Filesystem.Create(rel) - if err != nil { - return fmt.Errorf("failed to create the destination file %q: %w", rel, err) - } - defer dst.Close() - if _, err := io.Copy(dst, src); err != nil { - return fmt.Errorf("failed to copy file contents %q -> %q: %w", path, rel, err) - } - wt.Add(rel) - return nil - }); err != nil { - t.Fatalf("Failed populating Git repository worktree: %v", err) - } - - sig := object.Signature{ - Name: "Porch Unit Test", - Email: "porch-unit-test@kpt.dev", - When: time.Now(), - } - - hash, err := wt.Commit("Initial Commit", &gogit.CommitOptions{ - All: true, - Author: &sig, - Committer: &sig, - }) - if err != nil { - t.Fatalf("Failed creating initial commit: %v", err) - } - - main := plumbing.NewHashReference(plumbing.ReferenceName("refs/heads/main"), hash) - if err := repo.Storer.SetReference(main); err != nil { - t.Fatalf("Failed to set refs/heads/main to commit sha %s: %v", hash, err) - } - head := plumbing.NewSymbolicReference(plumbing.HEAD, "refs/heads/main") - if err := repo.Storer.SetReference(head); err != nil { - t.Fatalf("Failed to set HEAD to refs/heads/main: %v", err) - } - - _ = repo.Storer.RemoveReference(plumbing.Master) - - return repo -} - -func startGitServer(t *testing.T, repo *git.Repo, opts ...git.GitServerOption) string { - key := "default" - repos := git.NewStaticRepos() - if err := repos.Add(key, repo); err != nil { - t.Fatalf("repos.Add failed: %v", err) - } - - server, err := git.NewGitServer(repos) - if err != nil { - t.Fatalf("Failed to create git server: %v", err) - } - - var wg sync.WaitGroup - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(func() { - cancel() - wg.Wait() - }) - - addressChannel := make(chan net.Addr) - - wg.Add(1) - go func() { - defer wg.Done() - err := server.ListenAndServe(ctx, "127.0.0.1:0", addressChannel) - if err != nil { - if err == http.ErrServerClosed { - t.Log("Git server shut down successfully") - } else { - t.Errorf("Git server exited with error: %v", err) - } - } - }() - - // Wait for server to start up - address, ok := <-addressChannel - if !ok { - t.Fatalf("Server failed to start") - return "" - } - - return fmt.Sprintf("http://%s/%s", address, key) -} - -// TODO(mortent): See if we can restruture the packages to -// avoid having to create separate implementations of the auth -// interfaces here. -type credentialResolver struct { - username, password string -} - -type credential struct { - username, password string -} - -func (c *credential) Valid() bool { - return true -} - -func (c *credential) ToAuthMethod() transport.AuthMethod { - return &githttp.BasicAuth{ - Username: c.username, - Password: c.password, - } -} - -func randomString(n int) string { - const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - result := make([]byte, n) - for i := range result { - result[i] = letters[rand.Intn(len(letters))] - } - return string(result) -} - -func randomCredentials() *credentialResolver { - return &credentialResolver{ - username: randomString(30), - password: randomString(30), - } -} - -func (r *credentialResolver) ResolveCredential(ctx context.Context, namespace, name string) (repository.Credential, error) { - return &credential{ - username: r.username, - password: r.password, - }, nil -} - -func TestCloneGitBasicAuth(t *testing.T) { - testdata, err := filepath.Abs(filepath.Join(".", "testdata", "clone")) - if err != nil { - t.Fatalf("Failed to find testdata: %v", err) - } - - auth := randomCredentials() - gogitRepo := createRepoWithContents(t, testdata) - - repo, err := git.NewRepo(gogitRepo, git.WithBasicAuth(auth.username, auth.password)) - if err != nil { - t.Fatalf("NewRepo failed: %v", err) - } - - addr := startGitServer(t, repo) - - cpm := clonePackageMutation{ - task: &v1alpha1.Task{ - Type: "clone", - Clone: &v1alpha1.PackageCloneTaskSpec{ - Upstream: v1alpha1.UpstreamPackage{ - Type: "git", - Git: &v1alpha1.GitPackage{ - Repo: addr, - Ref: "main", - Directory: "configmap", - SecretRef: v1alpha1.SecretRef{ - Name: "git-credentials", - }, - }, - }, - }, - }, - namespace: "test-namespace", - name: "test-configmap", - credentialResolver: &credentialResolver{ - username: "", - password: "", - }, - } - - _, _, err = cpm.Apply(context.Background(), repository.PackageResources{}) - if err == nil { - t.Errorf("Expected error (unauthorized); got none") - } - - cpm.credentialResolver = auth - - r, _, err := cpm.Apply(context.Background(), repository.PackageResources{}) - if err != nil { - t.Errorf("task apply failed: %v", err) - } - - t.Logf("%v", r) -} diff --git a/porch/pkg/engine/doc.go b/porch/pkg/engine/doc.go deleted file mode 100644 index 2c9e59a180..0000000000 --- a/porch/pkg/engine/doc.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2022 The kpt 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. - -// Implementation of package orchestration engine -// The engine is independent of k8s runtime (k8s apiserver integration is in apiserver module) -package engine diff --git a/porch/pkg/engine/edit.go b/porch/pkg/engine/edit.go deleted file mode 100644 index 4583eaa15b..0000000000 --- a/porch/pkg/engine/edit.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "fmt" - - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "go.opentelemetry.io/otel/trace" -) - -type editPackageMutation struct { - task *api.Task - namespace string - repositoryName string - packageName string - repoOpener RepositoryOpener - referenceResolver ReferenceResolver -} - -var _ mutation = &editPackageMutation{} - -func (m *editPackageMutation) Apply(ctx context.Context, resources repository.PackageResources) (repository.PackageResources, *api.TaskResult, error) { - ctx, span := tracer.Start(ctx, "editPackageMutation::Apply", trace.WithAttributes()) - defer span.End() - - sourceRef := m.task.Edit.Source - - revision, err := (&PackageFetcher{ - repoOpener: m.repoOpener, - referenceResolver: m.referenceResolver, - }).FetchRevision(ctx, sourceRef, m.namespace) - if err != nil { - return repository.PackageResources{}, nil, fmt.Errorf("failed to fetch package %q: %w", sourceRef.Name, err) - } - - // We only allow edit to create new revision from the same package. - if revision.Key().Package != m.packageName || - revision.Key().Repository != m.repositoryName { - return repository.PackageResources{}, nil, fmt.Errorf("source revision must be from same package %s/%s", m.repositoryName, m.packageName) - } - - // We only allow edit to create new revisions from published packages. - if !api.LifecycleIsPublished(revision.Lifecycle()) { - return repository.PackageResources{}, nil, fmt.Errorf("source revision must be published") - } - - sourceResources, err := revision.GetResources(ctx) - if err != nil { - return repository.PackageResources{}, nil, fmt.Errorf("cannot read contents of package %q: %w", sourceRef.Name, err) - } - - return repository.PackageResources{ - Contents: sourceResources.Spec.Resources, - }, &api.TaskResult{Task: m.task}, nil -} diff --git a/porch/pkg/engine/edit_test.go b/porch/pkg/engine/edit_test.go deleted file mode 100644 index 0fa3e81f00..0000000000 --- a/porch/pkg/engine/edit_test.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "strings" - "testing" - - kptfile "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/engine/fake" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/google/go-cmp/cmp" -) - -func TestEdit(t *testing.T) { - pkg := "pkg" - packageName := "repo-1234567890" - repositoryName := "repo" - revision := "v1" - packageRevision := &fake.PackageRevision{ - Name: packageName, - PackageRevisionKey: repository.PackageRevisionKey{ - Package: pkg, - Repository: repositoryName, - Revision: revision, - }, - PackageLifecycle: v1alpha1.PackageRevisionLifecyclePublished, - Resources: &v1alpha1.PackageRevisionResources{ - Spec: v1alpha1.PackageRevisionResourcesSpec{ - PackageName: pkg, - Revision: revision, - RepositoryName: repositoryName, - Resources: map[string]string{ - kptfile.KptFileName: strings.TrimSpace(` -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: example - annotations: - config.kubernetes.io/local-config: "true" -info: - description: sample description - `), - }, - }, - }, - } - repo := &fake.Repository{ - PackageRevisions: []repository.PackageRevision{ - packageRevision, - }, - } - repoOpener := &fakeRepositoryOpener{ - repository: repo, - } - - epm := editPackageMutation{ - task: &v1alpha1.Task{ - Type: "edit", - Edit: &v1alpha1.PackageEditTaskSpec{ - Source: &v1alpha1.PackageRevisionRef{ - Name: packageName, - }, - }, - }, - - namespace: "test-namespace", - packageName: pkg, - repositoryName: repositoryName, - referenceResolver: &fakeReferenceResolver{}, - repoOpener: repoOpener, - } - - res, _, err := epm.Apply(context.Background(), repository.PackageResources{}) - if err != nil { - t.Errorf("task apply failed: %v", err) - } - - want := strings.TrimSpace(` -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: example - annotations: - config.kubernetes.io/local-config: "true" -info: - description: sample description - `) - got := strings.TrimSpace(res.Contents[kptfile.KptFileName]) - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("result mismatch (-want +got):\n%s", diff) - } -} - -// Implementation of the ReferenceResolver interface for testing. -type fakeReferenceResolver struct{} - -func (f *fakeReferenceResolver) ResolveReference(ctx context.Context, namespace, name string, result Object) error { - return nil -} - -type fakeRepositoryOpener struct { - repository repository.Repository -} - -func (f *fakeRepositoryOpener) OpenRepository(ctx context.Context, repositorySpec *configapi.Repository) (repository.Repository, error) { - return f.repository, nil -} diff --git a/porch/pkg/engine/engine.go b/porch/pkg/engine/engine.go deleted file mode 100644 index 62c7ae15e5..0000000000 --- a/porch/pkg/engine/engine.go +++ /dev/null @@ -1,1443 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "bytes" - "context" - "fmt" - "io/fs" - "os" - "path/filepath" - "reflect" - "strings" - - "github.com/GoogleContainerTools/kpt/internal/builtins" - "github.com/GoogleContainerTools/kpt/internal/fnruntime" - kptfile "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/pkg/fn" - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/cache" - "github.com/GoogleContainerTools/kpt/porch/pkg/kpt" - "github.com/GoogleContainerTools/kpt/porch/pkg/meta" - "github.com/GoogleContainerTools/kpt/porch/pkg/objects" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/trace" - corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/klog/v2" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/kustomize/kyaml/comments" - "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -var tracer = otel.Tracer("engine") - -const ( - OptimisticLockErrorMsg = "the object has been modified; please apply your changes to the latest version and try again" -) - -type CaDEngine interface { - // ObjectCache() is a cache of all our objects. - ObjectCache() WatcherManager - - UpdatePackageResources(ctx context.Context, repositoryObj *configapi.Repository, oldPackage *PackageRevision, old, new *api.PackageRevisionResources) (*PackageRevision, *api.RenderStatus, error) - ListFunctions(ctx context.Context, repositoryObj *configapi.Repository) ([]*Function, error) - - ListPackageRevisions(ctx context.Context, repositorySpec *configapi.Repository, filter repository.ListPackageRevisionFilter) ([]*PackageRevision, error) - CreatePackageRevision(ctx context.Context, repositoryObj *configapi.Repository, obj *api.PackageRevision, parent *PackageRevision) (*PackageRevision, error) - UpdatePackageRevision(ctx context.Context, repositoryObj *configapi.Repository, oldPackage *PackageRevision, old, new *api.PackageRevision, parent *PackageRevision) (*PackageRevision, error) - DeletePackageRevision(ctx context.Context, repositoryObj *configapi.Repository, obj *PackageRevision) error - - ListPackages(ctx context.Context, repositorySpec *configapi.Repository, filter repository.ListPackageFilter) ([]*Package, error) - CreatePackage(ctx context.Context, repositoryObj *configapi.Repository, obj *api.Package) (*Package, error) - UpdatePackage(ctx context.Context, repositoryObj *configapi.Repository, oldPackage *Package, old, new *api.Package) (*Package, error) - DeletePackage(ctx context.Context, repositoryObj *configapi.Repository, obj *Package) error -} - -type Package struct { - repoPackage repository.Package -} - -func (p *Package) GetPackage() *api.Package { - return p.repoPackage.GetPackage() -} - -func (p *Package) KubeObjectName() string { - return p.repoPackage.KubeObjectName() -} - -// TODO: This is a bit awkward, and we should see if there is a way to avoid -// having to expose this function. Any functionality that requires creating new -// engine.PackageRevision resources should be in the engine package. -func ToPackageRevision(pkgRev repository.PackageRevision, pkgRevMeta meta.PackageRevisionMeta) *PackageRevision { - return &PackageRevision{ - repoPackageRevision: pkgRev, - packageRevisionMeta: pkgRevMeta, - } -} - -type PackageRevision struct { - repoPackageRevision repository.PackageRevision - packageRevisionMeta meta.PackageRevisionMeta -} - -func (p *PackageRevision) GetPackageRevision(ctx context.Context) (*api.PackageRevision, error) { - repoPkgRev, err := p.repoPackageRevision.GetPackageRevision(ctx) - if err != nil { - return nil, err - } - var isLatest bool - if val, found := repoPkgRev.Labels[api.LatestPackageRevisionKey]; found && val == api.LatestPackageRevisionValue { - isLatest = true - } - repoPkgRev.Labels = p.packageRevisionMeta.Labels - if isLatest { - // copy the labels in case the cached object is being read by another go routine - labels := make(map[string]string, len(repoPkgRev.Labels)) - for k, v := range repoPkgRev.Labels { - labels[k] = v - } - labels[api.LatestPackageRevisionKey] = api.LatestPackageRevisionValue - repoPkgRev.Labels = labels - } - repoPkgRev.Annotations = p.packageRevisionMeta.Annotations - repoPkgRev.Finalizers = p.packageRevisionMeta.Finalizers - repoPkgRev.OwnerReferences = p.packageRevisionMeta.OwnerReferences - repoPkgRev.DeletionTimestamp = p.packageRevisionMeta.DeletionTimestamp - - return repoPkgRev, nil -} - -func (p *PackageRevision) KubeObjectName() string { - return p.repoPackageRevision.KubeObjectName() -} - -func (p *PackageRevision) GetResources(ctx context.Context) (*api.PackageRevisionResources, error) { - return p.repoPackageRevision.GetResources(ctx) -} - -type Function struct { - RepoFunction repository.Function -} - -func (f *Function) Name() string { - return f.RepoFunction.Name() -} - -func (f *Function) GetFunction() (*api.Function, error) { - return f.RepoFunction.GetFunction() -} - -func NewCaDEngine(opts ...EngineOption) (CaDEngine, error) { - engine := &cadEngine{} - for _, opt := range opts { - if err := opt.apply(engine); err != nil { - return nil, err - } - } - return engine, nil -} - -type cadEngine struct { - cache *cache.Cache - - // runnerOptionsResolver returns the RunnerOptions for function execution in the specified namespace. - runnerOptionsResolver func(namespace string) fnruntime.RunnerOptions - - runtime fn.FunctionRuntime - credentialResolver repository.CredentialResolver - referenceResolver ReferenceResolver - userInfoProvider repository.UserInfoProvider - metadataStore meta.MetadataStore - watcherManager *watcherManager -} - -var _ CaDEngine = &cadEngine{} - -type mutation interface { - Apply(ctx context.Context, resources repository.PackageResources) (repository.PackageResources, *api.TaskResult, error) -} - -// ObjectCache is a cache of all our objects. -func (cad *cadEngine) ObjectCache() WatcherManager { - return cad.watcherManager -} - -func (cad *cadEngine) OpenRepository(ctx context.Context, repositorySpec *configapi.Repository) (repository.Repository, error) { - ctx, span := tracer.Start(ctx, "cadEngine::OpenRepository", trace.WithAttributes()) - defer span.End() - - return cad.cache.OpenRepository(ctx, repositorySpec) -} - -func (cad *cadEngine) ListPackageRevisions(ctx context.Context, repositorySpec *configapi.Repository, filter repository.ListPackageRevisionFilter) ([]*PackageRevision, error) { - ctx, span := tracer.Start(ctx, "cadEngine::ListPackageRevisions", trace.WithAttributes()) - defer span.End() - - repo, err := cad.cache.OpenRepository(ctx, repositorySpec) - if err != nil { - return nil, err - } - pkgRevs, err := repo.ListPackageRevisions(ctx, filter) - if err != nil { - return nil, err - } - - var packageRevisions []*PackageRevision - for _, pr := range pkgRevs { - pkgRevMeta, err := cad.metadataStore.Get(ctx, types.NamespacedName{ - Name: pr.KubeObjectName(), - Namespace: pr.KubeObjectNamespace(), - }) - if err != nil { - // If a PackageRev CR doesn't exist, we treat the - // Packagerevision as not existing. - if apierrors.IsNotFound(err) { - continue - } - return nil, err - } - packageRevisions = append(packageRevisions, &PackageRevision{ - repoPackageRevision: pr, - packageRevisionMeta: pkgRevMeta, - }) - } - return packageRevisions, nil -} - -func buildPackageConfig(ctx context.Context, obj *api.PackageRevision, parent *PackageRevision) (*builtins.PackageConfig, error) { - config := &builtins.PackageConfig{} - - parentPath := "" - - var parentConfig *unstructured.Unstructured - if parent != nil { - parentObj, err := parent.GetPackageRevision(ctx) - if err != nil { - return nil, err - } - parentPath = parentObj.Spec.PackageName - - resources, err := parent.GetResources(ctx) - if err != nil { - return nil, fmt.Errorf("error getting resources from parent package %q: %w", parentObj.Name, err) - } - configMapObj, err := ExtractContextConfigMap(resources.Spec.Resources) - if err != nil { - return nil, fmt.Errorf("error getting configuration from parent package %q: %w", parentObj.Name, err) - } - parentConfig = configMapObj - - if parentConfig != nil { - // TODO: Should we support kinds other than configmaps? - var parentConfigMap corev1.ConfigMap - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(parentConfig.Object, &parentConfigMap); err != nil { - return nil, fmt.Errorf("error parsing ConfigMap from parent configuration: %w", err) - } - if s := parentConfigMap.Data[builtins.ConfigKeyPackagePath]; s != "" { - parentPath = s + "/" + parentPath - } - } - } - - if parentPath == "" { - config.PackagePath = obj.Spec.PackageName - } else { - config.PackagePath = parentPath + "/" + obj.Spec.PackageName - } - - return config, nil -} - -func (cad *cadEngine) CreatePackageRevision(ctx context.Context, repositoryObj *configapi.Repository, obj *api.PackageRevision, parent *PackageRevision) (*PackageRevision, error) { - ctx, span := tracer.Start(ctx, "cadEngine::CreatePackageRevision", trace.WithAttributes()) - defer span.End() - - packageConfig, err := buildPackageConfig(ctx, obj, parent) - if err != nil { - return nil, err - } - - // Validate package lifecycle. Cannot create a final package - switch obj.Spec.Lifecycle { - case "": - // Set draft as default - obj.Spec.Lifecycle = api.PackageRevisionLifecycleDraft - case api.PackageRevisionLifecycleDraft, api.PackageRevisionLifecycleProposed: - // These values are ok - case api.PackageRevisionLifecyclePublished, api.PackageRevisionLifecycleDeletionProposed: - // TODO: generate errors that can be translated to correct HTTP responses - return nil, fmt.Errorf("cannot create a package revision with lifecycle value 'Final'") - default: - return nil, fmt.Errorf("unsupported lifecycle value: %s", obj.Spec.Lifecycle) - } - - repo, err := cad.cache.OpenRepository(ctx, repositoryObj) - if err != nil { - return nil, err - } - - if err := repository.ValidateWorkspaceName(obj.Spec.WorkspaceName); err != nil { - return nil, fmt.Errorf("failed to create packagerevision: %w", err) - } - - revs, err := repo.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{ - Package: obj.Spec.PackageName}) - if err != nil { - return nil, fmt.Errorf("error listing package revisions: %w", err) - } - - if err := ensureUniqueWorkspaceName(repositoryObj, obj, revs); err != nil { - return nil, err - } - - draft, err := repo.CreatePackageRevision(ctx, obj) - if err != nil { - return nil, err - } - - if err := cad.applyTasks(ctx, draft, repositoryObj, obj, packageConfig); err != nil { - return nil, err - } - - if err := draft.UpdateLifecycle(ctx, obj.Spec.Lifecycle); err != nil { - return nil, err - } - - // Updates are done. - repoPkgRev, err := draft.Close(ctx) - if err != nil { - return nil, err - } - pkgRevMeta := meta.PackageRevisionMeta{ - Name: repoPkgRev.KubeObjectName(), - Namespace: repoPkgRev.KubeObjectNamespace(), - Labels: obj.Labels, - Annotations: obj.Annotations, - Finalizers: obj.Finalizers, - OwnerReferences: obj.OwnerReferences, - } - pkgRevMeta, err = cad.metadataStore.Create(ctx, pkgRevMeta, repositoryObj.Name, repoPkgRev.UID()) - if err != nil { - return nil, err - } - sent := cad.watcherManager.NotifyPackageRevisionChange(watch.Added, repoPkgRev, pkgRevMeta) - klog.Infof("engine: sent %d for new PackageRevision %s/%s", sent, repoPkgRev.KubeObjectNamespace(), repoPkgRev.KubeObjectName()) - return &PackageRevision{ - repoPackageRevision: repoPkgRev, - packageRevisionMeta: pkgRevMeta, - }, nil -} - -// The workspaceName must be unique, because it used to generate the package revision's metadata.name. -func ensureUniqueWorkspaceName(repositoryObj *configapi.Repository, obj *api.PackageRevision, existingRevs []repository.PackageRevision) error { - // HACK - // It's ok for the "main" revision to have the same workspace name - // So ignore main revisions in this calculation - mainRev := "" - if repositoryObj.Spec.Git != nil { - mainRev = repositoryObj.Spec.Git.Branch - } - - for _, r := range existingRevs { - k := r.Key() - if mainRev != "" && k.Revision == mainRev { - continue - } - if k.WorkspaceName == obj.Spec.WorkspaceName { - return fmt.Errorf("package revision workspaceNames must be unique; package revision with name %s in repo %s with "+ - "workspaceName %s already exists", obj.Spec.PackageName, obj.Spec.RepositoryName, obj.Spec.WorkspaceName) - } - } - return nil -} - -func getPackageRevision(ctx context.Context, repo repository.Repository, name string) (repository.PackageRevision, bool, error) { - repoPkgRevs, err := repo.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{ - KubeObjectName: name, - }) - if err != nil { - return nil, false, err - } - if len(repoPkgRevs) == 0 { - return nil, false, nil - } - return repoPkgRevs[0], true, nil -} - -// TODO: See if we can use a library here for parsing OCI image urls -func getBaseImage(image string) string { - if s := strings.Split(image, "@sha256:"); len(s) > 1 { - return s[0] - } - if s := strings.Split(image, ":"); len(s) > 1 { - return s[0] - } - return image -} - -func taskTypeOneOf(taskType api.TaskType, oneOf ...api.TaskType) bool { - for _, tt := range oneOf { - if taskType == tt { - return true - } - } - return false -} - -func (cad *cadEngine) applyTasks(ctx context.Context, draft repository.PackageDraft, repositoryObj *configapi.Repository, obj *api.PackageRevision, packageConfig *builtins.PackageConfig) error { - var mutations []mutation - - // Unless first task is Init or Clone, insert Init to create an empty package. - tasks := obj.Spec.Tasks - if len(tasks) == 0 || !taskTypeOneOf(tasks[0].Type, api.TaskTypeInit, api.TaskTypeClone, api.TaskTypeEdit) { - mutations = append(mutations, &initPackageMutation{ - name: obj.Spec.PackageName, - task: &api.Task{ - Init: &api.PackageInitTaskSpec{ - Subpackage: "", - Description: fmt.Sprintf("%s description", obj.Spec.PackageName), - }, - }, - }) - } - - for i := range tasks { - task := &tasks[i] - mutation, err := cad.mapTaskToMutation(ctx, obj, task, repositoryObj.Spec.Deployment, packageConfig) - if err != nil { - return err - } - mutations = append(mutations, mutation) - } - - // Render package after creation. - mutations = cad.conditionalAddRender(obj, mutations) - - baseResources := repository.PackageResources{} - if _, _, err := applyResourceMutations(ctx, draft, baseResources, mutations); err != nil { - return err - } - - return nil -} - -type RepositoryOpener interface { - OpenRepository(ctx context.Context, repositorySpec *configapi.Repository) (repository.Repository, error) -} - -func (cad *cadEngine) mapTaskToMutation(ctx context.Context, obj *api.PackageRevision, task *api.Task, isDeployment bool, packageConfig *builtins.PackageConfig) (mutation, error) { - switch task.Type { - case api.TaskTypeInit: - if task.Init == nil { - return nil, fmt.Errorf("init not set for task of type %q", task.Type) - } - return &initPackageMutation{ - name: obj.Spec.PackageName, - task: task, - }, nil - case api.TaskTypeClone: - if task.Clone == nil { - return nil, fmt.Errorf("clone not set for task of type %q", task.Type) - } - return &clonePackageMutation{ - task: task, - namespace: obj.Namespace, - name: obj.Spec.PackageName, - isDeployment: isDeployment, - repoOpener: cad, - credentialResolver: cad.credentialResolver, - referenceResolver: cad.referenceResolver, - packageConfig: packageConfig, - }, nil - - case api.TaskTypeUpdate: - if task.Update == nil { - return nil, fmt.Errorf("update not set for task of type %q", task.Type) - } - cloneTask := findCloneTask(obj) - if cloneTask == nil { - return nil, fmt.Errorf("upstream source not found for package rev %q; only cloned packages can be updated", obj.Spec.PackageName) - } - return &updatePackageMutation{ - cloneTask: cloneTask, - updateTask: task, - namespace: obj.Namespace, - repoOpener: cad, - referenceResolver: cad.referenceResolver, - pkgName: obj.Spec.PackageName, - }, nil - - case api.TaskTypePatch: - return buildPatchMutation(ctx, task) - - case api.TaskTypeEdit: - if task.Edit == nil { - return nil, fmt.Errorf("edit not set for task of type %q", task.Type) - } - return &editPackageMutation{ - task: task, - namespace: obj.Namespace, - packageName: obj.Spec.PackageName, - repositoryName: obj.Spec.RepositoryName, - repoOpener: cad, - referenceResolver: cad.referenceResolver, - }, nil - - case api.TaskTypeEval: - if task.Eval == nil { - return nil, fmt.Errorf("eval not set for task of type %q", task.Type) - } - // TODO: We should find a different way to do this. Probably a separate - // task for render. - if task.Eval.Image == "render" { - runnerOptions := cad.runnerOptionsResolver(obj.Namespace) - return &renderPackageMutation{ - runnerOptions: runnerOptions, - runtime: cad.runtime, - }, nil - } else { - runnerOptions := cad.runnerOptionsResolver(obj.Namespace) - return &evalFunctionMutation{ - runnerOptions: runnerOptions, - runtime: cad.runtime, - task: task, - }, nil - } - - default: - return nil, fmt.Errorf("task of type %q not supported", task.Type) - } -} - -func (cad *cadEngine) UpdatePackageRevision(ctx context.Context, repositoryObj *configapi.Repository, oldPackage *PackageRevision, oldObj, newObj *api.PackageRevision, parent *PackageRevision) (*PackageRevision, error) { - ctx, span := tracer.Start(ctx, "cadEngine::UpdatePackageRevision", trace.WithAttributes()) - defer span.End() - - newRV := newObj.GetResourceVersion() - if len(newRV) == 0 { - return nil, fmt.Errorf("resourceVersion must be specified for an update") - } - - if newRV != oldObj.GetResourceVersion() { - return nil, apierrors.NewConflict(api.Resource("packagerevisions"), oldObj.GetName(), fmt.Errorf(OptimisticLockErrorMsg)) - } - - repo, err := cad.cache.OpenRepository(ctx, repositoryObj) - if err != nil { - return nil, err - } - - // Check if the PackageRevision is in the terminating state and - // and this request removes the last finalizer. - repoPkgRev := oldPackage.repoPackageRevision - pkgRevMetaNN := types.NamespacedName{ - Name: repoPkgRev.KubeObjectName(), - Namespace: repoPkgRev.KubeObjectNamespace(), - } - pkgRevMeta, err := cad.metadataStore.Get(ctx, pkgRevMetaNN) - if err != nil { - return nil, err - } - // If this is in the terminating state and we are removing the last finalizer, - // we delete the resource instead of updating it. - if pkgRevMeta.DeletionTimestamp != nil && len(newObj.Finalizers) == 0 { - if err := cad.deletePackageRevision(ctx, repo, repoPkgRev, pkgRevMeta); err != nil { - return nil, err - } - return ToPackageRevision(repoPkgRev, pkgRevMeta), nil - } - - // Validate package lifecycle. Can only update a draft. - switch lifecycle := oldObj.Spec.Lifecycle; lifecycle { - default: - return nil, fmt.Errorf("invalid original lifecycle value: %q", lifecycle) - case api.PackageRevisionLifecycleDraft, api.PackageRevisionLifecycleProposed: - // Draft or proposed can be updated. - case api.PackageRevisionLifecyclePublished, api.PackageRevisionLifecycleDeletionProposed: - // Only metadata (currently labels and annotations) and lifecycle can be updated for published packages. - if oldObj.Spec.Lifecycle != newObj.Spec.Lifecycle { - if err := oldPackage.repoPackageRevision.UpdateLifecycle(ctx, newObj.Spec.Lifecycle); err != nil { - return nil, err - } - } - - pkgRevMeta, err = cad.updatePkgRevMeta(ctx, repoPkgRev, newObj) - if err != nil { - return nil, err - } - - sent := cad.watcherManager.NotifyPackageRevisionChange(watch.Modified, repoPkgRev, pkgRevMeta) - klog.Infof("engine: sent %d for updated PackageRevision metadata %s/%s", sent, repoPkgRev.KubeObjectNamespace(), repoPkgRev.KubeObjectName()) - return ToPackageRevision(repoPkgRev, pkgRevMeta), nil - } - switch lifecycle := newObj.Spec.Lifecycle; lifecycle { - default: - return nil, fmt.Errorf("invalid desired lifecycle value: %q", lifecycle) - case api.PackageRevisionLifecycleDraft, api.PackageRevisionLifecycleProposed, api.PackageRevisionLifecyclePublished, api.PackageRevisionLifecycleDeletionProposed: - // These values are ok - } - - if isRecloneAndReplay(oldObj, newObj) { - packageConfig, err := buildPackageConfig(ctx, newObj, parent) - if err != nil { - return nil, err - } - repoPkgRev, err := cad.recloneAndReplay(ctx, repo, repositoryObj, newObj, packageConfig) - if err != nil { - return nil, err - } - - pkgRevMeta, err = cad.updatePkgRevMeta(ctx, repoPkgRev, newObj) - if err != nil { - return nil, err - } - - sent := cad.watcherManager.NotifyPackageRevisionChange(watch.Modified, repoPkgRev, pkgRevMeta) - klog.Infof("engine: sent %d for reclone and replay PackageRevision %s/%s", sent, repoPkgRev.KubeObjectNamespace(), repoPkgRev.KubeObjectName()) - return ToPackageRevision(repoPkgRev, pkgRevMeta), nil - } - - var mutations []mutation - if len(oldObj.Spec.Tasks) > len(newObj.Spec.Tasks) { - return nil, fmt.Errorf("removing tasks is not yet supported") - } - for i := range oldObj.Spec.Tasks { - oldTask := &oldObj.Spec.Tasks[i] - newTask := &newObj.Spec.Tasks[i] - if oldTask.Type != newTask.Type { - return nil, fmt.Errorf("changing task types is not yet supported") - } - } - if len(newObj.Spec.Tasks) > len(oldObj.Spec.Tasks) { - if len(newObj.Spec.Tasks) > len(oldObj.Spec.Tasks)+1 { - return nil, fmt.Errorf("can only append one task at a time") - } - - newTask := newObj.Spec.Tasks[len(newObj.Spec.Tasks)-1] - if newTask.Type != api.TaskTypeUpdate { - return nil, fmt.Errorf("appended task is type %q, must be type %q", newTask.Type, api.TaskTypeUpdate) - } - if newTask.Update == nil { - return nil, fmt.Errorf("update not set for updateTask of type %q", newTask.Type) - } - - cloneTask := findCloneTask(oldObj) - if cloneTask == nil { - return nil, fmt.Errorf("upstream source not found for package rev %q; only cloned packages can be updated", oldObj.Spec.PackageName) - } - - mutation := &updatePackageMutation{ - cloneTask: cloneTask, - updateTask: &newTask, - repoOpener: cad, - referenceResolver: cad.referenceResolver, - namespace: repositoryObj.Namespace, - pkgName: oldObj.GetName(), - } - mutations = append(mutations, mutation) - } - - // Re-render if we are making changes. - mutations = cad.conditionalAddRender(newObj, mutations) - - draft, err := repo.UpdatePackageRevision(ctx, oldPackage.repoPackageRevision) - if err != nil { - return nil, err - } - - // If any of the fields in the API that are projections from the Kptfile - // must be updated in the Kptfile as well. - kfPatchTask, created, err := createKptfilePatchTask(ctx, oldPackage.repoPackageRevision, newObj) - if err != nil { - return nil, err - } - if created { - kfPatchMutation, err := buildPatchMutation(ctx, kfPatchTask) - if err != nil { - return nil, err - } - mutations = append(mutations, kfPatchMutation) - } - - // Re-render if we are making changes. - mutations = cad.conditionalAddRender(newObj, mutations) - - // TODO: Handle the case if alongside lifecycle change, tasks are changed too. - // Update package contents only if the package is in draft state - if oldObj.Spec.Lifecycle == api.PackageRevisionLifecycleDraft { - apiResources, err := oldPackage.GetResources(ctx) - if err != nil { - return nil, fmt.Errorf("cannot get package resources: %w", err) - } - resources := repository.PackageResources{ - Contents: apiResources.Spec.Resources, - } - - if _, _, err := applyResourceMutations(ctx, draft, resources, mutations); err != nil { - return nil, err - } - } - - if err := draft.UpdateLifecycle(ctx, newObj.Spec.Lifecycle); err != nil { - return nil, err - } - - // Updates are done. - repoPkgRev, err = draft.Close(ctx) - if err != nil { - return nil, err - } - - pkgRevMeta, err = cad.updatePkgRevMeta(ctx, repoPkgRev, newObj) - if err != nil { - return nil, err - } - - sent := cad.watcherManager.NotifyPackageRevisionChange(watch.Modified, repoPkgRev, pkgRevMeta) - klog.Infof("engine: sent %d for updated PackageRevision %s/%s", sent, repoPkgRev.KubeObjectNamespace(), repoPkgRev.KubeObjectName()) - return ToPackageRevision(repoPkgRev, pkgRevMeta), nil -} - -func (cad *cadEngine) updatePkgRevMeta(ctx context.Context, repoPkgRev repository.PackageRevision, apiPkgRev *api.PackageRevision) (meta.PackageRevisionMeta, error) { - pkgRevMeta := meta.PackageRevisionMeta{ - Name: repoPkgRev.KubeObjectName(), - Namespace: repoPkgRev.KubeObjectNamespace(), - Labels: apiPkgRev.Labels, - Annotations: apiPkgRev.Annotations, - Finalizers: apiPkgRev.Finalizers, - OwnerReferences: apiPkgRev.OwnerReferences, - } - return cad.metadataStore.Update(ctx, pkgRevMeta) -} - -func createKptfilePatchTask(ctx context.Context, oldPackage repository.PackageRevision, newObj *api.PackageRevision) (*api.Task, bool, error) { - kf, err := oldPackage.GetKptfile(ctx) - if err != nil { - return nil, false, err - } - - var orgKfString string - { - var buf bytes.Buffer - d := yaml.NewEncoder(&buf) - if err := d.Encode(kf); err != nil { - return nil, false, err - } - orgKfString = buf.String() - } - - var readinessGates []kptfile.ReadinessGate - for _, rg := range newObj.Spec.ReadinessGates { - readinessGates = append(readinessGates, kptfile.ReadinessGate{ - ConditionType: rg.ConditionType, - }) - } - - var conditions []kptfile.Condition - for _, c := range newObj.Status.Conditions { - conditions = append(conditions, kptfile.Condition{ - Type: c.Type, - Status: convertStatusToKptfile(c.Status), - Reason: c.Reason, - Message: c.Message, - }) - } - - if kf.Info == nil && len(readinessGates) > 0 { - kf.Info = &kptfile.PackageInfo{} - } - if len(readinessGates) > 0 { - kf.Info.ReadinessGates = readinessGates - } - - if kf.Status == nil && len(conditions) > 0 { - kf.Status = &kptfile.Status{} - } - if len(conditions) > 0 { - kf.Status.Conditions = conditions - } - - var newKfString string - { - var buf bytes.Buffer - d := yaml.NewEncoder(&buf) - if err := d.Encode(kf); err != nil { - return nil, false, err - } - newKfString = buf.String() - } - patchSpec, err := GeneratePatch(kptfile.KptFileName, orgKfString, newKfString) - if err != nil { - return nil, false, err - } - // If patch is empty, don't create a Task. - if patchSpec.Contents == "" { - return nil, false, nil - } - - return &api.Task{ - Type: api.TaskTypePatch, - Patch: &api.PackagePatchTaskSpec{ - Patches: []api.PatchSpec{ - patchSpec, - }, - }, - }, true, nil -} - -func convertStatusToKptfile(s api.ConditionStatus) kptfile.ConditionStatus { - switch s { - case api.ConditionTrue: - return kptfile.ConditionTrue - case api.ConditionFalse: - return kptfile.ConditionFalse - case api.ConditionUnknown: - return kptfile.ConditionUnknown - default: - panic(fmt.Errorf("unknown condition status: %v", s)) - } -} - -// conditionalAddRender adds a render mutation to the end of the mutations slice if the last -// entry is not already a render mutation. -func (cad *cadEngine) conditionalAddRender(subject client.Object, mutations []mutation) []mutation { - if len(mutations) == 0 || isRenderMutation(mutations[len(mutations)-1]) { - return mutations - } - - runnerOptions := cad.runnerOptionsResolver(subject.GetNamespace()) - - return append(mutations, &renderPackageMutation{ - runnerOptions: runnerOptions, - runtime: cad.runtime, - }) -} - -func isRenderMutation(m mutation) bool { - _, isRender := m.(*renderPackageMutation) - return isRender -} - -func (cad *cadEngine) DeletePackageRevision(ctx context.Context, repositoryObj *configapi.Repository, oldPackage *PackageRevision) error { - ctx, span := tracer.Start(ctx, "cadEngine::DeletePackageRevision", trace.WithAttributes()) - defer span.End() - - repo, err := cad.cache.OpenRepository(ctx, repositoryObj) - if err != nil { - return err - } - - // We delete the PackageRev regardless of any finalizers, since it - // will always have the same finalizers as the PackageRevision. This - // will put the PackageRev, and therefore the PackageRevision in the - // terminating state. - // But we only delete the PackageRevision from the repo once all finalizers - // have been removed. - namespacedName := types.NamespacedName{ - Name: oldPackage.repoPackageRevision.KubeObjectName(), - Namespace: oldPackage.repoPackageRevision.KubeObjectNamespace(), - } - pkgRevMeta, err := cad.metadataStore.Delete(ctx, namespacedName, false) - if err != nil { - return err - } - - if len(pkgRevMeta.Finalizers) > 0 { - klog.Infof("PackageRevision %s deleted, but still have finalizers: %s", oldPackage.KubeObjectName(), strings.Join(pkgRevMeta.Finalizers, ",")) - sent := cad.watcherManager.NotifyPackageRevisionChange(watch.Modified, oldPackage.repoPackageRevision, oldPackage.packageRevisionMeta) - klog.Infof("engine: sent %d modified for deleted PackageRevision %s/%s with finalizers", sent, oldPackage.repoPackageRevision.KubeObjectNamespace(), oldPackage.KubeObjectName()) - return nil - } - klog.Infof("PackageRevision %s deleted for real since no finalizers", oldPackage.KubeObjectName()) - - return cad.deletePackageRevision(ctx, repo, oldPackage.repoPackageRevision, oldPackage.packageRevisionMeta) -} - -func (cad *cadEngine) deletePackageRevision(ctx context.Context, repo repository.Repository, repoPkgRev repository.PackageRevision, pkgRevMeta meta.PackageRevisionMeta) error { - ctx, span := tracer.Start(ctx, "cadEngine::deletePackageRevision", trace.WithAttributes()) - defer span.End() - - if err := repo.DeletePackageRevision(ctx, repoPkgRev); err != nil { - return err - } - - nn := types.NamespacedName{ - Name: pkgRevMeta.Name, - Namespace: pkgRevMeta.Namespace, - } - if _, err := cad.metadataStore.Delete(ctx, nn, true); err != nil { - // If this fails, the CR will be cleaned up by the background job. - if !apierrors.IsNotFound(err) { - klog.Warningf("Error deleting PkgRevMeta %s: %v", nn.String(), err) - } - } - - sent := cad.watcherManager.NotifyPackageRevisionChange(watch.Deleted, repoPkgRev, pkgRevMeta) - klog.Infof("engine: sent %d for deleted PackageRevision %s/%s", sent, repoPkgRev.KubeObjectNamespace(), repoPkgRev.KubeObjectName()) - return nil -} - -func (cad *cadEngine) ListPackages(ctx context.Context, repositorySpec *configapi.Repository, filter repository.ListPackageFilter) ([]*Package, error) { - ctx, span := tracer.Start(ctx, "cadEngine::ListPackages", trace.WithAttributes()) - defer span.End() - - repo, err := cad.cache.OpenRepository(ctx, repositorySpec) - if err != nil { - return nil, err - } - - pkgs, err := repo.ListPackages(ctx, filter) - if err != nil { - return nil, err - } - var packages []*Package - for _, p := range pkgs { - packages = append(packages, &Package{ - repoPackage: p, - }) - } - - return packages, nil -} - -func (cad *cadEngine) CreatePackage(ctx context.Context, repositoryObj *configapi.Repository, obj *api.Package) (*Package, error) { - ctx, span := tracer.Start(ctx, "cadEngine::CreatePackage", trace.WithAttributes()) - defer span.End() - - repo, err := cad.cache.OpenRepository(ctx, repositoryObj) - if err != nil { - return nil, err - } - pkg, err := repo.CreatePackage(ctx, obj) - if err != nil { - return nil, err - } - - return &Package{ - repoPackage: pkg, - }, nil -} - -func (cad *cadEngine) UpdatePackage(ctx context.Context, repositoryObj *configapi.Repository, oldPackage *Package, oldObj, newObj *api.Package) (*Package, error) { - ctx, span := tracer.Start(ctx, "cadEngine::UpdatePackage", trace.WithAttributes()) - defer span.End() - - // TODO - var pkg *Package - return pkg, fmt.Errorf("Updating packages is not yet supported") -} - -func (cad *cadEngine) DeletePackage(ctx context.Context, repositoryObj *configapi.Repository, oldPackage *Package) error { - ctx, span := tracer.Start(ctx, "cadEngine::DeletePackage", trace.WithAttributes()) - defer span.End() - - repo, err := cad.cache.OpenRepository(ctx, repositoryObj) - if err != nil { - return err - } - - if err := repo.DeletePackage(ctx, oldPackage.repoPackage); err != nil { - return err - } - - return nil -} - -func (cad *cadEngine) UpdatePackageResources(ctx context.Context, repositoryObj *configapi.Repository, oldPackage *PackageRevision, old, new *api.PackageRevisionResources) (*PackageRevision, *api.RenderStatus, error) { - ctx, span := tracer.Start(ctx, "cadEngine::UpdatePackageResources", trace.WithAttributes()) - defer span.End() - - rev, err := oldPackage.repoPackageRevision.GetPackageRevision(ctx) - if err != nil { - return nil, nil, err - } - - newRV := new.GetResourceVersion() - if len(newRV) == 0 { - return nil, nil, fmt.Errorf("resourceVersion must be specified for an update") - } - - if newRV != old.GetResourceVersion() { - return nil, nil, apierrors.NewConflict(api.Resource("packagerevisionresources"), old.GetName(), fmt.Errorf(OptimisticLockErrorMsg)) - } - - // Validate package lifecycle. Can only update a draft. - switch lifecycle := rev.Spec.Lifecycle; lifecycle { - default: - return nil, nil, fmt.Errorf("invalid original lifecycle value: %q", lifecycle) - case api.PackageRevisionLifecycleDraft: - // Only drafts can be updated. - case api.PackageRevisionLifecycleProposed, api.PackageRevisionLifecyclePublished, api.PackageRevisionLifecycleDeletionProposed: - // TODO: generate errors that can be translated to correct HTTP responses - return nil, nil, fmt.Errorf("cannot update a package revision with lifecycle value %q; package must be Draft", lifecycle) - } - - repo, err := cad.cache.OpenRepository(ctx, repositoryObj) - if err != nil { - return nil, nil, err - } - draft, err := repo.UpdatePackageRevision(ctx, oldPackage.repoPackageRevision) - if err != nil { - return nil, nil, err - } - - runnerOptions := cad.runnerOptionsResolver(old.GetNamespace()) - - mutations := []mutation{ - &mutationReplaceResources{ - newResources: new, - oldResources: old, - }, - } - prevResources, err := oldPackage.repoPackageRevision.GetResources(ctx) - if err != nil { - return nil, nil, fmt.Errorf("cannot get package resources: %w", err) - } - resources := repository.PackageResources{ - Contents: prevResources.Spec.Resources, - } - appliedResources, _, err := applyResourceMutations(ctx, draft, resources, mutations) - if err != nil { - return nil, nil, err - } - - // render the package - // Render failure will not fail the overall API operation. - // The render error and result is captured as part of renderStatus above - // and is returned in packageresourceresources API's status field. We continue with - // saving the non-rendered resources to avoid losing user's changes. - // and supress this err. - _, renderStatus, _ := applyResourceMutations(ctx, - draft, - appliedResources, - []mutation{&renderPackageMutation{ - runnerOptions: runnerOptions, - runtime: cad.runtime, - }}) - - // No lifecycle change when updating package resources; updates are done. - repoPkgRev, err := draft.Close(ctx) - if err != nil { - return nil, renderStatus, err - } - return &PackageRevision{ - repoPackageRevision: repoPkgRev, - }, renderStatus, nil -} - -// applyResourceMutations mutates the resources and returns the most recent renderResult. -func applyResourceMutations(ctx context.Context, draft repository.PackageDraft, baseResources repository.PackageResources, mutations []mutation) (applied repository.PackageResources, renderStatus *api.RenderStatus, err error) { - var lastApplied mutation - for _, m := range mutations { - updatedResources, taskResult, err := m.Apply(ctx, baseResources) - if taskResult == nil && err == nil { - // a nil taskResult means nothing changed - continue - } - - var task *api.Task - if taskResult != nil { - task = taskResult.Task - } - if taskResult != nil && task.Type == api.TaskTypeEval { - renderStatus = taskResult.RenderStatus - } - if err != nil { - return updatedResources, renderStatus, err - } - - // if the last applied mutation was a render mutation, and so is this one, skip it - if lastApplied != nil && isRenderMutation(m) && isRenderMutation(lastApplied) { - continue - } - lastApplied = m - - if err := draft.UpdateResources(ctx, &api.PackageRevisionResources{ - Spec: api.PackageRevisionResourcesSpec{ - Resources: updatedResources.Contents, - }, - }, task); err != nil { - return updatedResources, renderStatus, err - } - baseResources = updatedResources - applied = updatedResources - } - - return applied, renderStatus, nil -} - -func (cad *cadEngine) ListFunctions(ctx context.Context, repositoryObj *configapi.Repository) ([]*Function, error) { - ctx, span := tracer.Start(ctx, "cadEngine::ListFunctions", trace.WithAttributes()) - defer span.End() - - repo, err := cad.cache.OpenRepository(ctx, repositoryObj) - if err != nil { - return nil, err - } - - fns, err := repo.ListFunctions(ctx) - if err != nil { - return nil, err - } - - var functions []*Function - for _, f := range fns { - functions = append(functions, &Function{ - RepoFunction: f, - }) - } - - return functions, nil -} - -type updatePackageMutation struct { - cloneTask *api.Task - updateTask *api.Task - repoOpener RepositoryOpener - referenceResolver ReferenceResolver - namespace string - pkgName string -} - -func (m *updatePackageMutation) Apply(ctx context.Context, resources repository.PackageResources) (repository.PackageResources, *api.TaskResult, error) { - ctx, span := tracer.Start(ctx, "updatePackageMutation::Apply", trace.WithAttributes()) - defer span.End() - - currUpstreamPkgRef, err := m.currUpstream() - if err != nil { - return repository.PackageResources{}, nil, err - } - - targetUpstream := m.updateTask.Update.Upstream - if targetUpstream.Type == api.RepositoryTypeGit || targetUpstream.Type == api.RepositoryTypeOCI { - return repository.PackageResources{}, nil, fmt.Errorf("update is not supported for non-porch upstream packages") - } - - originalResources, err := (&PackageFetcher{ - repoOpener: m.repoOpener, - referenceResolver: m.referenceResolver, - }).FetchResources(ctx, currUpstreamPkgRef, m.namespace) - if err != nil { - return repository.PackageResources{}, nil, fmt.Errorf("error fetching the resources for package %s with ref %+v", - m.pkgName, *currUpstreamPkgRef) - } - - upstreamRevision, err := (&PackageFetcher{ - repoOpener: m.repoOpener, - referenceResolver: m.referenceResolver, - }).FetchRevision(ctx, targetUpstream.UpstreamRef, m.namespace) - if err != nil { - return repository.PackageResources{}, nil, fmt.Errorf("error fetching revision for target upstream %s", targetUpstream.UpstreamRef.Name) - } - upstreamResources, err := upstreamRevision.GetResources(ctx) - if err != nil { - return repository.PackageResources{}, nil, fmt.Errorf("error fetching resources for target upstream %s", targetUpstream.UpstreamRef.Name) - } - - klog.Infof("performing pkg upgrade operation for pkg %s resource counts local[%d] original[%d] upstream[%d]", - m.pkgName, len(resources.Contents), len(originalResources.Spec.Resources), len(upstreamResources.Spec.Resources)) - - // May be have packageUpdater part of engine to make it easy for testing ? - updatedResources, err := (&defaultPackageUpdater{}).Update(ctx, - resources, - repository.PackageResources{ - Contents: originalResources.Spec.Resources, - }, - repository.PackageResources{ - Contents: upstreamResources.Spec.Resources, - }) - if err != nil { - return repository.PackageResources{}, nil, fmt.Errorf("error updating the package to revision %s", targetUpstream.UpstreamRef.Name) - } - - newUpstream, newUpstreamLock, err := upstreamRevision.GetLock() - if err != nil { - return repository.PackageResources{}, nil, fmt.Errorf("error fetching the resources for package revisions %s", targetUpstream.UpstreamRef.Name) - } - if err := kpt.UpdateKptfileUpstream("", updatedResources.Contents, newUpstream, newUpstreamLock); err != nil { - return repository.PackageResources{}, nil, fmt.Errorf("failed to apply upstream lock to package %q: %w", m.pkgName, err) - } - - // ensure merge-key comment is added to newly added resources. - result, err := ensureMergeKey(ctx, updatedResources) - if err != nil { - klog.Infof("failed to add merge key comments: %v", err) - } - return result, &api.TaskResult{Task: m.updateTask}, nil -} - -// Currently assumption is that downstream packages will be forked from a porch package. -// As per current implementation, upstream package ref is stored in a new update task but this may -// change so the logic of figuring out current upstream will live in this function. -func (m *updatePackageMutation) currUpstream() (*api.PackageRevisionRef, error) { - if m.cloneTask == nil || m.cloneTask.Clone == nil { - return nil, fmt.Errorf("package %s does not have original upstream info", m.pkgName) - } - upstream := m.cloneTask.Clone.Upstream - if upstream.Type == api.RepositoryTypeGit || upstream.Type == api.RepositoryTypeOCI { - return nil, fmt.Errorf("upstream package must be porch native package. Found it to be %s", upstream.Type) - } - return upstream.UpstreamRef, nil -} - -func findCloneTask(pr *api.PackageRevision) *api.Task { - if len(pr.Spec.Tasks) == 0 { - return nil - } - firstTask := pr.Spec.Tasks[0] - if firstTask.Type == api.TaskTypeClone { - return &firstTask - } - return nil -} - -func writeResourcesToDirectory(dir string, resources repository.PackageResources) error { - for k, v := range resources.Contents { - p := filepath.Join(dir, k) - dir := filepath.Dir(p) - if err := os.MkdirAll(dir, 0755); err != nil { - return fmt.Errorf("failed to create directory %q: %w", dir, err) - } - if err := os.WriteFile(p, []byte(v), 0644); err != nil { - return fmt.Errorf("failed to write file %q: %w", dir, err) - } - } - return nil -} - -func loadResourcesFromDirectory(dir string) (repository.PackageResources, error) { - // TODO: return abstraction instead of loading everything - result := repository.PackageResources{ - Contents: map[string]string{}, - } - if err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error { - if err != nil { - return err - } - if d.IsDir() { - return nil - } - rel, err := filepath.Rel(dir, path) - if err != nil { - return fmt.Errorf("cannot compute relative path %q, %q, %w", dir, path, err) - } - - contents, err := os.ReadFile(path) - if err != nil { - return fmt.Errorf("cannot read file %q: %w", dir, err) - } - result.Contents[rel] = string(contents) - return nil - }); err != nil { - return repository.PackageResources{}, err - } - - return result, nil -} - -type mutationReplaceResources struct { - newResources *api.PackageRevisionResources - oldResources *api.PackageRevisionResources -} - -func (m *mutationReplaceResources) Apply(ctx context.Context, resources repository.PackageResources) (repository.PackageResources, *api.TaskResult, error) { - ctx, span := tracer.Start(ctx, "mutationReplaceResources::Apply", trace.WithAttributes()) - defer span.End() - - patch := &api.PackagePatchTaskSpec{} - - old := resources.Contents - new, err := healConfig(old, m.newResources.Spec.Resources) - if err != nil { - return repository.PackageResources{}, nil, fmt.Errorf("failed to heal resources: %w", err) - } - - for k, newV := range new { - oldV, ok := old[k] - // New config or changed config - if !ok { - patchSpec := api.PatchSpec{ - File: k, - PatchType: api.PatchTypeCreateFile, - Contents: newV, - } - patch.Patches = append(patch.Patches, patchSpec) - } else if newV != oldV { - patchSpec, err := GeneratePatch(k, oldV, newV) - if err != nil { - return repository.PackageResources{}, nil, fmt.Errorf("error generating patch: %w", err) - } - if patchSpec.Contents == "" { - continue - } - patch.Patches = append(patch.Patches, patchSpec) - } - } - for k := range old { - // Deleted config - if _, ok := new[k]; !ok { - patchSpec := api.PatchSpec{ - File: k, - PatchType: api.PatchTypeDeleteFile, - } - patch.Patches = append(patch.Patches, patchSpec) - } - } - // If patch is empty, don't create a Task. - var taskResult *api.TaskResult - if len(patch.Patches) > 0 { - taskResult = &api.TaskResult{ - Task: &api.Task{ - Type: api.TaskTypePatch, - Patch: patch, - }, - } - } - return repository.PackageResources{Contents: new}, taskResult, nil -} - -func healConfig(old, new map[string]string) (map[string]string, error) { - // Copy comments from old config to new - oldResources, err := (&packageReader{ - input: repository.PackageResources{Contents: old}, - extra: map[string]string{}, - }).Read() - if err != nil { - return nil, fmt.Errorf("failed to read old packge resources: %w", err) - } - - var filter kio.FilterFunc = func(r []*yaml.RNode) ([]*yaml.RNode, error) { - for _, n := range r { - for _, original := range oldResources { - if n.GetNamespace() == original.GetNamespace() && - n.GetName() == original.GetName() && - n.GetApiVersion() == original.GetApiVersion() && - n.GetKind() == original.GetKind() { - comments.CopyComments(original, n) - } - } - } - return r, nil - } - - out := &packageWriter{ - output: repository.PackageResources{ - Contents: map[string]string{}, - }, - } - - extra := map[string]string{} - - if err := (kio.Pipeline{ - Inputs: []kio.Reader{&packageReader{ - input: repository.PackageResources{Contents: new}, - extra: extra, - }}, - Filters: []kio.Filter{filter}, - Outputs: []kio.Writer{out}, - ContinueOnEmptyResult: true, - }).Execute(); err != nil { - return nil, err - } - - healed := out.output.Contents - - for k, v := range extra { - healed[k] = v - } - - return healed, nil -} - -// isRecloneAndReplay determines if an update should be handled using reclone-and-replay semantics. -// We detect this by checking if both old and new versions start by cloning a package, but the version has changed. -// We may expand this scope in future. -func isRecloneAndReplay(oldObj, newObj *api.PackageRevision) bool { - oldTasks := oldObj.Spec.Tasks - newTasks := newObj.Spec.Tasks - if len(oldTasks) == 0 || len(newTasks) == 0 { - return false - } - - if oldTasks[0].Type != api.TaskTypeClone || newTasks[0].Type != api.TaskTypeClone { - return false - } - - if reflect.DeepEqual(oldTasks[0], newTasks[0]) { - return false - } - return true -} - -// recloneAndReplay performs an update by recloning the upstream package and replaying all tasks. -// This is more like a git rebase operation than the "classic" kpt update algorithm, which is more like a git merge. -func (cad *cadEngine) recloneAndReplay(ctx context.Context, repo repository.Repository, repositoryObj *configapi.Repository, newObj *api.PackageRevision, packageConfig *builtins.PackageConfig) (repository.PackageRevision, error) { - ctx, span := tracer.Start(ctx, "cadEngine::recloneAndReplay", trace.WithAttributes()) - defer span.End() - - // For reclone and replay, we create a new package every time - // the version should be in newObj so we will overwrite. - draft, err := repo.CreatePackageRevision(ctx, newObj) - if err != nil { - return nil, err - } - - if err := cad.applyTasks(ctx, draft, repositoryObj, newObj, packageConfig); err != nil { - return nil, err - } - - if err := draft.UpdateLifecycle(ctx, newObj.Spec.Lifecycle); err != nil { - return nil, err - } - - return draft.Close(ctx) -} - -// ExtractContextConfigMap returns the package-context configmap, if found -func ExtractContextConfigMap(resources map[string]string) (*unstructured.Unstructured, error) { - unstructureds, err := objects.Parser{}.AsUnstructureds(resources) - if err != nil { - return nil, err - } - - var matches []*unstructured.Unstructured - for _, o := range unstructureds { - configMapGK := schema.GroupKind{Kind: "ConfigMap"} - if o.GroupVersionKind().GroupKind() == configMapGK { - if o.GetName() == builtins.PkgContextName { - matches = append(matches, o) - } - } - } - if len(matches) == 0 { - return nil, nil - } - - if len(matches) > 1 { - return nil, fmt.Errorf("found multiple configmaps matching name %q", builtins.PkgContextFile) - } - - return matches[0], nil -} diff --git a/porch/pkg/engine/engine_test.go b/porch/pkg/engine/engine_test.go deleted file mode 100644 index a2fa222429..0000000000 --- a/porch/pkg/engine/engine_test.go +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "strings" - "testing" - - kptfile "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/engine/fake" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/google/go-cmp/cmp" -) - -func TestSomething(t *testing.T) { - testCases := map[string]struct { - repoPkgRev repository.PackageRevision - newApiPkgRev *api.PackageRevision - hasPatch bool - patch api.PatchSpec - }{ - "no gates or conditions": { - repoPkgRev: &fake.PackageRevision{ - Kptfile: kptfile.KptFile{}, - }, - newApiPkgRev: &api.PackageRevision{ - Spec: api.PackageRevisionSpec{}, - }, - hasPatch: false, - }, - "first gate and condition added": { - repoPkgRev: &fake.PackageRevision{ - Kptfile: kptfile.KptFile{}, - }, - newApiPkgRev: &api.PackageRevision{ - Spec: api.PackageRevisionSpec{ - ReadinessGates: []api.ReadinessGate{ - { - ConditionType: "foo", - }, - }, - }, - Status: api.PackageRevisionStatus{ - Conditions: []api.Condition{ - { - Type: "foo", - Status: api.ConditionTrue, - }, - }, - }, - }, - hasPatch: true, - patch: api.PatchSpec{ - File: kptfile.KptFileName, - Contents: strings.TrimSpace(` ---- Kptfile -+++ Kptfile -@@ -1 +1,7 @@ --{} -+info: -+ readinessGates: -+ - conditionType: foo -+status: -+ conditions: -+ - type: foo -+ status: "True" -`) + "\n", - PatchType: api.PatchTypePatchFile, - }, - }, - "additional readinessGates and conditions added": { - repoPkgRev: &fake.PackageRevision{ - Kptfile: kptfile.KptFile{ - Info: &kptfile.PackageInfo{ - ReadinessGates: []kptfile.ReadinessGate{ - { - ConditionType: "foo", - }, - }, - }, - Status: &kptfile.Status{ - Conditions: []kptfile.Condition{ - { - Type: "foo", - Status: kptfile.ConditionTrue, - }, - }, - }, - }, - }, - newApiPkgRev: &api.PackageRevision{ - Spec: api.PackageRevisionSpec{ - ReadinessGates: []api.ReadinessGate{ - { - ConditionType: "foo", - }, - { - ConditionType: "bar", - }, - }, - }, - Status: api.PackageRevisionStatus{ - Conditions: []api.Condition{ - { - Type: "foo", - Status: api.ConditionTrue, - Reason: "reason", - Message: "message", - }, - { - Type: "bar", - Status: api.ConditionFalse, - Reason: "reason", - Message: "message", - }, - }, - }, - }, - hasPatch: true, - patch: api.PatchSpec{ - File: kptfile.KptFileName, - Contents: strings.TrimSpace(` ---- Kptfile -+++ Kptfile -@@ -1,7 +1,14 @@ - info: - readinessGates: - - conditionType: foo -+ - conditionType: bar - status: - conditions: - - type: foo - status: "True" -+ reason: reason -+ message: message -+ - type: bar -+ status: "False" -+ reason: reason -+ message: message -`) + "\n", - PatchType: api.PatchTypePatchFile, - }, - }, - "no changes": { - repoPkgRev: &fake.PackageRevision{ - Kptfile: kptfile.KptFile{ - Info: &kptfile.PackageInfo{ - ReadinessGates: []kptfile.ReadinessGate{ - { - ConditionType: "foo", - }, - { - ConditionType: "bar", - }, - }, - }, - Status: &kptfile.Status{ - Conditions: []kptfile.Condition{ - { - Type: "foo", - Status: kptfile.ConditionTrue, - Reason: "reason", - Message: "message", - }, - { - Type: "bar", - Status: kptfile.ConditionFalse, - Reason: "reason", - Message: "message", - }, - }, - }, - }, - }, - newApiPkgRev: &api.PackageRevision{ - Spec: api.PackageRevisionSpec{ - ReadinessGates: []api.ReadinessGate{ - { - ConditionType: "foo", - }, - { - ConditionType: "bar", - }, - }, - }, - Status: api.PackageRevisionStatus{ - Conditions: []api.Condition{ - { - Type: "foo", - Status: api.ConditionTrue, - Reason: "reason", - Message: "message", - }, - { - Type: "bar", - Status: api.ConditionFalse, - Reason: "reason", - Message: "message", - }, - }, - }, - }, - hasPatch: false, - }, - "readinessGates and conditions removed": { - repoPkgRev: &fake.PackageRevision{ - Kptfile: kptfile.KptFile{ - Info: &kptfile.PackageInfo{ - ReadinessGates: []kptfile.ReadinessGate{ - { - ConditionType: "foo", - }, - { - ConditionType: "bar", - }, - }, - }, - Status: &kptfile.Status{ - Conditions: []kptfile.Condition{ - { - Type: "foo", - Status: kptfile.ConditionTrue, - Reason: "reason", - Message: "message", - }, - { - Type: "bar", - Status: kptfile.ConditionFalse, - Reason: "reason", - Message: "message", - }, - }, - }, - }, - }, - newApiPkgRev: &api.PackageRevision{ - Spec: api.PackageRevisionSpec{ - ReadinessGates: []api.ReadinessGate{ - { - ConditionType: "foo", - }, - }, - }, - Status: api.PackageRevisionStatus{ - Conditions: []api.Condition{ - { - Type: "foo", - Status: api.ConditionTrue, - }, - }, - }, - }, - hasPatch: true, - patch: api.PatchSpec{ - File: kptfile.KptFileName, - Contents: strings.TrimSpace(` ---- Kptfile -+++ Kptfile -@@ -1,14 +1,7 @@ - info: - readinessGates: - - conditionType: foo -- - conditionType: bar - status: - conditions: - - type: foo - status: "True" -- reason: reason -- message: message -- - type: bar -- status: "False" -- reason: reason -- message: message -`) + "\n", - PatchType: api.PatchTypePatchFile, - }, - }, - } - - for tn := range testCases { - tc := testCases[tn] - t.Run(tn, func(t *testing.T) { - task, hasPatch, err := createKptfilePatchTask(context.Background(), tc.repoPkgRev, tc.newApiPkgRev) - if err != nil { - t.Fatal(err) - } - - if tc.hasPatch && !hasPatch { - t.Errorf("expected patch, but didn't get one") - } - if !tc.hasPatch { - if hasPatch { - t.Errorf("expected no patch, but got one") - } - return - } - - if diff := cmp.Diff(tc.patch, task.Patch.Patches[0]); diff != "" { - t.Errorf("Unexpected result (-want, +got): %s", diff) - } - }) - } -} diff --git a/porch/pkg/engine/environment.go b/porch/pkg/engine/environment.go deleted file mode 100644 index ce6ed525ea..0000000000 --- a/porch/pkg/engine/environment.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" -) - -type Object interface { - metav1.Object - runtime.Object -} - -type ReferenceResolver interface { - ResolveReference(ctx context.Context, namespace, name string, result Object) error -} diff --git a/porch/pkg/engine/eval.go b/porch/pkg/engine/eval.go deleted file mode 100644 index 263039d64b..0000000000 --- a/porch/pkg/engine/eval.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "fmt" - - "github.com/GoogleContainerTools/kpt/internal/fnruntime" - v1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/pkg/fn" - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "go.opentelemetry.io/otel/trace" - "sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil" - "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -type evalFunctionMutation struct { - runtime fn.FunctionRuntime - runnerOptions fnruntime.RunnerOptions - task *api.Task -} - -func (m *evalFunctionMutation) Apply(ctx context.Context, resources repository.PackageResources) (repository.PackageResources, *api.TaskResult, error) { - ctx, span := tracer.Start(ctx, "evalFunctionMutation::Apply", trace.WithAttributes()) - defer span.End() - - e := m.task.Eval - - function := v1.Function{ - Image: e.Image, - } - if function.Image != "" && m.runnerOptions.ResolveToImage != nil { - img, err := m.runnerOptions.ResolveToImage(ctx, function.Image) - if err != nil { - return repository.PackageResources{}, nil, err - } - function.Image = img - } - - // TODO: Apply should accept filesystem instead of PackageResources - - runner, err := m.runtime.GetRunner(ctx, &function) - if err != nil { - return repository.PackageResources{}, nil, fmt.Errorf("failed to create function runner: %w", err) - } - - var functionConfig *yaml.RNode - if m.task.Eval.ConfigMap != nil { - if cm, err := fnruntime.NewConfigMap(m.task.Eval.ConfigMap); err != nil { - return repository.PackageResources{}, nil, fmt.Errorf("failed to create function config: %w", err) - } else { - functionConfig = cm - } - } else if len(m.task.Eval.Config.Raw) != 0 { - // raw is JSON (we expect), but we take advantage of the fact that YAML is a superset of JSON - config, err := yaml.Parse(string(m.task.Eval.Config.Raw)) - if err != nil { - return repository.PackageResources{}, nil, fmt.Errorf("error parsing function config: %w", err) - } - functionConfig = config - } - - ff := &runtimeutil.FunctionFilter{ - Run: runner.Run, - FunctionConfig: functionConfig, - Results: &yaml.RNode{}, - } - - pr := &packageReader{ - input: resources, - extra: map[string]string{}, - } - - // r := &kio.LocalPackageReader{ - // PackagePath: "/", - // IncludeSubpackages: true, - // FileSystem: filesys.FileSystemOrOnDisk{FileSystem: fs}, - // WrapBareSeqNode: true, - // } - - result := repository.PackageResources{ - Contents: map[string]string{}, - } - - pipeline := kio.Pipeline{ - Inputs: []kio.Reader{pr}, - Filters: []kio.Filter{ff}, - Outputs: []kio.Writer{&packageWriter{ - output: result, - }}, - } - - if err := pipeline.Execute(); err != nil { - return repository.PackageResources{}, nil, fmt.Errorf("failed to evaluate function: %w", err) - } - - // Return extras. TODO: Apply should accept FS. - for k, v := range pr.extra { - result.Contents[k] = v - } - - return result, &api.TaskResult{Task: m.task}, nil -} diff --git a/porch/pkg/engine/fake/packagerevision.go b/porch/pkg/engine/fake/packagerevision.go deleted file mode 100644 index 5f49931d42..0000000000 --- a/porch/pkg/engine/fake/packagerevision.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2022 The kpt 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. - -package fake - -import ( - "context" - - kptfile "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "k8s.io/apimachinery/pkg/types" -) - -// Implementation of the repository.PackageRevision interface for testing. -type PackageRevision struct { - Name string - Namespace string - Uid types.UID - PackageRevisionKey repository.PackageRevisionKey - PackageLifecycle v1alpha1.PackageRevisionLifecycle - PackageRevision *v1alpha1.PackageRevision - Resources *v1alpha1.PackageRevisionResources - Kptfile kptfile.KptFile -} - -func (pr *PackageRevision) CachedIdentifier() repository.CachedIdentifier { - return repository.CachedIdentifier{Key: pr.Key().String(), Version: pr.Key().Revision} -} - -func (pr *PackageRevision) KubeObjectName() string { - return pr.Name -} - -func (pr *PackageRevision) KubeObjectNamespace() string { - return pr.Namespace -} - -func (pr *PackageRevision) UID() types.UID { - return pr.Uid -} - -func (pr *PackageRevision) ResourceVersion() string { - return pr.PackageRevision.ResourceVersion -} - -func (pr *PackageRevision) Key() repository.PackageRevisionKey { - return pr.PackageRevisionKey -} - -func (pr *PackageRevision) Lifecycle() v1alpha1.PackageRevisionLifecycle { - return pr.PackageLifecycle -} - -func (pr *PackageRevision) GetPackageRevision(context.Context) (*v1alpha1.PackageRevision, error) { - return pr.PackageRevision, nil -} - -func (f *PackageRevision) GetResources(context.Context) (*v1alpha1.PackageRevisionResources, error) { - return f.Resources, nil -} - -func (f *PackageRevision) GetKptfile(ctx context.Context) (kptfile.KptFile, error) { - return f.Kptfile, nil -} - -func (f *PackageRevision) GetUpstreamLock(context.Context) (kptfile.Upstream, kptfile.UpstreamLock, error) { - return *f.Kptfile.Upstream, *f.Kptfile.UpstreamLock, nil -} - -func (f *PackageRevision) GetLock() (kptfile.Upstream, kptfile.UpstreamLock, error) { - return *f.Kptfile.Upstream, *f.Kptfile.UpstreamLock, nil -} - -func (f *PackageRevision) UpdateLifecycle(context.Context, v1alpha1.PackageRevisionLifecycle) error { - return nil -} diff --git a/porch/pkg/engine/fake/repository.go b/porch/pkg/engine/fake/repository.go deleted file mode 100644 index cd2ba340a6..0000000000 --- a/porch/pkg/engine/fake/repository.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2022 The kpt 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. - -package fake - -import ( - "context" - - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" -) - -// Implementation of the repository.Repository interface for testing. -// TODO(mortent): Implement stub functionality for all functions from the interface. -type Repository struct { - PackageRevisions []repository.PackageRevision - Packages []repository.Package -} - -var _ repository.Repository = &Repository{} - -func (r *Repository) Close() error { - return nil -} - -func (r *Repository) Version(ctx context.Context) (string, error) { - return "foo", nil -} - -func (r *Repository) ListPackageRevisions(_ context.Context, filter repository.ListPackageRevisionFilter) ([]repository.PackageRevision, error) { - var revs []repository.PackageRevision - for _, rev := range r.PackageRevisions { - if filter.KubeObjectName != "" && filter.KubeObjectName == rev.KubeObjectName() { - revs = append(revs, rev) - } - if filter.Package != "" && filter.Package == rev.Key().Package { - revs = append(revs, rev) - } - if filter.Revision != "" && filter.Revision == rev.Key().Revision { - revs = append(revs, rev) - } - if filter.WorkspaceName != "" && filter.WorkspaceName == rev.Key().WorkspaceName { - revs = append(revs, rev) - } - } - return revs, nil -} - -func (r *Repository) CreatePackageRevision(_ context.Context, pr *v1alpha1.PackageRevision) (repository.PackageDraft, error) { - return nil, nil -} - -func (r *Repository) DeletePackageRevision(context.Context, repository.PackageRevision) error { - return nil -} - -func (r *Repository) UpdatePackageRevision(context.Context, repository.PackageRevision) (repository.PackageDraft, error) { - return nil, nil -} - -func (r *Repository) ListPackages(context.Context, repository.ListPackageFilter) ([]repository.Package, error) { - return r.Packages, nil -} - -func (r *Repository) CreatePackage(_ context.Context, pr *v1alpha1.Package) (repository.Package, error) { - return nil, nil -} - -func (r *Repository) DeletePackage(_ context.Context, pr repository.Package) error { - return nil -} diff --git a/porch/pkg/engine/grpcruntime.go b/porch/pkg/engine/grpcruntime.go deleted file mode 100644 index 66ccd76f03..0000000000 --- a/porch/pkg/engine/grpcruntime.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "fmt" - "io" - - v1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/pkg/fn" - "github.com/GoogleContainerTools/kpt/porch/func/evaluator" - "github.com/GoogleContainerTools/kpt/porch/pkg/kpt" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - "k8s.io/klog/v2" -) - -type grpcRuntime struct { - cc *grpc.ClientConn - client evaluator.FunctionEvaluatorClient -} - -func newGRPCFunctionRuntime(address string) (*grpcRuntime, error) { - if address == "" { - return nil, fmt.Errorf("address is required to instantiate gRPC function runtime") - } - - klog.Infof("Dialing grpc function runner %q", address) - - cc, err := grpc.Dial(address, grpc.WithTransportCredentials(insecure.NewCredentials())) - if err != nil { - return nil, fmt.Errorf("failed to dial grpc function evaluator: %w", err) - } - - return &grpcRuntime{ - cc: cc, - client: evaluator.NewFunctionEvaluatorClient(cc), - }, err -} - -var _ kpt.FunctionRuntime = &grpcRuntime{} - -func (gr *grpcRuntime) GetRunner(ctx context.Context, fn *v1.Function) (fn.FunctionRunner, error) { - // TODO: Check if the function is actually available? - return &grpcRunner{ - ctx: ctx, - client: gr.client, - image: fn.Image, - }, nil -} - -func (gr *grpcRuntime) Close() error { - var err error - if gr.cc != nil { - if err = gr.cc.Close(); err != nil { - klog.Warningf("Failed to close grpc client connection: %v", err) - } - gr.cc = nil - } - return err -} - -type grpcRunner struct { - ctx context.Context - client evaluator.FunctionEvaluatorClient - image string -} - -var _ fn.FunctionRunner = &grpcRunner{} - -func (gr *grpcRunner) Run(r io.Reader, w io.Writer) error { - in, err := io.ReadAll(r) - if err != nil { - return fmt.Errorf("failed to read function runner input: %w", err) - } - - res, err := gr.client.EvaluateFunction(gr.ctx, &evaluator.EvaluateFunctionRequest{ - ResourceList: in, - Image: gr.image, - }) - if err != nil { - return fmt.Errorf("func eval %q failed: %w", gr.image, err) - } - if _, err := w.Write(res.ResourceList); err != nil { - return fmt.Errorf("failed to write function runner output: %w", err) - } - return nil -} diff --git a/porch/pkg/engine/init.go b/porch/pkg/engine/init.go deleted file mode 100644 index 415f72d3cf..0000000000 --- a/porch/pkg/engine/init.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "fmt" - - "github.com/GoogleContainerTools/kpt/pkg/kptpkg" - "github.com/GoogleContainerTools/kpt/pkg/printer" - "github.com/GoogleContainerTools/kpt/pkg/printer/fake" - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "go.opentelemetry.io/otel/trace" - "sigs.k8s.io/kustomize/kyaml/filesys" -) - -type initPackageMutation struct { - kptpkg.DefaultInitializer - name string - task *api.Task -} - -var _ mutation = &initPackageMutation{} - -func (m *initPackageMutation) Apply(ctx context.Context, resources repository.PackageResources) (repository.PackageResources, *api.TaskResult, error) { - ctx, span := tracer.Start(ctx, "initPackageMutation::Apply", trace.WithAttributes()) - defer span.End() - - fs := filesys.MakeFsInMemory() - // virtual fs expected a rooted filesystem - pkgPath := "/" - - if m.task.Init.Subpackage != "" { - pkgPath = "/" + m.task.Init.Subpackage - } - if err := fs.Mkdir(pkgPath); err != nil { - return repository.PackageResources{}, nil, err - } - err := m.Initialize(printer.WithContext(ctx, &fake.Printer{}), fs, kptpkg.InitOptions{ - PkgPath: pkgPath, - PkgName: m.name, - Desc: m.task.Init.Description, - Keywords: m.task.Init.Keywords, - Site: m.task.Init.Site, - }) - if err != nil { - return repository.PackageResources{}, nil, fmt.Errorf("failed to initialize pkg %q: %w", m.name, err) - } - - result, err := readResources(fs) - if err != nil { - return repository.PackageResources{}, nil, err - } - - return result, &api.TaskResult{Task: m.task}, nil -} diff --git a/porch/pkg/engine/init_test.go b/porch/pkg/engine/init_test.go deleted file mode 100644 index 71c67e93a0..0000000000 --- a/porch/pkg/engine/init_test.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "os" - "path/filepath" - "testing" - - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/google/go-cmp/cmp" -) - -func TestInit(t *testing.T) { - init := &initPackageMutation{ - name: "testpkg", - task: &api.Task{ - Init: &api.PackageInitTaskSpec{ - Description: "test package", - Keywords: []string{"test", "kpt", "pkg"}, - Site: "http://kpt.dev/testpkg", - }, - }, - } - - testdata, err := filepath.Abs(filepath.Join(".", "testdata", "init", "testpkg")) - if err != nil { - t.Fatalf("Failed to find testdata: %v", err) - } - - initializedPkg, _, err := init.Apply(context.Background(), repository.PackageResources{}) - if err != nil { - t.Errorf("package init failed: %v", err) - } - - filesToCompare := []string{"Kptfile", "README.md", "package-context.yaml"} - - for _, fi := range filesToCompare { - got, ok := initializedPkg.Contents[fi] - if !ok { - t.Errorf("Cannot find Kptfile in %v", initializedPkg.Contents) - } - - want, err := os.ReadFile(filepath.Join(testdata, fi)) - if err != nil { - t.Fatalf("Cannot read expected Kptfile: %v", err) - } - - if diff := cmp.Diff(string(want), got); diff != "" { - t.Errorf("Unexpected result (-want, +got): %s", diff) - } - } - -} diff --git a/porch/pkg/engine/kio.go b/porch/pkg/engine/kio.go deleted file mode 100644 index 7c90f53280..0000000000 --- a/porch/pkg/engine/kio.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "bytes" - "fmt" - "path" - "strings" - - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/kio/kioutil" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -type packageReader struct { - input repository.PackageResources - extra map[string]string -} - -var _ kio.Reader = &packageReader{} - -func (r *packageReader) Read() ([]*yaml.RNode, error) { - results := []*yaml.RNode{} - for k, v := range r.input.Contents { - base := path.Base(k) - ext := path.Ext(base) - - // TODO: use authoritative kpt filtering - if ext != ".yaml" && ext != ".yml" && base != "Kptfile" { - r.extra[k] = v - continue - } - - var reader kio.Reader = &kio.ByteReader{ - Reader: strings.NewReader(v), - SetAnnotations: map[string]string{ - kioutil.PathAnnotation: k, - }, - DisableUnwrapping: true, - } - nodes, err := reader.Read() - if err != nil { - // TODO: fail, or bypass this file too? - return nil, err - } - results = append(results, nodes...) - } - - return results, nil -} - -type packageWriter struct { - output repository.PackageResources -} - -var _ kio.Writer = &packageWriter{} - -func (w *packageWriter) Write(nodes []*yaml.RNode) error { - paths := map[string][]*yaml.RNode{} - for _, node := range nodes { - path := getPath(node) - paths[path] = append(paths[path], node) - } - - // TODO: write directly into the package resources abstraction. - // For now serializing into memory. - buf := &bytes.Buffer{} - for path, nodes := range paths { - bw := kio.ByteWriter{ - Writer: buf, - ClearAnnotations: []string{ - kioutil.PathAnnotation, - kioutil.LegacyPathAnnotation, - }, - } - if err := bw.Write(nodes); err != nil { - return err - } - w.output.Contents[path] = buf.String() - buf.Reset() - } - return nil -} - -func getPath(node *yaml.RNode) string { - ann := node.GetAnnotations() - if path, ok := ann[kioutil.PathAnnotation]; ok { - return path - } - ns := node.GetNamespace() - if ns == "" { - ns = "non-namespaced" - } - name := node.GetName() - if name == "" { - name = "unnamed" - } - // TODO: harden for escaping etc. - return path.Join(ns, fmt.Sprintf("%s.yaml", name)) -} - -type NodeToMapWriter struct { - Resources map[string]string -} diff --git a/porch/pkg/engine/mergekey.go b/porch/pkg/engine/mergekey.go deleted file mode 100644 index 8e50e8108c..0000000000 --- a/porch/pkg/engine/mergekey.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "fmt" - - "github.com/GoogleContainerTools/kpt/internal/util/addmergecomment" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "sigs.k8s.io/kustomize/kyaml/kio" -) - -// addMergeKeyMutation adds merge-key comment directive to reconcile -// identity of resources in a downstream package with the ones in upstream package -// This is required to ensure package update is able to merge resources in -// downstream package with upstream. -func ensureMergeKey(ctx context.Context, resources repository.PackageResources) (repository.PackageResources, error) { - pr := &packageReader{ - input: resources, - extra: map[string]string{}, - } - - result := repository.PackageResources{ - Contents: map[string]string{}, - } - - amc := &addmergecomment.AddMergeComment{} - - pipeline := kio.Pipeline{ - Inputs: []kio.Reader{pr}, - Filters: []kio.Filter{kio.FilterAll(amc)}, - Outputs: []kio.Writer{&packageWriter{ - output: result, - }}, - } - - if err := pipeline.Execute(); err != nil { - return repository.PackageResources{}, fmt.Errorf("failed to add merge-key directive: %w", err) - } - - for k, v := range pr.extra { - result.Contents[k] = v - } - - return result, nil -} diff --git a/porch/pkg/engine/options.go b/porch/pkg/engine/options.go deleted file mode 100644 index 61c8af7be2..0000000000 --- a/porch/pkg/engine/options.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "fmt" - - "github.com/GoogleContainerTools/kpt/internal/fnruntime" - "github.com/GoogleContainerTools/kpt/pkg/fn" - "github.com/GoogleContainerTools/kpt/porch/pkg/cache" - "github.com/GoogleContainerTools/kpt/porch/pkg/kpt" - "github.com/GoogleContainerTools/kpt/porch/pkg/meta" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" -) - -type EngineOption interface { - apply(engine *cadEngine) error -} - -type EngineOptionFunc func(engine *cadEngine) error - -var _ EngineOption = EngineOptionFunc(nil) - -func (f EngineOptionFunc) apply(engine *cadEngine) error { - return f(engine) -} - -func WithCache(cache *cache.Cache) EngineOption { - return EngineOptionFunc(func(engine *cadEngine) error { - engine.cache = cache - return nil - }) -} - -func WithBuiltinFunctionRuntime() EngineOption { - return EngineOptionFunc(func(engine *cadEngine) error { - runtime := newBuiltinRuntime() - if engine.runtime == nil { - engine.runtime = runtime - } else if mr, ok := engine.runtime.(*fn.MultiRuntime); ok { - mr.Add(runtime) - } else { - engine.runtime = fn.NewMultiRuntime([]fn.FunctionRuntime{engine.runtime, runtime}) - } - return nil - }) -} - -func WithGRPCFunctionRuntime(address string) EngineOption { - return EngineOptionFunc(func(engine *cadEngine) error { - runtime, err := newGRPCFunctionRuntime(address) - if err != nil { - return fmt.Errorf("failed to create function runtime: %w", err) - } - if engine.runtime == nil { - engine.runtime = runtime - } else if mr, ok := engine.runtime.(*fn.MultiRuntime); ok { - mr.Add(runtime) - } else { - engine.runtime = fn.NewMultiRuntime([]fn.FunctionRuntime{engine.runtime, runtime}) - } - return nil - }) -} - -func WithFunctionRuntime(runtime fn.FunctionRuntime) EngineOption { - return EngineOptionFunc(func(engine *cadEngine) error { - engine.runtime = runtime - return nil - }) -} - -func WithSimpleFunctionRuntime() EngineOption { - return EngineOptionFunc(func(engine *cadEngine) error { - engine.runtime = kpt.NewSimpleFunctionRuntime() - return nil - }) -} - -func WithRunnerOptions(options fnruntime.RunnerOptions) EngineOption { - return WithRunnerOptionsResolver(func(namespace string) fnruntime.RunnerOptions { return options }) -} - -func WithRunnerOptionsResolver(fn func(namespace string) fnruntime.RunnerOptions) EngineOption { - return EngineOptionFunc(func(engine *cadEngine) error { - engine.runnerOptionsResolver = fn - return nil - }) -} - -func WithCredentialResolver(resolver repository.CredentialResolver) EngineOption { - return EngineOptionFunc(func(engine *cadEngine) error { - engine.credentialResolver = resolver - return nil - }) -} - -func WithReferenceResolver(resolver ReferenceResolver) EngineOption { - return EngineOptionFunc(func(engine *cadEngine) error { - engine.referenceResolver = resolver - return nil - }) -} - -func WithUserInfoProvider(provider repository.UserInfoProvider) EngineOption { - return EngineOptionFunc(func(engine *cadEngine) error { - engine.userInfoProvider = provider - return nil - }) -} - -func WithMetadataStore(metadataStore meta.MetadataStore) EngineOption { - return EngineOptionFunc(func(engine *cadEngine) error { - engine.metadataStore = metadataStore - return nil - }) -} - -func WithWatcherManager(watcherManager *watcherManager) EngineOption { - return EngineOptionFunc(func(engine *cadEngine) error { - engine.watcherManager = watcherManager - return nil - }) -} diff --git a/porch/pkg/engine/package.go b/porch/pkg/engine/package.go deleted file mode 100644 index 5cc8b081af..0000000000 --- a/porch/pkg/engine/package.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "fmt" - - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" -) - -type PackageFetcher struct { - repoOpener RepositoryOpener - referenceResolver ReferenceResolver -} - -func (p *PackageFetcher) FetchRevision(ctx context.Context, packageRef *api.PackageRevisionRef, namespace string) (repository.PackageRevision, error) { - repositoryName, err := parseUpstreamRepository(packageRef.Name) - if err != nil { - return nil, err - } - var resolved configapi.Repository - if err := p.referenceResolver.ResolveReference(ctx, namespace, repositoryName, &resolved); err != nil { - return nil, fmt.Errorf("cannot find repository %s/%s: %w", namespace, repositoryName, err) - } - - repo, err := p.repoOpener.OpenRepository(ctx, &resolved) - if err != nil { - return nil, err - } - - revisions, err := repo.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{KubeObjectName: packageRef.Name}) - if err != nil { - return nil, err - } - - var revision repository.PackageRevision - for _, rev := range revisions { - if rev.KubeObjectName() == packageRef.Name { - revision = rev - break - } - } - if revision == nil { - return nil, fmt.Errorf("cannot find package revision %q", packageRef.Name) - } - - return revision, nil -} - -func (p *PackageFetcher) FetchResources(ctx context.Context, packageRef *api.PackageRevisionRef, namespace string) (*api.PackageRevisionResources, error) { - revision, err := p.FetchRevision(ctx, packageRef, namespace) - if err != nil { - return nil, err - } - - resources, err := revision.GetResources(ctx) - if err != nil { - return nil, fmt.Errorf("cannot read contents of package %q: %w", packageRef.Name, err) - } - return resources, nil -} diff --git a/porch/pkg/engine/patchgen.go b/porch/pkg/engine/patchgen.go deleted file mode 100644 index 8081ea390e..0000000000 --- a/porch/pkg/engine/patchgen.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "bytes" - "context" - "fmt" - "strings" - - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/bluekeyes/go-gitdiff/gitdiff" - "go.opentelemetry.io/otel/trace" - "k8s.io/klog/v2" - - "github.com/hexops/gotextdiff" - "github.com/hexops/gotextdiff/myers" - "github.com/hexops/gotextdiff/span" -) - -// GeneratePatch returns patch operations for transforming from oldV to newV. -func GeneratePatch(fileName string, oldV, newV string) (api.PatchSpec, error) { - edits := myers.ComputeEdits(span.URIFromPath(fileName), oldV, newV) - diff := fmt.Sprint(gotextdiff.ToUnified(fileName, fileName, oldV, edits)) - - patchSpec := api.PatchSpec{ - File: fileName, - PatchType: api.PatchTypePatchFile, - Contents: diff, - } - - return patchSpec, nil -} - -type applyPatchMutation struct { - patchTask *api.PackagePatchTaskSpec - task *api.Task -} - -var _ mutation = &applyPatchMutation{} - -func (m *applyPatchMutation) Apply(ctx context.Context, resources repository.PackageResources) (repository.PackageResources, *api.TaskResult, error) { - ctx, span := tracer.Start(ctx, "applyPatchMutation:::Apply", trace.WithAttributes()) - defer span.End() - - result := repository.PackageResources{ - Contents: map[string]string{}, - } - - for k, v := range resources.Contents { - result.Contents[k] = v - } - - for _, patchSpec := range m.patchTask.Patches { - switch patchSpec.PatchType { - case api.PatchTypeCreateFile: - if _, found := result.Contents[patchSpec.File]; found { - // TODO: We should be able to tolerate this. Either do a merge or create as a different filename "-2" - return result, nil, fmt.Errorf("patch wants to create file %q but already exists", patchSpec.File) - } - result.Contents[patchSpec.File] = patchSpec.Contents - case api.PatchTypeDeleteFile: - if _, found := result.Contents[patchSpec.File]; !found { - // TODO: I don't think this should be an error, but maybe we should use object manipulation more than file manipulation. - // TODO: Support object based patches where we can. - klog.Warningf("patch wants to delete file %q, but already deleted", patchSpec.File) - } - delete(result.Contents, patchSpec.File) - case api.PatchTypePatchFile: - oldContents, found := result.Contents[patchSpec.File] - if !found { - return result, nil, fmt.Errorf("patch specifies file %q which does not exist", patchSpec.File) - } - - files, preamble, err := gitdiff.Parse(strings.NewReader(patchSpec.Contents)) - if err != nil { - return result, nil, fmt.Errorf("error parsing patch: %w", err) - } - - if len(files) == 0 { - return result, nil, fmt.Errorf("patch did not specify any files") - } - if len(files) > 1 { - return result, nil, fmt.Errorf("patch specified multiple files") - } - if preamble != "" { - return result, nil, fmt.Errorf("patch had unexpected preamble %q", preamble) - } - - if files[0].OldName != patchSpec.File { - return result, nil, fmt.Errorf("patch contained unexpected name; got %q, want %q", files[0].OldName, patchSpec.File) - } - - if files[0].IsBinary { - return result, nil, fmt.Errorf("patch was a binary diff; expected text diff") - } - if files[0].IsCopy || files[0].IsDelete || files[0].IsNew || files[0].IsRename { - return result, nil, fmt.Errorf("patch was of an unexpected type (copy/delete/new/rename)") - } - if files[0].OldMode != files[0].NewMode { - return result, nil, fmt.Errorf("patch contained file mode change") - } - var output bytes.Buffer - if err := gitdiff.Apply(&output, strings.NewReader(oldContents), files[0]); err != nil { - return result, nil, fmt.Errorf("error applying patch: %w", err) - } - - patched := output.String() - result.Contents[patchSpec.File] = patched - default: - return result, nil, fmt.Errorf("unhandled patch type %q", patchSpec.PatchType) - } - } - - return result, &api.TaskResult{Task: m.task}, nil -} - -func buildPatchMutation(ctx context.Context, task *api.Task) (mutation, error) { - if task.Patch == nil { - return nil, fmt.Errorf("patch not set for task of type %q", task.Type) - } - - m := &applyPatchMutation{ - patchTask: task.Patch, - task: task, - } - return m, nil -} diff --git a/porch/pkg/engine/patchgen_test.go b/porch/pkg/engine/patchgen_test.go deleted file mode 100644 index 0460c59e5a..0000000000 --- a/porch/pkg/engine/patchgen_test.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "bytes" - "encoding/json" - "fmt" - "strings" - "testing" - - "github.com/bluekeyes/go-gitdiff/gitdiff" - "github.com/google/go-cmp/cmp" - "github.com/hexops/gotextdiff" - "github.com/hexops/gotextdiff/myers" - "github.com/hexops/gotextdiff/span" - "k8s.io/apimachinery/pkg/util/jsonmergepatch" - "sigs.k8s.io/yaml" -) - -func TestGoDiff(t *testing.T) { - oldYAML := ` -apiVersion: v1 -kind: ConfigMap -data: - foo1: bar - foo2: bar2 - foo3: bar3 -` - newYAML := ` -apiVersion: v1 -kind: ConfigMap -data: - foo1: bar11 - foo2: bar22 -` - - edits := myers.ComputeEdits(span.URIFromPath("a.txt"), oldYAML, newYAML) - got := fmt.Sprint(gotextdiff.ToUnified("a.txt", "b.txt", oldYAML, edits)) - - want := ` ---- a.txt -+++ b.txt -@@ -2,6 +2,5 @@ - apiVersion: v1 - kind: ConfigMap - data: -- foo1: bar -- foo2: bar2 -- foo3: bar3 -+ foo1: bar11 -+ foo2: bar22 -` - - got = strings.TrimSpace(got) - want = strings.TrimSpace(want) - - t.Logf("patch:\n%v", got) - - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("unexpected result from myers.ComputeEdits: (-want,+got): %s", diff) - } - - // files is a slice of *gitdiff.File describing the files changed in the patch - // preamble is a string of the content of the patch before the first file - files, preamble, err := gitdiff.Parse(strings.NewReader(got)) - if err != nil { - t.Errorf("unexpected result from gitdiff.Parse: %v", err) - } - - t.Logf("files=%#v", files) - t.Logf("preamble=%#v", preamble) - - // apply the changes in the patch to a source file - var output bytes.Buffer - if err := gitdiff.Apply(&output, strings.NewReader(oldYAML), files[0]); err != nil { - t.Errorf("unexpected result from gitdiff.Apply: %v", err) - } - - patched := output.String() - t.Logf("patched=%#v", patched) - - if diff := cmp.Diff(strings.TrimSpace(newYAML), strings.TrimSpace(patched)); diff != "" { - t.Logf("patch result:\n%s", patched) - t.Errorf("unexpected result from PatchApply: (-want,+got): %s", diff) - } -} - -func TestPatchJSONGen(t *testing.T) { - oldYAML := ` -apiVersion: v1 -kind: ConfigMap -data: - foo1: bar - foo2: bar2 - foo3: bar3 -` - newYAML := ` -apiVersion: v1 -kind: ConfigMap -data: - foo1: bar11 - foo2: bar22 -` - oldObj := make(map[string]interface{}) - if err := yaml.Unmarshal([]byte(oldYAML), &oldObj); err != nil { - t.Fatalf("error from yaml.Unmarshal: %v", err) - } - - newObj := make(map[string]interface{}) - if err := yaml.Unmarshal([]byte(newYAML), &newObj); err != nil { - t.Fatalf("error from yaml.Unmarshal: %v", err) - } - - oldJSON, err := json.Marshal(oldObj) - if err != nil { - t.Fatalf("error from json.Marshal: %v", err) - } - newJSON, err := json.Marshal(newObj) - if err != nil { - t.Fatalf("error from json.Marshal: %v", err) - } - - patch, err := jsonmergepatch.CreateThreeWayJSONMergePatch(oldJSON, newJSON, oldJSON) - if err != nil { - t.Fatalf("error from CreateThreeWayJSONMergePatch: %v", err) - } - - patchObject := make(map[string]interface{}) - if err := json.Unmarshal(patch, &patchObject); err != nil { - t.Errorf("error from json.Unmarshal: %v", err) - } - - patchYAML, err := yaml.Marshal(patchObject) - if err != nil { - t.Errorf("error from yaml.Marshal: %v", err) - } - - got := string(patchYAML) - - want := ` -data: - foo1: bar11 - foo2: bar22 - foo3: null -` - - got = strings.TrimSpace(got) - want = strings.TrimSpace(want) - - t.Logf("patch:\n%v", got) - - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("unexpected result from CreateThreeWayJSONMergePatch: (-want,+got): %s", diff) - } -} diff --git a/porch/pkg/engine/render.go b/porch/pkg/engine/render.go deleted file mode 100644 index f0d4b930dd..0000000000 --- a/porch/pkg/engine/render.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "encoding/json" - iofs "io/fs" - "path" - "strings" - - "github.com/GoogleContainerTools/kpt/internal/fnruntime" - fnresult "github.com/GoogleContainerTools/kpt/pkg/api/fnresult/v1" - "github.com/GoogleContainerTools/kpt/pkg/fn" - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/kpt" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "go.opentelemetry.io/otel/trace" - "k8s.io/klog/v2" - "sigs.k8s.io/kustomize/kyaml/filesys" -) - -type renderPackageMutation struct { - runtime fn.FunctionRuntime - runnerOptions fnruntime.RunnerOptions -} - -var _ mutation = &renderPackageMutation{} - -func (m *renderPackageMutation) Apply(ctx context.Context, resources repository.PackageResources) (repository.PackageResources, *api.TaskResult, error) { - ctx, span := tracer.Start(ctx, "renderPackageMutation::Apply", trace.WithAttributes()) - defer span.End() - - fs := filesys.MakeFsInMemory() - taskResult := &api.TaskResult{ - Task: &api.Task{ - Type: api.TaskTypeEval, - Eval: &api.FunctionEvalTaskSpec{ - Image: "render", - ConfigMap: nil, - }, - }, - RenderStatus: &api.RenderStatus{}, - } - pkgPath, err := writeResources(fs, resources) - if err != nil { - return repository.PackageResources{}, nil, err - } - - if pkgPath == "" { - // We need this for the no-resources case - // TODO: we should handle this better - klog.Warningf("skipping render as no package was found") - } else { - renderer := kpt.NewRenderer(m.runnerOptions) - result, err := renderer.Render(ctx, fs, fn.RenderOptions{ - PkgPath: pkgPath, - Runtime: m.runtime, - }) - if result != nil { - var rr api.ResultList - err := convertResultList(result, &rr) - if err != nil { - return repository.PackageResources{}, taskResult, err - } - taskResult.RenderStatus.Result = rr - } - if err != nil { - taskResult.RenderStatus.Err = err.Error() - return repository.PackageResources{}, taskResult, err - } - } - - renderedResources, err := readResources(fs) - if err != nil { - return repository.PackageResources{}, taskResult, err - } - - // TODO: There are internal tasks not represented in the API; Update the Apply interface to enable them. - return renderedResources, taskResult, nil -} - -func convertResultList(in *fnresult.ResultList, out *api.ResultList) error { - if in == nil { - return nil - } - srcBytes, err := json.Marshal(in) - if err != nil { - return err - } - - if err := json.Unmarshal(srcBytes, &out); err != nil { - return err - } - return nil -} - -// TODO: Implement filesystem abstraction directly rather than on top of PackageResources -func writeResources(fs filesys.FileSystem, resources repository.PackageResources) (string, error) { - var packageDir string // path to the topmost directory containing Kptfile - for k, v := range resources.Contents { - dir := path.Dir(k) - if dir == "." { - dir = "/" - } - if err := fs.MkdirAll(dir); err != nil { - return "", err - } - base := path.Base(k) - if err := fs.WriteFile(path.Join(dir, base), []byte(v)); err != nil { - return "", err - } - if base == "Kptfile" { - // Found Kptfile. Check if the current directory is ancestor of the current - // topmost package directory. If so, use it instead. - if packageDir == "" || dir == "/" || strings.HasPrefix(packageDir, dir+"/") { - packageDir = dir - } - } - } - // Return topmost directory containing Kptfile - return packageDir, nil -} - -func readResources(fs filesys.FileSystem) (repository.PackageResources, error) { - contents := map[string]string{} - - if err := fs.Walk("/", func(path string, info iofs.FileInfo, err error) error { - if info.Mode().IsRegular() { - data, err := fs.ReadFile(path) - if err != nil { - return err - } - contents[strings.TrimPrefix(path, "/")] = string(data) - } - return nil - }); err != nil { - return repository.PackageResources{}, err - } - - return repository.PackageResources{ - Contents: contents, - }, nil -} diff --git a/porch/pkg/engine/render_test.go b/porch/pkg/engine/render_test.go deleted file mode 100644 index 964313affe..0000000000 --- a/porch/pkg/engine/render_test.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "os" - "path/filepath" - "testing" - - "github.com/GoogleContainerTools/kpt/internal/fnruntime" - v1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/porch/pkg/kpt" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/google/go-cmp/cmp" - "sigs.k8s.io/kustomize/kyaml/filesys" - "sigs.k8s.io/kustomize/kyaml/kio" -) - -func TestRender(t *testing.T) { - runnerOptions := fnruntime.RunnerOptions{} - runnerOptions.InitDefaults() - - render := &renderPackageMutation{ - runnerOptions: runnerOptions, - runtime: kpt.NewSimpleFunctionRuntime(), - } - - testdata, err := filepath.Abs(filepath.Join(".", "testdata", "simple-render")) - if err != nil { - t.Fatalf("Failed to find testdata: %v", err) - } - packagePath := filepath.Join(testdata, "simple-bucket") - r := &kio.LocalPackageReader{ - PackagePath: packagePath, - IncludeSubpackages: true, - MatchFilesGlob: append(kio.MatchAll, v1.KptFileName), - FileSystem: filesys.FileSystemOrOnDisk{}, - } - - w := &packageWriter{ - output: repository.PackageResources{ - Contents: map[string]string{}, - }, - } - - if err := (kio.Pipeline{Inputs: []kio.Reader{r}, Outputs: []kio.Writer{w}}).Execute(); err != nil { - t.Fatalf("Failed to read package: %v", err) - } - - rendered, _, err := render.Apply(context.Background(), w.output) - if err != nil { - t.Errorf("package render failed: %v", err) - } - - got, ok := rendered.Contents["bucket.yaml"] - if !ok { - t.Errorf("Cannot find output config (bucket.yaml) in %v", rendered.Contents) - } - - want, err := os.ReadFile(filepath.Join(testdata, "expected.txt")) - if err != nil { - t.Fatalf("Cannot read expected.txt: %v", err) - } - - if diff := cmp.Diff(string(want), got); diff != "" { - t.Errorf("Unexpected result (-want, +got): %s", diff) - } -} diff --git a/porch/pkg/engine/replace_test.go b/porch/pkg/engine/replace_test.go deleted file mode 100644 index a2ea6cbfe8..0000000000 --- a/porch/pkg/engine/replace_test.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "bytes" - "context" - "path" - "path/filepath" - "testing" - - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/google/go-cmp/cmp" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -func TestReplaceResources(t *testing.T) { - ctx := context.Background() - - input := readPackage(t, filepath.Join("testdata", "replace")) - nocomment := removeComments(t, input) - - replace := &mutationReplaceResources{ - newResources: &v1alpha1.PackageRevisionResources{ - Spec: v1alpha1.PackageRevisionResourcesSpec{ - Resources: nocomment.Contents, - }, - }, - oldResources: &v1alpha1.PackageRevisionResources{ - Spec: v1alpha1.PackageRevisionResourcesSpec{ - Resources: input.Contents, - }, - }, - } - - output, _, err := replace.Apply(ctx, input) - if err != nil { - t.Fatalf("mutationReplaceResources.Apply failed: %v", err) - } - - if !cmp.Equal(input, output) { - t.Errorf("Diff: (-want,+got): %s", cmp.Diff(input, output)) - } -} - -func removeComments(t *testing.T, r repository.PackageResources) repository.PackageResources { - t.Helper() - - out := repository.PackageResources{ - Contents: map[string]string{}, - } - - for k, v := range r.Contents { - base := path.Base(k) - ext := path.Ext(base) - - if ext == ".yaml" || ext == ".yml" || base == "Kptfile" { - v = removeCommentsFromFile(t, k, v) - } - - out.Contents[k] = v - } - return out -} - -func removeCommentsFromFile(t *testing.T, name, contents string) string { - var data interface{} - if err := yaml.Unmarshal([]byte(contents), &data); err != nil { - t.Fatalf("Failed to unmarshal %q: %v", name, err) - } - - var nocomment bytes.Buffer - encoder := yaml.NewEncoder(&nocomment) - encoder.SetIndent(0) - if err := encoder.Encode(data); err != nil { - t.Fatalf("Failed to re-encode yaml output: %v", err) - } - - return nocomment.String() -} diff --git a/porch/pkg/engine/safejoin.go b/porch/pkg/engine/safejoin.go deleted file mode 100644 index 9896da5868..0000000000 --- a/porch/pkg/engine/safejoin.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "fmt" - "path/filepath" - "strings" -) - -// Relevant: https://github.com/golang/go/issues/20126 - -func filepathSafeJoin(dir string, relative string) (string, error) { - p := filepath.Join(dir, relative) - p = filepath.Clean(p) - - rel, err := filepath.Rel(dir, p) - if err != nil { - return "", fmt.Errorf("invalid relative path %q", relative) - } - if rel != relative || strings.HasPrefix(rel, ".."+string(filepath.Separator)) || strings.HasPrefix(rel, "."+string(filepath.Separator)) { - return "", fmt.Errorf("invalid relative path %q", relative) - } - return p, nil -} diff --git a/porch/pkg/engine/safejoin_test.go b/porch/pkg/engine/safejoin_test.go deleted file mode 100644 index 3c2e711fb6..0000000000 --- a/porch/pkg/engine/safejoin_test.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "fmt" - "testing" -) - -// Relevant: https://github.com/golang/go/issues/20126 - -func TestSafeJoin(t *testing.T) { - grid := []struct { - base string - relative string - want string - wantError bool - }{ - { - base: "/tmp", - relative: "foo", - want: "/tmp/foo", - }, - { - base: "/tmp/subdir/", - relative: "foo", - want: "/tmp/subdir/foo", - }, - { - base: "tmp", - relative: "foo", - want: "tmp/foo", - }, - { - base: "/tmp/subdir/", - relative: "/foo", - wantError: true, - }, - { - base: "/tmp/", - relative: "/tmp/foo", - wantError: true, - }, - { - base: "tmp/", - relative: "tmp/foo", - want: "tmp/tmp/foo", - }, - { - base: "tmp/", - relative: "../foo", - wantError: true, - }, - { - base: "tmp/", - relative: "a/../foo", - wantError: true, - }, - { - base: "tmp/", - relative: "a/../../foo", - wantError: true, - }, - { - base: "tmp/", - relative: "a/../../tmp/foo", - wantError: true, - }, - } - - for _, g := range grid { - t.Run(fmt.Sprintf("%#v", g), func(t *testing.T) { - got, err := filepathSafeJoin(g.base, g.relative) - if g.wantError { - if err == nil { - t.Errorf("got %q and nil error, want error", got) - } - } else { - if g.want != got { - t.Errorf("unexpected value; got %q, want %q", got, g.want) - } - } - }) - } -} diff --git a/porch/pkg/engine/testdata/clone/bucket/Kptfile b/porch/pkg/engine/testdata/clone/bucket/Kptfile deleted file mode 100644 index 4c6ddfde93..0000000000 --- a/porch/pkg/engine/testdata/clone/bucket/Kptfile +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: bucket -info: - description: Bucket test package diff --git a/porch/pkg/engine/testdata/clone/bucket/bucket.yaml b/porch/pkg/engine/testdata/clone/bucket/bucket.yaml deleted file mode 100644 index 776e8b6ac1..0000000000 --- a/porch/pkg/engine/testdata/clone/bucket/bucket.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: storage.cnrm.cloud.google.com/v1beta1 -kind: StorageBucket -metadata: - name: bucket-name - namespace: bucket-namespace - annotations: - cnrm.cloud.google.com/project-id: bucket-project -spec: - storageClass: standard - uniformBucketLevelAccess: true - versioning: - enabled: false diff --git a/porch/pkg/engine/testdata/clone/configmap/Kptfile b/porch/pkg/engine/testdata/clone/configmap/Kptfile deleted file mode 100644 index 536c1db189..0000000000 --- a/porch/pkg/engine/testdata/clone/configmap/Kptfile +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: configmap -info: - description: ConfigMap test package diff --git a/porch/pkg/engine/testdata/clone/configmap/configmap.yaml b/porch/pkg/engine/testdata/clone/configmap/configmap.yaml deleted file mode 100644 index 90c66af662..0000000000 --- a/porch/pkg/engine/testdata/clone/configmap/configmap.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: v1 -kind: ConfigMap -metadata: - name: configmap-name - namespace: configmap-namespace -data: - key: value diff --git a/porch/pkg/engine/testdata/context/expected/Kptfile b/porch/pkg/engine/testdata/context/expected/Kptfile deleted file mode 100644 index 1e92a6cfe5..0000000000 --- a/porch/pkg/engine/testdata/context/expected/Kptfile +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: input -info: - description: Builtin Function Test Package diff --git a/porch/pkg/engine/testdata/context/expected/bucket.yaml b/porch/pkg/engine/testdata/context/expected/bucket.yaml deleted file mode 100644 index 5dad26d4f8..0000000000 --- a/porch/pkg/engine/testdata/context/expected/bucket.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: storage.cnrm.cloud.google.com/v1beta1 -kind: StorageBucket -metadata: - name: bucket-name - namespace: bucket-namespace - annotations: - cnrm.cloud.google.com/project-id: bucket-project -spec: - storageClass: standard - uniformBucketLevelAccess: true - versioning: - enabled: false diff --git a/porch/pkg/engine/testdata/context/expected/package-context.yaml b/porch/pkg/engine/testdata/context/expected/package-context.yaml deleted file mode 100644 index 57b4e523a7..0000000000 --- a/porch/pkg/engine/testdata/context/expected/package-context.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: kptfile.kpt.dev - annotations: - config.kubernetes.io/local-config: "true" -data: - name: input - package-path: parent1/parent1.2/parent1.2.3/me diff --git a/porch/pkg/engine/testdata/context/input/Kptfile b/porch/pkg/engine/testdata/context/input/Kptfile deleted file mode 100644 index 1e92a6cfe5..0000000000 --- a/porch/pkg/engine/testdata/context/input/Kptfile +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: input -info: - description: Builtin Function Test Package diff --git a/porch/pkg/engine/testdata/context/input/bucket.yaml b/porch/pkg/engine/testdata/context/input/bucket.yaml deleted file mode 100644 index 5dad26d4f8..0000000000 --- a/porch/pkg/engine/testdata/context/input/bucket.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: storage.cnrm.cloud.google.com/v1beta1 -kind: StorageBucket -metadata: - name: bucket-name - namespace: bucket-namespace - annotations: - cnrm.cloud.google.com/project-id: bucket-project -spec: - storageClass: standard - uniformBucketLevelAccess: true - versioning: - enabled: false diff --git a/porch/pkg/engine/testdata/init/testpkg/Kptfile b/porch/pkg/engine/testdata/init/testpkg/Kptfile deleted file mode 100644 index 7883a64930..0000000000 --- a/porch/pkg/engine/testdata/init/testpkg/Kptfile +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: testpkg - annotations: - config.kubernetes.io/local-config: "true" -info: - site: http://kpt.dev/testpkg - description: test package - keywords: - - test - - kpt - - pkg diff --git a/porch/pkg/engine/testdata/init/testpkg/README.md b/porch/pkg/engine/testdata/init/testpkg/README.md deleted file mode 100644 index 9a34a509d6..0000000000 --- a/porch/pkg/engine/testdata/init/testpkg/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# testpkg - -## Description -test package - -## Usage - -### Fetch the package -`kpt pkg get REPO_URI[.git]/PKG_PATH[@VERSION] testpkg` -Details: https://kpt.dev/reference/cli/pkg/get/ - -### View package content -`kpt pkg tree testpkg` -Details: https://kpt.dev/reference/cli/pkg/tree/ - -### Apply the package -``` -kpt live init testpkg -kpt live apply testpkg --reconcile-timeout=2m --output=table -``` -Details: https://kpt.dev/reference/cli/live/ diff --git a/porch/pkg/engine/testdata/init/testpkg/package-context.yaml b/porch/pkg/engine/testdata/init/testpkg/package-context.yaml deleted file mode 100644 index 6c33d9e4d7..0000000000 --- a/porch/pkg/engine/testdata/init/testpkg/package-context.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: kptfile.kpt.dev - annotations: - config.kubernetes.io/local-config: "true" -data: - name: example diff --git a/porch/pkg/engine/testdata/replace/Kptfile b/porch/pkg/engine/testdata/replace/Kptfile deleted file mode 100644 index 9529df9a5f..0000000000 --- a/porch/pkg/engine/testdata/replace/Kptfile +++ /dev/null @@ -1,23 +0,0 @@ -# top comment -apiVersion: kpt.dev/v1 -# Kptfile info -info: - # Kptfile description - description: A Google Cloud Storage bucket -# Kptfile kind -kind: Kptfile -# Kptfile metadata -metadata: - annotations: - blueprints.cloud.google.com/title: Google Cloud Storage Bucket blueprint - name: simple-bucket -# Kptfile pipeline -pipeline: - # Kptfile mutators - mutators: - - configMap: - name: updated-bucket-name - namespace: updated-namespace - project-id: updated-project-id - storage-class: updated-storage-class - image: gcr.io/kpt-fn/apply-setters:v0.2.0 diff --git a/porch/pkg/engine/testdata/replace/README.md b/porch/pkg/engine/testdata/replace/README.md deleted file mode 100644 index 6f0623fa41..0000000000 --- a/porch/pkg/engine/testdata/replace/README.md +++ /dev/null @@ -1 +0,0 @@ -# replace test \ No newline at end of file diff --git a/porch/pkg/engine/testdata/replace/bucket.yaml b/porch/pkg/engine/testdata/replace/bucket.yaml deleted file mode 100644 index 935e6573c0..0000000000 --- a/porch/pkg/engine/testdata/replace/bucket.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# top comment -apiVersion: storage.cnrm.cloud.google.com/v1beta1 -kind: StorageBucket -# metadata comment -metadata: # kpt-merge: config-control/blueprints-project-bucket - # annotations comment - annotations: - cnrm.cloud.google.com/force-destroy: "false" - cnrm.cloud.google.com/project-id: blueprints-project # kpt-set: ${project-id} - name: blueprints-project-bucket # kpt-set: ${project-id}-${name} - namespace: config-control # kpt-set: ${namespace} -# spec comment -spec: - storageClass: standard # kpt-set: ${storage-class} - uniformBucketLevelAccess: true - # Versioning is enabled - versioning: - enabled: false diff --git a/porch/pkg/engine/testdata/simple-render/expected.txt b/porch/pkg/engine/testdata/simple-render/expected.txt deleted file mode 100644 index 43515e7cec..0000000000 --- a/porch/pkg/engine/testdata/simple-render/expected.txt +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2022 The kpt 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. -apiVersion: storage.cnrm.cloud.google.com/v1beta1 -kind: StorageBucket -metadata: # kpt-merge: config-control/blueprints-project-bucket - name: updated-project-id-updated-bucket-name # kpt-set: ${project-id}-${name} - namespace: updated-namespace # kpt-set: ${namespace} - annotations: - cnrm.cloud.google.com/force-destroy: "false" - cnrm.cloud.google.com/project-id: updated-project-id # kpt-set: ${project-id} - cnrm.cloud.google.com/blueprint: 'kpt-fn' -spec: - storageClass: updated-storage-class # kpt-set: ${storage-class} - uniformBucketLevelAccess: true - versioning: - enabled: false diff --git a/porch/pkg/engine/testdata/simple-render/simple-bucket/Kptfile b/porch/pkg/engine/testdata/simple-render/simple-bucket/Kptfile deleted file mode 100644 index 213724d131..0000000000 --- a/porch/pkg/engine/testdata/simple-render/simple-bucket/Kptfile +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2022 The kpt 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. -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: simple-bucket - annotations: - blueprints.cloud.google.com/title: Google Cloud Storage Bucket blueprint -info: - description: A Google Cloud Storage bucket -pipeline: - mutators: - - image: gcr.io/kpt-fn/apply-setters:v0.2.0 - configMap: - name: updated-bucket-name - namespace: updated-namespace - project-id: updated-project-id - storage-class: updated-storage-class diff --git a/porch/pkg/engine/testdata/simple-render/simple-bucket/bucket.yaml b/porch/pkg/engine/testdata/simple-render/simple-bucket/bucket.yaml deleted file mode 100644 index fc85436726..0000000000 --- a/porch/pkg/engine/testdata/simple-render/simple-bucket/bucket.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. -apiVersion: storage.cnrm.cloud.google.com/v1beta1 -kind: StorageBucket -metadata: # kpt-merge: config-control/blueprints-project-bucket - name: blueprints-project-bucket # kpt-set: ${project-id}-${name} - namespace: config-control # kpt-set: ${namespace} - annotations: - cnrm.cloud.google.com/force-destroy: "false" - cnrm.cloud.google.com/project-id: blueprints-project # kpt-set: ${project-id} -spec: - storageClass: standard # kpt-set: ${storage-class} - uniformBucketLevelAccess: true - versioning: - enabled: false diff --git a/porch/pkg/engine/testdata/update/local/Kptfile b/porch/pkg/engine/testdata/update/local/Kptfile deleted file mode 100644 index 56adbcedae..0000000000 --- a/porch/pkg/engine/testdata/update/local/Kptfile +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: backend - annotations: - config.kubernetes.io/local-config: "true" -upstream: - type: git - git: - repo: https://github.com/droot/pkg-catalog.git - directory: basens - ref: basens/v0 -upstreamLock: - type: git - git: - repo: https://github.com/droot/pkg-catalog.git - directory: basens - ref: basens/v0 - commit: b3e1d439516a5e8d49adc0c82d3e95578570dbfa -info: - description: kpt package for provisioning namespace -pipeline: - mutators: - - image: gcr.io/kpt-fn/set-namespace:v0.3.4 - configPath: package-context.yaml - - image: gcr.io/kpt-fn/apply-replacements:v0.1.0 - configPath: update-rolebinding.yaml diff --git a/porch/pkg/engine/testdata/update/local/README.md b/porch/pkg/engine/testdata/update/local/README.md deleted file mode 100644 index 2b9db73e13..0000000000 --- a/porch/pkg/engine/testdata/update/local/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# basens - -## Description -kpt package for provisioning namespace - -## Usage - -### Fetch the package -`kpt pkg get REPO_URI[.git]/PKG_PATH[@VERSION] basens` -Details: https://kpt.dev/reference/cli/pkg/get/ - -### View package content -`kpt pkg tree basens` -Details: https://kpt.dev/reference/cli/pkg/tree/ - -### Apply the package -``` -kpt live init basens -kpt live apply basens --reconcile-timeout=2m --output=table -``` -Details: https://kpt.dev/reference/cli/live/ diff --git a/porch/pkg/engine/testdata/update/local/namespace.yaml b/porch/pkg/engine/testdata/update/local/namespace.yaml deleted file mode 100644 index 5a044679d3..0000000000 --- a/porch/pkg/engine/testdata/update/local/namespace.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: # kpt-merge: example - name: backend -spec: {} diff --git a/porch/pkg/engine/testdata/update/local/package-context.yaml b/porch/pkg/engine/testdata/update/local/package-context.yaml deleted file mode 100644 index 9b77f45e74..0000000000 --- a/porch/pkg/engine/testdata/update/local/package-context.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: kptfile.kpt.dev - annotations: - config.kubernetes.io/local-config: "true" -data: - name: backend diff --git a/porch/pkg/engine/testdata/update/local/resourcequota.yaml b/porch/pkg/engine/testdata/update/local/resourcequota.yaml deleted file mode 100644 index 02e22b0876..0000000000 --- a/porch/pkg/engine/testdata/update/local/resourcequota.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: v1 -kind: ResourceQuota -metadata: # kpt-merge: example/default - name: default - namespace: backend -spec: - hard: - cpu: "40" - memory: 40G diff --git a/porch/pkg/engine/testdata/update/local/rolebinding.yaml b/porch/pkg/engine/testdata/update/local/rolebinding.yaml deleted file mode 100644 index f57f1f2eba..0000000000 --- a/porch/pkg/engine/testdata/update/local/rolebinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: # kpt-merge: example/app-admin - name: app-admin - namespace: backend -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: app-admin -subjects: -- apiGroup: rbac.authorization.k8s.io - kind: Group - name: backend.admin@bigco.com diff --git a/porch/pkg/engine/testdata/update/local/update-rolebinding.yaml b/porch/pkg/engine/testdata/update/local/update-rolebinding.yaml deleted file mode 100644 index 6fdff58263..0000000000 --- a/porch/pkg/engine/testdata/update/local/update-rolebinding.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: fn.kpt.dev/v1alpha1 -kind: ApplyReplacements -metadata: # kpt-merge: example/update-rolebinding - name: update-rolebinding - annotations: - config.kubernetes.io/local-config: "true" -replacements: -- source: - kind: ConfigMap - name: kptfile.kpt.dev - fieldPath: data.name - targets: - - select: - name: app-admin - kind: RoleBinding - fieldPaths: - - subjects.[kind=Group].name - options: - delimiter: '.' - index: 0 diff --git a/porch/pkg/engine/testdata/update/original/Kptfile b/porch/pkg/engine/testdata/update/original/Kptfile deleted file mode 100644 index db6271356c..0000000000 --- a/porch/pkg/engine/testdata/update/original/Kptfile +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: basens - annotations: - config.kubernetes.io/local-config: "true" -info: - description: kpt package for provisioning namespace -pipeline: - mutators: - - image: gcr.io/kpt-fn/set-namespace:v0.3.4 - configPath: package-context.yaml - - image: gcr.io/kpt-fn/apply-replacements:v0.1.0 - configPath: update-rolebinding.yaml diff --git a/porch/pkg/engine/testdata/update/original/README.md b/porch/pkg/engine/testdata/update/original/README.md deleted file mode 100644 index 2b9db73e13..0000000000 --- a/porch/pkg/engine/testdata/update/original/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# basens - -## Description -kpt package for provisioning namespace - -## Usage - -### Fetch the package -`kpt pkg get REPO_URI[.git]/PKG_PATH[@VERSION] basens` -Details: https://kpt.dev/reference/cli/pkg/get/ - -### View package content -`kpt pkg tree basens` -Details: https://kpt.dev/reference/cli/pkg/tree/ - -### Apply the package -``` -kpt live init basens -kpt live apply basens --reconcile-timeout=2m --output=table -``` -Details: https://kpt.dev/reference/cli/live/ diff --git a/porch/pkg/engine/testdata/update/original/namespace.yaml b/porch/pkg/engine/testdata/update/original/namespace.yaml deleted file mode 100644 index 9219ae329f..0000000000 --- a/porch/pkg/engine/testdata/update/original/namespace.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: example -spec: {} diff --git a/porch/pkg/engine/testdata/update/original/package-context.yaml b/porch/pkg/engine/testdata/update/original/package-context.yaml deleted file mode 100644 index 6c33d9e4d7..0000000000 --- a/porch/pkg/engine/testdata/update/original/package-context.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: kptfile.kpt.dev - annotations: - config.kubernetes.io/local-config: "true" -data: - name: example diff --git a/porch/pkg/engine/testdata/update/original/resourcequota.yaml b/porch/pkg/engine/testdata/update/original/resourcequota.yaml deleted file mode 100644 index a5c7f9dc39..0000000000 --- a/porch/pkg/engine/testdata/update/original/resourcequota.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: v1 -kind: ResourceQuota -metadata: - name: default - namespace: example -spec: - hard: - cpu: "40" - memory: 40G diff --git a/porch/pkg/engine/testdata/update/original/rolebinding.yaml b/porch/pkg/engine/testdata/update/original/rolebinding.yaml deleted file mode 100644 index 12ce8875c0..0000000000 --- a/porch/pkg/engine/testdata/update/original/rolebinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: app-admin - namespace: example -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: app-admin -subjects: -- apiGroup: rbac.authorization.k8s.io - kind: Group - name: example.admin@bigco.com diff --git a/porch/pkg/engine/testdata/update/original/update-rolebinding.yaml b/porch/pkg/engine/testdata/update/original/update-rolebinding.yaml deleted file mode 100644 index a20edf5049..0000000000 --- a/porch/pkg/engine/testdata/update/original/update-rolebinding.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: fn.kpt.dev/v1alpha1 -kind: ApplyReplacements -metadata: - name: update-rolebinding - annotations: - config.kubernetes.io/local-config: "true" -replacements: -- source: - kind: ConfigMap - name: kptfile.kpt.dev - fieldPath: data.name - targets: - - select: - name: app-admin - kind: RoleBinding - fieldPaths: - - subjects.[kind=Group].name - options: - delimiter: '.' - index: 0 diff --git a/porch/pkg/engine/testdata/update/updated/Kptfile b/porch/pkg/engine/testdata/update/updated/Kptfile deleted file mode 100644 index 56adbcedae..0000000000 --- a/porch/pkg/engine/testdata/update/updated/Kptfile +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: backend - annotations: - config.kubernetes.io/local-config: "true" -upstream: - type: git - git: - repo: https://github.com/droot/pkg-catalog.git - directory: basens - ref: basens/v0 -upstreamLock: - type: git - git: - repo: https://github.com/droot/pkg-catalog.git - directory: basens - ref: basens/v0 - commit: b3e1d439516a5e8d49adc0c82d3e95578570dbfa -info: - description: kpt package for provisioning namespace -pipeline: - mutators: - - image: gcr.io/kpt-fn/set-namespace:v0.3.4 - configPath: package-context.yaml - - image: gcr.io/kpt-fn/apply-replacements:v0.1.0 - configPath: update-rolebinding.yaml diff --git a/porch/pkg/engine/testdata/update/updated/README.md b/porch/pkg/engine/testdata/update/updated/README.md deleted file mode 100644 index 2b9db73e13..0000000000 --- a/porch/pkg/engine/testdata/update/updated/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# basens - -## Description -kpt package for provisioning namespace - -## Usage - -### Fetch the package -`kpt pkg get REPO_URI[.git]/PKG_PATH[@VERSION] basens` -Details: https://kpt.dev/reference/cli/pkg/get/ - -### View package content -`kpt pkg tree basens` -Details: https://kpt.dev/reference/cli/pkg/tree/ - -### Apply the package -``` -kpt live init basens -kpt live apply basens --reconcile-timeout=2m --output=table -``` -Details: https://kpt.dev/reference/cli/live/ diff --git a/porch/pkg/engine/testdata/update/updated/namespace.yaml b/porch/pkg/engine/testdata/update/updated/namespace.yaml deleted file mode 100644 index 5a044679d3..0000000000 --- a/porch/pkg/engine/testdata/update/updated/namespace.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: # kpt-merge: example - name: backend -spec: {} diff --git a/porch/pkg/engine/testdata/update/updated/package-context.yaml b/porch/pkg/engine/testdata/update/updated/package-context.yaml deleted file mode 100644 index 9b77f45e74..0000000000 --- a/porch/pkg/engine/testdata/update/updated/package-context.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: kptfile.kpt.dev - annotations: - config.kubernetes.io/local-config: "true" -data: - name: backend diff --git a/porch/pkg/engine/testdata/update/updated/resourcequota.yaml b/porch/pkg/engine/testdata/update/updated/resourcequota.yaml deleted file mode 100644 index e7bc953ef8..0000000000 --- a/porch/pkg/engine/testdata/update/updated/resourcequota.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: v1 -kind: ResourceQuota -metadata: # kpt-merge: example/default - name: default - namespace: backend -spec: - hard: - cpu: "40" - memory: 60G diff --git a/porch/pkg/engine/testdata/update/updated/rolebinding.yaml b/porch/pkg/engine/testdata/update/updated/rolebinding.yaml deleted file mode 100644 index f57f1f2eba..0000000000 --- a/porch/pkg/engine/testdata/update/updated/rolebinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: # kpt-merge: example/app-admin - name: app-admin - namespace: backend -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: app-admin -subjects: -- apiGroup: rbac.authorization.k8s.io - kind: Group - name: backend.admin@bigco.com diff --git a/porch/pkg/engine/testdata/update/updated/update-rolebinding.yaml b/porch/pkg/engine/testdata/update/updated/update-rolebinding.yaml deleted file mode 100644 index 6fdff58263..0000000000 --- a/porch/pkg/engine/testdata/update/updated/update-rolebinding.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: fn.kpt.dev/v1alpha1 -kind: ApplyReplacements -metadata: # kpt-merge: example/update-rolebinding - name: update-rolebinding - annotations: - config.kubernetes.io/local-config: "true" -replacements: -- source: - kind: ConfigMap - name: kptfile.kpt.dev - fieldPath: data.name - targets: - - select: - name: app-admin - kind: RoleBinding - fieldPaths: - - subjects.[kind=Group].name - options: - delimiter: '.' - index: 0 diff --git a/porch/pkg/engine/testdata/update/upstream/Kptfile b/porch/pkg/engine/testdata/update/upstream/Kptfile deleted file mode 100644 index 65fe6a65b9..0000000000 --- a/porch/pkg/engine/testdata/update/upstream/Kptfile +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: basens - annotations: - config.kubernetes.io/local-config: "true" -info: - description: kpt package for provisioning namespace -pipeline: - mutators: - - image: gcr.io/kpt-fn/set-namespace:v0.3.4 - configPath: package-context.yaml - - image: gcr.io/kpt-fn/apply-replacements:v0.1.0 - configPath: update-rolebinding.yaml diff --git a/porch/pkg/engine/testdata/update/upstream/README.md b/porch/pkg/engine/testdata/update/upstream/README.md deleted file mode 100644 index 2b9db73e13..0000000000 --- a/porch/pkg/engine/testdata/update/upstream/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# basens - -## Description -kpt package for provisioning namespace - -## Usage - -### Fetch the package -`kpt pkg get REPO_URI[.git]/PKG_PATH[@VERSION] basens` -Details: https://kpt.dev/reference/cli/pkg/get/ - -### View package content -`kpt pkg tree basens` -Details: https://kpt.dev/reference/cli/pkg/tree/ - -### Apply the package -``` -kpt live init basens -kpt live apply basens --reconcile-timeout=2m --output=table -``` -Details: https://kpt.dev/reference/cli/live/ diff --git a/porch/pkg/engine/testdata/update/upstream/namespace.yaml b/porch/pkg/engine/testdata/update/upstream/namespace.yaml deleted file mode 100644 index 9219ae329f..0000000000 --- a/porch/pkg/engine/testdata/update/upstream/namespace.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: example -spec: {} diff --git a/porch/pkg/engine/testdata/update/upstream/package-context.yaml b/porch/pkg/engine/testdata/update/upstream/package-context.yaml deleted file mode 100644 index 6c33d9e4d7..0000000000 --- a/porch/pkg/engine/testdata/update/upstream/package-context.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: kptfile.kpt.dev - annotations: - config.kubernetes.io/local-config: "true" -data: - name: example diff --git a/porch/pkg/engine/testdata/update/upstream/resourcequota.yaml b/porch/pkg/engine/testdata/update/upstream/resourcequota.yaml deleted file mode 100644 index 5a56078dda..0000000000 --- a/porch/pkg/engine/testdata/update/upstream/resourcequota.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: v1 -kind: ResourceQuota -metadata: - name: default - namespace: example -spec: - hard: - cpu: "40" - memory: 60G diff --git a/porch/pkg/engine/testdata/update/upstream/rolebinding.yaml b/porch/pkg/engine/testdata/update/upstream/rolebinding.yaml deleted file mode 100644 index 12ce8875c0..0000000000 --- a/porch/pkg/engine/testdata/update/upstream/rolebinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: app-admin - namespace: example -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: app-admin -subjects: -- apiGroup: rbac.authorization.k8s.io - kind: Group - name: example.admin@bigco.com diff --git a/porch/pkg/engine/testdata/update/upstream/update-rolebinding.yaml b/porch/pkg/engine/testdata/update/upstream/update-rolebinding.yaml deleted file mode 100644 index a20edf5049..0000000000 --- a/porch/pkg/engine/testdata/update/upstream/update-rolebinding.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: fn.kpt.dev/v1alpha1 -kind: ApplyReplacements -metadata: - name: update-rolebinding - annotations: - config.kubernetes.io/local-config: "true" -replacements: -- source: - kind: ConfigMap - name: kptfile.kpt.dev - fieldPath: data.name - targets: - - select: - name: app-admin - kind: RoleBinding - fieldPaths: - - subjects.[kind=Group].name - options: - delimiter: '.' - index: 0 diff --git a/porch/pkg/engine/testing.go b/porch/pkg/engine/testing.go deleted file mode 100644 index a2abb43140..0000000000 --- a/porch/pkg/engine/testing.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "fmt" - "io/fs" - "os" - "path/filepath" - "testing" - - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" -) - -func readPackage(t *testing.T, packageDir string) repository.PackageResources { - results := map[string]string{} - - if err := filepath.Walk(packageDir, func(p string, info fs.FileInfo, err error) error { - if err != nil { - return err - } - if info.IsDir() { - return nil - } else if !info.Mode().IsRegular() { - return fmt.Errorf("irregular file object detected: %q (%s)", p, info.Mode()) - } - rel, err := filepath.Rel(packageDir, p) - if err != nil { - return fmt.Errorf("failed to get relative path from %q to %q: %w", packageDir, p, err) - } - contents, err := os.ReadFile(p) - if err != nil { - return fmt.Errorf("failed to open the source file %q: %w", p, err) - } - results[rel] = string(contents) - return nil - }); err != nil { - t.Errorf("Failed to read package from disk %q: %v", packageDir, err) - } - return repository.PackageResources{ - Contents: results, - } -} - -func writePackage(t *testing.T, packageDir string, contents repository.PackageResources) { - for k, v := range contents.Contents { - abs := filepath.Join(packageDir, k) - dir := filepath.Dir(abs) - if err := os.MkdirAll(dir, 0755); err != nil { - t.Fatalf("Failed to crete directory %q: %v", dir, err) - } - if err := os.WriteFile(abs, []byte(v), 0644); err != nil { - t.Errorf("Failed to write package file %q: %v", abs, err) - } - } -} diff --git a/porch/pkg/engine/update.go b/porch/pkg/engine/update.go deleted file mode 100644 index 7df18abf4b..0000000000 --- a/porch/pkg/engine/update.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "os" - "path/filepath" - - "github.com/GoogleContainerTools/kpt/internal/util/update" - "github.com/GoogleContainerTools/kpt/pkg/printer" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" -) - -// packageUpdater knows how to update a local package given original and upstream package resources. -type packageUpdater interface { - Update(ctx context.Context, localResources, originalResources, upstreamResources repository.PackageResources) (updatedResources repository.PackageResources, err error) -} - -// defaultPackageUpdater implements packageUpdater interface. -type defaultPackageUpdater struct{} - -func (m *defaultPackageUpdater) Update( - ctx context.Context, - localResources, - originalResources, - upstreamResources repository.PackageResources) (updatedResources repository.PackageResources, err error) { - - localDir, err := os.MkdirTemp("", "kpt-pkg-update-*") - if err != nil { - return repository.PackageResources{}, err - } - defer os.RemoveAll(localDir) - - originalDir, err := os.MkdirTemp("", "kpt-pkg-update-*") - if err != nil { - return repository.PackageResources{}, err - } - defer os.RemoveAll(originalDir) - - upstreamDir, err := os.MkdirTemp("", "kpt-pkg-update-*") - if err != nil { - return repository.PackageResources{}, err - } - defer os.RemoveAll(upstreamDir) - - if err := writeResourcesToDirectory(localDir, localResources); err != nil { - return repository.PackageResources{}, err - } - - if err := writeResourcesToDirectory(originalDir, originalResources); err != nil { - return repository.PackageResources{}, err - } - - if err := writeResourcesToDirectory(upstreamDir, upstreamResources); err != nil { - return repository.PackageResources{}, err - } - - if err := m.do(ctx, localDir, originalDir, upstreamDir); err != nil { - return repository.PackageResources{}, err - } - - return loadResourcesFromDirectory(localDir) -} - -// PkgUpdate is a wrapper around `kpt pkg update`, running it against the package in packageDir -func (m *defaultPackageUpdater) do(ctx context.Context, localPkgDir, originalPkgDir, upstreamPkgDir string) error { - // TODO: Printer should be a logr - pr := printer.New(os.Stdout, os.Stderr) - ctx = printer.WithContext(ctx, pr) - - { - relPath := "." - localPath := filepath.Join(localPkgDir, relPath) - updatedPath := filepath.Join(upstreamPkgDir, relPath) - originPath := filepath.Join(originalPkgDir, relPath) - isRoot := true - - updateOptions := update.Options{ - RelPackagePath: relPath, - LocalPath: localPath, - UpdatedPath: updatedPath, - OriginPath: originPath, - IsRoot: isRoot, - } - updater := update.ResourceMergeUpdater{} - if err := updater.Update(updateOptions); err != nil { - return err - } - } - return nil -} diff --git a/porch/pkg/engine/update_test.go b/porch/pkg/engine/update_test.go deleted file mode 100644 index 6e63cbe96b..0000000000 --- a/porch/pkg/engine/update_test.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "path/filepath" - "testing" - - "github.com/google/go-cmp/cmp" -) - -func TestPkgUpdate(t *testing.T) { - dfUpdater := &defaultPackageUpdater{} - - testdata, err := filepath.Abs(filepath.Join(".", "testdata", "update")) - if err != nil { - t.Fatalf("Failed to find testdata: %v", err) - } - - localResources, err := loadResourcesFromDirectory(filepath.Join(testdata, "local")) - if err != nil { - t.Fatalf("failed to read local resources: %v", err) - } - - originalResources, err := loadResourcesFromDirectory(filepath.Join(testdata, "original")) - if err != nil { - t.Fatalf("failed to read original resources: %v", err) - } - - upstreamResources, err := loadResourcesFromDirectory(filepath.Join(testdata, "upstream")) - if err != nil { - t.Fatalf("failed to read upstream resources: %v", err) - } - - expectedResources, err := loadResourcesFromDirectory(filepath.Join(testdata, "updated")) - if err != nil { - t.Fatalf("failed to read expected updated resources: %v", err) - } - - updatedResources, err := dfUpdater.Update(context.Background(), localResources, originalResources, upstreamResources) - if err != nil { - t.Errorf("unexpected err: %v", err) - } - - for k, v := range updatedResources.Contents { - want := expectedResources.Contents[k] - if diff := cmp.Diff(want, v); diff != "" && k != "Kptfile" { - // TODO(droot): figure out correct expectation for Kptfile - t.Errorf("file: %s unexpected result (-want, +got): %s", k, diff) - } - } -} diff --git a/porch/pkg/engine/watchermanager.go b/porch/pkg/engine/watchermanager.go deleted file mode 100644 index 8217404d0f..0000000000 --- a/porch/pkg/engine/watchermanager.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2022 The kpt 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. - -package engine - -import ( - "context" - "sync" - - "github.com/GoogleContainerTools/kpt/porch/pkg/meta" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/klog/v2" -) - -// ObjectCache caches objects across repositories, and allows for watching. -type WatcherManager interface { - WatchPackageRevisions(ctx context.Context, filter repository.ListPackageRevisionFilter, callback ObjectWatcher) error -} - -// PackageRevisionWatcher is the callback interface for watchers. -type ObjectWatcher interface { - OnPackageRevisionChange(eventType watch.EventType, obj repository.PackageRevision, objMeta meta.PackageRevisionMeta) bool -} - -func NewWatcherManager() *watcherManager { - return &watcherManager{} -} - -// watcherManager implements WatcherManager -type watcherManager struct { - mutex sync.Mutex - - // watchers is a list of all the change-listeners. - // As an optimization, values in this slice can be nil; we use this when the watch ends. - watchers []*watcher -} - -// watcher is a single change listener. -type watcher struct { - // isDoneFunction should return non-nil when the watcher is finished. - // This is normally bound to ctx.Err() - isDoneFunction func() error - - // callback is called for each object change. - callback ObjectWatcher - - // filter can limit the objects reported. - filter repository.ListPackageRevisionFilter -} - -// WatchPackageRevision adds a change-listener that will be called for all changes. -func (r *watcherManager) WatchPackageRevisions(ctx context.Context, filter repository.ListPackageRevisionFilter, callback ObjectWatcher) error { - r.mutex.Lock() - defer r.mutex.Unlock() - - // reap any dead watchers - for i, watcher := range r.watchers { - if watcher == nil { - continue - } - if err := watcher.isDoneFunction(); err != nil { - klog.Infof("stopping watcher in reaper: %v", err) - r.watchers[i] = nil - continue - } - } - - w := &watcher{ - isDoneFunction: ctx.Err, - callback: callback, - filter: filter, - } - - active := 0 - // See if we have an empty slot in the watchers list - inserted := false - for i, watcher := range r.watchers { - if watcher != nil { - active += 1 - } else if !inserted { - active += 1 - r.watchers[i] = w - inserted = true - } - } - - if !inserted { - // We didn't slot it in to an existing slot, append it - active += 1 - r.watchers = append(r.watchers, w) - } - - klog.Infof("added watcher %p; there are now %d active watchers and %d slots", w, active, len(r.watchers)) - return nil -} - -// notifyPackageRevisionChange is called to send a change notification to all interested listeners. -func (r *watcherManager) NotifyPackageRevisionChange(eventType watch.EventType, obj repository.PackageRevision, objMeta meta.PackageRevisionMeta) int { - r.mutex.Lock() - defer r.mutex.Unlock() - - sent := 0 - for i, watcher := range r.watchers { - if watcher == nil { - continue - } - if err := watcher.isDoneFunction(); err != nil { - klog.Infof("stopping watcher in response to error %v", err) - r.watchers[i] = nil - continue - } - if keepGoing := watcher.callback.OnPackageRevisionChange(eventType, obj, objMeta); !keepGoing { - klog.Infof("stopping watcher in response to !keepGoing") - r.watchers[i] = nil - } - sent += 1 - } - - return sent -} diff --git a/porch/pkg/git/annotation.go b/porch/pkg/git/annotation.go deleted file mode 100644 index c8b96bdc1c..0000000000 --- a/porch/pkg/git/annotation.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import ( - "encoding/json" - "fmt" - "strings" - - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/go-git/go-git/v5/plumbing/object" -) - -// gitAnnotation is the structured data that we store with commits. -// Currently this is stored as a json-encoded blob in the commit message, -// in future we might use git notes or a similar mechanism. -// TODO: Rationalize with OCI data structure? -type gitAnnotation struct { - // PackagePath is the path of the package we modified. - // This is useful for disambiguating which package we are modifying in a tree of packages, - // without having to check file paths. - PackagePath string `json:"package,omitempty"` - - // WorkspaceName holds the workspaceName of the package revision the commit - // belongs to. - WorkspaceName v1alpha1.WorkspaceName `json:"workspaceName,omitempty"` - - // Revision hold the revision of the package revision the commit - // belongs to. - Revision string `json:"revision,omitempty"` - - // Task holds the task we performed, if a task caused the commit. - Task *v1alpha1.Task `json:"task,omitempty"` -} - -// ExtractGitAnnotations reads the gitAnnotations from the given commit. -// If no annotation are found, it returns [], nil -// If an invalid annotation is found, it returns an error. -func ExtractGitAnnotations(commit *object.Commit) ([]*gitAnnotation, error) { - var annotations []*gitAnnotation - - for _, line := range strings.Split(commit.Message, "\n") { - line = strings.TrimSpace(line) - if strings.HasPrefix(line, "kpt:") { - annotation := &gitAnnotation{} - b := []byte(strings.TrimPrefix(line, "kpt:")) - if err := json.Unmarshal(b, annotation); err != nil { - return nil, fmt.Errorf("failed to unmarshal task command %q: %w", line, err) - } - annotations = append(annotations, annotation) - } - } - - return annotations, nil -} - -// AnnotateCommitMessage adds the gitAnnotation to the commit message. -func AnnotateCommitMessage(message string, annotation *gitAnnotation) (string, error) { - b, err := json.Marshal(annotation) - if err != nil { - return "", fmt.Errorf("error marshaling annotation: %w", err) - } - - message += "\n\nkpt:" + string(b) + "\n" - - return message, nil -} diff --git a/porch/pkg/git/commit.go b/porch/pkg/git/commit.go deleted file mode 100644 index 12a941c2e9..0000000000 --- a/porch/pkg/git/commit.go +++ /dev/null @@ -1,434 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import ( - "context" - "fmt" - "io" - "io/fs" - "path" - "sort" - "strings" - "time" - - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/filemode" - "github.com/go-git/go-git/v5/plumbing/object" -) - -const ( - porchSignatureName = "Package Orchestration Service" - porchSignatureEmail = "porch@kpt.dev" -) - -type commitHelper struct { - repository *gitRepository - - // trees holds a map of all the tree objects we are writing to. - // We reuse the existing object.Tree structures. - // When a tree is dirty, we set the hash as plumbing.ZeroHash. - trees map[string]*object.Tree - - // parentCommitHash holds the hash of the parent commit, or ZeroHash if this is the first commit. - parentCommitHash plumbing.Hash - - // userInfoProvider provides user information for the commit - userInfoProvider repository.UserInfoProvider -} - -// if packageTree is zero, new tree for the package will be created (effectively replacing the package with the subsequently provided -// contents). If the packageTree is provided, the tree will be used as the initial package contents, possibly subsequently modified. -func newCommitHelper(repo *gitRepository, userInfoProvider repository.UserInfoProvider, - parentCommitHash plumbing.Hash, packagePath string, packageTree plumbing.Hash) (*commitHelper, error) { - var root *object.Tree - - if parentCommitHash.IsZero() { - // No parent commit, start with an empty tree - root = &object.Tree{} - } else { - parentCommit, err := repo.getCommit(parentCommitHash) - if err != nil { - return nil, fmt.Errorf("cannot resolve parent commit hash %s to commit: %w", parentCommitHash, err) - } - t, err := parentCommit.Tree() - if err != nil { - return nil, fmt.Errorf("cannot resolve parent commit's (%s) tree (%s) to tree object: %w", parentCommitHash, parentCommit.TreeHash, err) - } - root = t - } - - trees, err := initializeTrees(repo, root, packagePath, packageTree) - if err != nil { - return nil, err - } - - ch := &commitHelper{ - repository: repo, - trees: trees, - parentCommitHash: parentCommitHash, - userInfoProvider: userInfoProvider, - } - - return ch, nil -} - -// Initializes ancestor trees of the package, reading them from the storer. -// If packageTree hash is provided, it will be used as the package's initial tree. Otherwise, new tree will be used -// (effectively replacing the package with an empty one). -func initializeTrees(repo *gitRepository, root *object.Tree, packagePath string, - packageTreeHash plumbing.Hash) (map[string]*object.Tree, error) { - - trees := map[string]*object.Tree{ - "": root, - } - - parts := strings.Split(packagePath, "/") - if len(parts) == 0 { - // empty package path is invalid - return nil, fmt.Errorf("invalid package path: %q", packagePath) - } - - // Load all ancestor trees - parent := root - for i, max := 0, len(parts)-1; i < max; i++ { - name := parts[i] - path := strings.Join(parts[0:i+1], "/") - - var current *object.Tree - switch existing := findEntry(parent, name); { - case existing == nil: - // Create new empty tree for this ancestor. - current = &object.Tree{} - - case existing.Mode == filemode.Dir: - // Existing entry is a tree. use it - hash := existing.Hash - curr, err := repo.getTree(hash) - if err != nil { - return nil, fmt.Errorf("cannot read existing tree %s; root %q, path %q", hash, root.Hash, path) - } - current = curr - - default: - // Existing entry is not a tree. Error. - return nil, fmt.Errorf("path %q is %s, not a directory in tree %s, root %q", path, existing.Mode, existing.Hash, root.Hash) - } - - // Set tree in the parent - setOrAddTreeEntry(parent, object.TreeEntry{ - Name: name, - Mode: filemode.Dir, - Hash: plumbing.ZeroHash, - }) - - trees[strings.Join(parts[0:i+1], "/")] = current - parent = current - } - - // Initialize the package tree. - lastPart := parts[len(parts)-1] - if !packageTreeHash.IsZero() { - // Initialize with the supplied package tree. - packageTree, err := repo.getTree(packageTreeHash) - if err != nil { - return nil, fmt.Errorf("cannot find existing package tree %s for package %q: %w", packageTreeHash, packagePath, err) - } - trees[packagePath] = packageTree - setOrAddTreeEntry(parent, object.TreeEntry{ - Name: lastPart, - Mode: filemode.Dir, - Hash: plumbing.ZeroHash, - }) - } else { - // Remove the entry if one exists - removeTreeEntry(parent, lastPart) - } - - return trees, nil -} - -// Returns a pointer to the entry if found (by name); nil if not found -func findEntry(tree *object.Tree, name string) *object.TreeEntry { - for i := range tree.Entries { - e := &tree.Entries[i] - if e.Name == name { - return e - } - } - return nil -} - -// setOrAddTreeEntry will overwrite the existing entry (by name) or insert if not present. -func setOrAddTreeEntry(tree *object.Tree, entry object.TreeEntry) { - for i := range tree.Entries { - e := &tree.Entries[i] - if e.Name == entry.Name { - *e = entry // Overwrite the tree entry - return - } - } - // Not found. append new - tree.Entries = append(tree.Entries, entry) -} - -// removeTreeEntry will remove the specified entry (by name) -func removeTreeEntry(tree *object.Tree, name string) { - entries := tree.Entries - for i := range entries { - e := &entries[i] - if e.Name == name { - tree.Entries = append(entries[:i], entries[i+1:]...) - return - } - } -} - -// storeFile writes a blob with contents at the specified path -func (h *commitHelper) storeFile(path, contents string) error { - hash, err := h.repository.storeBlob(contents) - if err != nil { - return err - } - - if err := h.storeBlobHashInTrees(path, hash); err != nil { - return err - } - return nil -} - -// storeTree sets the tree of the provided path to the tree -// referenced by the provided hash. -func (h *commitHelper) storeTree(path string, hash plumbing.Hash) error { - parentPath, pkg := split(path) - tree := h.ensureTree(parentPath) - setOrAddTreeEntry(tree, object.TreeEntry{ - Name: pkg, - Mode: filemode.Dir, - }) - pTree, err := h.repository.getTree(hash) - if err != nil { - return err - } - h.trees[path] = pTree - return nil -} - -// readFile returns the contents of the blob at path. -// If the file is not found it returns an error satisfying os.IsNotExist -func (h *commitHelper) readFile(path string) ([]byte, error) { - dir, filename := split(path) - tree := h.trees[dir] - if tree == nil { - return nil, fs.ErrNotExist - } - - entry := findEntry(tree, filename) - if entry == nil { - return nil, fs.ErrNotExist - } - - blob, err := h.repository.blobObject(entry.Hash) - if err != nil { - // This is an internal consistency error, so we don't return ErrNotExist - return nil, fmt.Errorf("error reading from git: %w", err) - } - r, err := blob.Reader() - if err != nil { - return nil, fmt.Errorf("error reading from git: %w", err) - } - defer r.Close() - - b, err := io.ReadAll(r) - if err != nil { - return nil, fmt.Errorf("error reading from git: %w", err) - } - return b, nil -} - -// commit stores all changes in git and creates a commit object. -func (h *commitHelper) commit(ctx context.Context, message string, pkgPath string, additionalParentCommits ...plumbing.Hash) (commit, pkgTree plumbing.Hash, err error) { - rootTreeHash, err := h.storeTrees("") - if err != nil { - return plumbing.ZeroHash, plumbing.ZeroHash, err - } - - var ui *repository.UserInfo - if h.userInfoProvider != nil { - ui = h.userInfoProvider.GetUserInfo(ctx) - } - - var parentCommits []plumbing.Hash - if !h.parentCommitHash.IsZero() { - parentCommits = append(parentCommits, h.parentCommitHash) - } - parentCommits = append(parentCommits, additionalParentCommits...) - - commit, err = h.storeCommit(parentCommits, rootTreeHash, ui, message) - if err != nil { - return plumbing.ZeroHash, plumbing.ZeroHash, err - } - // Update the parentCommitHash so the correct parent will be used for the - // next commit. - h.parentCommitHash = commit - - if pkg, ok := h.trees[pkgPath]; ok { - pkgTree = pkg.Hash - } else { - pkgTree = plumbing.ZeroHash - } - - return commit, pkgTree, nil -} - -// split returns the full directory path and file name -// If there is no directory, it returns an empty directory path and the path as the filename. -func split(path string) (string, string) { - i := strings.LastIndex(path, "/") - if i >= 0 { - return path[:i], path[i+1:] - } - return "", path -} - -// ensureTrees ensures we have a trees for all directories in fullPath. -// fullPath is expected to be a directory path. -func (h *commitHelper) ensureTree(fullPath string) *object.Tree { - if tree, ok := h.trees[fullPath]; ok { - return tree - } - - dir, base := split(fullPath) - parent := h.ensureTree(dir) - - te := object.TreeEntry{ - Name: base, - Mode: filemode.Dir, - } - - for ei, ev := range parent.Entries { - // Replace whole subtrees modified by the package contents. - if ev.Name == te.Name && !ev.Hash.IsZero() { - parent.Entries[ei] = te - goto added - } - } - // Append a new entry - parent.Entries = append(parent.Entries, te) - -added: - tree := &object.Tree{} - h.trees[fullPath] = tree - return tree -} - -// storeBlobHashInTrees writes the (previously stored) blob hash at fullpath, marking all the directory trees as dirty. -func (h *commitHelper) storeBlobHashInTrees(fullPath string, hash plumbing.Hash) error { - dir, file := split(fullPath) - if file == "" { - return fmt.Errorf("invalid resource path: %q; no file name", fullPath) - } - - tree := h.ensureTree(dir) - setOrAddTreeEntry(tree, object.TreeEntry{ - Name: file, - Mode: filemode.Regular, - Hash: hash, - }) - - return nil -} - -// storeTrees writes the tree at treePath to git, first writing all child trees. -func (h *commitHelper) storeTrees(treePath string) (plumbing.Hash, error) { - tree, ok := h.trees[treePath] - if !ok { - return plumbing.Hash{}, fmt.Errorf("failed to find a tree %q", treePath) - } - - entries := tree.Entries - sort.Slice(entries, func(i, j int) bool { - return entrySortKey(&entries[i]) < entrySortKey(&entries[j]) - }) - - // Store all child trees and get their hashes - for i := range entries { - e := &entries[i] - if e.Mode != filemode.Dir { - continue - } - if !e.Hash.IsZero() { - continue - } - - hash, err := h.storeTrees(path.Join(treePath, e.Name)) - if err != nil { - return plumbing.Hash{}, err - } - e.Hash = hash - } - - treeHash, err := h.repository.storeTree(tree) - if err != nil { - return plumbing.Hash{}, err - } - - tree.Hash = treeHash - return treeHash, nil -} - -// Git sorts tree entries as though directories have '/' appended to them. -func entrySortKey(e *object.TreeEntry) string { - if e.Mode == filemode.Dir { - return e.Name + "/" - } - return e.Name -} - -// storeCommit creates and writes a commit object to git. -func (h *commitHelper) storeCommit(parentCommits []plumbing.Hash, tree plumbing.Hash, userInfo *repository.UserInfo, message string) (plumbing.Hash, error) { - now := time.Now() - var authorName, authorEmail string - if userInfo != nil { - // Authenticated user info only provides one value... - authorName = userInfo.Name - authorEmail = userInfo.Email - } else { - // Defaults - authorName = porchSignatureName - authorEmail = porchSignatureEmail - } - commit := &object.Commit{ - Author: object.Signature{ - Name: authorName, - Email: authorEmail, - When: now, - }, - Committer: object.Signature{ - Name: porchSignatureName, - Email: porchSignatureEmail, - When: now, - }, - Message: message, - TreeHash: tree, - } - - if len(parentCommits) > 0 { - commit.ParentHashes = parentCommits - } - - return h.repository.storeCommit(commit) -} diff --git a/porch/pkg/git/commit_test.go b/porch/pkg/git/commit_test.go deleted file mode 100644 index 837a6ffd63..0000000000 --- a/porch/pkg/git/commit_test.go +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import ( - "context" - "fmt" - "path" - "path/filepath" - "testing" - "time" - - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/object" -) - -func TestPackageCommitEmptyRepo(t *testing.T) { - tempdir := t.TempDir() - gitRepo := OpenGitRepositoryFromArchive(t, filepath.Join("testdata", "empty-repository.tar"), tempdir) - repo := &gitRepository{ - repo: gitRepo, - } - - ctx := context.Background() - - var userInfoProvider repository.UserInfoProvider - parent := plumbing.ZeroHash // Empty repository - packageTree := plumbing.ZeroHash // Empty package - packagePath := "catalog/namespaces/istions" - ch, err := newCommitHelper(repo, userInfoProvider, parent, packagePath, packageTree) - if err != nil { - t.Fatalf("newCommitHelper(%q) failed: %v", packagePath, err) - } - - filePath := path.Join(packagePath, "hello.txt") - fileContents := "Hello, World!" - if err := ch.storeFile(filePath, fileContents); err != nil { - t.Fatalf("storeFile(%q, %q) failed: %v", filePath, fileContents, err) - } - - message := fmt.Sprintf("Commit Message: %d", time.Now().UnixMicro()) - commitHash, treeHash, err := ch.commit(ctx, message, packagePath) - if err != nil { - t.Fatalf("Commit failed: %v", err) - } - if commitHash.IsZero() { - t.Errorf("Commit returned zero commit hash") - } - if treeHash.IsZero() { - t.Errorf("Commit returned zero package tree hash") - } - - commit := getCommitObject(t, gitRepo, commitHash) - if got, want := commit.Message, message; got != want { - t.Errorf("Commit message: got %q, want %q", got, want) - } - root, err := commit.Tree() - if err != nil { - t.Fatalf("Failed to get tree from commit %q: %v", commitHash, err) - } - entry := findTreeEntry(t, root, packagePath) - if got, want := entry.Hash, treeHash; got != want { - t.Errorf("Packag tree hash: got %s, want %s", got, want) - } - file := findFile(t, root, filePath) - got, err := file.Contents() - if err != nil { - t.Fatalf("Failed to read contents of file %q under the root commit tree %q: %v", filePath, root.Hash, err) - } - if want := fileContents; got != want { - t.Errorf("File contents: got %q, want %q", got, want) - } -} - -func TestPackageCommitToMain(t *testing.T) { - tempdir := t.TempDir() - gitRepo := OpenGitRepositoryFromArchive(t, filepath.Join("testdata", "drafts-repository.tar"), tempdir) - repo := &gitRepository{ - repo: gitRepo, - } - - ctx := context.Background() - - var userInfoProvider repository.UserInfoProvider - - // Commit `bucket`` package from drafts/bucket/v1 into main - - main := resolveReference(t, gitRepo, DefaultMainReferenceName) - packagePath := "bucket" - - // Confirm no 'bucket' package in main - mainRoot := getCommitTree(t, gitRepo, main.Hash()) - { - entry, err := mainRoot.FindEntry(packagePath) - if entry != nil || err != object.ErrEntryNotFound { - t.Fatalf("Unexpectedly found %q package in main branch: %v, %v", packagePath, entry, err) - } - } - draft := resolveReference(t, gitRepo, plumbing.NewBranchReferenceName("drafts/bucket/v1")) - draftTree := getCommitTree(t, gitRepo, draft.Hash()) - bucketEntry := findTreeEntry(t, draftTree, packagePath) - bucketTree := bucketEntry.Hash - ch, err := newCommitHelper(repo, userInfoProvider, main.Hash(), packagePath, bucketTree) - if err != nil { - t.Fatalf("Failed to create commit helper: %v", err) - } - - commitHash, treeHash, err := ch.commit(ctx, "Move bucket to main", packagePath) - if err != nil { - t.Fatalf("Commit failed: %v", err) - } - if commitHash.IsZero() { - t.Errorf("Commit returned zero commit hash") - } - if treeHash.IsZero() { - t.Errorf("Commit returned zero package tree hash") - } - - commitTree := getCommitTree(t, gitRepo, commitHash) - packageEntry := findTreeEntry(t, commitTree, packagePath) - if got, want := packageEntry.Hash, bucketTree; got != want { - t.Errorf("Package copied into main branch with unexpected tree hash; got %s, want %s", got, want) - } -} - -type testUserInfoProvider struct { - userInfo *repository.UserInfo -} - -func (p *testUserInfoProvider) GetUserInfo(ctx context.Context) *repository.UserInfo { - return p.userInfo -} - -func TestCommitWithUser(t *testing.T) { - tempdir := t.TempDir() - gitRepo := OpenGitRepositoryFromArchive(t, filepath.Join("testdata", "trivial-repository.tar"), tempdir) - repo := &gitRepository{ - repo: gitRepo, - } - - ctx := context.Background() - main := resolveReference(t, gitRepo, DefaultMainReferenceName) - - { - const testEmail = "porch-test@porch-domain.com" - const testName = "Porch Test" - // Make one commit with user info provided - userInfoProvider := &testUserInfoProvider{ - userInfo: &repository.UserInfo{ - Name: testName, - Email: testEmail, - }, - } - - var zeroHash plumbing.Hash - const packagePath = "testpackage" - ch, err := newCommitHelper(repo, userInfoProvider, main.Hash(), packagePath, zeroHash) - if err != nil { - t.Fatalf("newCommitHelper(%q) failed: %v", packagePath, err) - } - - filePath := path.Join(packagePath, "hello.txt") - fileContents := "Hello, World!" - if err := ch.storeFile(filePath, fileContents); err != nil { - t.Fatalf("storeFile(%q, %q) failed: %v", filePath, fileContents, err) - } - - message := fmt.Sprintf("Commit Message: %d", time.Now().UnixMicro()) - commitHash, _, err := ch.commit(ctx, message, packagePath) - if err != nil { - t.Fatalf("commit failed: %v", err) - } - - commit := getCommitObject(t, gitRepo, commitHash) - - if got, want := commit.Author.Email, testEmail; got != want { - t.Errorf("Commit.Author.Email: got %q, want %q", got, want) - } - if got, want := commit.Author.Name, testName; got != want { - t.Errorf("Commit.Author.Name: got %q, want %q", got, want) - } - - // Committer is Porch - if got, want := commit.Committer.Email, porchSignatureEmail; got != want { - t.Errorf("Commit.Author.Email: got %q, want %q", got, want) - } - if got, want := commit.Committer.Name, porchSignatureName; got != want { - t.Errorf("Commit.Author.Name: got %q, want %q", got, want) - } - } - - { - // And another without ... - userInfoProvider := &testUserInfoProvider{ - userInfo: nil, - } - - var zeroHash plumbing.Hash - const packagePath = "testpackage-nouser" - ch, err := newCommitHelper(repo, userInfoProvider, main.Hash(), packagePath, zeroHash) - if err != nil { - t.Fatalf("newCommitHelper(%q) failed: %v", packagePath, err) - } - - filePath := path.Join(packagePath, "hello-nouser.txt") - fileContents := "Hello, World!" - if err := ch.storeFile(filePath, fileContents); err != nil { - t.Fatalf("storeFile(%q, %q) failed: %v", filePath, fileContents, err) - } - - message := fmt.Sprintf("Commit Message: %d", time.Now().UnixMicro()) - commitHash, _, err := ch.commit(ctx, message, packagePath) - if err != nil { - t.Fatalf("commit failed: %v", err) - } - - commit := getCommitObject(t, gitRepo, commitHash) - - if got, want := commit.Author.Email, porchSignatureEmail; got != want { - t.Errorf("Commit.Author.Email: got %q, want %q", got, want) - } - if got, want := commit.Author.Name, porchSignatureName; got != want { - t.Errorf("Commit.Author.Name: got %q, want %q", got, want) - } - - // Committer is Porch - if got, want := commit.Committer.Email, porchSignatureEmail; got != want { - t.Errorf("Commit.Author.Email: got %q, want %q", got, want) - } - if got, want := commit.Committer.Name, porchSignatureName; got != want { - t.Errorf("Commit.Author.Name: got %q, want %q", got, want) - } - - // Check the message - if got, want := commit.Message, message; got != want { - t.Errorf("Commit.Message: got %q, want %q", got, want) - } - } -} diff --git a/porch/pkg/git/dir.go b/porch/pkg/git/dir.go deleted file mode 100644 index fb037f4efa..0000000000 --- a/porch/pkg/git/dir.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import "strings" - -// Determines whether a package specified by a path is in a directory given. -func packageInDirectory(pkg, dir string) bool { - if dir == "" { - return true - } - if strings.HasPrefix(pkg, dir) { - if len(pkg) == len(dir) { - return true - } - if pkg[len(dir)] == '/' { - return true - } - } - return false -} diff --git a/porch/pkg/git/dir_test.go b/porch/pkg/git/dir_test.go deleted file mode 100644 index 03f2696f4b..0000000000 --- a/porch/pkg/git/dir_test.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import "testing" - -func TestPackageInDirectory(t *testing.T) { - for _, tc := range []struct { - pkg, dir string - want bool - }{ - { - pkg: "root/nested", - dir: "", - want: true, - }, { - pkg: "catalog/package", - dir: "cat", - want: false, - }, - { - pkg: "catalog/package", - dir: "catalog", - want: true, - }, - { - pkg: "catalog/package/nested", - dir: "catalog/packages", - want: false, - }, - { - pkg: "catalog/package/nested", - dir: "catalog/package", - want: true, - }, - { - pkg: "catalog/package/nested", - dir: "catalog/package/nest", - want: false, - }, - { - pkg: "catalog/package/nested", - dir: "catalog/package/nested", - want: true, - }, - { - pkg: "catalog/package/nested", - dir: "catalog/package/nested/even-more", - want: false, - }, - } { - if got, want := packageInDirectory(tc.pkg, tc.dir), tc.want; got != want { - t.Errorf("packageInDirectory(%q, %q): got %t, want %t", tc.pkg, tc.dir, got, want) - } - } -} diff --git a/porch/pkg/git/doc.go b/porch/pkg/git/doc.go deleted file mode 100644 index 70e8a42a48..0000000000 --- a/porch/pkg/git/doc.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2022 The kpt 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. - -// Git Repository Adapter -// -// This component implements integration of git into package orchestration. -// A local clone of a registered git repository is created in a cache, and -// periodically refreshed. -// All package operations happen on the local copy; on completion of an -// operation (create, update, delete package revision or its resources) -// any new changes (in one or more commits) are pushed to the remote -// repository. -// -// # Branching Strategy -// -// Porch doesn't create tracking branches for remotes. This indirection -// would add a layer of complexity where branches can become out of sync -// and in need of reconciliation and conflict resolution. Instead, Porch -// analyzes the remote references (refs/remotes/origin/branch...) to -// discover packges. These refs are never directly updated by Porch other -// than by push or fetch to/from remote. -// Any intermediate commits Porch makes are either in 'detached HEAD' -// mode, or using temporary branches (these will become relevant if/when -// Porch implements repository garbage collection). -// -// Porch uses the default convention for naming remote branches -// (refs/remotes/origin/branch...) in order to make direct introspection -// of the repositories aligned with traditional git repositories. -package git diff --git a/porch/pkg/git/draft.go b/porch/pkg/git/draft.go deleted file mode 100644 index 458ccadcf5..0000000000 --- a/porch/pkg/git/draft.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import ( - "context" - "time" - - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/go-git/go-git/v5/plumbing" - "go.opentelemetry.io/otel/trace" -) - -type gitPackageDraft struct { - parent *gitRepository // repo is repo containing the package - path string // the path to the package from the repo root - revision string - workspaceName v1alpha1.WorkspaceName - updated time.Time - tasks []v1alpha1.Task - - // New value of the package revision lifecycle - lifecycle v1alpha1.PackageRevisionLifecycle - - // ref to the base of the package update commit chain (used for conditional push) - base *plumbing.Reference - - // name of the branch where the changes will be pushed - branch BranchName - - // Current HEAD of the package changes (commit sha) - commit plumbing.Hash - - // Cached tree of the package itself, some descendent of commit.Tree() - tree plumbing.Hash -} - -var _ repository.PackageDraft = &gitPackageDraft{} - -func (d *gitPackageDraft) UpdateResources(ctx context.Context, new *v1alpha1.PackageRevisionResources, change *v1alpha1.Task) error { - ctx, span := tracer.Start(ctx, "gitPackageDraft::UpdateResources", trace.WithAttributes()) - defer span.End() - - return d.parent.UpdateDraftResources(ctx, d, new, change) -} - -func (d *gitPackageDraft) UpdateLifecycle(ctx context.Context, new v1alpha1.PackageRevisionLifecycle) error { - d.lifecycle = new - return nil -} - -// Finish round of updates. -func (d *gitPackageDraft) Close(ctx context.Context) (repository.PackageRevision, error) { - ctx, span := tracer.Start(ctx, "gitPackageDraft::Close", trace.WithAttributes()) - defer span.End() - - return d.parent.CloseDraft(ctx, d) -} diff --git a/porch/pkg/git/git.go b/porch/pkg/git/git.go deleted file mode 100644 index 37857916e2..0000000000 --- a/porch/pkg/git/git.go +++ /dev/null @@ -1,1805 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import ( - "bytes" - "context" - "crypto/sha256" - "encoding/hex" - "errors" - "fmt" - "io" - "os" - "path" - "path/filepath" - "strings" - "sync" - "time" - - kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/config" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/filemode" - "github.com/go-git/go-git/v5/plumbing/object" - "github.com/go-git/go-git/v5/plumbing/storer" - "github.com/go-git/go-git/v5/plumbing/transport" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/trace" - "k8s.io/klog/v2" -) - -var tracer = otel.Tracer("git") - -const ( - DefaultMainReferenceName plumbing.ReferenceName = "refs/heads/main" - OriginName string = "origin" -) - -type GitRepository interface { - repository.Repository - GetPackageRevision(ctx context.Context, ref, path string) (repository.PackageRevision, kptfilev1.GitLock, error) - UpdateDeletionProposedCache() error -} - -//go:generate go run golang.org/x/tools/cmd/stringer@v0.19.0 -type=MainBranchStrategy -linecomment -type MainBranchStrategy int - -const ( - ErrorIfMissing MainBranchStrategy = iota // ErrorIsMissing - CreateIfMissing // CreateIfMissing - SkipVerification // SkipVerification -) - -type GitRepositoryOptions struct { - CredentialResolver repository.CredentialResolver - UserInfoProvider repository.UserInfoProvider - MainBranchStrategy MainBranchStrategy -} - -func OpenRepository(ctx context.Context, name, namespace string, spec *configapi.GitRepository, deployment bool, root string, opts GitRepositoryOptions) (GitRepository, error) { - ctx, span := tracer.Start(ctx, "OpenRepository", trace.WithAttributes()) - defer span.End() - - replace := strings.NewReplacer("/", "-", ":", "-") - dir := filepath.Join(root, replace.Replace(spec.Repo)) - - // Cleanup the cache directory in case initialization fails. - cleanup := dir - defer func() { - if cleanup != "" { - os.RemoveAll(cleanup) - } - }() - - var repo *git.Repository - - if fi, err := os.Stat(dir); err != nil { - if !os.IsNotExist(err) { - return nil, err - } - - r, err := initEmptyRepository(dir) - if err != nil { - return nil, fmt.Errorf("error cloning git repository %q: %w", spec.Repo, err) - } - - repo = r - } else if !fi.IsDir() { - // Internal error - corrupted cache. We will cleanup on the way out. - return nil, fmt.Errorf("cannot clone git repository %q: %w", spec.Repo, err) - } else { - cleanup = "" // Existing directory; do not delete it. - - r, err := openRepository(dir) - if err != nil { - return nil, err - } - - repo = r - } - - // Create Remote - if err := initializeOrigin(repo, spec.Repo); err != nil { - return nil, fmt.Errorf("error cloning git repository %q, cannot create remote: %v", spec.Repo, err) - } - - branch := MainBranch - if spec.Branch != "" { - branch = BranchName(spec.Branch) - } - - repository := &gitRepository{ - name: name, - namespace: namespace, - repo: repo, - branch: branch, - directory: strings.Trim(spec.Directory, "/"), - secret: spec.SecretRef.Name, - credentialResolver: opts.CredentialResolver, - userInfoProvider: opts.UserInfoProvider, - cacheDir: dir, - deployment: deployment, - } - - if err := repository.fetchRemoteRepository(ctx); err != nil { - return nil, err - } - - if err := repository.verifyRepository(ctx, &opts); err != nil { - return nil, err - } - - cleanup = "" // Success. Keep the git directory. - - return repository, nil -} - -type gitRepository struct { - name string // Repository resource name - namespace string // Repository resource namespace - secret string // Name of the k8s Secret resource containing credentials - branch BranchName // The main branch from repository registration (defaults to 'main' if unspecified) - directory string // Directory within the repository where to look for packages. - repo *git.Repository - credentialResolver repository.CredentialResolver - userInfoProvider repository.UserInfoProvider - - // Folder used for the local git cache. - cacheDir string - - // deployment holds spec.deployment - // TODO: Better caching here, support repository spec changes - deployment bool - - // credential contains the information needed to authenticate against - // a git repository. - credential repository.Credential - - // deletionProposedCache contains the deletionProposed branches that - // exist in the repo so that we can easily check them without iterating - // through all the refs each time - deletionProposedCache map[BranchName]bool - - mutex sync.Mutex -} - -var _ GitRepository = &gitRepository{} - -func (r *gitRepository) Close() error { - if err := os.RemoveAll(r.cacheDir); err != nil { - return fmt.Errorf("error cleaning up local git cache for repo %s: %v", r.name, err) - } - return nil -} - -func (r *gitRepository) Version(ctx context.Context) (string, error) { - ctx, span := tracer.Start(ctx, "gitRepository::Version", trace.WithAttributes()) - defer span.End() - r.mutex.Lock() - defer r.mutex.Unlock() - - if err := r.fetchRemoteRepository(ctx); err != nil { - return "", err - } - - refs, err := r.repo.References() - if err != nil { - return "", err - } - - b := bytes.Buffer{} - for { - ref, err := refs.Next() - if err == io.EOF { - break - } - - b.WriteString(ref.String()) - } - - hash := sha256.Sum256(b.Bytes()) - return hex.EncodeToString(hash[:]), nil -} - -func (r *gitRepository) ListPackages(ctx context.Context, filter repository.ListPackageFilter) ([]repository.Package, error) { - ctx, span := tracer.Start(ctx, "gitRepository::ListPackages", trace.WithAttributes()) - defer span.End() - - // TODO - return nil, fmt.Errorf("ListPackages not yet supported for git repos") -} - -func (r *gitRepository) CreatePackage(ctx context.Context, obj *v1alpha1.Package) (repository.Package, error) { - ctx, span := tracer.Start(ctx, "gitRepository::CreatePackage", trace.WithAttributes()) - defer span.End() - - // TODO: Create a 'Package' resource and an initial, empty 'PackageRevision' - return nil, fmt.Errorf("CreatePackage not yet supported for git repos") -} - -func (r *gitRepository) DeletePackage(ctx context.Context, obj repository.Package) error { - ctx, span := tracer.Start(ctx, "gitRepository::DeletePackage", trace.WithAttributes()) - defer span.End() - - // TODO: Support package deletion using subresources (similar to the package revision approval flow) - return fmt.Errorf("DeletePackage not yet supported for git repos") -} - -func (r *gitRepository) ListPackageRevisions(ctx context.Context, filter repository.ListPackageRevisionFilter) ([]repository.PackageRevision, error) { - ctx, span := tracer.Start(ctx, "gitRepository::ListPackageRevisions", trace.WithAttributes()) - defer span.End() - r.mutex.Lock() - defer r.mutex.Unlock() - - pkgRevs, err := r.listPackageRevisions(ctx, filter) - if err != nil { - return nil, err - } - var repoPkgRevs []repository.PackageRevision - for i := range pkgRevs { - repoPkgRevs = append(repoPkgRevs, pkgRevs[i]) - } - return repoPkgRevs, nil -} - -func (r *gitRepository) listPackageRevisions(ctx context.Context, filter repository.ListPackageRevisionFilter) ([]*gitPackageRevision, error) { - ctx, span := tracer.Start(ctx, "gitRepository::listPackageRevisions", trace.WithAttributes()) - defer span.End() - - if err := r.fetchRemoteRepository(ctx); err != nil { - return nil, err - } - - refs, err := r.repo.References() - if err != nil { - return nil, err - } - - var main *plumbing.Reference - var drafts []*gitPackageRevision - var result []*gitPackageRevision - - mainBranch := r.branch.RefInLocal() // Looking for the registered branch - - // if a cache is available, use it - cache := repository.PackageRevisionCacheFromContext(ctx) - draftCache := 0 - tagCache := 0 - mainCache := 0 - draftLoaded := 0 - tagLoaded := 0 - mainLoaded := 0 - for { - ref, err := refs.Next() - if err == io.EOF { - break - } - - switch name := ref.Name(); { - case name == mainBranch: - main = ref - continue - - case isProposedBranchNameInLocal(ref.Name()), isDraftBranchNameInLocal(ref.Name()): - var draft *gitPackageRevision - if entry, ok := cache[ref.Name().String()]; ok { - if entry.Version == ref.Hash().String() { - dd, good := entry.PackageRevision.(*gitPackageRevision) - if !good { - klog.Warningf("Found current cached branch %s version %s, but it is not a gitPackageRevision", ref.Name(), entry.Version) - } else { - draft = dd - draftCache += 1 - } - } - } - - if draft == nil { - draft, err = r.loadDraft(ctx, ref) - if err != nil { - return nil, fmt.Errorf("failed to load package draft %q: %w", name.String(), err) - } - if draft != nil { - draftLoaded += 1 - } - } - if draft != nil { - drafts = append(drafts, draft) - } else { - klog.Warningf("no package draft found for ref %v", ref) - } - case isTagInLocalRepo(ref.Name()): - var tagged *gitPackageRevision - if entry, ok := cache[ref.Name().String()]; ok { - if entry.Version == ref.Hash().String() { - dd, good := entry.PackageRevision.(*gitPackageRevision) - if !good { - klog.Warningf("Found current cached branch %s version %s, but it is not a gitPackageRevision", ref.Name(), entry.Version) - } else { - tagged = dd - tagCache += 1 - } - } - } - if tagged == nil { - tagged, err = r.loadTaggedPackage(ctx, ref) - if err != nil { - // this tag is not associated with any package (e.g. could be a release tag) - continue - } - if tagged != nil { - tagLoaded += 1 - } - } - if tagged != nil && filter.Matches(tagged) { - result = append(result, tagged) - } - } - } - - if main != nil { - // Look for any package whose cached identifier starts with main.Name() - // There will be one for each pacakge found in main, but they all will have the same - // hash. If that matches main.Hash() there is no change in main and so we can just - // copy all the packages rather than rediscovering. - var mainpkgs []*gitPackageRevision - for k, v := range cache { - if strings.Index(k, main.Name().String()) == 0 { - if v.Version != main.Hash().String() { - continue - } - gpr, ok := v.PackageRevision.(*gitPackageRevision) - if !ok { - klog.Warningf("Found current cached main package %s version %s, but it is not a gitPackageRevision", k, v.Version) - } else { - mainpkgs = append(mainpkgs, gpr) - mainCache += 1 - } - } - } - - // TODO: ignore packages that are unchanged in main branch, compared to a tagged version? - if len(mainpkgs) == 0 { - mp, err := r.discoverFinalizedPackages(ctx, main) - if err != nil { - return nil, err - } - mainpkgs = mp - mainLoaded = len(mainpkgs) - } - for _, p := range mainpkgs { - if filter.Matches(p) { - result = append(result, p) - } - } - } - - for _, p := range drafts { - if filter.Matches(p) { - result = append(result, p) - } - } - - klog.Infof("repo %s/%s: %d draftCache, %d draftLoaded, %d tagCache, %d tagLoaded, %d mainCache, %d mainLoaded", r.namespace, r.name, - draftCache, draftLoaded, tagCache, tagLoaded, mainCache, mainLoaded) - return result, nil -} - -func (r *gitRepository) CreatePackageRevision(ctx context.Context, obj *v1alpha1.PackageRevision) (repository.PackageDraft, error) { - ctx, span := tracer.Start(ctx, "gitRepository::CreatePackageRevision", trace.WithAttributes()) - defer span.End() - r.mutex.Lock() - defer r.mutex.Unlock() - - var base plumbing.Hash - refName := r.branch.RefInLocal() - switch main, err := r.repo.Reference(refName, true); { - case err == nil: - base = main.Hash() - case err == plumbing.ErrReferenceNotFound: - // reference not found - empty repository. Package draft has no parent commit - default: - return nil, fmt.Errorf("error when resolving target branch for the package: %w", err) - } - - if err := repository.ValidateWorkspaceName(obj.Spec.WorkspaceName); err != nil { - return nil, fmt.Errorf("failed to create packagerevision: %w", err) - } - - packagePath := filepath.Join(r.directory, obj.Spec.PackageName) - - // TODO use git branches to leverage uniqueness - draft := createDraftName(packagePath, obj.Spec.WorkspaceName) - - // TODO: This should also create a new 'Package' resource if one does not already exist - - return &gitPackageDraft{ - parent: r, - path: packagePath, - workspaceName: obj.Spec.WorkspaceName, - lifecycle: v1alpha1.PackageRevisionLifecycleDraft, - updated: time.Now(), - base: nil, // Creating a new package - tasks: nil, // Creating a new package - branch: draft, - commit: base, - }, nil -} - -func (r *gitRepository) UpdatePackageRevision(ctx context.Context, old repository.PackageRevision) (repository.PackageDraft, error) { - ctx, span := tracer.Start(ctx, "gitRepository::UpdatePackageRevision", trace.WithAttributes()) - defer span.End() - r.mutex.Lock() - defer r.mutex.Unlock() - - oldGitPackage, ok := old.(*gitPackageRevision) - if !ok { - return nil, fmt.Errorf("cannot update non-git package %T", old) - } - - ref := oldGitPackage.ref - if ref == nil { - return nil, fmt.Errorf("cannot update final package") - } - - head, err := r.repo.Reference(ref.Name(), true) - if err != nil { - return nil, fmt.Errorf("cannot find draft package branch %q: %w", ref.Name(), err) - } - - rev, err := r.loadDraft(ctx, head) - if err != nil { - return nil, fmt.Errorf("cannot load draft package: %w", err) - } - if rev == nil { - return nil, fmt.Errorf("cannot load draft package %q (package not found)", ref.Name()) - } - - // Fetch lifecycle directly from the repository rather than from the gitPackageRevision. This makes - // sure we don't end up requesting the same lock twice. - lifecycle := r.getLifecycle(ctx, oldGitPackage) - - return &gitPackageDraft{ - parent: r, - path: oldGitPackage.path, - revision: oldGitPackage.revision, - workspaceName: oldGitPackage.workspaceName, - lifecycle: lifecycle, - updated: rev.updated, - base: rev.ref, - tree: rev.tree, - commit: rev.commit, - tasks: rev.tasks, - }, nil -} - -func (r *gitRepository) DeletePackageRevision(ctx context.Context, old repository.PackageRevision) error { - ctx, span := tracer.Start(ctx, "gitRepository::DeletePackageRevision", trace.WithAttributes()) - defer span.End() - r.mutex.Lock() - defer r.mutex.Unlock() - - oldGit, ok := old.(*gitPackageRevision) - if !ok { - return fmt.Errorf("cannot delete non-git package: %T", old) - } - - ref := oldGit.ref - if ref == nil { - // This is an internal error. In some rare cases (see GetPackageRevision below) we create - // package revisions without refs. They should never be returned via the API though. - return fmt.Errorf("cannot delete package with no ref: %s", oldGit.path) - } - - // We can only delete packages which have their own ref. Refs that are shared with other packages - // (main branch, tag that doesn't contain package path in its name, ...) cannot be deleted. - - refSpecs := newPushRefSpecBuilder() - - switch rn := ref.Name(); { - case rn.IsTag(): - // Delete tag only if it is package-specific. - name := createFinalTagNameInLocal(oldGit.path, oldGit.revision) - if rn != name { - return fmt.Errorf("cannot delete package tagged with a tag that is not specific to the package: %s", rn) - } - - // Delete the tag - refSpecs.AddRefToDelete(ref) - - // If this revision was proposed for deletion, we need to delete the associated branch. - if err := r.removeDeletionProposedBranchIfExists(ctx, oldGit.path, oldGit.revision); err != nil { - return err - } - - case isDraftBranchNameInLocal(rn), isProposedBranchNameInLocal(rn): - // PackageRevision is proposed or draft; delete the branch directly. - refSpecs.AddRefToDelete(ref) - - case isBranchInLocalRepo(rn): - // Delete package from the branch - commitHash, err := r.createPackageDeleteCommit(ctx, rn, oldGit) - if err != nil { - return err - } - - // Remove the proposed for deletion branch. We end up here when users - // try to delete the main branch version of a packagerevision. - if err := r.removeDeletionProposedBranchIfExists(ctx, oldGit.path, oldGit.revision); err != nil { - return err - } - - // Update the reference - refSpecs.AddRefToPush(commitHash, rn) - - default: - return fmt.Errorf("cannot delete package with the ref name %s", rn) - } - - // Update references - if err := r.pushAndCleanup(ctx, refSpecs); err != nil { - return fmt.Errorf("failed to update git references: %v", err) - } - return nil -} - -func (r *gitRepository) removeDeletionProposedBranchIfExists(ctx context.Context, path, revision string) error { - refSpecsForDeletionProposed := newPushRefSpecBuilder() - deletionProposedBranch := createDeletionProposedName(path, revision) - refSpecsForDeletionProposed.AddRefToDelete(plumbing.NewHashReference(deletionProposedBranch.RefInLocal(), plumbing.ZeroHash)) - if err := r.pushAndCleanup(ctx, refSpecsForDeletionProposed); err != nil { - if errors.Is(err, git.NoErrAlreadyUpToDate) { - // the deletionProposed branch might not have existed, so we ignore this error - klog.Warningf("branch %s does not exist", deletionProposedBranch) - } else { - klog.Errorf("unexpected error while removing deletionProposed branch: %v", err) - return err - } - } - return nil -} - -func (r *gitRepository) GetPackageRevision(ctx context.Context, version, path string) (repository.PackageRevision, kptfilev1.GitLock, error) { - ctx, span := tracer.Start(ctx, "gitRepository::GetPackageRevision", trace.WithAttributes()) - defer span.End() - r.mutex.Lock() - defer r.mutex.Unlock() - - var hash plumbing.Hash - - // Trim leading and trailing slashes - path = strings.Trim(path, "/") - - // Versions map to gitRepo tags in one of two ways: - // - // * directly (tag=version)- but then this means that all packages in the repo must be versioned together. - // * prefixed (tag=) - solving the co-versioning problem. - // - // We have to check both forms when looking up a version. - refNames := []string{} - if path != "" { - refNames = append(refNames, path+"/"+version) - // HACK: Is this always refs/remotes/origin ? Is it ever not (i.e. do we need both forms?) - refNames = append(refNames, "refs/remotes/origin/"+path+"/"+version) - } - refNames = append(refNames, version) - // HACK: Is this always refs/remotes/origin ? Is it ever not (i.e. do we need both forms?) - refNames = append(refNames, "refs/remotes/origin/"+version) - - for _, ref := range refNames { - if resolved, err := r.repo.ResolveRevision(plumbing.Revision(ref)); err != nil { - if errors.Is(err, plumbing.ErrReferenceNotFound) { - continue - } - return nil, kptfilev1.GitLock{}, fmt.Errorf("error resolving git reference %q: %w", ref, err) - } else { - hash = *resolved - break - } - } - - if hash.IsZero() { - r.dumpAllRefs() - - return nil, kptfilev1.GitLock{}, fmt.Errorf("cannot find git reference (tried %v)", refNames) - } - - return r.loadPackageRevision(ctx, version, path, hash) -} - -func (r *gitRepository) loadPackageRevision(ctx context.Context, version, path string, hash plumbing.Hash) (repository.PackageRevision, kptfilev1.GitLock, error) { - ctx, span := tracer.Start(ctx, "gitRepository::loadPackageRevision", trace.WithAttributes()) - defer span.End() - - if !packageInDirectory(path, r.directory) { - return nil, kptfilev1.GitLock{}, fmt.Errorf("cannot find package %s@%s; package is not under the Repository.spec.directory", path, version) - } - - origin, err := r.repo.Remote("origin") - if err != nil { - return nil, kptfilev1.GitLock{}, fmt.Errorf("cannot determine repository origin: %w", err) - } - - lock := kptfilev1.GitLock{ - Repo: origin.Config().URLs[0], - Directory: path, - Ref: version, - } - - commit, err := r.repo.CommitObject(hash) - if err != nil { - return nil, lock, fmt.Errorf("cannot resolve git reference %s (hash: %s) to commit: %w", version, hash, err) - } - lock.Commit = commit.Hash.String() - - krmPackage, err := r.findPackage(commit, path) - if err != nil { - return nil, lock, err - } - - if krmPackage == nil { - return nil, lock, fmt.Errorf("cannot find package %s@%s", path, version) - } - - var ref *plumbing.Reference = nil // Cannot determine ref; this package will be considered final (immutable). - - var revision string - var workspace v1alpha1.WorkspaceName - last := strings.LastIndex(version, "/") - - if strings.HasPrefix(version, "drafts/") || strings.HasPrefix(version, "proposed/") { - // the passed in version is a ref to an unpublished package revision - workspace = v1alpha1.WorkspaceName(version[last+1:]) - } else { - // the passed in version is a ref to a published package revision - if version == string(r.branch) || last < 0 { - revision = version - } else { - revision = version[last+1:] - } - workspace, err = getPkgWorkspace(ctx, commit, krmPackage, ref) - if err != nil { - return nil, kptfilev1.GitLock{}, err - } - } - - packageRevision, err := krmPackage.buildGitPackageRevision(ctx, revision, workspace, ref) - if err != nil { - return nil, lock, err - } - return packageRevision, lock, nil -} - -func (r *gitRepository) discoverFinalizedPackages(ctx context.Context, ref *plumbing.Reference) ([]*gitPackageRevision, error) { - ctx, span := tracer.Start(ctx, "gitRepository::discoverFinalizedPackages", trace.WithAttributes()) - defer span.End() - - commit, err := r.repo.CommitObject(ref.Hash()) - if err != nil { - return nil, err - } - - var revision string - if rev, ok := getBranchNameInLocalRepo(ref.Name()); ok { - revision = rev - } else if rev, ok = getTagNameInLocalRepo(ref.Name()); ok { - revision = rev - } else { - // TODO: ignore the ref instead? - return nil, fmt.Errorf("cannot determine revision from ref: %q", rev) - } - - krmPackages, err := r.discoverPackagesInTree(commit, DiscoverPackagesOptions{FilterPrefix: r.directory, Recurse: true}) - if err != nil { - return nil, err - } - - var result []*gitPackageRevision - for _, krmPackage := range krmPackages.packages { - workspace, err := getPkgWorkspace(ctx, commit, krmPackage, ref) - if err != nil { - return nil, err - } - packageRevision, err := krmPackage.buildGitPackageRevision(ctx, revision, workspace, ref) - if err != nil { - return nil, err - } - result = append(result, packageRevision) - } - return result, nil -} - -// loadDraft will load the draft package. If the package isn't found (we now require a Kptfile), it will return (nil, nil) -func (r *gitRepository) loadDraft(ctx context.Context, ref *plumbing.Reference) (*gitPackageRevision, error) { - ctx, span := tracer.Start(ctx, "gitRepository::loadDraft", trace.WithAttributes()) - defer span.End() - - name, workspaceName, err := parseDraftName(ref) - if err != nil { - return nil, err - } - - // Only load drafts in the directory specified at repository registration. - if !packageInDirectory(name, r.directory) { - return nil, nil - } - - commit, err := r.repo.CommitObject(ref.Hash()) - if err != nil { - return nil, fmt.Errorf("cannot resolve draft branch to commit (corrupted repository?): %w", err) - } - - krmPackage, err := r.findPackage(commit, name) - if err != nil { - return nil, err - } - - if krmPackage == nil { - klog.Warningf("draft package %q was not found", name) - return nil, nil - } - - packageRevision, err := krmPackage.buildGitPackageRevision(ctx, "", workspaceName, ref) - if err != nil { - return nil, err - } - - return packageRevision, nil -} - -func (r *gitRepository) UpdateDeletionProposedCache() error { - r.mutex.Lock() - defer r.mutex.Unlock() - return r.updateDeletionProposedCache() -} - -func (r *gitRepository) updateDeletionProposedCache() error { - r.deletionProposedCache = make(map[BranchName]bool) - - err := r.fetchRemoteRepository(context.Background()) - if err != nil { - return err - } - refs, err := r.repo.References() - if err != nil { - return err - } - - for { - ref, err := refs.Next() - if err == io.EOF { - break - } - if err != nil { - klog.Errorf("error getting next ref: %v", err) - break - } - - branch, isDeletionProposedBranch := getdeletionProposedBranchNameInLocal(ref.Name()) - if isDeletionProposedBranch { - r.deletionProposedCache[deletionProposedPrefix+branch] = true - } - } - - return nil -} - -func parseDraftName(draft *plumbing.Reference) (name string, workspaceName v1alpha1.WorkspaceName, err error) { - refName := draft.Name() - var suffix string - if b, ok := getDraftBranchNameInLocal(refName); ok { - suffix = string(b) - } else if b, ok = getProposedBranchNameInLocal(refName); ok { - suffix = string(b) - } else { - return "", "", fmt.Errorf("invalid draft ref name: %q", refName) - } - - revIndex := strings.LastIndex(suffix, "/") - if revIndex <= 0 { - return "", "", fmt.Errorf("invalid draft ref name; missing workspaceName suffix: %q", refName) - } - name, workspaceName = suffix[:revIndex], v1alpha1.WorkspaceName(suffix[revIndex+1:]) - return name, workspaceName, nil -} - -func (r *gitRepository) loadTaggedPackage(ctx context.Context, tag *plumbing.Reference) (*gitPackageRevision, error) { - ctx, span := tracer.Start(ctx, "gitRepository::loadTaggedPackage", trace.WithAttributes()) - defer span.End() - - name, ok := getTagNameInLocalRepo(tag.Name()) - if !ok { - return nil, fmt.Errorf("invalid tag ref: %q", tag) - } - slash := strings.LastIndex(name, "/") - - if slash < 0 { - // tag= - // could be a release tag or something else, we ignore these types of tags - return nil, nil - - } - - // tag=/version - path, revision := name[:slash], name[slash+1:] - - if !packageInDirectory(path, r.directory) { - return nil, nil - } - - commit, err := r.repo.CommitObject(tag.Hash()) - if err != nil { - return nil, fmt.Errorf("cannot resolve tag %q to commit (corrupted repository?): %w", name, err) - } - - krmPackage, err := r.findPackage(commit, path) - if err != nil { - klog.Warningf("Skipping %q; cannot find %q (corrupted repository?): %w", name, path, err) - return nil, nil - } - - if krmPackage == nil { - klog.Warningf("Skipping %q: Kptfile not found", name) - return nil, nil - } - - workspaceName, err := getPkgWorkspace(ctx, commit, krmPackage, tag) - if err != nil { - return nil, err - } - - packageRevision, err := krmPackage.buildGitPackageRevision(ctx, revision, workspaceName, tag) - if err != nil { - return nil, err - } - - return packageRevision, nil - -} - -func (r *gitRepository) dumpAllRefs() { - refs, err := r.repo.References() - if err != nil { - klog.Warningf("failed to get references: %v", err) - } else { - for { - ref, err := refs.Next() - if err != nil { - if err != io.EOF { - klog.Warningf("failed to get next reference: %v", err) - } - break - } - klog.Infof("ref %#v", ref.Name()) - } - } - - branches, err := r.repo.Branches() - if err != nil { - klog.Warningf("failed to get branches: %v", err) - } else { - for { - branch, err := branches.Next() - if err != nil { - if err != io.EOF { - klog.Warningf("failed to get next branch: %v", err) - } - break - } - klog.Infof("branch %#v", branch.Name()) - } - } -} - -// getAuthMethod fetches the credentials for authenticating to git. It caches the -// credentials between calls and refresh credentials when the tokens have expired. -func (r *gitRepository) getAuthMethod(ctx context.Context, forceRefresh bool) (transport.AuthMethod, error) { - // If no secret is provided, we try without any auth. - if r.secret == "" { - return nil, nil - } - - if r.credential == nil || !r.credential.Valid() || forceRefresh { - if cred, err := r.credentialResolver.ResolveCredential(ctx, r.namespace, r.secret); err != nil { - return nil, fmt.Errorf("failed to obtain credential from secret %s/%s: %w", r.namespace, r.secret, err) - } else { - r.credential = cred - } - } - - return r.credential.ToAuthMethod(), nil -} - -func (r *gitRepository) GetRepo() (string, error) { - r.mutex.Lock() - defer r.mutex.Unlock() - - origin, err := r.repo.Remote("origin") - if err != nil { - return "", fmt.Errorf("cannot determine repository origin: %w", err) - } - - return origin.Config().URLs[0], nil -} - -func (r *gitRepository) fetchRemoteRepository(ctx context.Context) error { - ctx, span := tracer.Start(ctx, "gitRepository::fetchRemoteRepository", trace.WithAttributes()) - defer span.End() - - // Fetch - switch err := r.doGitWithAuth(ctx, func(auth transport.AuthMethod) error { - return r.repo.Fetch(&git.FetchOptions{ - RemoteName: OriginName, - Auth: auth, - Prune: git.Prune, - }) - }); err { - case nil: // OK - case git.NoErrAlreadyUpToDate: - case transport.ErrEmptyRemoteRepository: - - default: - return fmt.Errorf("cannot fetch repository %s/%s: %w", r.namespace, r.name, err) - } - - return nil -} - -// Verifies repository. Repository must be fetched already. -func (r *gitRepository) verifyRepository(ctx context.Context, opts *GitRepositoryOptions) error { - // When opening a temporary repository, such as for cloning a package - // from unregistered upstream, we won't be pushing into the remote so - // we don't need to verify presence of the main branch. - if opts.MainBranchStrategy == SkipVerification { - return nil - } - - if _, err := r.repo.Reference(r.branch.RefInLocal(), false); err != nil { - switch opts.MainBranchStrategy { - case ErrorIfMissing: - return fmt.Errorf("branch %q doesn't exist: %v", r.branch, err) - case CreateIfMissing: - klog.Infof("Creating branch %s in repository %s", r.branch, r.name) - if err := r.createBranch(ctx, r.branch); err != nil { - return fmt.Errorf("error creating main branch %q: %v", r.branch, err) - } - default: - return fmt.Errorf("unknown main branch strategy %q", opts.MainBranchStrategy.String()) - } - } - return nil -} - -const ( - fileContent = "Created by porch" - fileName = "README.md" - commitMessage = "Initial commit for main branch by porch" -) - -// createBranch creates the provided branch by creating a commit containing -// a README.md file on the root of the repo and then pushing it to the branch. -func (r *gitRepository) createBranch(ctx context.Context, branch BranchName) error { - fileHash, err := r.storeBlob(fileContent) - if err != nil { - return err - } - - tree := &object.Tree{} - tree.Entries = append(tree.Entries, object.TreeEntry{ - Name: fileName, - Mode: filemode.Regular, - Hash: fileHash, - }) - - treeEo := r.repo.Storer.NewEncodedObject() - if err := tree.Encode(treeEo); err != nil { - return err - } - - treeHash, err := r.repo.Storer.SetEncodedObject(treeEo) - if err != nil { - return err - } - - now := time.Now() - commit := &object.Commit{ - Author: object.Signature{ - Name: porchSignatureName, - Email: porchSignatureEmail, - When: now, - }, - Committer: object.Signature{ - Name: porchSignatureName, - Email: porchSignatureEmail, - When: now, - }, - Message: commitMessage, - TreeHash: treeHash, - } - commitHash, err := r.storeCommit(commit) - if err != nil { - return err - } - - refSpecs := newPushRefSpecBuilder() - refSpecs.AddRefToPush(commitHash, branch.RefInLocal()) - return r.pushAndCleanup(ctx, refSpecs) -} - -func (r *gitRepository) getCommit(h plumbing.Hash) (*object.Commit, error) { - return object.GetCommit(r.repo.Storer, h) -} - -func (r *gitRepository) storeCommit(commit *object.Commit) (plumbing.Hash, error) { - eo := r.repo.Storer.NewEncodedObject() - if err := commit.Encode(eo); err != nil { - return plumbing.Hash{}, err - } - return r.repo.Storer.SetEncodedObject(eo) -} - -// Creates a commit which deletes the package from the branch, and returns its commit hash. -// If the branch doesn't exist, will return zero hash and no error. -func (r *gitRepository) createPackageDeleteCommit(ctx context.Context, branch plumbing.ReferenceName, pkg *gitPackageRevision) (plumbing.Hash, error) { - var zero plumbing.Hash - - local, err := refInRemoteFromRefInLocal(branch) - if err != nil { - return zero, err - } - // Fetch the branch - // TODO: Fetch only as part of conflict resolution & Retry - switch err := r.doGitWithAuth(ctx, func(auth transport.AuthMethod) error { - return r.repo.Fetch(&git.FetchOptions{ - RemoteName: OriginName, - RefSpecs: []config.RefSpec{config.RefSpec(fmt.Sprintf("+%s:%s", local, branch))}, - Auth: auth, - Tags: git.NoTags, - }) - }); err { - case nil, git.NoErrAlreadyUpToDate: - // ok - default: - return zero, fmt.Errorf("failed to fetch remote repository: %w", err) - } - - // find the branch - ref, err := r.repo.Reference(branch, true) - if err != nil { - // branch doesn't exist, and therefore package doesn't exist either. - klog.Infof("Branch %q no longer exist, deleting a package from it is unnecessary", branch) - return zero, nil - } - commit, err := r.repo.CommitObject(ref.Hash()) - if err != nil { - return zero, fmt.Errorf("failed to resolve main branch to commit: %w", err) - } - root, err := commit.Tree() - if err != nil { - return zero, fmt.Errorf("failed to find commit tree for %s: %w", ref, err) - } - - packagePath := pkg.path - - // Find the package in the tree - switch _, err := root.FindEntry(packagePath); err { - case object.ErrEntryNotFound: - // Package doesn't exist; no need to delete it - return zero, nil - case nil: - // found - default: - return zero, fmt.Errorf("failed to find package %q in the repositrory ref %q: %w,", packagePath, ref, err) - } - - // Create commit helper. Use zero hash for the initial package tree. Commit helper will initialize trees - // without TreeEntry for this package present - the package is deleted. - ch, err := newCommitHelper(r, r.userInfoProvider, commit.Hash, packagePath, zero) - if err != nil { - return zero, fmt.Errorf("failed to initialize commit of package %q to %q: %w", packagePath, ref, err) - } - - message := fmt.Sprintf("Delete %s", packagePath) - commitHash, _, err := ch.commit(ctx, message, packagePath) - if err != nil { - return zero, fmt.Errorf("failed to commit package %q to %q: %w", packagePath, ref, err) - } - return commitHash, nil -} - -func (r *gitRepository) PushAndCleanup(ctx context.Context, ph *pushRefSpecBuilder) error { - r.mutex.Lock() - defer r.mutex.Unlock() - - return r.pushAndCleanup(ctx, ph) -} - -func (r *gitRepository) pushAndCleanup(ctx context.Context, ph *pushRefSpecBuilder) error { - specs, require, err := ph.BuildRefSpecs() - if err != nil { - return err - } - - if err := r.doGitWithAuth(ctx, func(auth transport.AuthMethod) error { - return r.repo.Push(&git.PushOptions{ - RemoteName: OriginName, - RefSpecs: specs, - Auth: auth, - RequireRemoteRefs: require, - // TODO(justinsb): Need to ensure this is a compare-and-swap - Force: true, - }) - }); err != nil { - return err - } - return nil -} - -func (r *gitRepository) loadTasks(ctx context.Context, startCommit *object.Commit, packagePath string, - workspaceName v1alpha1.WorkspaceName) ([]v1alpha1.Task, error) { - - var logOptions = git.LogOptions{ - From: startCommit.Hash, - Order: git.LogOrderCommitterTime, - } - - // NOTE: We don't prune the commits with the filepath; this is because it's a relatively expensive operation, - // as we have to visit the whole trees. Visiting the commits is comparatively fast. - // // Prune the commits we visit a bit - though the actual gate is on the gitAnnotation - // if packagePath != "" { - // if !strings.HasSuffix(packagePath, "/") { - // packagePath += "/" - // } - // pathFilter := func(p string) bool { - // matchesPackage := strings.HasPrefix(p, packagePath) - // return matchesPackage - // } - // logOptions.PathFilter = pathFilter - // } - - commits, err := r.repo.Log(&logOptions) - if err != nil { - return nil, fmt.Errorf("error walking commits: %w", err) - } - - var tasks []v1alpha1.Task - - done := false - visitCommit := func(commit *object.Commit) error { - if done { - return nil - } - - gitAnnotations, err := ExtractGitAnnotations(commit) - if err != nil { - return err - } - - for _, gitAnnotation := range gitAnnotations { - packageMatches := gitAnnotation.PackagePath == packagePath - workspaceNameMatches := gitAnnotation.WorkspaceName == workspaceName || - // this is needed for porch package revisions created before the workspaceName field existed - (gitAnnotation.Revision == string(workspaceName) && gitAnnotation.WorkspaceName == "") - - if packageMatches && workspaceNameMatches { - // We are iterating through the commits in reverse order. - // Tasks that are read from separate commits will be recorded in - // reverse order. - // The entire `tasks` slice will get reversed later, which will give us the - // tasks in chronological order. - if gitAnnotation.Task != nil { - tasks = append(tasks, *gitAnnotation.Task) - } - - if gitAnnotation.Task != nil && (gitAnnotation.Task.Type == v1alpha1.TaskTypeClone || gitAnnotation.Task.Type == v1alpha1.TaskTypeInit) { - // we have reached the beginning of this package revision and don't need to - // continue further - done = true - break - } - } - } - - // TODO: If a commit has no annotations defined, we should treat it like a patch. - // This will allow direct manipulation of the git repo. - // We should also probably _not_ record an annotation for a patch task, so we - // can allow direct editing. - return nil - } - - if err := commits.ForEach(visitCommit); err != nil { - return nil, fmt.Errorf("error visiting commits: %w", err) - } - - // We need to reverse the tasks so they appear in chronological order - reverseSlice(tasks) - - return tasks, nil -} - -func (r *gitRepository) GetResources(hash plumbing.Hash) (map[string]string, error) { - r.mutex.Lock() - defer r.mutex.Unlock() - - resources := map[string]string{} - - tree, err := r.repo.TreeObject(hash) - if err == nil { - // Files() iterator iterates recursively over all files in the tree. - fit := tree.Files() - defer fit.Close() - for { - file, err := fit.Next() - if err == io.EOF { - break - } else if err != nil { - return nil, fmt.Errorf("failed to load package resources: %w", err) - } - - content, err := file.Contents() - if err != nil { - return nil, fmt.Errorf("failed to read package file contents: %q, %w", file.Name, err) - } - - // TODO: decide whether paths should include package directory or not. - resources[file.Name] = content - //resources[path.Join(p.path, file.Name)] = content - } - } - return resources, nil -} - -// findLatestPackageCommit returns the latest commit from the history that pertains -// to the package given by the packagePath. If no commit is found, it will return nil. -func (r *gitRepository) findLatestPackageCommit(ctx context.Context, startCommit *object.Commit, packagePath string) (*object.Commit, error) { - var commit *object.Commit - err := r.packageHistoryIterator(startCommit, packagePath, func(c *object.Commit) error { - commit = c - return storer.ErrStop - }) - return commit, err -} - -// commitCallback is the function type that needs to be provided to the history iterator functions. -type commitCallback func(*object.Commit) error - -// packageRevisionHistoryIterator traverses the git history from the provided commit, and invokes -// the callback function for every commit pertaining to the provided packagerevision. -func (r *gitRepository) packageRevisionHistoryIterator(startCommit *object.Commit, packagePath, revision string, cb commitCallback) error { - return r.traverseHistory(startCommit, func(commit *object.Commit) error { - gitAnnotations, err := ExtractGitAnnotations(commit) - if err != nil { - return err - } - - for _, gitAnnotation := range gitAnnotations { - if gitAnnotation.PackagePath == packagePath && gitAnnotation.Revision == revision { - - if err := cb(commit); err != nil { - return err - } - - if gitAnnotation.Task != nil && (gitAnnotation.Task.Type == v1alpha1.TaskTypeClone || gitAnnotation.Task.Type == v1alpha1.TaskTypeInit) { - break - } - } - } - return nil - }) -} - -// packageHistoryIterator traverses the git history from the provided commit and invokes -// the callback function for every commit pertaining to the provided package. -func (r *gitRepository) packageHistoryIterator(startCommit *object.Commit, packagePath string, cb commitCallback) error { - return r.traverseHistory(startCommit, func(commit *object.Commit) error { - gitAnnotations, err := ExtractGitAnnotations(commit) - if err != nil { - return err - } - - for _, gitAnnotation := range gitAnnotations { - if gitAnnotation.PackagePath == packagePath { - - if err := cb(commit); err != nil { - return err - } - - if gitAnnotation.Task != nil && (gitAnnotation.Task.Type == v1alpha1.TaskTypeClone || gitAnnotation.Task.Type == v1alpha1.TaskTypeInit) { - break - } - } - } - return nil - }) -} - -func (r *gitRepository) traverseHistory(startCommit *object.Commit, cb commitCallback) error { - var logOptions = git.LogOptions{ - From: startCommit.Hash, - Order: git.LogOrderCommitterTime, - } - - commits, err := r.repo.Log(&logOptions) - if err != nil { - return fmt.Errorf("error walking commits: %w", err) - } - - if err := commits.ForEach(cb); err != nil { - return fmt.Errorf("error visiting commits: %w", err) - } - - return nil -} - -func (r *gitRepository) blobObject(h plumbing.Hash) (*object.Blob, error) { - return r.repo.BlobObject(h) -} - -// StoreBlob is a helper method to write a blob to the git store. -func (r *gitRepository) storeBlob(value string) (plumbing.Hash, error) { - data := []byte(value) - eo := r.repo.Storer.NewEncodedObject() - eo.SetType(plumbing.BlobObject) - eo.SetSize(int64(len(data))) - - w, err := eo.Writer() - if err != nil { - return plumbing.Hash{}, err - } - - if _, err := w.Write(data); err != nil { - w.Close() - return plumbing.Hash{}, err - } - - if err := w.Close(); err != nil { - return plumbing.Hash{}, err - } - - return r.repo.Storer.SetEncodedObject(eo) -} - -func (r *gitRepository) getTree(h plumbing.Hash) (*object.Tree, error) { - return object.GetTree(r.repo.Storer, h) -} - -func (r *gitRepository) storeTree(tree *object.Tree) (plumbing.Hash, error) { - eo := r.repo.Storer.NewEncodedObject() - if err := tree.Encode(eo); err != nil { - return plumbing.Hash{}, err - } - - treeHash, err := r.repo.Storer.SetEncodedObject(eo) - if err != nil { - return plumbing.Hash{}, err - } - return treeHash, nil -} - -func (r *gitRepository) GetLifecycle(ctx context.Context, pkgRev *gitPackageRevision) v1alpha1.PackageRevisionLifecycle { - ctx, span := tracer.Start(ctx, "GitRepository::GetLifecycle", trace.WithAttributes()) - defer span.End() - r.mutex.Lock() - defer r.mutex.Unlock() - - return r.getLifecycle(ctx, pkgRev) -} - -func (r *gitRepository) getLifecycle(ctx context.Context, pkgRev *gitPackageRevision) v1alpha1.PackageRevisionLifecycle { - switch ref := pkgRev.ref; { - case ref == nil: - return r.checkPublishedLifecycle(pkgRev) - case isDraftBranchNameInLocal(ref.Name()): - return v1alpha1.PackageRevisionLifecycleDraft - case isProposedBranchNameInLocal(ref.Name()): - return v1alpha1.PackageRevisionLifecycleProposed - default: - return r.checkPublishedLifecycle(pkgRev) - } -} - -func (r *gitRepository) checkPublishedLifecycle(pkgRev *gitPackageRevision) v1alpha1.PackageRevisionLifecycle { - if r.deletionProposedCache == nil { - if err := r.updateDeletionProposedCache(); err != nil { - klog.Errorf("failed to update deletionProposed cache: %v", err) - return v1alpha1.PackageRevisionLifecyclePublished - } - } - - branchName := createDeletionProposedName(pkgRev.path, pkgRev.revision) - if _, found := r.deletionProposedCache[branchName]; found { - return v1alpha1.PackageRevisionLifecycleDeletionProposed - } - - return v1alpha1.PackageRevisionLifecyclePublished -} - -func (r *gitRepository) UpdateLifecycle(ctx context.Context, pkgRev *gitPackageRevision, newLifecycle v1alpha1.PackageRevisionLifecycle) error { - ctx, span := tracer.Start(ctx, "GitRepository::UpdateLifecycle", trace.WithAttributes()) - defer span.End() - r.mutex.Lock() - defer r.mutex.Unlock() - - old := r.getLifecycle(ctx, pkgRev) - if !v1alpha1.LifecycleIsPublished(old) { - return fmt.Errorf("cannot update lifecycle for draft package revision") - } - refSpecs := newPushRefSpecBuilder() - deletionProposedBranch := createDeletionProposedName(pkgRev.path, pkgRev.revision) - - if old == v1alpha1.PackageRevisionLifecyclePublished { - if newLifecycle != v1alpha1.PackageRevisionLifecycleDeletionProposed { - return fmt.Errorf("invalid new lifecycle value: %q", newLifecycle) - } - // Push the package revision into a deletionProposed branch. - r.deletionProposedCache[deletionProposedBranch] = true - refSpecs.AddRefToPush(pkgRev.commit, deletionProposedBranch.RefInLocal()) - } - if old == v1alpha1.PackageRevisionLifecycleDeletionProposed { - if newLifecycle != v1alpha1.PackageRevisionLifecyclePublished { - return fmt.Errorf("invalid new lifecycle value: %q", newLifecycle) - } - - // Delete the deletionProposed branch - delete(r.deletionProposedCache, deletionProposedBranch) - ref := plumbing.NewHashReference(deletionProposedBranch.RefInLocal(), pkgRev.commit) - refSpecs.AddRefToDelete(ref) - } - - if err := r.pushAndCleanup(ctx, refSpecs); err != nil { - if !errors.Is(err, git.NoErrAlreadyUpToDate) { - return err - } - } - - return nil -} - -func (r *gitRepository) UpdateDraftResources(ctx context.Context, draft *gitPackageDraft, new *v1alpha1.PackageRevisionResources, change *v1alpha1.Task) error { - ctx, span := tracer.Start(ctx, "gitPackageDraft::UpdateResources", trace.WithAttributes()) - defer span.End() - r.mutex.Lock() - defer r.mutex.Unlock() - - ch, err := newCommitHelper(r, r.userInfoProvider, draft.commit, draft.path, plumbing.ZeroHash) - if err != nil { - return fmt.Errorf("failed to commit package: %w", err) - } - - for k, v := range new.Spec.Resources { - ch.storeFile(path.Join(draft.path, k), v) - } - - // Because we can't read the package back without a Kptfile, make sure one is present - { - p := path.Join(draft.path, "Kptfile") - _, err := ch.readFile(p) - if os.IsNotExist(err) { - // We could write the file here; currently we return an error - return fmt.Errorf("package must contain Kptfile at root") - } - } - - annotation := &gitAnnotation{ - PackagePath: draft.path, - WorkspaceName: draft.workspaceName, - Revision: draft.revision, - Task: change, - } - message := "Intermediate commit" - if change != nil { - message += fmt.Sprintf(": %s", change.Type) - draft.tasks = append(draft.tasks, *change) - } - message += "\n" - - message, err = AnnotateCommitMessage(message, annotation) - if err != nil { - return err - } - - commitHash, packageTree, err := ch.commit(ctx, message, draft.path) - if err != nil { - return fmt.Errorf("failed to commit package: %w", err) - } - - draft.tree = packageTree - draft.commit = commitHash - return nil -} - -func (r *gitRepository) CloseDraft(ctx context.Context, d *gitPackageDraft) (*gitPackageRevision, error) { - r.mutex.Lock() - defer r.mutex.Unlock() - - refSpecs := newPushRefSpecBuilder() - draftBranch := createDraftName(d.path, d.workspaceName) - proposedBranch := createProposedName(d.path, d.workspaceName) - - var newRef *plumbing.Reference - - switch d.lifecycle { - case v1alpha1.PackageRevisionLifecyclePublished, v1alpha1.PackageRevisionLifecycleDeletionProposed: - // Finalize the package revision. Assign it a revision number of latest + 1. - revisions, err := r.listPackageRevisions(ctx, repository.ListPackageRevisionFilter{ - Package: d.path, - }) - if err != nil { - return nil, err - } - - var revs []string - for _, rev := range revisions { - if v1alpha1.LifecycleIsPublished(r.getLifecycle(ctx, rev)) { - revs = append(revs, rev.Key().Revision) - } - } - - d.revision, err = repository.NextRevisionNumber(revs) - if err != nil { - return nil, err - } - - // Finalize the package revision. Commit it to main branch. - commitHash, newTreeHash, commitBase, err := r.commitPackageToMain(ctx, d) - if err != nil { - return nil, err - } - - tag := createFinalTagNameInLocal(d.path, d.revision) - refSpecs.AddRefToPush(commitHash, r.branch.RefInLocal()) // Push new main branch - refSpecs.AddRefToPush(commitHash, tag) // Push the tag - refSpecs.RequireRef(commitBase) // Make sure main didn't advance - - // Delete base branch (if one exists and should be deleted) - switch base := d.base; { - case base == nil: // no branch to delete - case base.Name() == draftBranch.RefInLocal(), base.Name() == proposedBranch.RefInLocal(): - refSpecs.AddRefToDelete(base) - } - - // Update package draft - d.commit = commitHash - d.tree = newTreeHash - newRef = plumbing.NewHashReference(tag, commitHash) - - case v1alpha1.PackageRevisionLifecycleProposed: - // Push the package revision into a proposed branch. - refSpecs.AddRefToPush(d.commit, proposedBranch.RefInLocal()) - - // Delete base branch (if one exists and should be deleted) - switch base := d.base; { - case base == nil: // no branch to delete - case base.Name() != proposedBranch.RefInLocal(): - refSpecs.AddRefToDelete(base) - } - - // Update package referemce (commit and tree hash stay the same) - newRef = plumbing.NewHashReference(proposedBranch.RefInLocal(), d.commit) - - case v1alpha1.PackageRevisionLifecycleDraft: - // Push the package revision into a draft branch. - refSpecs.AddRefToPush(d.commit, draftBranch.RefInLocal()) - // Delete base branch (if one exists and should be deleted) - switch base := d.base; { - case base == nil: // no branch to delete - case base.Name() != draftBranch.RefInLocal(): - refSpecs.AddRefToDelete(base) - } - - // Update package reference (commit and tree hash stay the same) - newRef = plumbing.NewHashReference(draftBranch.RefInLocal(), d.commit) - - default: - return nil, fmt.Errorf("package has unrecognized lifecycle: %q", d.lifecycle) - } - - if err := d.parent.pushAndCleanup(ctx, refSpecs); err != nil { - // No changes is fine. No need to return an error. - if !errors.Is(err, git.NoErrAlreadyUpToDate) { - return nil, err - } - } - - // for backwards compatibility with packages that existed before porch supported - // descriptions, we populate the workspaceName as the revision number if it is empty - if d.workspaceName == "" { - d.workspaceName = v1alpha1.WorkspaceName(d.revision) - } - - return &gitPackageRevision{ - repo: d.parent, - path: d.path, - revision: d.revision, - workspaceName: d.workspaceName, - updated: d.updated, - ref: newRef, - tree: d.tree, - commit: newRef.Hash(), - tasks: d.tasks, - }, nil -} - -// doGitWithAuth fetches auth information for git and provides it -// to the provided function which performs the operation against a git repo. -func (r *gitRepository) doGitWithAuth(ctx context.Context, op func(transport.AuthMethod) error) error { - auth, err := r.getAuthMethod(ctx, false) - if err != nil { - return fmt.Errorf("failed to obtain git credentials: %w", err) - } - err = op(auth) - if err != nil { - if !errors.Is(err, transport.ErrAuthenticationRequired) { - return err - } - klog.Infof("Authentication failed. Trying to refresh credentials") - // TODO: Consider having some kind of backoff here. - auth, err := r.getAuthMethod(ctx, true) - if err != nil { - return fmt.Errorf("failed to obtain git credentials: %w", err) - } - return op(auth) - } - return nil -} - -func (r *gitRepository) commitPackageToMain(ctx context.Context, d *gitPackageDraft) (commitHash, newPackageTreeHash plumbing.Hash, base *plumbing.Reference, err error) { - branch := r.branch - localRef := branch.RefInLocal() - - var zero plumbing.Hash - - // Fetch main - switch err := r.doGitWithAuth(ctx, func(auth transport.AuthMethod) error { - return r.repo.Fetch(&git.FetchOptions{ - RemoteName: OriginName, - RefSpecs: []config.RefSpec{branch.ForceFetchSpec()}, - Auth: auth, - }) - }); err { - case nil, git.NoErrAlreadyUpToDate: - // ok - default: - return zero, zero, nil, fmt.Errorf("failed to fetch remote repository: %w", err) - } - - // Find localTarget branch - localTarget, err := r.repo.Reference(localRef, false) - if err != nil { - // TODO: handle empty repositories - NotFound error - return zero, zero, nil, fmt.Errorf("failed to find 'main' branch: %w", err) - } - headCommit, err := r.repo.CommitObject(localTarget.Hash()) - if err != nil { - return zero, zero, nil, fmt.Errorf("failed to resolve main branch to commit: %w", err) - } - packagePath := d.path - - // TODO: Check for out-of-band update of the package in main branch - // (compare package tree in target branch and common base) - ch, err := newCommitHelper(r, r.userInfoProvider, headCommit.Hash, packagePath, d.tree) - if err != nil { - return zero, zero, nil, fmt.Errorf("failed to initialize commit of package %s to %s", packagePath, localRef) - } - - // Add a commit without changes to mark that the package revision is approved. The gitAnnotation is - // included so that we can later associate the commit with the correct packagerevision. - message, err := AnnotateCommitMessage(fmt.Sprintf("Approve %s/%s", packagePath, d.revision), &gitAnnotation{ - PackagePath: packagePath, - WorkspaceName: d.workspaceName, - Revision: d.revision, - }) - if err != nil { - return zero, zero, nil, fmt.Errorf("failed annotation commit message for package %s: %v", packagePath, err) - } - commitHash, newPackageTreeHash, err = ch.commit(ctx, message, packagePath, d.commit) - if err != nil { - return zero, zero, nil, fmt.Errorf("failed to commit package %s to %s", packagePath, localRef) - } - - return commitHash, newPackageTreeHash, localTarget, nil -} - -// findPackage finds the packages in the git repository, under commit, if it is exists at path. -// If no package is found at that path, returns nil, nil -func (r *gitRepository) findPackage(commit *object.Commit, packagePath string) (*packageListEntry, error) { - t, err := r.discoverPackagesInTree(commit, DiscoverPackagesOptions{FilterPrefix: packagePath, Recurse: false}) - if err != nil { - return nil, err - } - return t.packages[packagePath], nil -} - -// discoverPackagesInTree finds the packages in the git repository, under commit. -// If filterPrefix is non-empty, only packages with the specified prefix will be returned. -// It is not an error if filterPrefix matches no packages or even is not a real directory name; -// we will simply return an empty list of packages. -func (r *gitRepository) discoverPackagesInTree(commit *object.Commit, opt DiscoverPackagesOptions) (*packageList, error) { - t := &packageList{ - parent: r, - commit: commit, - packages: make(map[string]*packageListEntry), - } - - rootTree, err := commit.Tree() - if err != nil { - return nil, fmt.Errorf("cannot resolve commit %v to tree (corrupted repository?): %w", commit.Hash, err) - } - - if opt.FilterPrefix != "" { - tree, err := rootTree.Tree(opt.FilterPrefix) - if err != nil { - if err == object.ErrDirectoryNotFound { - // We treat the filter prefix as a filter, the path doesn't have to exist - klog.Warningf("could not find filterPrefix %q in commit %v; returning no packages", opt.FilterPrefix, commit.Hash) - return t, nil - } else { - return nil, fmt.Errorf("error getting tree %s: %w", opt.FilterPrefix, err) - } - } - rootTree = tree - } - - if err := t.discoverPackages(rootTree, opt.FilterPrefix, opt.Recurse); err != nil { - return nil, err - } - - return t, nil -} - -// See https://eli.thegreenplace.net/2021/generic-functions-on-slices-with-go-type-parameters/ -// func ReverseSlice[T any](s []T) { // Ready for generics! -func reverseSlice(s []v1alpha1.Task) { - first := 0 - last := len(s) - 1 - for first < last { - s[first], s[last] = s[last], s[first] - first++ - last-- - } -} - -func getPkgWorkspace(ctx context.Context, commit *object.Commit, p *packageListEntry, ref *plumbing.Reference) (v1alpha1.WorkspaceName, error) { - if ref == nil || (!isTagInLocalRepo(ref.Name()) && !isDraftBranchNameInLocal(ref.Name()) && !isProposedBranchNameInLocal(ref.Name())) { - // packages on the main branch may have unrelated commits, we need to find the latest commit relevant to this package - c, err := p.parent.parent.findLatestPackageCommit(ctx, p.parent.commit, p.path) - if err != nil { - return "", err - } - if c != nil { - commit = c - } - } - annotations, err := ExtractGitAnnotations(commit) - if err != nil { - return "", err - } - workspaceName := v1alpha1.WorkspaceName("") - for _, a := range annotations { - if a.PackagePath != p.path { - continue - } - if a.WorkspaceName != "" { - workspaceName = a.WorkspaceName - break - } - } - return workspaceName, nil -} diff --git a/porch/pkg/git/git_test.go b/porch/pkg/git/git_test.go deleted file mode 100644 index bbb1a9cf65..0000000000 --- a/porch/pkg/git/git_test.go +++ /dev/null @@ -1,1272 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import ( - "bytes" - "context" - "flag" - "fmt" - "os" - "path/filepath" - "reflect" - "strings" - "testing" - "time" - - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - gogit "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/filemode" - "github.com/go-git/go-git/v5/plumbing/object" - "github.com/google/go-cmp/cmp" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/klog/v2" -) - -func TestMain(m *testing.M) { - klog.InitFlags(nil) - flag.Parse() - os.Exit(m.Run()) -} - -func TestGit(t *testing.T) { - for _, gs := range []GitSuite{ - {branch: "main"}, - {branch: "feature"}, - {branch: "nested/release"}, - } { - name := strings.ReplaceAll(gs.branch, "/", "-") - t.Run(name, func(t *testing.T) { - Run(gs, t) - }) - } -} - -func Run(suite interface{}, t *testing.T) { - sv := reflect.ValueOf(suite) - st := reflect.TypeOf(suite) - - for i, max := 0, st.NumMethod(); i < max; i++ { - m := st.Method(i) - if strings.HasPrefix(m.Name, "Test") { - t.Run(m.Name, func(t *testing.T) { - m.Func.Call([]reflect.Value{sv, reflect.ValueOf((t))}) - }) - } - } -} - -type GitSuite struct { - branch string -} - -func (g GitSuite) TestOpenEmptyRepository(t *testing.T) { - tempdir := t.TempDir() - tarfile := filepath.Join("testdata", "empty-repository.tar") - repo, address := ServeGitRepositoryWithBranch(t, tarfile, tempdir, g.branch) - - ctx := context.Background() - const ( - name = "empty" - namespace = "default" - deployment = true - ) - - repository := &configapi.GitRepository{ - Repo: address, - Branch: g.branch, - Directory: "/", - } - - if _, err := OpenRepository(ctx, name, namespace, repository, deployment, tempdir, GitRepositoryOptions{}); err == nil { - t.Errorf("Unexpectedly succeeded opening empty repository with main branch validation enabled.") - } - - if _, err := OpenRepository(ctx, name, namespace, repository, deployment, tempdir, GitRepositoryOptions{MainBranchStrategy: SkipVerification}); err != nil { - t.Errorf("Failed to open empty git repository with main branch validation disabled: %v", err) - } - - if _, err := OpenRepository(ctx, name, namespace, repository, deployment, tempdir, GitRepositoryOptions{MainBranchStrategy: CreateIfMissing}); err != nil { - t.Errorf("Failed to create new main branch: %v", err) - } - _, err := repo.Reference(BranchName(g.branch).RefInRemote(), false) - if err != nil { - t.Errorf("Couldn't find branch %q after opening repository with CreateIfMissing strategy: %v", g.branch, err) - } -} - -// TestGitPackageRoundTrip creates a package in git and verifies we can read the contents back. -func (g GitSuite) TestGitPackageRoundTrip(t *testing.T) { - tempdir := t.TempDir() - p := filepath.Join(tempdir, "repo") - serverRepo := InitEmptyRepositoryWithWorktree(t, p) - - if err := g.initRepo(serverRepo); err != nil { - t.Fatalf("failed to init repo: %v", err) - } - - ctx := context.Background() - gitServerURL := ServeExistingRepository(t, serverRepo) - - // Now that we are running a git server, we can create a GitRepository backed by it - - const ( - repositoryName = "roundtrip" - packageName = "test-package" - workspace = "test-workspace" - namespace = "default" - deployment = true - ) - spec := &configapi.GitRepository{ - Repo: gitServerURL, - Branch: g.branch, - } - - root := filepath.Join(tempdir, "work") - repo, err := OpenRepository(ctx, repositoryName, namespace, spec, deployment, root, GitRepositoryOptions{}) - if err != nil { - t.Fatalf("failed to open repository: %v", err) - } - // TODO: is there any state? should we defer repo.Close() - - t.Logf("repo is %#v", repo) - - // Push a package to the repo - - wantResources := map[string]string{ - "hello": "world", - } - - // We require a Kptfile to indicate the package boundary - wantResources["Kptfile"] = "placeholder" - - { - packageRevision := &v1alpha1.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - }, - Spec: v1alpha1.PackageRevisionSpec{ - PackageName: packageName, - WorkspaceName: workspace, - RepositoryName: repositoryName, - }, - Status: v1alpha1.PackageRevisionStatus{}, - } - - draft, err := repo.CreatePackageRevision(ctx, packageRevision) - if err != nil { - t.Fatalf("CreatePackageRevision(%#v) failed: %v", packageRevision, err) - } - - newResources := &v1alpha1.PackageRevisionResources{} - newResources.Spec.Resources = wantResources - task := &v1alpha1.Task{} - if err := draft.UpdateResources(ctx, newResources, task); err != nil { - t.Fatalf("draft.UpdateResources(%#v, %#v) failed: %v", newResources, task, err) - } - - revision, err := draft.Close(ctx) - if err != nil { - t.Fatalf("draft.Close() failed: %v", err) - } - klog.Infof("created revision %v", revision.KubeObjectName()) - } - - // We approve the draft so that we can fetch it - { - revisions, err := repo.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{}) - if err != nil { - t.Fatalf("ListPackageRevisons failed: %v", err) - } - - original := findPackageRevision(t, revisions, repository.PackageRevisionKey{ - Repository: repositoryName, - Package: packageName, - WorkspaceName: workspace, - }) - - update, err := repo.UpdatePackageRevision(ctx, original) - if err != nil { - t.Fatalf("UpdatePackageRevision(%#v failed: %v", original, err) - } - if err := update.UpdateLifecycle(ctx, v1alpha1.PackageRevisionLifecyclePublished); err != nil { - t.Fatalf("UpdateLifecycle failed: %v", err) - } - approved, err := update.Close(ctx) - if err != nil { - t.Fatalf("Close() of %q, %q failed: %v", packageName, workspace, err) - } - if approved.Key().Revision != "v1" { - t.Fatalf("UpdateLifecycle did not assign correct revision number; got %s, want v1", - approved.Key().Revision) - } - - klog.Infof("approved revision %v", approved.KubeObjectName()) - } - - // Get the package again, the resources should match what we push - { - version := "v1" - - path := "test-package" - packageRevision, gitLock, err := repo.GetPackageRevision(ctx, version, path) - if err != nil { - t.Fatalf("GetPackageRevision(%q, %q) failed: %v", version, path, err) - } - - t.Logf("packageRevision is %s", packageRevision.KubeObjectName()) - t.Logf("gitLock is %#v", gitLock) - - resources, err := packageRevision.GetResources(ctx) - if err != nil { - t.Fatalf("GetResources() failed: %v", err) - } - - t.Logf("resources is %v", resources.Spec.Resources) - - if !reflect.DeepEqual(resources.Spec.Resources, wantResources) { - t.Fatalf("resources did not match expected; got %v, want %v", resources.Spec.Resources, wantResources) - } - } -} - -// initRepo is a helper that creates a first commit, ensuring the repo is not empty. -func (g GitSuite) initRepo(repo *gogit.Repository) error { - store := repo.Storer - - var objectHash plumbing.Hash - { - data := []byte("This is a test repo") - eo := store.NewEncodedObject() - eo.SetType(plumbing.BlobObject) - eo.SetSize(int64(len(data))) - - w, err := eo.Writer() - if err != nil { - return fmt.Errorf("error creating object writer: %w", err) - } - - if _, err = w.Write(data); err != nil { - w.Close() - return fmt.Errorf("error writing object data: %w", err) - } - if err := w.Close(); err != nil { - return fmt.Errorf("error closing object data: %w", err) - } - - if h, err := store.SetEncodedObject(eo); err != nil { - return fmt.Errorf("error storing object: %w", err) - } else { - objectHash = h - } - } - - var treeHash plumbing.Hash - { - tree := object.Tree{} - - te := object.TreeEntry{ - Name: "README.md", - Mode: filemode.Regular, - Hash: objectHash, - } - tree.Entries = append(tree.Entries, te) - - eo := store.NewEncodedObject() - if err := tree.Encode(eo); err != nil { - return fmt.Errorf("error encoding tree: %w", err) - } - if h, err := store.SetEncodedObject(eo); err != nil { - return fmt.Errorf("error storing tree: %w", err) - } else { - treeHash = h - } - } - - var commitHash plumbing.Hash - { - now := time.Now() - commit := &object.Commit{ - Author: object.Signature{ - Name: "Porch Author", - Email: "author@kpt.dev", - When: now, - }, - Committer: object.Signature{ - Name: "Porch Committer", - Email: "committer@kpt.dev", - When: now, - }, - Message: "First commit", - TreeHash: treeHash, - } - - eo := store.NewEncodedObject() - if err := commit.Encode(eo); err != nil { - return fmt.Errorf("error encoding commit: %w", err) - } - if h, err := store.SetEncodedObject(eo); err != nil { - return fmt.Errorf("error storing commit: %w", err) - } else { - commitHash = h - } - } - - { - name := plumbing.NewBranchReferenceName(g.branch) - ref := plumbing.NewHashReference(name, commitHash) - if err := repo.Storer.SetReference(ref); err != nil { - return fmt.Errorf("error setting reference %q: %w", name, err) - } - - // gogit uses suboptimal default reference name; delete it - repo.Storer.RemoveReference(plumbing.Master) - - // create correct HEAD as a symbolic reference of the branch - head := plumbing.NewSymbolicReference(plumbing.HEAD, name) - if err := repo.Storer.SetReference(head); err != nil { - return fmt.Errorf("error creating HEAD ref to %q: %w", ref, err) - } - } - - return nil -} - -const Kptfile = ` -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: empty -info: - description: Empty Package -` - -func (g GitSuite) TestListPackagesTrivial(t *testing.T) { - tempdir := t.TempDir() - tarfile := filepath.Join("testdata", "trivial-repository.tar") - _, address := ServeGitRepositoryWithBranch(t, tarfile, tempdir, g.branch) - - ctx := context.Background() - const ( - repositoryName = "empty" - namespace = "default" - deployment = true - ) - - git, err := OpenRepository(ctx, repositoryName, namespace, &configapi.GitRepository{ - Repo: address, - Branch: g.branch, - Directory: "/", - SecretRef: configapi.SecretRef{}, - }, deployment, tempdir, GitRepositoryOptions{}) - if err != nil { - t.Fatalf("Failed to open Git repository loaded from %q: %v", tarfile, err) - } - - revisions, err := git.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{}) - if err != nil { - t.Fatalf("Failed to list packages from %q: %v", tarfile, err) - } - if got, want := len(revisions), 0; got != want { - t.Errorf("Number of packges in empty repository: got %d, want %d", got, want) - } - - packageRevision := &v1alpha1.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - }, - Spec: v1alpha1.PackageRevisionSpec{ - PackageName: "test-package", - WorkspaceName: "test-workspace", - RepositoryName: repositoryName, - Lifecycle: v1alpha1.PackageRevisionLifecycleDraft, - }, - } - - // Create a package draft - draft, err := git.CreatePackageRevision(ctx, packageRevision) - if err != nil { - t.Fatalf("CreatePackageRevision() failed: %v", err) - } - resources := &v1alpha1.PackageRevisionResources{ - Spec: v1alpha1.PackageRevisionResourcesSpec{ - Resources: map[string]string{ - "Kptfile": Kptfile, - }, - }, - } - if err := draft.UpdateResources(ctx, resources, &v1alpha1.Task{ - Type: v1alpha1.TaskTypeInit, - Init: &v1alpha1.PackageInitTaskSpec{ - Description: "Empty Package", - }, - }); err != nil { - t.Fatalf("UpdateResources() failed: %v", err) - } - newRevision, err := draft.Close(ctx) - if err != nil { - t.Fatalf("draft.Close() failed: %v", err) - } - - result, err := newRevision.GetPackageRevision(ctx) - if err != nil { - t.Errorf("didn't expect error, but got %v", err) - } - if got, want := result.Spec.Lifecycle, v1alpha1.PackageRevisionLifecycleDraft; got != want { - t.Errorf("Newly created package type: got %q, want %q", got, want) - } - - // Verify - verify, err := gogit.PlainOpen(filepath.Join(tempdir, ".git")) - if err != nil { - t.Fatalf("Failed to open git repository for verification: %v", err) - } - logRefs(t, verify, "Ref: ") - draftRefName := plumbing.NewBranchReferenceName("drafts/test-package/test-workspace") - if _, err = verify.Reference(draftRefName, true); err != nil { - t.Errorf("Failed to resolve %q references: %v", draftRefName, err) - } -} - -// trivial-repository.tar has a repon with a `main` branch and a single empty commit. -func (g GitSuite) TestCreatePackageInTrivialRepository(t *testing.T) { - tempdir := t.TempDir() - tarfile := filepath.Join("testdata", "trivial-repository.tar") - _, address := ServeGitRepositoryWithBranch(t, tarfile, tempdir, g.branch) - - ctx := context.Background() - const ( - repositoryName = "trivial" - namespace = "default" - deployment = true - ) - - git, err := OpenRepository(ctx, repositoryName, namespace, &configapi.GitRepository{ - Repo: address, - Branch: g.branch, - Directory: "/", - SecretRef: configapi.SecretRef{}, - }, deployment, tempdir, GitRepositoryOptions{}) - if err != nil { - t.Fatalf("Failed to open Git repository loaded from %q: %v", tarfile, err) - } - - revisions, err := git.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{}) - if err != nil { - t.Fatalf("Failed to list packages from %q: %v", tarfile, err) - } - if got, want := len(revisions), 0; got != want { - t.Errorf("Number of packges in the trivial repository: got %d, want %d", got, want) - } - - packageRevision := &v1alpha1.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - }, - Spec: v1alpha1.PackageRevisionSpec{ - PackageName: "test-package", - WorkspaceName: "test-workspace", - RepositoryName: repositoryName, - Lifecycle: v1alpha1.PackageRevisionLifecycleDraft, - }, - } - - // Create a package draft - draft, err := git.CreatePackageRevision(ctx, packageRevision) - if err != nil { - t.Fatalf("CreatePackageRevision() failed: %v", err) - } - resources := &v1alpha1.PackageRevisionResources{ - Spec: v1alpha1.PackageRevisionResourcesSpec{ - Resources: map[string]string{ - "Kptfile": Kptfile, - }, - }, - } - if err := draft.UpdateResources(ctx, resources, &v1alpha1.Task{ - Type: v1alpha1.TaskTypeInit, - Init: &v1alpha1.PackageInitTaskSpec{ - Description: "Empty Package", - }, - }); err != nil { - t.Fatalf("UpdateResources() failed: %v", err) - } - newRevision, err := draft.Close(ctx) - if err != nil { - t.Fatalf("draft.Close() failed: %v", err) - } - - result, err := newRevision.GetPackageRevision(ctx) - if err != nil { - t.Errorf("didn't expect error, but got %v", err) - } - if got, want := result.Spec.Lifecycle, v1alpha1.PackageRevisionLifecycleDraft; got != want { - t.Errorf("Newly created package type: got %q, want %q", got, want) - } -} - -func (g GitSuite) TestListPackagesSimple(t *testing.T) { - tempdir := t.TempDir() - tarfile := filepath.Join("testdata", "simple-repository.tar") - _, address := ServeGitRepositoryWithBranch(t, tarfile, tempdir, g.branch) - - ctx := context.Background() - const ( - repositoryName = "simple" - namespace = "default" - deployment = true - ) - - git, err := OpenRepository(ctx, repositoryName, namespace, &configapi.GitRepository{ - Repo: address, - Branch: g.branch, - Directory: "/", - SecretRef: configapi.SecretRef{}, - }, deployment, tempdir, GitRepositoryOptions{}) - if err != nil { - t.Fatalf("Failed to open Git repository loaded from %q: %v", tarfile, err) - } - - revisions, err := git.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{}) - if err != nil { - t.Fatalf("Failed to list packages from %q: %v", tarfile, err) - } - - want := map[repository.PackageRevisionKey]v1alpha1.PackageRevisionLifecycle{ - {Repository: "simple", Package: "empty", Revision: "v1", WorkspaceName: "v1"}: v1alpha1.PackageRevisionLifecyclePublished, - {Repository: "simple", Package: "basens", Revision: "v1", WorkspaceName: "v1"}: v1alpha1.PackageRevisionLifecyclePublished, - {Repository: "simple", Package: "basens", Revision: "v2", WorkspaceName: "v2"}: v1alpha1.PackageRevisionLifecyclePublished, - {Repository: "simple", Package: "istions", Revision: "v1", WorkspaceName: "v1"}: v1alpha1.PackageRevisionLifecyclePublished, - {Repository: "simple", Package: "istions", Revision: "v2", WorkspaceName: "v2"}: v1alpha1.PackageRevisionLifecyclePublished, - - // TODO: may want to filter these out, for example by including only those package - // revisions from main branch that differ in content (their tree hash) from another - // taged revision of the package. - {Repository: "simple", Package: "empty", Revision: g.branch, WorkspaceName: v1alpha1.WorkspaceName(g.branch)}: v1alpha1.PackageRevisionLifecyclePublished, - {Repository: "simple", Package: "basens", Revision: g.branch, WorkspaceName: v1alpha1.WorkspaceName(g.branch)}: v1alpha1.PackageRevisionLifecyclePublished, - {Repository: "simple", Package: "istions", Revision: g.branch, WorkspaceName: v1alpha1.WorkspaceName(g.branch)}: v1alpha1.PackageRevisionLifecyclePublished, - } - - got := map[repository.PackageRevisionKey]v1alpha1.PackageRevisionLifecycle{} - for _, r := range revisions { - rev, err := r.GetPackageRevision(ctx) - if err != nil { - t.Errorf("didn't expect error, but got %v", err) - } - got[repository.PackageRevisionKey{ - Repository: rev.Spec.RepositoryName, - Package: rev.Spec.PackageName, - WorkspaceName: rev.Spec.WorkspaceName, - Revision: rev.Spec.Revision, - }] = rev.Spec.Lifecycle - } - - if !cmp.Equal(want, got) { - t.Errorf("Package Revisions in simple-repository: (-want,+got): %s", cmp.Diff(want, got)) - } -} - -func (g GitSuite) TestListPackagesDrafts(t *testing.T) { - tempdir := t.TempDir() - tarfile := filepath.Join("testdata", "drafts-repository.tar") - _, address := ServeGitRepositoryWithBranch(t, tarfile, tempdir, g.branch) - - ctx := context.Background() - const ( - repositoryName = "drafts" - namespace = "default" - deployment = true - ) - - git, err := OpenRepository(ctx, repositoryName, namespace, &configapi.GitRepository{ - Repo: address, - Branch: g.branch, - Directory: "/", - SecretRef: configapi.SecretRef{}, - }, deployment, tempdir, GitRepositoryOptions{}) - if err != nil { - t.Fatalf("Failed to open Git repository loaded from %q: %v", tarfile, err) - } - - revisions, err := git.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{}) - if err != nil { - t.Fatalf("Failed to list packages from %q: %v", tarfile, err) - } - - want := map[repository.PackageRevisionKey]v1alpha1.PackageRevisionLifecycle{ - {Repository: "drafts", Package: "empty", Revision: "v1", WorkspaceName: "v1"}: v1alpha1.PackageRevisionLifecyclePublished, - {Repository: "drafts", Package: "basens", Revision: "v1", WorkspaceName: "v1"}: v1alpha1.PackageRevisionLifecyclePublished, - {Repository: "drafts", Package: "basens", Revision: "v2", WorkspaceName: "v2"}: v1alpha1.PackageRevisionLifecyclePublished, - {Repository: "drafts", Package: "istions", Revision: "v1", WorkspaceName: "v1"}: v1alpha1.PackageRevisionLifecyclePublished, - {Repository: "drafts", Package: "istions", Revision: "v2", WorkspaceName: "v2"}: v1alpha1.PackageRevisionLifecyclePublished, - - {Repository: "drafts", Package: "bucket", WorkspaceName: "v1"}: v1alpha1.PackageRevisionLifecycleDraft, - {Repository: "drafts", Package: "none", WorkspaceName: "v1"}: v1alpha1.PackageRevisionLifecycleDraft, - {Repository: "drafts", Package: "pkg-with-history", WorkspaceName: "v1"}: v1alpha1.PackageRevisionLifecycleDraft, - - // TODO: filter main branch out? see above - {Repository: "drafts", Package: "basens", WorkspaceName: v1alpha1.WorkspaceName(g.branch), Revision: g.branch}: v1alpha1.PackageRevisionLifecyclePublished, - {Repository: "drafts", Package: "empty", WorkspaceName: v1alpha1.WorkspaceName(g.branch), Revision: g.branch}: v1alpha1.PackageRevisionLifecyclePublished, - {Repository: "drafts", Package: "istions", WorkspaceName: v1alpha1.WorkspaceName(g.branch), Revision: g.branch}: v1alpha1.PackageRevisionLifecyclePublished, - } - - got := map[repository.PackageRevisionKey]v1alpha1.PackageRevisionLifecycle{} - for _, r := range revisions { - rev, err := r.GetPackageRevision(ctx) - if err != nil { - t.Errorf("didn't expect error, but got %v", err) - } - got[repository.PackageRevisionKey{ - Repository: rev.Spec.RepositoryName, - Package: rev.Spec.PackageName, - Revision: rev.Spec.Revision, - WorkspaceName: rev.Spec.WorkspaceName, - }] = rev.Spec.Lifecycle - } - - if !cmp.Equal(want, got) { - t.Errorf("Package Revisions in drafts-repository: (-want,+got): %s", cmp.Diff(want, got)) - } -} - -func (g GitSuite) TestApproveDraft(t *testing.T) { - tempdir := t.TempDir() - tarfile := filepath.Join("testdata", "drafts-repository.tar") - repo, address := ServeGitRepositoryWithBranch(t, tarfile, tempdir, g.branch) - - const ( - repositoryName = "approve" - namespace = "default" - draft BranchName = "drafts/bucket/v1" - finalReferenceName plumbing.ReferenceName = "refs/tags/bucket/v1" - deployment = true - ) - ctx := context.Background() - git, err := OpenRepository(ctx, repositoryName, namespace, &configapi.GitRepository{ - Repo: address, - Branch: g.branch, - Directory: "/", - }, deployment, tempdir, GitRepositoryOptions{}) - if err != nil { - t.Fatalf("Failed to open Git repository loaded from %q: %v", tarfile, err) - } - - revisions, err := git.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{}) - if err != nil { - t.Fatalf("ListPackageRevisions failed: %v", err) - } - - bucket := findPackageRevision(t, revisions, repository.PackageRevisionKey{ - Repository: repositoryName, - Package: "bucket", - WorkspaceName: "v1", - }) - - // Before Update; Check server references. Draft must exist, final not. - refMustExist(t, repo, draft.RefInRemote()) - refMustNotExist(t, repo, finalReferenceName) - - update, err := git.UpdatePackageRevision(ctx, bucket) - if err != nil { - t.Fatalf("UpdatePackageRevision failed: %v", err) - } - - update.UpdateLifecycle(ctx, v1alpha1.PackageRevisionLifecyclePublished) - - new, err := update.Close(ctx) - if err != nil { - t.Fatalf("Close failed: %v", err) - } - - rev, err := new.GetPackageRevision(ctx) - if err != nil { - t.Errorf("didn't expect error, but got %v", err) - } - if got, want := rev.Spec.Lifecycle, v1alpha1.PackageRevisionLifecyclePublished; got != want { - t.Errorf("Approved package lifecycle: got %s, want %s", got, want) - } - - // After Update: Final must exist, draft must not exist - refMustNotExist(t, repo, draft.RefInRemote()) - refMustExist(t, repo, finalReferenceName) -} - -func (g GitSuite) TestApproveDraftWithHistory(t *testing.T) { - tempdir := t.TempDir() - tarfile := filepath.Join("testdata", "drafts-repository.tar") - repo, address := ServeGitRepositoryWithBranch(t, tarfile, tempdir, g.branch) - - const ( - repositoryName = "approve" - namespace = "default" - draft BranchName = "drafts/pkg-with-history/v1" - finalReferenceName plumbing.ReferenceName = "refs/tags/pkg-with-history/v1" - deployment = true - ) - ctx := context.Background() - git, err := OpenRepository(ctx, repositoryName, namespace, &configapi.GitRepository{ - Repo: address, - Branch: g.branch, - Directory: "/", - }, deployment, tempdir, GitRepositoryOptions{}) - if err != nil { - t.Fatalf("Failed to open Git repository loaded from %q: %v", tarfile, err) - } - - revisions, err := git.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{}) - if err != nil { - t.Fatalf("ListPackageRevisions failed: %v", err) - } - - bucket := findPackageRevision(t, revisions, repository.PackageRevisionKey{ - Repository: repositoryName, - Package: "pkg-with-history", - WorkspaceName: "v1", - }) - - // Before Update; Check server references. Draft must exist, final not. - refMustExist(t, repo, draft.RefInRemote()) - refMustNotExist(t, repo, finalReferenceName) - - update, err := git.UpdatePackageRevision(ctx, bucket) - if err != nil { - t.Fatalf("UpdatePackageRevision failed: %v", err) - } - - update.UpdateLifecycle(ctx, v1alpha1.PackageRevisionLifecyclePublished) - - new, err := update.Close(ctx) - if err != nil { - t.Fatalf("Close failed: %v", err) - } - - rev, err := new.GetPackageRevision(ctx) - if err != nil { - t.Errorf("didn't expect error, but got %v", err) - } - if got, want := rev.Spec.Lifecycle, v1alpha1.PackageRevisionLifecyclePublished; got != want { - t.Errorf("Approved package lifecycle: got %s, want %s", got, want) - } - if got, want := len(rev.Spec.Tasks), 4; got != want { - t.Errorf("Approved package task count: got %d, want %d", got, want) - } - - // After Update: Final must exist, draft must not exist - refMustNotExist(t, repo, draft.RefInRemote()) - refMustExist(t, repo, finalReferenceName) -} - -func (g GitSuite) TestDeletePackages(t *testing.T) { - tempdir := t.TempDir() - tarfile := filepath.Join("testdata", "drafts-repository.tar") - repo, address := ServeGitRepositoryWithBranch(t, tarfile, tempdir, g.branch) - - const ( - repositoryName = "delete" - namespace = "delete-namespace" - deployment = true - ) - - ctx := context.Background() - git, err := OpenRepository(ctx, repositoryName, namespace, &configapi.GitRepository{ - Repo: address, - Branch: g.branch, - }, deployment, tempdir, GitRepositoryOptions{}) - if err != nil { - t.Fatalf("OpenRepository(%q) failed: %v", address, err) - } - - // If we delete one of these packages, we expect the reference to be deleted too - wantDeletedRefs := map[repository.PackageRevisionKey]plumbing.ReferenceName{ - {Repository: "delete", Package: "bucket", Revision: "v1"}: "refs/heads/drafts/bucket/v1", - {Repository: "delete", Package: "none", Revision: "v1"}: "refs/heads/drafts/none/v1", - {Repository: "delete", Package: "basens", Revision: "v1"}: "refs/tags/basens/v1", - {Repository: "delete", Package: "basens", Revision: "v2"}: "refs/tags/basens/v2", - {Repository: "delete", Package: "empty", Revision: "v1"}: "refs/tags/empty/v1", - {Repository: "delete", Package: "istions", Revision: "v1"}: "refs/tags/istions/v1", - {Repository: "delete", Package: "istions", Revision: "v2"}: "refs/tags/istions/v2", - } - - // Delete all packages - all, err := git.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{}) - if err != nil { - t.Fatalf("ListPackageRevisions failed: %v", err) - } - - for len(all) > 0 { - // Delete one of the packages - deleting := all[0] - pr, err := deleting.GetPackageRevision(ctx) - if err != nil { - t.Fatalf("didn't expect error, but got %v", err) - } - name := repository.PackageRevisionKey{Repository: pr.Spec.RepositoryName, Package: pr.Spec.PackageName, - Revision: pr.Spec.Revision, WorkspaceName: pr.Spec.WorkspaceName} - - if rn, ok := wantDeletedRefs[name]; ok { - // Verify the reference still exists - refMustExist(t, repo, rn) - } - - if err := git.DeletePackageRevision(ctx, deleting); err != nil { - t.Fatalf("DeletePackageRevision(%q) failed: %v", deleting.KubeObjectName(), err) - } - - if rn, ok := wantDeletedRefs[name]; ok { - // Verify the reference no longer exists - refMustNotExist(t, repo, rn) - } - - // Re-list packages and check the deleted package is absent - all, err = git.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{}) - if err != nil { - t.Fatalf("ListPackageRevisions failed: %v", err) - } - - packageMustNotExist(t, all, name) - } - - // The only got references should be main and HEAD - got := map[plumbing.ReferenceName]bool{} - forEachRef(t, repo, func(ref *plumbing.Reference) error { - got[ref.Name()] = true - return nil - }) - - // branch may be `refs/heads/main` for some test runs - branch := plumbing.NewBranchReferenceName(g.branch) - want := map[plumbing.ReferenceName]bool{ - branch: true, - DefaultMainReferenceName: true, - "HEAD": true, - } - if !cmp.Equal(want, got) { - t.Fatalf("Unexpected references after deleting all packages (-want, +got): %s", cmp.Diff(want, got)) - } - - // And there should be no packages in main branch - main := resolveReference(t, repo, branch) - tree := getCommitTree(t, repo, main.Hash()) - if len(tree.Entries) > 0 { - var b bytes.Buffer - for i := range tree.Entries { - e := &tree.Entries[i] - fmt.Fprintf(&b, "%s: %s (%s)", e.Name, e.Hash, e.Mode) - } - // Tree is not empty after deleting all packages - t.Errorf("%q branch has non-empty tree after all packages have been deleted: %s", branch, b.String()) - } -} - -// Test introduces package in the upstream repo and lists is after refresh. -func (g GitSuite) TestRefreshRepo(t *testing.T) { - upstreamDir := t.TempDir() - downstreamDir := t.TempDir() - tarfile := filepath.Join("testdata", "simple-repository.tar") - upstream := OpenGitRepositoryFromArchiveWithWorktree(t, tarfile, upstreamDir) - InitializeBranch(t, upstream, g.branch) - address := ServeExistingRepository(t, upstream) - - const ( - repositoryName = "refresh" - namespace = "refresh-namespace" - deployment = true - ) - - newPackageName := repository.PackageRevisionKey{ - Repository: "refresh", - Package: "newpkg", - Revision: "v3", - WorkspaceName: "v3", - } - - ctx := context.Background() - git, err := OpenRepository(ctx, repositoryName, namespace, &configapi.GitRepository{ - Repo: address, - }, deployment, downstreamDir, GitRepositoryOptions{}) - if err != nil { - t.Fatalf("OpenRepository(%q) failed: %v", address, err) - } - - all, err := git.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{}) - if err != nil { - t.Fatalf("ListPackageRevisions failed: %v", err) - } - - // Confirm we listed some package(s) - findPackageRevision(t, all, repository.PackageRevisionKey{Repository: "refresh", Package: "basens", - Revision: "v2", WorkspaceName: "v2"}) - packageMustNotExist(t, all, newPackageName) - - // Create package in the upstream repository - wt, err := upstream.Worktree() - if err != nil { - t.Fatalf("Worktree failed: %v", err) - } - - name := plumbing.NewBranchReferenceName(g.branch) - main := resolveReference(t, upstream, name) - if err := wt.Checkout(&gogit.CheckoutOptions{ - Branch: main.Name(), - Force: true, - }); err != nil { - t.Fatalf("Checkout failed: %v", err) - } - - const kptfileName = "newpkg/Kptfile" - file, err := wt.Filesystem.Create(kptfileName) - if err != nil { - t.Fatalf("Filesystem.Create failed: %v", err) - } - if _, err := file.Write([]byte(Kptfile)); err != nil { - t.Fatalf("Failed to write file: %v", err) - } - if _, err := wt.Add(kptfileName); err != nil { - t.Fatalf("Failed to add file to index: %v", err) - } - sig := object.Signature{ - Name: "Test", - Email: "test@kpt.dev", - When: time.Now(), - } - commit, err := wt.Commit("Hello", &gogit.CommitOptions{ - Author: &sig, - Committer: &sig, - }) - if err != nil { - t.Fatalf("Commit failed: %v", err) - } - - tag := plumbing.NewHashReference(plumbing.NewTagReferenceName("newpkg/v3"), commit) - if err := upstream.Storer.SetReference(tag); err != nil { - t.Fatalf("Failed to create tag %s: %v", tag, err) - } - - all, err = git.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{}) - if err != nil { - t.Fatalf("ListPackageRevisions(Refresh) failed; %v", err) - } - findPackageRevision(t, all, newPackageName) -} - -// The test deletes packages on the upstream one by one and validates they were -// pruned in the registered repository on refresh. -func (g GitSuite) TestPruneRemotes(t *testing.T) { - tempdir := t.TempDir() - tarfile := filepath.Join("testdata", "drafts-repository.tar") - repo, address := ServeGitRepositoryWithBranch(t, tarfile, tempdir, g.branch) - - const ( - name = "prune" - namespace = "prune-namespace" - deployment = true - ) - - ctx := context.Background() - git, err := OpenRepository(ctx, name, namespace, &configapi.GitRepository{ - Repo: address, - Branch: g.branch, - }, deployment, tempdir, GitRepositoryOptions{}) - if err != nil { - t.Fatalf("OpenRepository(%q) failed: %v", address, err) - } - - for _, pair := range []struct { - ref plumbing.ReferenceName - pkg repository.PackageRevisionKey - }{ - { - ref: "refs/heads/drafts/bucket/v1", - pkg: repository.PackageRevisionKey{Repository: "prune", Package: "bucket", WorkspaceName: "v1"}, - }, - { - ref: "refs/heads/drafts/none/v1", - pkg: repository.PackageRevisionKey{Repository: "prune", Package: "none", WorkspaceName: "v1"}, - }, - { - ref: "refs/tags/basens/v1", - pkg: repository.PackageRevisionKey{Repository: "prune", Package: "basens", Revision: "v1", WorkspaceName: "v1"}, - }, - { - ref: "refs/tags/basens/v2", - pkg: repository.PackageRevisionKey{Repository: "prune", Package: "basens", Revision: "v2", WorkspaceName: "v2"}, - }, - { - ref: "refs/tags/empty/v1", - pkg: repository.PackageRevisionKey{Repository: "prune", Package: "empty", Revision: "v1", WorkspaceName: "v1"}, - }, - { - ref: "refs/tags/istions/v1", - pkg: repository.PackageRevisionKey{Repository: "prune", Package: "istions", Revision: "v1", WorkspaceName: "v1"}, - }, - { - ref: "refs/tags/istions/v2", - pkg: repository.PackageRevisionKey{Repository: "prune", Package: "istions", Revision: "v2", WorkspaceName: "v2"}, - }, - } { - repositoryMustHavePackageRevision(t, git, pair.pkg) - refMustExist(t, repo, pair.ref) - if err := repo.Storer.RemoveReference(pair.ref); err != nil { - t.Fatalf("RemoveReference(%q) failed: %v", pair.ref, err) - } - repositoryMustNotHavePackageRevision(t, git, pair.pkg) - } -} - -func (g GitSuite) TestNested(t *testing.T) { - tempdir := t.TempDir() - tarfile := filepath.Join("testdata", "nested-repository.tar") - repo, address := ServeGitRepositoryWithBranch(t, tarfile, tempdir, g.branch) - - ctx := context.Background() - const ( - repositoryName = "nested" - namespace = "default" - deployment = true - ) - - git, err := OpenRepository(ctx, repositoryName, namespace, &configapi.GitRepository{ - Repo: address, - Branch: g.branch, - Directory: "/", - }, deployment, tempdir, GitRepositoryOptions{}) - if err != nil { - t.Fatalf("Failed to open Git repository loaded from %q: %v", tarfile, err) - } - - revisions, err := git.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{}) - if err != nil { - t.Fatalf("Failed to list packages from %q: %v", tarfile, err) - } - - // Name of the registered branch - branch := plumbing.NewBranchReferenceName(g.branch) - - // Check that all tags and branches have their packages. - want := map[string]v1alpha1.PackageRevisionLifecycle{} - forEachRef(t, repo, func(ref *plumbing.Reference) error { - switch name := string(ref.Name()); { - case strings.HasPrefix(name, tagsPrefixInRemoteRepo): - want[strings.TrimPrefix(name, tagsPrefixInRemoteRepo)] = v1alpha1.PackageRevisionLifecyclePublished - case strings.HasPrefix(name, draftsPrefixInRemoteRepo): - want[strings.TrimPrefix(name, draftsPrefixInRemoteRepo)] = v1alpha1.PackageRevisionLifecycleDraft - case strings.HasPrefix(name, proposedPrefixInRemoteRepo): - want[strings.TrimPrefix(name, proposedPrefixInRemoteRepo)] = v1alpha1.PackageRevisionLifecycleProposed - case name == string(branch): - // Skip the registered 'main' branch. - case name == string(DefaultMainReferenceName), name == "HEAD": - // skip main and HEAD - default: - // There should be no other refs in the repository. - return fmt.Errorf("unexpected reference: %s", ref) - } - return nil - }) - - got := map[string]v1alpha1.PackageRevisionLifecycle{} - for _, pr := range revisions { - rev, err := pr.GetPackageRevision(ctx) - if err != nil { - t.Errorf("didn't expect error, but got %v", err) - } - if rev.Spec.Revision == g.branch { - // skip packages with the revision of the main registered branch, - // to match the above simplified package discovery algo. - continue - } - if rev.Spec.Lifecycle == v1alpha1.PackageRevisionLifecyclePublished { - got[fmt.Sprintf("%s/%s", rev.Spec.PackageName, rev.Spec.Revision)] = rev.Spec.Lifecycle - } else { - got[fmt.Sprintf("%s/%s", rev.Spec.PackageName, rev.Spec.WorkspaceName)] = rev.Spec.Lifecycle - } - } - - if !cmp.Equal(want, got) { - t.Errorf("Discovered packages differ: (-want,+got): %s", cmp.Diff(want, got)) - } -} - -func createPackageRevisionMap(revisions []repository.PackageRevision) map[string]bool { - result := map[string]bool{} - for _, pr := range revisions { - key := pr.Key() - if key.WorkspaceName != "" { - result[fmt.Sprintf("%s/%s", key.Package, key.WorkspaceName)] = true - } else { - result[fmt.Sprintf("%s/%s", key.Package, key.Revision)] = true - } - } - return result -} - -func sliceToSet(s []string) map[string]bool { - result := map[string]bool{} - for _, v := range s { - result[v] = true - } - return result -} - -func (g GitSuite) TestNestedDirectories(t *testing.T) { - ctx := context.Background() - - for _, tc := range []struct { - directory string - packages []string - }{ - { - directory: "sample", - packages: []string{"/v1", "/v2", "/" + g.branch}, - }, - { - directory: "nonexistent", - packages: []string{}, - }, - { - directory: "catalog/gcp", - packages: []string{ - "cloud-sql/v1", - "spanner/v1", - "bucket/v2", - "bucket/v1", - "bucket/" + g.branch, - }, - }, - } { - t.Run(tc.directory, func(t *testing.T) { - tempdir := t.TempDir() - tarfile := filepath.Join("testdata", "nested-repository.tar") - _, address := ServeGitRepositoryWithBranch(t, tarfile, tempdir, g.branch) - - const ( - repositoryName = "directory" - namespace = "default" - deployment = true - ) - - git, err := OpenRepository(ctx, repositoryName, namespace, &configapi.GitRepository{ - Repo: address, - Branch: g.branch, - Directory: tc.directory, - }, deployment, tempdir, GitRepositoryOptions{}) - if err != nil { - t.Fatalf("Failed to open Git repository loaded from %q with directory %q: %v", tarfile, tc.directory, err) - } - - revisions, err := git.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{}) - if err != nil { - t.Fatalf("Failed to list packages from %q: %v", tarfile, err) - } - - got := createPackageRevisionMap(revisions) - want := sliceToSet(tc.packages) - - if !cmp.Equal(want, got) { - t.Errorf("Packages rooted in %q; Unexpected result (-want,+got): %s", tc.directory, cmp.Diff(want, got)) - } - }) - } -} - -func (g GitSuite) TestAuthor(t *testing.T) { - ctx := context.Background() - - testCases := map[string]struct { - pkg string - workspace string - revision string - author string - timestamp time.Time - }{ - "draft packagerevision does not have publishing info in status": { - pkg: "draft-pkg", - workspace: "v1", - author: "", - timestamp: time.Time{}, - }, - "published packagerevision on tag": { - pkg: "pkg-with-anno", - revision: "v1", - workspace: "v1", - author: "pkg-with-anno-author@example.com", - timestamp: time.Date(2022, time.August, 26, 22, 47, 35, 0, time.UTC), - }, - "published packagerevision on main without commit annotations": { - pkg: "pkg-without-anno", - revision: g.branch, - workspace: g.branch, - author: "", - timestamp: time.Time{}, - }, - "published packagerevision on main with commit annotations": { - pkg: "pkg-with-anno", - revision: g.branch, - workspace: g.branch, - author: "pkg-with-anno-author@example.com", - timestamp: time.Date(2022, time.August, 26, 22, 47, 35, 0, time.UTC), - }, - } - - for tn := range testCases { - tc := testCases[tn] - t.Run(tn, func(t *testing.T) { - tempdir := t.TempDir() - tarfile := filepath.Join("testdata", "publishinfo-repository.tar") - _, address := ServeGitRepositoryWithBranch(t, tarfile, tempdir, g.branch) - - const ( - repositoryName = "directory" - namespace = "default" - deployment = true - ) - - git, err := OpenRepository(ctx, repositoryName, namespace, &configapi.GitRepository{ - Repo: address, - Branch: g.branch, - }, deployment, tempdir, GitRepositoryOptions{}) - if err != nil { - t.Fatalf("Failed to open Git repository loaded from %q: %v", tarfile, err) - } - - revisions, err := git.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{}) - if err != nil { - t.Fatalf("ListPackageRevisions failed: %v", err) - } - - _ = revisions - draftPkg := findPackageRevision(t, revisions, repository.PackageRevisionKey{ - Repository: repositoryName, - Package: tc.pkg, - WorkspaceName: v1alpha1.WorkspaceName(tc.workspace), - Revision: tc.revision, - }) - rev, err := draftPkg.GetPackageRevision(ctx) - if err != nil { - t.Errorf("didn't expect error, but got %v", err) - } - if got, want := rev.Status.PublishedBy, tc.author; got != want { - t.Errorf("expected %q, but got %q", want, got) - } - - if got, want := rev.Status.PublishedAt.Time, tc.timestamp; !want.Equal(got) { - t.Errorf("expected %v, but got %v", want, got) - } - - }) - } -} diff --git a/porch/pkg/git/gogit.go b/porch/pkg/git/gogit.go deleted file mode 100644 index 6ffcebed73..0000000000 --- a/porch/pkg/git/gogit.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import ( - "github.com/go-git/go-billy/v5/osfs" - "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/config" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/cache" - "github.com/go-git/go-git/v5/storage/filesystem" -) - -// This file contains helpers for interacting with gogit. - -func initEmptyRepository(path string) (*git.Repository, error) { - isBare := true // Porch only uses bare repositories - repo, err := git.PlainInit(path, isBare) - if err != nil { - return nil, err - } - if err := initializeDefaultBranches(repo); err != nil { - return nil, err - } - return repo, nil -} - -func initializeDefaultBranches(repo *git.Repository) error { - // Adjust default references - if err := repo.Storer.RemoveReference(plumbing.Master); err != nil { - return err - } - // gogit points HEAD at a wrong branch; point it at main - main := plumbing.NewSymbolicReference(plumbing.HEAD, DefaultMainReferenceName) - if err := repo.Storer.SetReference(main); err != nil { - return err - } - return nil -} - -func openRepository(path string) (*git.Repository, error) { - dot := osfs.New(path) - storage := filesystem.NewStorage(dot, cache.NewObjectLRUDefault()) - return git.Open(storage, dot) -} - -func initializeOrigin(repo *git.Repository, address string) error { - cfg, err := repo.Config() - if err != nil { - return err - } - - cfg.Remotes[OriginName] = &config.RemoteConfig{ - Name: OriginName, - URLs: []string{address}, - Fetch: defaultFetchSpec, - } - - if err := repo.SetConfig(cfg); err != nil { - return err - } - - return nil -} diff --git a/porch/pkg/git/mainbranchstrategy_string.go b/porch/pkg/git/mainbranchstrategy_string.go deleted file mode 100644 index 7707bcc99a..0000000000 --- a/porch/pkg/git/mainbranchstrategy_string.go +++ /dev/null @@ -1,25 +0,0 @@ -// Code generated by "stringer -type=MainBranchStrategy -linecomment"; DO NOT EDIT. - -package git - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[ErrorIfMissing-0] - _ = x[CreateIfMissing-1] - _ = x[SkipVerification-2] -} - -const _MainBranchStrategy_name = "ErrorIsMissingCreateIfMissingSkipVerification" - -var _MainBranchStrategy_index = [...]uint8{0, 14, 29, 45} - -func (i MainBranchStrategy) String() string { - if i < 0 || i >= MainBranchStrategy(len(_MainBranchStrategy_index)-1) { - return "MainBranchStrategy(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _MainBranchStrategy_name[_MainBranchStrategy_index[i]:_MainBranchStrategy_index[i+1]] -} diff --git a/porch/pkg/git/package.go b/porch/pkg/git/package.go deleted file mode 100644 index 9a0772bf12..0000000000 --- a/porch/pkg/git/package.go +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import ( - "context" - "crypto/sha1" - "encoding/hex" - "fmt" - "path/filepath" - "strings" - "time" - - "github.com/GoogleContainerTools/kpt/internal/pkg" - kptfile "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/go-git/go-git/v5/plumbing" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/klog/v2" -) - -type gitPackageRevision struct { - repo *gitRepository // repo is repo containing the package - path string // the path to the package from the repo root - revision string - workspaceName v1alpha1.WorkspaceName - updated time.Time - updatedBy string - ref *plumbing.Reference // ref is the Git reference at which the package exists - tree plumbing.Hash // Cached tree of the package itself, some descendent of commit.Tree() - commit plumbing.Hash // Current version of the package (commit sha) - tasks []v1alpha1.Task -} - -var _ repository.PackageRevision = &gitPackageRevision{} - -// Kubernetes resource names requirements do not allow to encode arbitrary directory -// path: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names -// Because we need a resource names that are stable over time, and avoid conflict, we -// compute a hash of the package path and revision. -// For implementation convenience (though this is temporary) we prepend the repository -// name in order to aide package discovery on the server. With improvements to caching -// layer, the prefix will be removed (this may happen without notice) so it should not -// be relied upon by clients. -func (p *gitPackageRevision) KubeObjectName() string { - // The published package revisions on the main branch will have the same workspaceName - // as the most recently published package revision, so we need to ensure it has a unique - // and unchanging name. - var s string - if p.revision == string(p.repo.branch) { - s = p.revision - } else { - s = string(p.workspaceName) - } - hash := sha1.Sum([]byte(fmt.Sprintf("%s:%s:%s", p.repo.name, p.path, s))) - return p.repo.name + "-" + hex.EncodeToString(hash[:]) -} - -func (p *gitPackageRevision) KubeObjectNamespace() string { - return p.repo.namespace -} - -func (p *gitPackageRevision) UID() types.UID { - return p.uid() -} - -func (p *gitPackageRevision) CachedIdentifier() repository.CachedIdentifier { - if p.ref != nil { - k := p.ref.Name().String() - if p.revision == string(p.repo.branch) { - k += ":" + p.path - } - return repository.CachedIdentifier{Key: k, Version: p.ref.Hash().String()} - } - - return repository.CachedIdentifier{} -} - -func (p *gitPackageRevision) ResourceVersion() string { - return p.commit.String() -} - -func (p *gitPackageRevision) Key() repository.PackageRevisionKey { - // if the repository has been registered with a directory, then the - // package name is the package path relative to the registered directory - packageName := p.path - if p.repo.directory != "" { - pn, err := filepath.Rel(p.repo.directory, packageName) - if err != nil { - klog.Errorf("error computing package name relative to registered directory: %w", err) - } - packageName = strings.TrimLeft(pn, "./") - } - - return repository.PackageRevisionKey{ - Repository: p.repo.name, - Package: packageName, - Revision: p.revision, - WorkspaceName: p.workspaceName, - } -} - -func (p *gitPackageRevision) uid() types.UID { - var s string - if p.revision == string(p.repo.branch) { - s = p.revision - } else { - s = string(p.workspaceName) - } - return types.UID(fmt.Sprintf("uid:%s:%s", p.path, s)) -} - -func (p *gitPackageRevision) GetPackageRevision(ctx context.Context) (*v1alpha1.PackageRevision, error) { - key := p.Key() - - _, lock, _ := p.GetUpstreamLock(ctx) - lockCopy := &v1alpha1.UpstreamLock{} - - // TODO: Use kpt definition of UpstreamLock in the package revision status - // when https://github.com/GoogleContainerTools/kpt/issues/3297 is complete. - // Until then, we have to translate from one type to another. - if lock.Git != nil { - lockCopy = &v1alpha1.UpstreamLock{ - Type: v1alpha1.OriginType(lock.Type), - Git: &v1alpha1.GitLock{ - Repo: lock.Git.Repo, - Directory: lock.Git.Directory, - Commit: lock.Git.Commit, - Ref: lock.Git.Ref, - }, - } - } - - kf, _ := p.GetKptfile(ctx) - - status := v1alpha1.PackageRevisionStatus{ - UpstreamLock: lockCopy, - Deployment: p.repo.deployment, - Conditions: repository.ToApiConditions(kf), - } - - if v1alpha1.LifecycleIsPublished(p.Lifecycle()) { - if !p.updated.IsZero() { - status.PublishedAt = metav1.Time{Time: p.updated} - } - if p.updatedBy != "" { - status.PublishedBy = p.updatedBy - } - } - - return &v1alpha1.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: v1alpha1.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: p.KubeObjectName(), - Namespace: p.repo.namespace, - UID: p.uid(), - ResourceVersion: p.commit.String(), - CreationTimestamp: metav1.Time{ - Time: p.updated, - }, - }, - Spec: v1alpha1.PackageRevisionSpec{ - PackageName: key.Package, - RepositoryName: key.Repository, - Lifecycle: p.Lifecycle(), - Tasks: p.tasks, - ReadinessGates: repository.ToApiReadinessGates(kf), - WorkspaceName: key.WorkspaceName, - Revision: key.Revision, - }, - Status: status, - }, nil -} - -func (p *gitPackageRevision) GetResources(ctx context.Context) (*v1alpha1.PackageRevisionResources, error) { - resources, err := p.repo.GetResources(p.tree) - if err != nil { - return nil, fmt.Errorf("failed to load package resources: %w", err) - } - - key := p.Key() - - return &v1alpha1.PackageRevisionResources{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevisionResources", - APIVersion: v1alpha1.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: p.KubeObjectName(), - Namespace: p.repo.namespace, - UID: p.uid(), - ResourceVersion: p.commit.String(), - CreationTimestamp: metav1.Time{ - Time: p.updated, - }, - OwnerReferences: []metav1.OwnerReference{}, // TODO: should point to repository resource - }, - Spec: v1alpha1.PackageRevisionResourcesSpec{ - PackageName: key.Package, - WorkspaceName: key.WorkspaceName, - Revision: key.Revision, - RepositoryName: key.Repository, - - Resources: resources, - }, - }, nil -} - -func (p *gitPackageRevision) GetKptfile(ctx context.Context) (kptfile.KptFile, error) { - resources, err := p.repo.GetResources(p.tree) - if err != nil { - return kptfile.KptFile{}, fmt.Errorf("error loading package resources: %w", err) - } - kfString, found := resources[kptfile.KptFileName] - if !found { - return kptfile.KptFile{}, fmt.Errorf("packagerevision does not have a Kptfile") - } - kf, err := pkg.DecodeKptfile(strings.NewReader(kfString)) - if err != nil { - return kptfile.KptFile{}, fmt.Errorf("error decoding Kptfile: %w", err) - } - return *kf, nil -} - -// GetUpstreamLock returns the upstreamLock info present in the Kptfile of the package. -func (p *gitPackageRevision) GetUpstreamLock(ctx context.Context) (kptfile.Upstream, kptfile.UpstreamLock, error) { - kf, err := p.GetKptfile(ctx) - if err != nil { - return kptfile.Upstream{}, kptfile.UpstreamLock{}, fmt.Errorf("cannot determine package lock; cannot retrieve resources: %w", err) - } - - if kf.Upstream == nil || kf.UpstreamLock == nil || kf.Upstream.Git == nil { - // the package doesn't have any upstream package. - return kptfile.Upstream{}, kptfile.UpstreamLock{}, nil - } - return *kf.Upstream, *kf.UpstreamLock, nil -} - -// GetLock returns the self version of the package. Think of it as the Git commit information -// that represent the package revision of this package. Please note that it uses Upstream types -// to represent this information but it has no connection with the associated upstream package (if any). -func (p *gitPackageRevision) GetLock() (kptfile.Upstream, kptfile.UpstreamLock, error) { - repo, err := p.repo.GetRepo() - if err != nil { - return kptfile.Upstream{}, kptfile.UpstreamLock{}, fmt.Errorf("cannot determine package lock: %w", err) - } - - if p.ref == nil { - return kptfile.Upstream{}, kptfile.UpstreamLock{}, fmt.Errorf("cannot determine package lock; package has no ref") - } - - ref, err := refInRemoteFromRefInLocal(p.ref.Name()) - if err != nil { - return kptfile.Upstream{}, kptfile.UpstreamLock{}, fmt.Errorf("cannot determine package lock for %q: %v", p.ref, err) - } - - return kptfile.Upstream{ - Type: kptfile.GitOrigin, - Git: &kptfile.Git{ - Repo: repo, - Directory: p.path, - Ref: ref.Short(), - }, - }, kptfile.UpstreamLock{ - Type: kptfile.GitOrigin, - Git: &kptfile.GitLock{ - Repo: repo, - Directory: p.path, - Ref: ref.Short(), - Commit: p.commit.String(), - }, - }, nil -} - -func (p *gitPackageRevision) Lifecycle() v1alpha1.PackageRevisionLifecycle { - return p.repo.GetLifecycle(context.Background(), p) -} - -func (p *gitPackageRevision) UpdateLifecycle(ctx context.Context, new v1alpha1.PackageRevisionLifecycle) error { - return p.repo.UpdateLifecycle(ctx, p, new) -} - -// TODO: Define a type `gitPackage` to implement the Repository.Package interface diff --git a/porch/pkg/git/package_test.go b/porch/pkg/git/package_test.go deleted file mode 100644 index 382ed6fe49..0000000000 --- a/porch/pkg/git/package_test.go +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import ( - "context" - "path/filepath" - "testing" - - v1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/go-git/go-git/v5/plumbing" - "github.com/google/go-cmp/cmp" -) - -func (g GitSuite) TestLock(t *testing.T) { - tempdir := t.TempDir() - tarfile := filepath.Join("testdata", "drafts-repository.tar") - repo, address := ServeGitRepositoryWithBranch(t, tarfile, tempdir, g.branch) - - ctx := context.Background() - const ( - repositoryName = "lock" - namespace = "default" - deployment = true - ) - - git, err := OpenRepository(ctx, repositoryName, namespace, &configapi.GitRepository{ - Repo: address, - Branch: g.branch, - Directory: "/", - }, deployment, tempdir, GitRepositoryOptions{}) - if err != nil { - t.Fatalf("Failed to open Git repository loaded from %q: %v", tarfile, err) - } - - revisions, err := git.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{}) - if err != nil { - t.Fatalf("Failed to list packages from %q: %v", tarfile, err) - } - - wantRefs := map[repository.PackageRevisionKey]string{ - {Repository: repositoryName, Package: "empty", Revision: "v1", WorkspaceName: "v1"}: "empty/v1", - {Repository: repositoryName, Package: "basens", Revision: "v1", WorkspaceName: "v1"}: "basens/v1", - {Repository: repositoryName, Package: "basens", Revision: "v2", WorkspaceName: "v2"}: "basens/v2", - {Repository: repositoryName, Package: "istions", Revision: "v1", WorkspaceName: "v1"}: "istions/v1", - {Repository: repositoryName, Package: "istions", Revision: "v2", WorkspaceName: "v2"}: "istions/v2", - - {Repository: repositoryName, Package: "basens", Revision: g.branch, WorkspaceName: v1alpha1.WorkspaceName(g.branch)}: g.branch, - {Repository: repositoryName, Package: "empty", Revision: g.branch, WorkspaceName: v1alpha1.WorkspaceName(g.branch)}: g.branch, - {Repository: repositoryName, Package: "istions", Revision: g.branch, WorkspaceName: v1alpha1.WorkspaceName(g.branch)}: g.branch, - } - - for _, rev := range revisions { - if rev.Lifecycle() != v1alpha1.PackageRevisionLifecyclePublished { - continue - } - - upstream, lock, err := rev.GetLock() - if err != nil { - t.Errorf("GetUpstreamLock(%q) failed: %v", rev.Key(), err) - } - if got, want := upstream.Type, v1.GitOrigin; got != want { - t.Errorf("upstream.Type: got %s, want %s", got, want) - } - if got, want := lock.Type, v1.GitOrigin; got != want { - t.Errorf("lock.Type: got %s, want %s", got, want) - } - - key := rev.Key() - wantRef, ok := wantRefs[key] - if !ok { - t.Errorf("Unexpected package found; %q", rev.Key()) - } - - type gitAddress struct { - Repo, Directory, Ref string - } - - // Check upstream values - if got, want := (gitAddress{ - Repo: upstream.Git.Repo, - Directory: upstream.Git.Directory, - Ref: upstream.Git.Ref, - }), (gitAddress{ - Repo: address, - Directory: key.Package, - Ref: wantRef, - }); !cmp.Equal(want, got) { - t.Errorf("Package upstream differs (-want,+got): %s", cmp.Diff(want, got)) - } - - // Check upstream lock values - if got, want := (gitAddress{ - Repo: lock.Git.Repo, - Directory: lock.Git.Directory, - Ref: lock.Git.Ref, - }), (gitAddress{ - Repo: address, - Directory: key.Package, - Ref: wantRef, - }); !cmp.Equal(want, got) { - t.Errorf("Package upstream lock differs (-want,+got): %s", cmp.Diff(want, got)) - } - - // Check the commit - if commit, err := repo.ResolveRevision(plumbing.Revision(wantRef)); err != nil { - t.Errorf("ResolveRevision(%q) failed: %v", wantRef, err) - } else if got, want := lock.Git.Commit, commit.String(); got != want { - t.Errorf("Commit: got %s, want %s", got, want) - } - } -} diff --git a/porch/pkg/git/package_tree.go b/porch/pkg/git/package_tree.go deleted file mode 100644 index 0133161e80..0000000000 --- a/porch/pkg/git/package_tree.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import ( - "context" - "fmt" - "path" - "time" - - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/filemode" - "github.com/go-git/go-git/v5/plumbing/object" - "k8s.io/klog/v2" -) - -// packageList holds a list of packages in the git repository -type packageList struct { - // parent is the gitRepository of which this is part - parent *gitRepository - - // commit is the commit at which we scanned for packages - commit *object.Commit - - // packages holds the packages we found - packages map[string]*packageListEntry -} - -// packageListEntry is a single package found in a git repository -type packageListEntry struct { - // parent is the packageList of which we are part - parent *packageList - - // path is the relative path to the root of the package (directory containing the Kptfile) - path string - - // treeHash is the git-hash of the git tree corresponding to Path - treeHash plumbing.Hash -} - -// buildGitPackageRevision creates a gitPackageRevision for the packageListEntry -// TODO: Can packageListEntry just _be_ a gitPackageRevision? -func (p *packageListEntry) buildGitPackageRevision(ctx context.Context, revision string, workspace v1alpha1.WorkspaceName, ref *plumbing.Reference) (*gitPackageRevision, error) { - repo := p.parent.parent - tasks, err := repo.loadTasks(ctx, p.parent.commit, p.path, workspace) - if err != nil { - return nil, err - } - - var updated time.Time - var updatedBy string - - // For the published packages on a tag or draft and proposed branches we know that the latest commit - // if specific to the package in question. Thus, we can just take the last commit on the tag/branch. - // If the ref is nil, we consider the package as being final and on the package branch. - if ref != nil && (isTagInLocalRepo(ref.Name()) || isDraftBranchNameInLocal(ref.Name()) || isProposedBranchNameInLocal(ref.Name())) { - updated = p.parent.commit.Author.When - updatedBy = p.parent.commit.Author.Email - } else { - // If we are on the package branch, we can not assume that the last commit - // pertains to the package in question. So we scan the git history to find - // the last commit for the package based on the porch commit tags. We don't - // use the revision here, since we are looking at the package branch while - // the revisions only helps identify the tags. - commit, err := repo.findLatestPackageCommit(ctx, p.parent.commit, p.path) - if err != nil { - return nil, err - } - if commit != nil { - updated = commit.Author.When - updatedBy = commit.Author.Email - } - // If not commit was found with the porch commit tags, we don't really - // know who approved the package or when it happend. We could find this - // by scanning the tree for every commit, but that is a pretty expensive - // operation. - } - - // for backwards compatibility with packages that existed before porch supported - // workspaceNames, we populate the workspaceName as the revision number if it is empty - if workspace == "" { - workspace = v1alpha1.WorkspaceName(revision) - } - - return &gitPackageRevision{ - repo: repo, - path: p.path, - workspaceName: workspace, - revision: revision, - updated: updated, - updatedBy: updatedBy, - ref: ref, - tree: p.treeHash, - commit: p.parent.commit.Hash, - tasks: tasks, - }, nil -} - -// DiscoveryPackagesOptions holds the configuration for walking a git tree -type DiscoverPackagesOptions struct { - // FilterPrefix restricts package discovery to a particular subdirectory. - // The subdirectory is not required to exist (we will return an empty list of packages). - FilterPrefix string - - // Recurse enables recursive traversal of the git tree. - Recurse bool -} - -// discoverPackages is the recursive function we use to traverse the tree and find packages. -// tree is the git-tree we are search, treePath is the repo-relative-path to tree. -func (t *packageList) discoverPackages(tree *object.Tree, treePath string, recurse bool) error { - for _, e := range tree.Entries { - if e.Name == "Kptfile" { - p := path.Join(treePath, e.Name) - if !e.Mode.IsRegular() { - klog.Warningf("skipping %q: Kptfile is not a file", p) - continue - } - - // Found a package - t.packages[treePath] = &packageListEntry{ - path: treePath, - treeHash: tree.Hash, - parent: t, - } - } - } - - if recurse { - for _, e := range tree.Entries { - if e.Mode != filemode.Dir { - continue - } - - // This is safe because this function is only called holding the mutex in gitRepository - dirTree, err := t.parent.repo.TreeObject(e.Hash) - if err != nil { - return fmt.Errorf("error getting git tree %v: %w", e.Hash, err) - } - - if err := t.discoverPackages(dirTree, path.Join(treePath, e.Name), recurse); err != nil { - return err - } - } - } - - return nil -} diff --git a/porch/pkg/git/primitives_test.go b/porch/pkg/git/primitives_test.go deleted file mode 100644 index 9d9c6cf1f3..0000000000 --- a/porch/pkg/git/primitives_test.go +++ /dev/null @@ -1,479 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import ( - "fmt" - "path/filepath" - "strings" - "testing" - "time" - - "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/config" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/object" -) - -func TestUpdateRef(t *testing.T) { - gitdir := t.TempDir() - repo := OpenGitRepositoryFromArchiveWithWorktree(t, filepath.Join("testdata", "drafts-repository.tar"), gitdir) - - const draftReferenceName plumbing.ReferenceName = "refs/heads/drafts/bucket/v1" - - draftRef := resolveReference(t, repo, draftReferenceName) - - { - // Crete a commit and advance the draft reference. - commit := createTestCommit(t, repo, draftRef.Hash(), "Commit One", "one.txt", "File one") - newDraft := plumbing.NewHashReference(draftReferenceName, commit) - - if err := repo.Storer.CheckAndSetReference(newDraft, draftRef); err != nil { - t.Fatalf("Failed to update reference %s with check %s", newDraft, draftRef) - } - } - - { - // Create another (competing) commit with draft parent; - // we shouldn't be able to update the ref to that commit - commit := createTestCommit(t, repo, draftRef.Hash(), "Commit Two", "two.txt", "File two") - newDraft := plumbing.NewHashReference(draftReferenceName, commit) - if err := repo.Storer.CheckAndSetReference(newDraft, draftRef); err == nil { - t.Fatalf("Unexpectedly succeeded to update reference %s with check %s", newDraft, draftRef) - } else { - t.Logf("Expected error: %v", err) - } - } -} - -func TestSetNewRef(t *testing.T) { - temp := t.TempDir() - repo := OpenGitRepositoryFromArchive(t, filepath.Join("testdata", "simple-repository.tar"), temp) - - logRefs(t, repo, "Simple: ") - - basens := resolveReference(t, repo, "refs/tags/basens/v1") - - const draftReferenceName plumbing.ReferenceName = "refs/heads/test-reference" - zero := plumbing.NewHashReference(draftReferenceName, plumbing.ZeroHash) - test := plumbing.NewHashReference(draftReferenceName, basens.Hash()) - - if err := repo.Storer.CheckAndSetReference(test, zero); err != nil { - t.Errorf("CheckAndSetReference(%s, zero) failed: %v", test, err) - } - - // Try again, this time it should fail. - if err := repo.Storer.CheckAndSetReference(test, zero); err == nil { - t.Errorf("Second CheckAndSetReference(%s, zero) unexpectedly succeeded", test) - } -} - -func TestSimpleFetch(t *testing.T) { - upstreamDir := t.TempDir() - downstreamDir := t.TempDir() - upstream, address := ServeGitRepository(t, filepath.Join("testdata", "drafts-repository.tar"), upstreamDir) - downstream := initRepositoryWithRemote(t, downstreamDir, address) - - const remoteDraftReferenceName = "refs/remotes/origin/drafts/bucket/v1" - - originRef := resolveReference(t, upstream, "refs/heads/drafts/bucket/v1") - refMustNotExist(t, downstream, remoteDraftReferenceName) - fetch(t, downstream) - - clonedRef := resolveReference(t, downstream, remoteDraftReferenceName) - if got, want := clonedRef.Hash(), originRef.Hash(); got != want { - t.Errorf("%s after fetch; got %s, want %s", remoteDraftReferenceName, clonedRef, originRef) - } - - logRefs(t, downstream, "Fetched: ") -} - -func TestSimplePush(t *testing.T) { - upstreamDir := t.TempDir() - downstreamDir := t.TempDir() - - upstream, address := ServeGitRepository(t, filepath.Join("testdata", "drafts-repository.tar"), upstreamDir) - downstream := initRepositoryWithRemote(t, downstreamDir, address) - fetch(t, downstream) - - const ( - draftReferenceName plumbing.ReferenceName = "refs/heads/drafts/bucket/v1" - remoteDraftReferenceName plumbing.ReferenceName = "refs/remotes/origin/drafts/bucket/v1" - ) - - draftRef := resolveReference(t, downstream, remoteDraftReferenceName) - - var commit plumbing.Hash - { - // Create a first commit in test branch - commit = createTestCommit(t, downstream, draftRef.Hash(), "Draft Commit", "readme.txt", "Hello, World!") - if err := downstream.Push(&git.PushOptions{ - RemoteName: OriginName, - RefSpecs: []config.RefSpec{ - config.RefSpec(fmt.Sprintf("%s:%s", commit, draftReferenceName)), - }, - RequireRemoteRefs: []config.RefSpec{}, - }); err != nil { - t.Fatalf("Push failed: %v", err) - } - - // Verify draft advanced - originDraft := resolveReference(t, upstream, draftReferenceName) - if got, want := originDraft.Hash(), commit; got != want { - t.Errorf("Updated draft reference at origin: %s, got %s, want %s", originDraft, got, want) - } - } - - { - // Create a competing concurrent in a test branch - concurrent := createTestCommit(t, downstream, draftRef.Hash(), "Competing Commit", "test.txt", "competing commit") - switch err := downstream.Push(&git.PushOptions{ - RemoteName: OriginName, - RefSpecs: []config.RefSpec{ - config.RefSpec(fmt.Sprintf("%s:%s", concurrent, draftReferenceName)), - }, - RequireRemoteRefs: []config.RefSpec{}, - }); { - case err == git.ErrNonFastForwardUpdate: - // ok - case err == nil: - t.Fatalf("Second push unexpectedly succeeded") - case strings.Contains(err.Error(), "non-fast-forward update"): - // ok - // TODO: preferably we get strongly typed error here... - default: - t.Fatalf("Unexpected error when pushing competing commit: %v", err) - } - } - - // Verify the commit in both repositories to point at expected value (first commit) - originDraftRef := resolveReference(t, upstream, draftReferenceName) - localDraftRef := resolveReference(t, downstream, remoteDraftReferenceName) - - if got, want := originDraftRef.Hash(), commit; got != want { - t.Errorf("Updated draft reference at origin: %s, got %s, want %s", originDraftRef, got, want) - } - if got, want := localDraftRef.Hash(), commit; got != want { - t.Errorf("Updated draft reference in local repo: %s, got %s, want %s", localDraftRef, got, want) - } -} - -// Test concurrent tag pushes. -func TestFinalPush(t *testing.T) { - upstreamDir := t.TempDir() - downstreamDir := t.TempDir() - upstream, address := ServeGitRepository(t, filepath.Join("testdata", "drafts-repository.tar"), upstreamDir) - downstream := initRepositoryWithRemote(t, downstreamDir, address) - - fetch(t, downstream) - - const ( - mainReferenceName plumbing.ReferenceName = "refs/heads/main" - remoteMainReferenceName plumbing.ReferenceName = "refs/remotes/origin/main" - packageTagReferenceName plumbing.ReferenceName = "refs/tags/package/v1" - ) - - main := resolveReference(t, downstream, remoteMainReferenceName) - - var commit plumbing.Hash - { - // Create first commit and tag (finalized package) - commit = createTestCommit(t, downstream, main.Hash(), "Package One", "one.txt", "initial") - if err := downstream.Push(&git.PushOptions{ - RemoteName: OriginName, - RefSpecs: []config.RefSpec{ - config.RefSpec(fmt.Sprintf("%s:%s", commit, mainReferenceName)), - config.RefSpec(fmt.Sprintf("%s:%s", commit, packageTagReferenceName)), - }, - RequireRemoteRefs: []config.RefSpec{ - config.RefSpec(fmt.Sprintf("%s:%s", main.Hash(), mainReferenceName)), - }, - }); err != nil { - t.Fatalf("Push failed: %v", err) - } - - if tag, err := downstream.Reference(packageTagReferenceName, false); err != nil { - t.Errorf("Failed to find pushed tag") - } else if got, want := tag.Hash(), commit; got != want { - t.Errorf("Tag hash after push: got %s, want %s", got, want) - } - } - - { - // Create a competing concurrent finalized package. - concurrent := createTestCommit(t, downstream, main.Hash(), "Package One", "one.txt", "concurrent") - - // Simulated concurrent push should fail - switch err := downstream.Push(&git.PushOptions{ - RemoteName: OriginName, - RefSpecs: []config.RefSpec{ - config.RefSpec(fmt.Sprintf("%s:%s", concurrent, mainReferenceName)), - }, - RequireRemoteRefs: []config.RefSpec{}, - }); { - case err == git.ErrNonFastForwardUpdate: - // ok - case err == nil: - t.Fatalf("Second push unexpectedly succeeded") - case strings.Contains(err.Error(), "non-fast-forward update: refs/heads/main"): - // ok - default: - t.Fatalf("Unexpected error pushing concurrent commit: %v", err) - } - - // Liewise, push to the tag should fail - switch err := downstream.Push(&git.PushOptions{ - RemoteName: OriginName, - RefSpecs: []config.RefSpec{ - config.RefSpec(fmt.Sprintf("%s:%s", concurrent, packageTagReferenceName)), - }, - RequireRemoteRefs: []config.RefSpec{}, - }); { - case err == git.ErrNonFastForwardUpdate: - // ok - case err == nil: - t.Fatalf("Second push unexpectedly succeeded") - case strings.Contains(err.Error(), "non-fast-forward update: refs/tags/package/v1"): - // ok - default: - t.Fatalf("Unexpected error pushing concurrent commit: %v", err) - } - - } - - // Double check that the upstream main is the expected commit - upstreamMain := resolveReference(t, upstream, mainReferenceName) - if got, want := upstreamMain.Hash(), commit; got != want { - t.Errorf("Upstream main %s after push: got %s, want %s", upstreamMain, got, want) - } -} - -// Simulate case where a remote ref (refs/remotes/origin/...) is out of sync -// with the remote repository and will be force-overwritten on fetch. -func TestRepoRecovery(t *testing.T) { - upstreamDir := t.TempDir() - downstreamDir := t.TempDir() - upstream, address := ServeGitRepository(t, filepath.Join("testdata", "drafts-repository.tar"), upstreamDir) - downstream := initRepositoryWithRemote(t, downstreamDir, address) - - const ( - draftReferenceName plumbing.ReferenceName = "refs/heads/drafts/bucket/v1" - remoteDraftReferenceName plumbing.ReferenceName = "refs/remotes/origin/drafts/bucket/v1" - istionsReferenceName plumbing.ReferenceName = "refs/tags/istions/v1" - ) - - fetch(t, downstream) - - upstreamDraftRef := resolveReference(t, upstream, draftReferenceName) - - // Simulate repository data corruption - reset remoteDraftReferenceName to another commit - // We will create a new commit for the draft with the shared parent. - draftRef := resolveReference(t, downstream, remoteDraftReferenceName) - draftCommit := getCommitObject(t, downstream, draftRef.Hash()) - parent, err := draftCommit.Parent(0) - if err != nil { - t.Fatalf("Failed to get parent of commit %s: %v", draftRef, err) - } - - conflicting := createTestCommit(t, downstream, parent.Hash, "Conflicting Commit", "conflict.txt", "file contents") - // Overwrite the remote ref in the downstream repository - newRef := plumbing.NewHashReference(remoteDraftReferenceName, conflicting) - if err := downstream.Storer.CheckAndSetReference(newRef, draftRef); err != nil { - t.Fatalf("Failed to intentionally overwrite a remote reference %s: %v", newRef, err) - } - - // Corrupt the istions reference (tag) also - istioRef := resolveReference(t, downstream, istionsReferenceName) - istioNew := plumbing.NewHashReference(istionsReferenceName, conflicting) - if err := downstream.Storer.CheckAndSetReference(istioNew, istioRef); err != nil { - t.Fatalf("Failed to intentionally overwrite a tag: %s: %v", istioNew, err) - } - - // Perhaps overly cautious; check the reference value - { - ref := resolveReference(t, downstream, remoteDraftReferenceName) - if got, want := ref.Hash(), conflicting; got != want { - t.Errorf("Unexpected ref value %s after overwrite; got %s, want %s", ref, got, want) - } - } - - // Re-fetch. Expect ref to go back - fetch(t, downstream) - - // Re-resolve the corrupted reference - { - ref := resolveReference(t, downstream, remoteDraftReferenceName) - if got, want := ref.Hash(), draftRef.Hash(); got != want { - t.Errorf("Ref %s was not reset by re-fetch; got %s, want %s", ref, got, want) - } - - // Check also against the upstreamDraftRef - if got, want := ref.Hash(), upstreamDraftRef.Hash(); got != want { - t.Errorf("Ref %s was reset to an unexpected value, not matching upstream repository; got %s, want %s", ref, got, want) - } - } - - // Re-resolve the tag - { - ref := resolveReference(t, downstream, istionsReferenceName) - if got, want := ref.Hash(), istioRef.Hash(); got != want { - t.Errorf("Tag %s was not reset by re-fetch; got %s, want %s", ref, got, want) - } - } -} - -func TestProposal(t *testing.T) { - upstreamDir := t.TempDir() - downstreamDir := t.TempDir() - upstream, address := ServeGitRepository(t, filepath.Join("testdata", "drafts-repository.tar"), upstreamDir) - downstream := initRepositoryWithRemote(t, downstreamDir, address) - - fetch(t, downstream) - - const ( - draftRef plumbing.ReferenceName = "refs/remotes/origin/drafts/bucket/v1" - proposedRef plumbing.ReferenceName = "refs/remotes/origin/proposed/bucket/v1" - upstreamDraftRef plumbing.ReferenceName = "refs/heads/drafts/bucket/v1" - upstreamProposedRef plumbing.ReferenceName = "refs/heads/proposed/bucket/v1" - ) - - bucket := resolveReference(t, downstream, draftRef) - - // Simulate changing package to proposed - if err := downstream.Push(&git.PushOptions{ - RemoteName: OriginName, - RefSpecs: []config.RefSpec{ - config.RefSpec(fmt.Sprintf("%s:%s", bucket.Hash(), upstreamProposedRef)), - config.RefSpec(fmt.Sprintf(":%s", upstreamDraftRef)), - }, - RequireRemoteRefs: []config.RefSpec{ - config.RefSpec(fmt.Sprintf("%s:%s", bucket.Hash(), upstreamDraftRef)), - }, - }); err != nil { - t.Fatalf("Push failed: %v", err) - } - - refMustNotExist(t, downstream, draftRef) - - // Verify upstream - { - ref := resolveReference(t, upstream, upstreamProposedRef) - if got, want := ref.Hash(), bucket.Hash(); got != want { - t.Errorf("Proposed in upstream: got %s, want %s", got, want) - } - - refMustNotExist(t, upstream, upstreamDraftRef) - } -} - -func TestDeleteUpstreamBranches(t *testing.T) { - upstreamDir := t.TempDir() - downstreamDir := t.TempDir() - upstream, address := ServeGitRepository(t, filepath.Join("testdata", "drafts-repository.tar"), upstreamDir) - downstream := initRepositoryWithRemote(t, downstreamDir, address) - - logRefs(t, downstream, "Init: ") - - fetch(t, downstream) - logRefs(t, downstream, "Before: ") - - // Delete upstream tags and branches - forEachRef(t, upstream, func(ref *plumbing.Reference) error { - if ref.Name() != DefaultMainReferenceName { // keep main - return upstream.Storer.RemoveReference(ref.Name()) - } - return nil - }) - - logRefs(t, upstream, "Upstream: ") - - // Refetch - switch err := downstream.Fetch(&git.FetchOptions{ - RemoteName: OriginName, - Tags: git.NoTags, - Prune: git.Prune, - }); err { - case nil, git.NoErrAlreadyUpToDate: - // ok - default: - t.Fatalf("Fetch failed: %s", err) - } - - // Make sure the local refs were deleted. - forEachRef(t, downstream, func(ref *plumbing.Reference) error { - switch ref.Name() { - case "HEAD", "refs/remotes/origin/main": - // ok - default: - return fmt.Errorf("found unexpected reference %s", ref) - } - return nil - }) - - logRefs(t, downstream, "After:") -} - -func initRepositoryWithRemote(t *testing.T, dir, address string) *git.Repository { - repo := InitEmptyRepositoryWithWorktree(t, dir) - - if _, err := repo.CreateRemote(&config.RemoteConfig{ - Name: OriginName, - URLs: []string{address}, - Fetch: defaultFetchSpec, - }); err != nil { - t.Fatalf("CreateRemote failed: %v", err) - } - return repo -} - -func createTestCommit(t *testing.T, repo *git.Repository, parent plumbing.Hash, message, name, contents string) plumbing.Hash { - wt, err := repo.Worktree() - if err != nil { - t.Fatalf("Failed getting worktree: %v", err) - } - if err := wt.Checkout(&git.CheckoutOptions{ - Hash: parent, - Force: true, - Keep: false, - }); err != nil { - t.Fatalf("Failed checking out worktree: %v", err) - } - - f, err := wt.Filesystem.Create(name) - if err != nil { - t.Fatalf("Failed creating file: %v", err) - } - defer f.Close() - if _, err := f.Write([]byte(contents)); err != nil { - t.Fatalf("Failed to write file: %v", err) - } - if _, err := wt.Add(name); err != nil { - t.Fatalf("Failed to add file to index: %v", err) - } - sig := object.Signature{ - Name: "Test", - Email: "test@kpt.dev", - When: time.Now(), - } - commit, err := wt.Commit("Hello", &git.CommitOptions{ - Author: &sig, - Committer: &sig, - Parents: []plumbing.Hash{parent}, - }) - if err != nil { - t.Fatalf("Commit failed: %v", err) - } - return commit -} diff --git a/porch/pkg/git/push.go b/porch/pkg/git/push.go deleted file mode 100644 index b567987207..0000000000 --- a/porch/pkg/git/push.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import ( - "fmt" - - "github.com/go-git/go-git/v5/config" - "github.com/go-git/go-git/v5/plumbing" -) - -type pushRefSpecBuilder struct { - pushRefs map[plumbing.ReferenceName]plumbing.Hash - require map[plumbing.ReferenceName]plumbing.Hash -} - -func newPushRefSpecBuilder() *pushRefSpecBuilder { - return &pushRefSpecBuilder{ - pushRefs: map[plumbing.ReferenceName]plumbing.Hash{}, - require: map[plumbing.ReferenceName]plumbing.Hash{}, - } -} - -func (b *pushRefSpecBuilder) AddRefToPush(hash plumbing.Hash, to plumbing.ReferenceName) { - b.pushRefs[to] = hash -} - -func (b *pushRefSpecBuilder) AddRefToDelete(ref *plumbing.Reference) { - b.AddRefToPush(plumbing.ZeroHash, ref.Name()) - b.RequireRef(ref) -} - -func (b *pushRefSpecBuilder) RequireRef(ref *plumbing.Reference) { - if ref != nil { - b.require[ref.Name()] = ref.Hash() - } -} - -func (b *pushRefSpecBuilder) BuildRefSpecs() (push []config.RefSpec, require []config.RefSpec, err error) { - for local, hash := range b.pushRefs { - remote, err := refInRemoteFromRefInLocal(local) - if err != nil { - return nil, nil, err - } - - if !hash.IsZero() { - push = append(push, config.RefSpec(fmt.Sprintf("%s:%s", hash, remote))) - } else { - push = append(push, config.RefSpec(fmt.Sprintf(":%s", remote))) - } - } - - for local, hash := range b.require { - remote, err := refInRemoteFromRefInLocal(local) - if err != nil { - return nil, nil, err - } - if !hash.IsZero() { - require = append(require, config.RefSpec(fmt.Sprintf("%s:%s", hash, remote))) - } - } - - return push, require, nil -} diff --git a/porch/pkg/git/ref.go b/porch/pkg/git/ref.go deleted file mode 100644 index 54d074d003..0000000000 --- a/porch/pkg/git/ref.go +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import ( - "fmt" - "strings" - - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/go-git/go-git/v5/config" - "github.com/go-git/go-git/v5/plumbing" -) - -const ( - MainBranch BranchName = "main" - - branchPrefixInLocalRepo = "refs/remotes/" + OriginName + "/" - branchPrefixInRemoteRepo = "refs/heads/" - tagsPrefixInLocalRepo = "refs/tags/" - tagsPrefixInRemoteRepo = "refs/tags/" - - branchRefSpec config.RefSpec = config.RefSpec("+" + branchPrefixInRemoteRepo + "*:" + branchPrefixInLocalRepo + "*") - tagRefSpec config.RefSpec = config.RefSpec("+" + tagsPrefixInRemoteRepo + "*:" + tagsPrefixInLocalRepo + "*") - - draftsPrefix = "drafts/" - draftsPrefixInLocalRepo = branchPrefixInLocalRepo + draftsPrefix - draftsPrefixInRemoteRepo = branchPrefixInRemoteRepo + draftsPrefix - - proposedPrefix = "proposed/" - proposedPrefixInLocalRepo = branchPrefixInLocalRepo + proposedPrefix - proposedPrefixInRemoteRepo = branchPrefixInRemoteRepo + proposedPrefix - - deletionProposedPrefix = "deletionProposed/" - deletionProposedPrefixInLocalRepo = branchPrefixInLocalRepo + deletionProposedPrefix - deletionProposedPrefixInRemoteRepo = branchPrefixInRemoteRepo + deletionProposedPrefix -) - -var ( - // The default fetch spec contains both branches and tags. - // This enables push of a tag which will automatically update - // its local reference, avoiding explicitly setting of refs. - defaultFetchSpec []config.RefSpec = []config.RefSpec{ - branchRefSpec, - tagRefSpec, - } - - // DO NOT USE for fetches. Used for reverse reference mapping only. - reverseFetchSpec []config.RefSpec = []config.RefSpec{ - config.RefSpec(branchPrefixInLocalRepo + "*:" + branchPrefixInRemoteRepo + "*"), - config.RefSpec(tagsPrefixInLocalRepo + "*:" + tagsPrefixInRemoteRepo + "*"), - } -) - -// BranchName represents a relative branch name (i.e. 'main', 'drafts/bucket/v1') -// and supports transformation to the ReferenceName in local (cached) repository -// (those references are in the form 'refs/remotes/origin/...') or in the remote -// repository (those references are in the form 'refs/heads/...'). -type BranchName string - -func (b BranchName) RefInRemote() plumbing.ReferenceName { - return plumbing.ReferenceName(branchPrefixInRemoteRepo + string(b)) -} - -func (b BranchName) RefInLocal() plumbing.ReferenceName { - return plumbing.ReferenceName(branchPrefixInLocalRepo + string(b)) -} - -func (b BranchName) ForceFetchSpec() config.RefSpec { - return config.RefSpec(fmt.Sprintf("+%s:%s", b.RefInRemote(), b.RefInLocal())) -} - -func isProposedBranchNameInLocal(n plumbing.ReferenceName) bool { - return strings.HasPrefix(n.String(), proposedPrefixInLocalRepo) -} - -func getProposedBranchNameInLocal(n plumbing.ReferenceName) (BranchName, bool) { - b, ok := trimOptionalPrefix(n.String(), proposedPrefixInLocalRepo) - return BranchName(b), ok -} - -func isDraftBranchNameInLocal(n plumbing.ReferenceName) bool { - return strings.HasPrefix(n.String(), draftsPrefixInLocalRepo) -} - -func getDraftBranchNameInLocal(n plumbing.ReferenceName) (BranchName, bool) { - b, ok := trimOptionalPrefix(n.String(), draftsPrefixInLocalRepo) - return BranchName(b), ok -} - -func isDeletionProposedBranchNameInLocal(n plumbing.ReferenceName) bool { - return strings.HasPrefix(n.String(), deletionProposedPrefixInLocalRepo) -} - -func getdeletionProposedBranchNameInLocal(n plumbing.ReferenceName) (BranchName, bool) { - b, ok := trimOptionalPrefix(n.String(), deletionProposedPrefixInLocalRepo) - return BranchName(b), ok -} - -func isBranchInLocalRepo(n plumbing.ReferenceName) bool { - return strings.HasPrefix(n.String(), branchPrefixInLocalRepo) -} - -func getBranchNameInLocalRepo(n plumbing.ReferenceName) (string, bool) { - return trimOptionalPrefix(n.String(), branchPrefixInLocalRepo) -} - -func isTagInLocalRepo(n plumbing.ReferenceName) bool { - return strings.HasPrefix(n.String(), tagsPrefixInLocalRepo) -} - -func getTagNameInLocalRepo(n plumbing.ReferenceName) (string, bool) { - return trimOptionalPrefix(n.String(), tagsPrefixInLocalRepo) -} - -func createDraftName(pkg string, wn v1alpha1.WorkspaceName) BranchName { - return BranchName(draftsPrefix + pkg + "/" + string(wn)) -} - -func createProposedName(pkg string, wn v1alpha1.WorkspaceName) BranchName { - return BranchName(proposedPrefix + pkg + "/" + string(wn)) -} - -func createDeletionProposedName(pkg string, revision string) BranchName { - return BranchName(deletionProposedPrefix + pkg + "/" + revision) -} - -func trimOptionalPrefix(s, prefix string) (string, bool) { - if strings.HasPrefix(s, prefix) { - return strings.TrimPrefix(s, prefix), true - } - return "", false -} - -func createFinalTagNameInLocal(pkg, rev string) plumbing.ReferenceName { - return plumbing.ReferenceName(tagsPrefixInLocalRepo + pkg + "/" + rev) -} - -func refInLocalFromRefInRemote(n plumbing.ReferenceName) (plumbing.ReferenceName, error) { - return translateReference(n, defaultFetchSpec) -} - -func refInRemoteFromRefInLocal(n plumbing.ReferenceName) (plumbing.ReferenceName, error) { - return translateReference(n, reverseFetchSpec) -} - -func translateReference(n plumbing.ReferenceName, specs []config.RefSpec) (plumbing.ReferenceName, error) { - for _, spec := range specs { - if spec.Match(n) { - return spec.Dst(n), nil - } - } - return "", fmt.Errorf("cannot translate reference %s", n) -} diff --git a/porch/pkg/git/ref_test.go b/porch/pkg/git/ref_test.go deleted file mode 100644 index c52a18a0a4..0000000000 --- a/porch/pkg/git/ref_test.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import ( - "testing" - - "github.com/go-git/go-git/v5/plumbing" -) - -func TestBranchNames(t *testing.T) { - const main BranchName = "main" - - if got, want := main.RefInRemote(), "refs/heads/main"; string(got) != want { - t.Errorf("%s in remote repository: got %s, wnat %s", main, got, want) - } - if got, want := main.RefInLocal(), "refs/remotes/origin/main"; string(got) != want { - t.Errorf("%s in local repository: got %s, wnat %s", main, got, want) - } -} - -func TestValidateRefSpecs(t *testing.T) { - if err := branchRefSpec.Validate(); err != nil { - t.Errorf("%s validation failed: %v", branchRefSpec, err) - } - if err := tagRefSpec.Validate(); err != nil { - t.Errorf("%s validation failed: %v", tagRefSpec, err) - } -} - -func TestTranslate(t *testing.T) { - for _, tc := range []struct { - remote plumbing.ReferenceName - local plumbing.ReferenceName - }{ - { - remote: "refs/heads/drafts/bucket/v1", - local: "refs/remotes/origin/drafts/bucket/v1", - }, - { - remote: "refs/tags/bucket/v1", - local: "refs/tags/bucket/v1", - }, - { - remote: "refs/heads/main", - local: "refs/remotes/origin/main", - }, - } { - got, err := refInLocalFromRefInRemote(tc.remote) - if err != nil { - t.Errorf("refInLocalFromRefInRemote(%s) failed: %v", tc.remote, err) - } - if want := tc.local; got != want { - t.Errorf("refInLocalFromRefInRemote(%s): got %s, want %s", tc.remote, got, want) - } - - got, err = refInRemoteFromRefInLocal(tc.local) - if err != nil { - t.Errorf("refInRemoteFromRefInLocal(%s) failed: %v", tc.local, err) - } - if want := tc.remote; got != want { - t.Errorf("refInRemoteFromRefInLocal(%s): got %s, want %s", tc.local, got, want) - } - } -} diff --git a/porch/pkg/git/repo.go b/porch/pkg/git/repo.go deleted file mode 100644 index 05a1e13e68..0000000000 --- a/porch/pkg/git/repo.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import gogit "github.com/go-git/go-git/v5" - -// Repo manages a single git repository -type Repo struct { - gogit *gogit.Repository - - // Basic auth - username string - password string -} - -// NewRepo constructs an instance of Repo -func NewRepo(gogit *gogit.Repository, options ...GitRepoOption) (*Repo, error) { - r := &Repo{ - gogit: gogit, - } - for _, option := range options { - if err := option.apply(r); err != nil { - return nil, err - } - } - return r, nil -} - -// GitRepoOption is implemented by configuration settings for git repository. -type GitRepoOption interface { - apply(*Repo) error -} - -type optionBasicAuth struct { - username, password string -} - -func (o *optionBasicAuth) apply(s *Repo) error { - s.username, s.password = o.username, o.password - return nil -} - -func WithBasicAuth(username, password string) GitRepoOption { - return &optionBasicAuth{ - username: username, - password: password, - } -} diff --git a/porch/pkg/git/repos.go b/porch/pkg/git/repos.go deleted file mode 100644 index 5a20830ac9..0000000000 --- a/porch/pkg/git/repos.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import ( - "context" - "fmt" - "path/filepath" - "sync" - "time" - - gogit "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/object" -) - -type Repos interface { - FindRepo(ctx context.Context, id string) (*Repo, error) -} - -// StaticRepos holds multiple registered git repositories -type StaticRepos struct { - mutex sync.Mutex - repos map[string]*Repo -} - -// NewRepos constructs an instance of Repos -func NewStaticRepos() *StaticRepos { - return &StaticRepos{ - repos: make(map[string]*Repo), - } -} - -// FindRepo returns a repo registered under the specified id, or nil if none is registered. -func (r *StaticRepos) FindRepo(ctx context.Context, id string) (*Repo, error) { - r.mutex.Lock() - defer r.mutex.Unlock() - - return r.repos[id], nil -} - -// Add registers a git repository under the specified id -func (r *StaticRepos) Add(id string, repo *Repo) error { - if !isRepoIDAllowed(id) { - return fmt.Errorf("invalid name %q", id) - } - - r.mutex.Lock() - defer r.mutex.Unlock() - if _, found := r.repos[id]; found { - return fmt.Errorf("repo %q already exists", id) - } - r.repos[id] = repo - return nil -} - -func NewDynamicRepos(baseDir string, gitRepoOptions []GitRepoOption) *DynamicRepos { - return &DynamicRepos{ - baseDir: baseDir, - repos: make(map[string]*dynamicRepo), - gitRepoOptions: gitRepoOptions, - } -} - -type DynamicRepos struct { - mutex sync.Mutex - repos map[string]*dynamicRepo - baseDir string - gitRepoOptions []GitRepoOption -} - -type dynamicRepo struct { - mutex sync.Mutex - repo *Repo - dir string - gitRepoOptions []GitRepoOption -} - -func isRepoIDAllowed(s string) bool { - if len(s) == 0 { - return false - } - for _, r := range s { - if r >= 'a' && r <= 'z' { - // OK - } else if r >= '0' && r <= '9' { - // OK - } else { - switch r { - case '-': - // OK - default: - return false - } - } - } - return true -} - -func (r *DynamicRepos) FindRepo(ctx context.Context, id string) (*Repo, error) { - dir := filepath.Join(r.baseDir, id) - if !isRepoIDAllowed(id) { - return nil, fmt.Errorf("invalid name %q", id) - } - - r.mutex.Lock() - repo := r.repos[id] - if repo == nil { - repo = &dynamicRepo{ - dir: dir, - gitRepoOptions: r.gitRepoOptions, - } - r.repos[id] = repo - } - r.mutex.Unlock() - - return repo.open() -} - -func (r *dynamicRepo) open() (*Repo, error) { - r.mutex.Lock() - defer r.mutex.Unlock() - - if r.repo == nil { - var gogitRepo *gogit.Repository - var err error - - if gogitRepo, err = gogit.PlainOpen(r.dir); err != nil { - if err != gogit.ErrRepositoryNotExists { - return nil, fmt.Errorf("failed to open git repository %q: %w", r.dir, err) - } - isBare := true - gogitRepo, err = gogit.PlainInit(r.dir, isBare) - if err != nil { - return nil, fmt.Errorf("failed to initialize git repository %q: %w", r.dir, err) - } - if err := CreateEmptyCommit(gogitRepo); err != nil { - return nil, err - } - - // Delete go-git default branch - _ = gogitRepo.Storer.RemoveReference(plumbing.Master) - } - repo, err := NewRepo(gogitRepo, r.gitRepoOptions...) - if err != nil { - return nil, err - } - r.repo = repo - } - - return r.repo, nil -} - -func CreateEmptyCommit(repo *gogit.Repository) error { - store := repo.Storer - // Create first commit using empty tree. - emptyTree := object.Tree{} - encodedTree := store.NewEncodedObject() - if err := emptyTree.Encode(encodedTree); err != nil { - return fmt.Errorf("failed to encode initial empty commit tree: %w", err) - } - - treeHash, err := store.SetEncodedObject(encodedTree) - if err != nil { - return fmt.Errorf("failed to create initial empty commit tree: %w", err) - } - - sig := object.Signature{ - Name: "Git Server", - Email: "git-server@kpt.dev", - When: time.Now(), - } - - commit := object.Commit{ - Author: sig, - Committer: sig, - Message: "Empty Commit", - TreeHash: treeHash, - ParentHashes: []plumbing.Hash{}, // No parents - } - - encodedCommit := store.NewEncodedObject() - if err := commit.Encode(encodedCommit); err != nil { - return fmt.Errorf("failed to encode initial empty commit: %w", err) - } - - commitHash, err := store.SetEncodedObject(encodedCommit) - if err != nil { - return fmt.Errorf("failed to create initial empty commit: %w", err) - } - - main := plumbing.NewHashReference(plumbing.ReferenceName("refs/heads/main"), commitHash) - if err := repo.Storer.SetReference(main); err != nil { - return fmt.Errorf("failed to set refs/heads/main to commit sha %s: %w", commitHash, err) - } - - head := plumbing.NewSymbolicReference(plumbing.HEAD, "refs/heads/main") - if err := repo.Storer.SetReference(head); err != nil { - return fmt.Errorf("failed to set HEAD to refs/heads/main: %w", err) - } - - return nil -} diff --git a/porch/pkg/git/testdata/.gitignore b/porch/pkg/git/testdata/.gitignore deleted file mode 100644 index 48b7ffa3bc..0000000000 --- a/porch/pkg/git/testdata/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -empty-repository/ -trivial-repository/ -simple-repository/ -drafts-repository/ -nested-repository/ -publishinfo-repository/ diff --git a/porch/pkg/git/testdata/Makefile b/porch/pkg/git/testdata/Makefile deleted file mode 100644 index a8fe00df2f..0000000000 --- a/porch/pkg/git/testdata/Makefile +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2022 The kpt 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. - -REPOSITORIES = \ - empty-repository.tar \ - trivial-repository.tar \ - simple-repository.tar \ - drafts-repository.tar \ - nested-repository.tar \ - publishinfo-repository.tar - - -.PHONY: expand -expand: - @for f in $(REPOSITORIES); do \ - dir=$${f%.*}; \ - rm -rf $${dir}; mkdir $${dir}; \ - tar xf $${f} -C $${dir}; \ - echo "$${f} --> $${dir}/"; \ - done - -.PHONY: checkout -checkout: expand - @for f in $(REPOSITORIES); do \ - dir=$${f%.*}; \ - (cd $${dir}; git reset --hard refs/heads/main -- 2>/dev/null ); \ - done - -.PHONY: tars -tars: - @for f in $(REPOSITORIES); do \ - dir=$${f%.*}; \ - ../../../scripts/tar-test-repo.sh $${dir}/ $${f}; \ - rm -rf $${dir}; \ - echo "$${dir}/ --> $${f}"; \ - done - -.PHONY: clean -clean: - @for f in $(REPOSITORIES); do \ - dir=$${f%.*}; \ - rm -rf $${dir}; \ - done diff --git a/porch/pkg/git/testdata/README.md b/porch/pkg/git/testdata/README.md deleted file mode 100644 index 50872ab018..0000000000 --- a/porch/pkg/git/testdata/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Git Repository Test Data - -The `tar` files in this directory contain archived Git repositories -which the tests unarchive into a temporary directory as a starting point -of the tests. This is to avoid constructing the repositories in code by -synthesizing commits, and (over time) to set up scenarios for handling -edge cases, etc. - -The repositories are archived as bare, i.e. only their `.git` directory -is included in the archive. - -To inspect the git repository contents - -```sh -mkdir repo -cd repo - -# This will unarchive the .git directory. -tar xfv .tar -# Checkout the main branch and populate the worktree. -git reset --hard main -``` - -The scripts used to create and archive these repositories are: -* [scripts/create-test-repo.sh](../../../../scripts/create-test-repo.sh) -* [scripts/tar-test-repo.sh](../../../../scripts/tar-test-repo.sh) diff --git a/porch/pkg/git/testdata/drafts-repository.md b/porch/pkg/git/testdata/drafts-repository.md deleted file mode 100644 index 2e22065099..0000000000 --- a/porch/pkg/git/testdata/drafts-repository.md +++ /dev/null @@ -1,52 +0,0 @@ -# Drafts Repository - -For easier orientation, an overview of the contents of the `drafts-repository.tar`. - -## Contents - -The repository in `drafts-repository.tar` has the following contents in `main` branch: - -``` -. -├── basens -│   ├── Kptfile -│   ├── namespace.yaml -│   ├── package-context.yaml -│   └── README.md -├── empty -│   ├── Kptfile -│   └── README.md -└── istions - ├── istions.yaml - ├── Kptfile - ├── package-context.yaml - └── README.md -``` - -## Commits - -The commit graph of the repository is: - -``` -| * 81d54c8aa3dd939fd36713f7074e9e1ad4f34612 (drafts/pkg-with-history/v1) Intermediate commit: eval -| * 1c3f6bf69d579b544c6e60abbba2763987d2a019 Intermediate commit: patch -| * 23371b72a0c5b5d7713030db1e9b89da402b91c4 Intermediate commit: eval -| * dc1bde5e9044f76996664978fef79d88e01e8693 Intermediate commit: init -|/ -| * 487eaa0fe7652a313dcdb05790aa32034398593a (drafts/none/v1) Add none package with Kptfile marker -|/ -* c7edca419782f88646f9572b0a829d686b2d91bd (HEAD -> main, tag: istions/v2) Add Istio Namespace Resource -* c93d417f1393ae5d7def978da70c42b62e645cda (tag: basens/v2) Add Base Namespace Resource -| * 032c503a3921f322850e9bd49319346e0e0b129d (drafts/bucket/v1) Add Bucket Resource -| * 1950b803f552e4c89ac17c528ec466c1a7375083 Add Bucket Package Context -| * 5ea104c29951f3c3995ae15c4a367823794bd47d Empty Bucket Package -|/ -* f8fb59f626182319ec78dd542afcce35f98811e2 (tag: istions/v1) Add Istio Namespace Package Context -* 740397bf8f594b785f6802755945bd58a5e94192 (tag: basens/v1) Add Base Namespace Package Context -* 3d21cf677b3afcca132e0b415144e83f1f2ca2a9 Empty Istio Namespace -* ca725b9cd90d5a3ee22101f0ea66f83e40217a6f Empty Base Namespace -* 7a6308e79524221d74f549bac53bf1ed771958f7 (tag: empty/v1) Empty Package - -``` - -In addition to several published packages there are two drafts (`none` and `bucket`). diff --git a/porch/pkg/git/testdata/drafts-repository.tar b/porch/pkg/git/testdata/drafts-repository.tar deleted file mode 100644 index 65039aef99..0000000000 Binary files a/porch/pkg/git/testdata/drafts-repository.tar and /dev/null differ diff --git a/porch/pkg/git/testdata/empty-repository.md b/porch/pkg/git/testdata/empty-repository.md deleted file mode 100644 index a9d6cfc754..0000000000 --- a/porch/pkg/git/testdata/empty-repository.md +++ /dev/null @@ -1,13 +0,0 @@ -# Empty Repository - -For easier orientation, an overview of the contents of the `empty-repository.tar`. - -## Contents - -The repository in `empty-repository.tar` is truly empty. It has no commits, no refs. -Because `HEAD` is required for a valid git repository, `HEAD` is a symbolic ref to -(non-existent) `refs/heads/main`. - -## Commits - -There are no commits in this repository. diff --git a/porch/pkg/git/testdata/empty-repository.tar b/porch/pkg/git/testdata/empty-repository.tar deleted file mode 100644 index 785343a6f9..0000000000 Binary files a/porch/pkg/git/testdata/empty-repository.tar and /dev/null differ diff --git a/porch/pkg/git/testdata/nested-repository.md b/porch/pkg/git/testdata/nested-repository.md deleted file mode 100644 index 9b74b8312b..0000000000 --- a/porch/pkg/git/testdata/nested-repository.md +++ /dev/null @@ -1,61 +0,0 @@ -# Nested Repository - -For easier orientation, an overview of the contents of the `nested-repository.tar`. - -## Contents - -The repository in `nested-repository.tar` has the following contents -in `main` branch: - -``` -. -├── catalog -│   ├── empty -│   │   ├── Kptfile -│   │   └── README.md -│   ├── gcp -│   │   └── bucket -│   │   ├── bucket.yaml -│   │   ├── Kptfile -│   │   ├── package-context.yaml -│   │   └── README.md -│   └── namespace -│   ├── basens -│   │   ├── Kptfile -│   │   ├── namespace.yaml -│   │   ├── package-context.yaml -│   │   └── README.md -│   └── istions -│   ├── Kptfile -│   ├── namespace.yaml -│   ├── package-context.yaml -│   └── README.md -└── sample - ├── Kptfile - ├── package-context.yaml - └── README.md -``` - -## Commits - -The commit graph of the repository is: - -``` -* 1149bc62eca4a4a28b40695bcf44c22a4d28bc17 (drafts/catalog/gcp/cloud-sql/v1) Cloud SQL Package -| * d671169ffac0c7587b4dc41c667276f14c023fd1 (drafts/catalog/gcp/spanner/v1) Spanner Package -| | * e495fc033b38c5873b4575f21ded28e923744d04 (drafts/catalog/gcp/bucket/v2) Enable Bucket Versioning -| |/ -| * 1e155ee719634981881bcb696530e355fa9c9aba (HEAD -> main, tag: sample/v2) Sample Package Context -|/ -* 27c4e150a4a6b19ca4f54e3ba68779ebf3a04845 (tag: catalog/gcp/bucket/v1) Bucket Package -* 46ddff37bea3fda36a1b64b88539d89064d7f163 (tag: catalog/namespace/basens/v3) Base Namespace Resource -* 381c4a21013c5cd7d4304e069e9f7135adeddee3 (tag: catalog/namespace/istions/v3) Istio Namespace Resource -* c7b38567d2d12dd1848ed0a6bdc55a121bbe2fa2 (tag: catalog/namespace/istions/v2) Istio Namespacd Package Context -* e7ae90895740d60b01101293311f64c2d16e64eb (tag: catalog/namespace/basens/v2) Base Namespace Package Context -* 0c94de6fd7f46e8a2d1fe1a60d90a759b54cae94 (tag: catalog/namespace/istions/v1) Istio Namespace -* f006a6654ef6d06010d1460038b993934151da08 (tag: catalog/namespace/basens/v1) Base Namespace -* b8d4e1b2c3a87dd98c55f8991391c740a550a0bf (tag: catalog/empty/v1) Empty Package -* caac51094e012cf41b4dcdb14a269b8145bf0fbf (tag: sample/v1) Sample Package -* 0f890879a10df9aaa9b263035eea955335451804 Empty Commit - -``` diff --git a/porch/pkg/git/testdata/nested-repository.tar b/porch/pkg/git/testdata/nested-repository.tar deleted file mode 100644 index 51d96e29b5..0000000000 Binary files a/porch/pkg/git/testdata/nested-repository.tar and /dev/null differ diff --git a/porch/pkg/git/testdata/publishinfo-repository.md b/porch/pkg/git/testdata/publishinfo-repository.md deleted file mode 100644 index ba68c4374e..0000000000 --- a/porch/pkg/git/testdata/publishinfo-repository.md +++ /dev/null @@ -1,39 +0,0 @@ -# Publishinfo Repository - -For easier orientation, an overview of the contents of the `publishinfo-repository.tar`. - -## Contents - -The repository in `publishinfo-repository.tar` has the following contents in `main` branch: - -``` -. -├── basens -│   ├── Kptfile -│   ├── namespace.yaml -│   ├── package-context.yaml -│   └── README.md -├── empty -│   ├── Kptfile -│   └── README.md -└── istions - ├── istions.yaml - ├── Kptfile - ├── package-context.yaml - └── README.md -``` - -## Commits - -The commit graph of the repository is: - -``` -* be44230bd839acd9d858a043f8c18ee7122a72b2 Approval for some-pkg/v1 -| * 95a763c92a74e2083a7370e5a21085ecdfd8f552 (drafts/draft-pkg/v1) Intermediate commit: eval -| * 59c9c0a2922cb1c774bdb3d92012e6f12257790c Intermediate commit: init -|/ -* e5cba80404423634a363ad48b5053f5858fa100e (tag: tag: pkg-without-anno/v1) Approval for package pkg-without-anno/v1 -* 32ff5cca76b53939a6d4ba1d963a277aadbf7d11 (tag: pkg-with-anno/v1) Approve pkg-with-anno/v1 -* c5cad50cc87e87ae89a108b9ab683124bf47dc53 Intermediate commit: eval -* 5db484f0431493935c140b760441b65cf1c34608 Intermediate commit: init -``` diff --git a/porch/pkg/git/testdata/publishinfo-repository.tar b/porch/pkg/git/testdata/publishinfo-repository.tar deleted file mode 100644 index adb3e1899f..0000000000 Binary files a/porch/pkg/git/testdata/publishinfo-repository.tar and /dev/null differ diff --git a/porch/pkg/git/testdata/simple-repository.md b/porch/pkg/git/testdata/simple-repository.md deleted file mode 100644 index 87fba4edad..0000000000 --- a/porch/pkg/git/testdata/simple-repository.md +++ /dev/null @@ -1,38 +0,0 @@ -# Simple Repository - -The repository archive `simple-repository.tar` contains few published packages and no drafts. - -## Contents - -The repository contents in the `main` branch are: - -``` -. -├── basens -│   ├── Kptfile -│   ├── namespace.yaml -│   ├── package-context.yaml -│   └── README.md -├── empty -│   ├── Kptfile -│   └── README.md -└── istions - ├── istions.yaml - ├── Kptfile - ├── package-context.yaml - └── README.md -``` - -## Commits - -The commit graph of the repository is: - -``` -* c7edca419782f88646f9572b0a829d686b2d91bd (HEAD -> main, tag: istions/v2) Add Istio Namespace Resource -* c93d417f1393ae5d7def978da70c42b62e645cda (tag: basens/v2) Add Base Namespace Resource -* f8fb59f626182319ec78dd542afcce35f98811e2 (tag: istions/v1) Add Istio Namespace Package Context -* 740397bf8f594b785f6802755945bd58a5e94192 (tag: basens/v1) Add Base Namespace Package Context -* 3d21cf677b3afcca132e0b415144e83f1f2ca2a9 Empty Istio Namespace -* ca725b9cd90d5a3ee22101f0ea66f83e40217a6f Empty Base Namespace -* 7a6308e79524221d74f549bac53bf1ed771958f7 (tag: empty/v1) Empty Package -``` diff --git a/porch/pkg/git/testdata/simple-repository.tar b/porch/pkg/git/testdata/simple-repository.tar deleted file mode 100644 index 8f47900dc1..0000000000 Binary files a/porch/pkg/git/testdata/simple-repository.tar and /dev/null differ diff --git a/porch/pkg/git/testdata/trivial-repository.md b/porch/pkg/git/testdata/trivial-repository.md deleted file mode 100644 index 79e069a657..0000000000 --- a/porch/pkg/git/testdata/trivial-repository.md +++ /dev/null @@ -1,16 +0,0 @@ -# Trivial Repository - -For easier orientation, an overview of the contents of the `trivial-repository.tar`. - -## Contents - -The repository in `trivial-repository.tar` contains a single, empty, commit, in its -`main` branch. - -## Commits - -The commit graph is: - -``` -* 0f890879a10df9aaa9b263035eea955335451804 (HEAD -> main) Empty Commit -``` diff --git a/porch/pkg/git/testdata/trivial-repository.tar b/porch/pkg/git/testdata/trivial-repository.tar deleted file mode 100644 index 2744785635..0000000000 Binary files a/porch/pkg/git/testdata/trivial-repository.tar and /dev/null differ diff --git a/porch/pkg/git/testing.go b/porch/pkg/git/testing.go deleted file mode 100644 index 751a2541dd..0000000000 --- a/porch/pkg/git/testing.go +++ /dev/null @@ -1,648 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import ( - "bufio" - "compress/gzip" - "context" - "encoding/hex" - "fmt" - "io" - "net" - "net/http" - "sort" - "strings" - "time" - - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/filemode" - "github.com/go-git/go-git/v5/plumbing/format/packfile" - "github.com/go-git/go-git/v5/plumbing/format/pktline" - "github.com/go-git/go-git/v5/plumbing/object" - "github.com/go-git/go-git/v5/plumbing/protocol/packp/capability" - "github.com/go-git/go-git/v5/storage" - "k8s.io/klog/v2" -) - -// GitServer is a mock git server implementing "just enough" of the git protocol -type GitServer struct { - repos Repos -} - -// NewGitServer constructs a GitServer backed by the specified repo. -func NewGitServer(repos Repos, opts ...GitServerOption) (*GitServer, error) { - gs := &GitServer{ - repos: repos, - } - - for _, opt := range opts { - if err := opt.apply(gs); err != nil { - return nil, err - } - } - - return gs, nil -} - -// ListenAndServe starts the git server on "listen". -// The address we actually start listening on will be posted to addressChannel -func (s *GitServer) ListenAndServe(ctx context.Context, listen string, addressChannel chan<- net.Addr) error { - httpServer := &http.Server{ - Addr: listen, - Handler: s, - ReadTimeout: 10 * time.Second, - WriteTimeout: 60 * time.Second, // We need more time to build the pack file - MaxHeaderBytes: 1 << 20, - } - - ln, err := net.Listen("tcp", httpServer.Addr) - if err != nil { - close(addressChannel) - return err - } - - ctxWithCancel, cancel := context.WithCancel(ctx) - defer cancel() - - go func() { - <-ctxWithCancel.Done() - if err := httpServer.Shutdown(context.Background()); err != nil { - klog.Warningf("error from git httpServer.Shutdown: %v", err) - } - if err := httpServer.Close(); err != nil { - klog.Warningf("error from git httpServer.Close: %v", err) - } - }() - - addressChannel <- ln.Addr() - - return httpServer.Serve(ln) -} - -// ServeHTTP is the entrypoint for http requests. -func (s *GitServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { - if err := s.serveRequest(w, r); err != nil { - klog.Warningf("internal error from %s %s: %v", r.Method, r.URL, err) - - http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) - } -} - -// serveRequest is the main dispatcher for http requests. -func (s *GitServer) serveRequest(w http.ResponseWriter, r *http.Request) error { - pathTokens := strings.Split(strings.TrimPrefix(r.URL.Path, "/"), "/") - if len(pathTokens) > 1 { - repoID := pathTokens[0] - repo, err := s.repos.FindRepo(r.Context(), repoID) - if err != nil { - klog.Warningf("500 for %s %s: %v", r.Method, r.URL, err) - http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) - return nil - - } - if repo == nil { - // TODO: Should we send something consistent with auth failure? - klog.Warningf("404 for %s %s (repo not found)", r.Method, r.URL) - http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) - return nil - } - - if repo.username != "" || repo.password != "" { - username, password, ok := r.BasicAuth() - if !ok || username != repo.username || password != repo.password { - http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden) - return nil - } - } - gitPath := strings.Join(pathTokens[1:], "/") - if gitPath == "info/refs" { - return s.serveGitInfoRefs(w, r, repo) - } - if gitPath == "git-upload-pack" { - return s.serveGitUploadPack(w, r, repo) - } - if gitPath == "git-receive-pack" { - return s.serveGitReceivePack(w, r, repo) - } - } - - klog.Warningf("404 for %s %s", r.Method, r.URL) - http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) - return nil -} - -// serveGitInfoRefs serves the info/refs (discovery) endpoint -func (s *GitServer) serveGitInfoRefs(w http.ResponseWriter, r *http.Request, repo *Repo) error { - query := r.URL.Query() - serviceName := query.Get("service") - - capabilities := []string{string(capability.DeleteRefs)} - - switch serviceName { - case "git-upload-pack": - // OK - capabilities = append(capabilities, "symref=HEAD:refs/heads/main") - - case "git-receive-pack": - // OK - - default: - return fmt.Errorf("unknown service-name %q", serviceName) - } - - // We send an advertisement for each of our references - it, err := repo.gogit.References() - if err != nil { - return fmt.Errorf("failed to get git references: %w", err) - } - - // Find HEAD so we can return it first (https://git-scm.com/docs/http-protocol) - var head *plumbing.Reference - refs := map[string]*plumbing.Reference{} // Resolving symbolic refs will lead to dupes. De-dupe them. - if err := it.ForEach(func(ref *plumbing.Reference) error { - var resolved *plumbing.Reference - // Resolve symbolic references. - switch ref.Type() { - case plumbing.SymbolicReference: - if r, err := repo.gogit.Reference(ref.Name(), true); err != nil { - klog.Warningf("Skipping unresolvable symbolic reference %q: %v", ref.Name(), err) - return nil - } else { - resolved = r - } - case plumbing.HashReference: - resolved = ref - default: - return fmt.Errorf("unexpected reference encountered: %s", ref) - } - - resolvedName := resolved.Name() - if resolvedName.IsRemote() { - klog.Infof("skipping remote ref %q", resolvedName) - return nil - } - - refs[resolvedName.String()] = resolved - if ref.Name() == plumbing.HEAD { - head = resolved - } - return nil - }); err != nil { - return fmt.Errorf("error iterating through references: %w", err) - } - - w.Header().Set("Content-Type", "application/x-"+serviceName+"-advertisement") - w.Header().Set("Cache-Control", "no-cache") - w.WriteHeader(http.StatusOK) - - gw := NewPacketLineWriter(w) - - gw.WriteLine("# service=" + serviceName) - gw.WriteZeroPacketLine() - - sorted := sortedRefs(refs, head) - writeRefs(gw, sorted, capabilities) - - gw.WriteZeroPacketLine() - - if err := gw.Flush(); err != nil { - klog.Warningf("error from flush: %v", err) - // Too late to send a real error code - return nil - } - - return nil -} - -func sortedRefs(refs map[string]*plumbing.Reference, head *plumbing.Reference) []*plumbing.Reference { - sorted := make([]*plumbing.Reference, 0, len(refs)) - for _, v := range refs { - sorted = append(sorted, v) - } - sort.Slice(sorted, func(i, j int) bool { - switch { - case sorted[i] == head: - return true - case sorted[j] == head: - return false - default: - return sorted[i].Name().String() < sorted[j].Name().String() - } - }) - return sorted -} - -func writeRefs(gw *PacketLineWriter, sorted []*plumbing.Reference, capabilities []string) { - // empty_list = PKT-LINE(zero-id SP "capabilities^{}" NUL cap-list LF) - if len(sorted) == 0 { - var zero plumbing.Hash - s := fmt.Sprintf("%s capabilities^{}\000%s", zero, strings.Join(capabilities, " ")) - gw.WriteLine(s) - return - } - - // non_empty_list = PKT-LINE(obj-id SP name NUL cap_list LF) - // *ref_record - // ref_record = any_ref / peeled_ref - // any_ref = PKT-LINE(obj-id SP name LF) - for i, ref := range sorted { - s := fmt.Sprintf("%s %s", ref.Hash(), ref.Name()) - if i == 0 { - // We attach capabilities to the first line - s += "\000" + strings.Join(capabilities, " ") - } - gw.WriteLine(s) - } -} - -// serveGitUploadPack serves the git-upload-pack endpoint -func (s *GitServer) serveGitUploadPack(w http.ResponseWriter, r *http.Request, repo *Repo) error { - // See https://git-scm.com/docs/pack-protocol/2.2.3#_packfile_negotiation - - // The client sends a line for each sha it wants and each sha it has - scanner := pktline.NewScanner(r.Body) - for { - if !scanner.Scan() { - err := scanner.Err() - if err != nil { - return fmt.Errorf("error parsing request: %w", err) - } - break - } - line := scanner.Bytes() - klog.V(4).Infof("request line: %s", string(line)) - } - - // We implement a very dumb version of the protocol; we always send everything - // This works, and is correct on the "clean pull" scenario, but is not efficient in the real world. - - // Gather all the objects - walker := newObjectWalker(repo.gogit.Storer) - if err := walker.walkAllRefs(); err != nil { - return fmt.Errorf("error walking refs: %w", err) - } - - objects := make([]plumbing.Hash, 0, len(walker.seen)) - for h := range walker.seen { - objects = append(objects, h) - } - - // Send a NAK indicating we're sending everything - encoder := NewPacketLineWriter(w) - encoder.WriteLine("NAK") - if err := encoder.Flush(); err != nil { - klog.Warningf("error encoding response: %v", err) - return nil // Too late - } - - // Send the packfile data - klog.Infof("sending %d objects in packfile", len(objects)) - - useRefDeltas := false - storer := repo.gogit.Storer - - // TODO: Buffer on disk first? - packFileEncoder := packfile.NewEncoder(w, storer, useRefDeltas) - - // packWindow specifies the size of the sliding window used - // to compare objects for delta compression; - // 0 turns off delta compression entirely. - packWindow := uint(0) - - packfileHash, err := packFileEncoder.Encode(objects, packWindow) - if err != nil { - klog.Warningf("error encoding packfile: %v", err) - return nil // Too late - } - - klog.Infof("packed as %v", packfileHash) - - return nil -} - -type GitHash = plumbing.Hash - -// RefUpdate stores requested tag/branch updates -type RefUpdate struct { - From GitHash - To GitHash - Ref string -} - -func (s *GitServer) serveGitReceivePack(w http.ResponseWriter, r *http.Request, repo *Repo) error { - var refUpdates []RefUpdate - - body := r.Body - - contentEncoding := r.Header.Get("Content-Encoding") - switch contentEncoding { - case "": - // OK - - case "gzip": - gzr, err := gzip.NewReader(body) - if err != nil { - return fmt.Errorf("gzip.NewReader failed: %w", err) - } - defer gzr.Close() - body = gzr - - default: - return fmt.Errorf("unknown content-encoding %q", contentEncoding) - } - - // The client sends a line for each ref it wants to update, then it sends the packfile data - gr := pktline.NewScanner(body) - - var clientCapabilites []string - - firstLine := true - for { - if !gr.Scan() { - err := gr.Err() - if err != nil { - return fmt.Errorf("error reading request line: %w", err) - } - return fmt.Errorf("error reading request line: EOF") - } - - line := string(gr.Bytes()) - - klog.V(4).Infof("client sent %q", line) - if line == "" { - break - } - - tokens := strings.SplitN(line, " ", 3) - if len(tokens) != 3 { - return fmt.Errorf("unexpected line (spaces) %q", line) - } - refTokens := strings.Split(tokens[2], "\000") - ref := refTokens[0] - if !firstLine { - if len(refTokens) != 1 { - return fmt.Errorf("unexpected line (nulls) %q", line) - } - } else { - if len(refTokens) > 1 { - clientCapabilites = refTokens[1:] - } - firstLine = false - } - - from, err := parseHash(tokens[0]) - if err != nil { - return fmt.Errorf("unexpected line (hash1) %q", line) - } - - to, err := parseHash(tokens[1]) - if err != nil { - return fmt.Errorf("unexpected line (hash2) %q", line) - } - - refUpdates = append(refUpdates, RefUpdate{From: from, To: to, Ref: ref}) - } - - klog.V(2).Infof("clientCapabilites %v", clientCapabilites) - klog.V(2).Infof("updates %+v", refUpdates) - - // TODO: In a real implementation, we would check the shas here - - w.Header().Set("Content-Type", "application/x-git-upload-pack-result") - w.Header().Set("Cache-Control", "no-cache") - w.WriteHeader(http.StatusOK) - - gitWriter := NewPacketLineWriter(w) - - switch err := packfile.UpdateObjectStorage(repo.gogit.Storer, body); err { - case nil, packfile.ErrEmptyPackfile: - // ok - default: - klog.Warningf("error parsing packfile: %v", err) - gitWriter.WriteLine("unpack error parsing packfile") - gitWriter.Flush() - return nil - } - - // TODO: In a real implementation, we would validate the packfile data - - gitWriter.WriteLine("unpack ok") - gitWriter.WriteZeroPacketLine() - if err := gitWriter.Flush(); err != nil { - klog.Warningf("error flushing response: %w", err) - return nil // too late for real errors - } - - // Having accepted the packfile into our store, we should update the SHAs - - // TODO: Concurrency, if we ever pull this out of test code - for _, refUpdate := range refUpdates { - switch { - case refUpdate.To.IsZero(): - klog.Infof("Deleting reference %s", refUpdate.Ref) - repo.gogit.Storer.RemoveReference(plumbing.ReferenceName(refUpdate.Ref)) - - default: - ref := plumbing.NewHashReference(plumbing.ReferenceName(refUpdate.Ref), refUpdate.To) - if err := repo.gogit.Storer.SetReference(ref); err != nil { - klog.Warningf("failed to update reference %v: %v", refUpdate, err) - } else { - klog.Warningf("updated reference %v -> %v", refUpdate.Ref, refUpdate.To) - } - } - } - - return nil -} - -// objectWalker is based on objectWalker in go-git/v5 - -type objectWalker struct { - Storer storage.Storer - // seen is the set of objects seen in the repo. - // seen map can become huge if walking over large - // repos. Thus using struct{} as the value type. - seen map[plumbing.Hash]struct{} -} - -func newObjectWalker(s storage.Storer) *objectWalker { - return &objectWalker{s, map[plumbing.Hash]struct{}{}} -} - -// walkAllRefs walks all (hash) references from the repo. -func (p *objectWalker) walkAllRefs() error { - // Walk over all the references in the repo. - it, err := p.Storer.IterReferences() - if err != nil { - return err - } - defer it.Close() - err = it.ForEach(func(ref *plumbing.Reference) error { - // Exit this iteration early for non-hash references. - if ref.Type() != plumbing.HashReference { - return nil - } - return p.walkObjectTree(ref.Hash()) - }) - return err -} - -func (p *objectWalker) isSeen(hash plumbing.Hash) bool { - _, seen := p.seen[hash] - return seen -} - -func (p *objectWalker) add(hash plumbing.Hash) { - p.seen[hash] = struct{}{} -} - -// walkObjectTree walks over all objects and remembers references -// to them in the objectWalker. This is used instead of the revlist -// walks because memory usage is tight with huge repos. -func (p *objectWalker) walkObjectTree(hash plumbing.Hash) error { - // Check if we have already seen, and mark this object - if p.isSeen(hash) { - return nil - } - p.add(hash) - // Fetch the object. - obj, err := object.GetObject(p.Storer, hash) - if err != nil { - return fmt.Errorf("getting object %s failed: %v", hash, err) - } - // Walk all children depending on object type. - switch obj := obj.(type) { - case *object.Commit: - err = p.walkObjectTree(obj.TreeHash) - if err != nil { - return err - } - for _, h := range obj.ParentHashes { - err = p.walkObjectTree(h) - if err != nil { - return err - } - } - case *object.Tree: - nextEntry: - for i := range obj.Entries { - switch obj.Entries[i].Mode { - case filemode.Executable, filemode.Regular, filemode.Symlink: - p.add(obj.Entries[i].Hash) - continue nextEntry - case filemode.Submodule: - // hash is the submodule ref, I believe - continue nextEntry - case filemode.Dir: - // process recursively - default: - klog.Warningf("unknown entry mode %s", obj.Entries[i].Mode) - } - // Normal walk for sub-trees (and symlinks etc). - err = p.walkObjectTree(obj.Entries[i].Hash) - if err != nil { - return err - } - } - case *object.Tag: - return p.walkObjectTree(obj.Target) - default: - // Error out on unhandled object types. - return fmt.Errorf("unknown object %s %s %T", obj.ID(), obj.Type(), obj) - } - return nil -} - -// parseHash is a helper that parses a GitHash provided by the client. -func parseHash(s string) (GitHash, error) { - var h GitHash - b, err := hex.DecodeString(s) - if err != nil { - return h, fmt.Errorf("hash %q was not hex", s) - } - if len(b) != 20 { - return h, fmt.Errorf("hash %q was wrong length", s) - } - copy(h[:], b) - return h, nil -} - -// NewPackageLineWriter constructs a PacketLineWriter -func NewPacketLineWriter(w io.Writer) *PacketLineWriter { - bw := bufio.NewWriter(w) - return &PacketLineWriter{ - w: bw, - } -} - -// PacketLineWriter implements the git protocol line framing, with deferred error handling. -type PacketLineWriter struct { - err error - w *bufio.Writer -} - -// Flush writes any buffered data, and returns an error if one has accumulated. -func (w *PacketLineWriter) Flush() error { - if w.err != nil { - return w.err - } - return w.w.Flush() -} - -// WriteLine frames and writes a line, accumulating errors until Flush is called. -func (w *PacketLineWriter) WriteLine(s string) { - if w.err != nil { - return - } - - n := 4 + len(s) + 1 - prefix := fmt.Sprintf("%04x", n) - - if _, err := w.w.Write([]byte(prefix)); err != nil { - w.err = err - return - } - if _, err := w.w.Write([]byte(s)); err != nil { - w.err = err - return - } - if _, err := w.w.Write([]byte("\n")); err != nil { - w.err = err - return - } - - klog.V(4).Infof("writing pktline %q", s) -} - -// WriteZeroPacketLine writes a special "0000" line - often used to indicate the end of a block in the git protocol -func (w *PacketLineWriter) WriteZeroPacketLine() { - if w.err != nil { - return - } - - if _, err := w.w.Write([]byte("0000")); err != nil { - w.err = err - return - } - - klog.V(4).Infof("writing pktline 0000") -} - -// Options - -type GitServerOption interface { - apply(*GitServer) error -} diff --git a/porch/pkg/git/testing_repo.go b/porch/pkg/git/testing_repo.go deleted file mode 100644 index 144aa8b1af..0000000000 --- a/porch/pkg/git/testing_repo.go +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright 2022 The kpt 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. - -package git - -import ( - "archive/tar" - "context" - "io" - "net" - "os" - "path/filepath" - "sync" - "testing" - - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - gogit "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/object" -) - -func OpenGitRepositoryFromArchive(t *testing.T, tarfile, tempdir string) *gogit.Repository { - t.Helper() - - extractTar(t, tarfile, tempdir) - - git, err := gogit.PlainOpen(filepath.Join(tempdir, ".git")) - if err != nil { - t.Fatalf("Failed to open Git Repository extracted from %q: %v", tarfile, err) - } - - return git -} - -func OpenGitRepositoryFromArchiveWithWorktree(t *testing.T, tarfile, path string) *gogit.Repository { - t.Helper() - - extractTar(t, tarfile, path) - - repo, err := gogit.PlainOpen(path) - if err != nil { - t.Fatalf("Failed to open Git repository extracted from %q: %v", tarfile, err) - } - return repo -} - -func InitEmptyRepositoryWithWorktree(t *testing.T, path string) *gogit.Repository { - t.Helper() - - repo, err := gogit.PlainInit(path, false) - if err != nil { - t.Fatalf("Failed to initialize empty Git repository: %v", err) - } - if err := initializeDefaultBranches(repo); err != nil { - t.Fatalf("Failed to remove default branches") - } - return repo -} - -func ServeGitRepositoryWithBranch(t *testing.T, tarfile, tempdir, branch string) (*gogit.Repository, string) { - t.Helper() - - git := OpenGitRepositoryFromArchive(t, tarfile, tempdir) - InitializeBranch(t, git, branch) - return git, ServeExistingRepository(t, git) -} - -func InitializeBranch(t *testing.T, git *gogit.Repository, branch string) { - t.Helper() - - // If main branch exists, rename it to the specified ref - main, err := git.Reference(DefaultMainReferenceName, false) - switch err { - case nil: - // found `main branch` - case plumbing.ErrReferenceNotFound: - // main doesn't exist, we won't create the target branch either. - return - default: - t.Fatalf("Error getting %s branch: %v", DefaultMainReferenceName, err) - return - } - - // `main` branch was found. Create the target branch off of it if needed. - name := plumbing.NewBranchReferenceName(branch) - if name != DefaultMainReferenceName { - ref := plumbing.NewHashReference(name, main.Hash()) - if err := git.Storer.SetReference(ref); err != nil { - t.Fatalf("Error creating target branch %q from %q: %v", ref, main, err) - } - - t.Cleanup(func() { - // Verify that main didn't move during the test - new, err := git.Reference(DefaultMainReferenceName, false) - if err != nil { - t.Fatalf("Error getting %s branch after test run: %v", gogit.DefaultRemoteName, err) - } - - if main.Hash() != new.Hash() { - t.Fatalf("%q branch moved unexpectedly during the test to %q", main, new) - } - }) - } -} - -func ServeGitRepository(t *testing.T, tarfile, tempdir string) (*gogit.Repository, string) { - t.Helper() - - git := OpenGitRepositoryFromArchive(t, tarfile, tempdir) - return git, ServeExistingRepository(t, git) -} - -func ServeExistingRepository(t *testing.T, git *gogit.Repository) string { - t.Helper() - - repo, err := NewRepo(git) - if err != nil { - t.Fatalf("NewRepo failed: %v", err) - } - - key := "default" - - repos := NewStaticRepos() - if err := repos.Add(key, repo); err != nil { - t.Fatalf("repos.Add failed: %v", err) - } - - server, err := NewGitServer(repos) - if err != nil { - t.Fatalf("NewGitServer() failed: %v", err) - } - - var wg sync.WaitGroup - - serverAddressChannel := make(chan net.Addr) - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(func() { - cancel() - wg.Wait() - }) - - wg.Add(1) - go func() { - defer wg.Done() - if err := server.ListenAndServe(ctx, "127.0.0.1:0", serverAddressChannel); err != nil { - if ctx.Err() == nil { - t.Errorf("Git Server ListenAndServe failed: %v", err) - } - } - }() - - address, ok := <-serverAddressChannel - if !ok { - t.Fatalf("Git Server failed to start") - } - return "http://" + address.String() + "/" + key -} - -func extractTar(t *testing.T, tarfile string, dir string) { - t.Helper() - - reader, err := os.Open(tarfile) - if err != nil { - t.Fatalf("Open(%q) failed: %v", tarfile, err) - } - defer reader.Close() - tr := tar.NewReader(reader) - - for { - hdr, err := tr.Next() - if err == io.EOF { - break - } - if err != nil { - t.Fatalf("Reading tar file %q failed: %v", tarfile, err) - } - if hdr.FileInfo().IsDir() { - path := filepath.Join(dir, hdr.Name) - if err := os.MkdirAll(path, 0755); err != nil { - t.Fatalf("MkdirAll(%q) failed: %v", path, err) - } - continue - } - path := filepath.Join(dir, filepath.Dir(hdr.Name)) - if err := os.MkdirAll(path, 0755); err != nil { - t.Fatalf("MkdirAll(%q) failed: %v", path, err) - } - path = filepath.Join(dir, hdr.Name) - saveToFile(t, path, tr) - } -} - -func saveToFile(t *testing.T, path string, src io.Reader) { - t.Helper() - - dst, err := os.Create(path) - if err != nil { - t.Fatalf("Create(%q) failed; %v", path, err) - } - defer dst.Close() - if _, err := io.Copy(dst, src); err != nil { - t.Fatalf("Copy from tar to %q failed: %v", path, err) - } -} - -func resolveReference(t *testing.T, repo *gogit.Repository, name plumbing.ReferenceName) *plumbing.Reference { - t.Helper() - - ref, err := repo.Reference(name, true) - if err != nil { - t.Fatalf("Failed to resolve %q: %v", name, err) - } - return ref -} - -func getCommitObject(t *testing.T, repo *gogit.Repository, hash plumbing.Hash) *object.Commit { - t.Helper() - - commit, err := repo.CommitObject(hash) - if err != nil { - t.Fatalf("Failed to find commit object for %q: %v", hash, err) - } - return commit -} - -func getCommitTree(t *testing.T, repo *gogit.Repository, hash plumbing.Hash) *object.Tree { - t.Helper() - - commit := getCommitObject(t, repo, hash) - tree, err := commit.Tree() - if err != nil { - t.Fatalf("Failed to get tree from commit %q: %v", hash, err) - } - return tree -} - -func findTreeEntry(t *testing.T, tree *object.Tree, path string) *object.TreeEntry { - t.Helper() - - entry, err := tree.FindEntry(path) - if err != nil { - t.Fatalf("Failed to find path %q in tree %q: %v", path, tree.Hash, err) - } - return entry -} - -func findFile(t *testing.T, tree *object.Tree, path string) *object.File { - t.Helper() - - file, err := tree.File(path) - if err != nil { - t.Fatalf("Failed to find file %q under the root commit tree %q: %v", path, tree.Hash, err) - } - return file -} - -func findPackageRevision(t *testing.T, revisions []repository.PackageRevision, key repository.PackageRevisionKey) repository.PackageRevision { - t.Helper() - - for _, r := range revisions { - if r.Key() == key { - return r - } - } - t.Fatalf("PackageRevision %q not found", key) - return nil -} - -func packageMustNotExist(t *testing.T, revisions []repository.PackageRevision, key repository.PackageRevisionKey) { - t.Helper() - - for _, r := range revisions { - if key == r.Key() { - t.Fatalf("PackageRevision %q expected to not exist was found", key) - } - } -} - -func repositoryMustHavePackageRevision(t *testing.T, git GitRepository, name repository.PackageRevisionKey) { - t.Helper() - - list, err := git.ListPackageRevisions(context.Background(), repository.ListPackageRevisionFilter{}) - if err != nil { - t.Fatalf("ListPackageRevisions failed: %v", err) - } - findPackageRevision(t, list, name) -} - -func repositoryMustNotHavePackageRevision(t *testing.T, git GitRepository, name repository.PackageRevisionKey) { - t.Helper() - - list, err := git.ListPackageRevisions(context.Background(), repository.ListPackageRevisionFilter{}) - if err != nil { - t.Fatalf("ListPackageRevisions failed: %v", err) - } - packageMustNotExist(t, list, name) -} - -func refMustExist(t *testing.T, repo *gogit.Repository, name plumbing.ReferenceName) { - t.Helper() - - switch _, err := repo.Reference(name, false); err { - case nil: - // ok - case plumbing.ErrReferenceNotFound: - t.Fatalf("Reference %s must exist but was not found: %v", name, err) - default: - t.Fatalf("Unexpected error resolving reference %q: %v", name, err) - } -} - -func refMustNotExist(t *testing.T, repo *gogit.Repository, name plumbing.ReferenceName) { - t.Helper() - - switch ref, err := repo.Reference(name, false); err { - case nil: - t.Fatalf("Reference %s must not exist but was found: %s", name, ref) - case plumbing.ErrReferenceNotFound: - // ok - default: - t.Fatalf("Unexpected error resolving reference %q: %v", name, err) - } -} - -func forEachRef(t *testing.T, repo *gogit.Repository, fn func(*plumbing.Reference) error) { - t.Helper() - - refs, err := repo.References() - if err != nil { - t.Fatalf("Failed to create references iterator: %v", err) - } - if err := refs.ForEach(fn); err != nil { - t.Fatalf("References.ForEach failed: %v", err) - } -} - -func logRefs(t *testing.T, repo *gogit.Repository, logPrefix string) { - t.Helper() - - forEachRef(t, repo, func(ref *plumbing.Reference) error { - t.Logf("%s%s", logPrefix, ref) - return nil - }) -} - -func fetch(t *testing.T, repo *gogit.Repository) { - t.Helper() - - switch err := repo.Fetch(&gogit.FetchOptions{ - RemoteName: OriginName, - Tags: gogit.NoTags, - }); err { - case nil, gogit.NoErrAlreadyUpToDate: - // ok - default: - t.Fatalf("Fetch failed: %s", err) - } -} diff --git a/porch/pkg/googleurl/parser.go b/porch/pkg/googleurl/parser.go deleted file mode 100644 index 27e202845e..0000000000 --- a/porch/pkg/googleurl/parser.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2022 The kpt 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. - -package googleurl - -import ( - "fmt" - "net/url" - "strings" -) - -// Link holds the results of parsing a google selfLink URL. -type Link struct { - // Service is the service name e.g. container.googleapis.com - Service string - // Version is the version in the link - Version string - - // Project is the GCP project ID in the link - Project string - - // Zone is the GCP zone found in the link - Zone string - - // Location is the GCP location (region or zone) found in the link - Location string - - // Extra holds any additional named fields found in the link - Extra map[string]string -} - -// Parse parses the selfLink into fields in a Link object. -// A selfLink is expected to have a version as the first path token, otherwise use ParseUnversioned. -func Parse(selfLink string) (*Link, error) { - u, err := url.Parse(selfLink) - if err != nil { - return nil, fmt.Errorf("selfLink %q was not a valid URL", selfLink) - } - - link := &Link{ - Service: u.Host, - } - - tokens := strings.Split(strings.TrimPrefix(u.Path, "/"), "/") - - link.Version = tokens[0] - tokens = tokens[1:] - - if len(tokens)%2 != 0 { - return nil, fmt.Errorf("unexpected url %q (unexpected tokens)", selfLink) - } - - return parseTokens(link, tokens) -} - -func parseTokens(link *Link, tokens []string) (*Link, error) { - for i := 0; i < len(tokens); i += 2 { - switch tokens[i] { - case "projects": - link.Project = tokens[i+1] - case "zones": - link.Zone = tokens[i+1] - case "locations": - link.Location = tokens[i+1] - default: - if link.Extra == nil { - link.Extra = make(map[string]string) - } - link.Extra[tokens[i]] = tokens[i+1] - } - } - return link, nil -} - -// ParseUnversioned parses the unversioned selfLink into fields in a Link object. -// An unversioned reference differs from a normal selfLink in that it doesn't have a version, -// for example "//container.googleapis.com/projects/example-project/locations/us-central1/clusters/example-cluster" -func ParseUnversioned(selfLink string) (*Link, error) { - u, err := url.Parse(selfLink) - if err != nil { - return nil, fmt.Errorf("selfLink %q was not a valid URL", selfLink) - } - - link := &Link{ - Service: u.Host, - } - - tokens := strings.Split(strings.TrimPrefix(u.Path, "/"), "/") - - if len(tokens)%2 != 0 { - return nil, fmt.Errorf("unexpected url %q (unexpected tokens)", selfLink) - } - - return parseTokens(link, tokens) -} diff --git a/porch/pkg/googleurl/parser_test.go b/porch/pkg/googleurl/parser_test.go deleted file mode 100644 index b1d10b5a58..0000000000 --- a/porch/pkg/googleurl/parser_test.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2022 The kpt 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. - -package googleurl - -import ( - "testing" - - "github.com/google/go-cmp/cmp" -) - -func TestParse(t *testing.T) { - grid := []struct { - SelfLink string - Want Link - }{ - { - SelfLink: "https://container.googleapis.com/v1/projects/justinsb-acp-dev/locations/us-central1/clusters/auto-gke/nodePools/default-pool", - Want: Link{ - Service: "container.googleapis.com", - Version: "v1", - Project: "justinsb-acp-dev", - Location: "us-central1", - Extra: map[string]string{ - "clusters": "auto-gke", - "nodePools": "default-pool", - }, - }, - }, - { - SelfLink: "//gkehub.googleapis.com/v1/projects/justinsb-acp-dev/locations/global/memberships/example-cluster-1", - Want: Link{ - Service: "gkehub.googleapis.com", - Version: "v1", - Project: "justinsb-acp-dev", - Location: "global", - Extra: map[string]string{ - "memberships": "example-cluster-1", - }, - }, - }, - } - - for _, g := range grid { - t.Run(g.SelfLink, func(t *testing.T) { - got, err := Parse(g.SelfLink) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if diff := cmp.Diff(g.Want, *got); diff != "" { - t.Errorf("unexpected diff (+got,-want): %s", diff) - } - }) - } -} - -func TestParseUnversioned(t *testing.T) { - grid := []struct { - SelfLink string - Want Link - }{ - { - SelfLink: "//container.googleapis.com/projects/example-project/locations/us-central1/clusters/example-cluster", - Want: Link{ - Service: "container.googleapis.com", - Project: "example-project", - Location: "us-central1", - Extra: map[string]string{ - "clusters": "example-cluster", - }, - }, - }, - } - - for _, g := range grid { - t.Run(g.SelfLink, func(t *testing.T) { - got, err := ParseUnversioned(g.SelfLink) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if diff := cmp.Diff(g.Want, *got); diff != "" { - t.Errorf("unexpected diff (+got,-want): %s", diff) - } - }) - } -} diff --git a/porch/pkg/kpt/clone.go b/porch/pkg/kpt/clone.go deleted file mode 100644 index 29d587c4a7..0000000000 --- a/porch/pkg/kpt/clone.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2022 The kpt 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. - -package kpt - -import ( - "fmt" - "strings" - - internalpkg "github.com/GoogleContainerTools/kpt/internal/pkg" - kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -// TODO: Accept a virtual filesystem or other package abstraction -func UpdateUpstream(kptfileContents string, name string, upstream kptfilev1.Upstream, lock kptfilev1.UpstreamLock) (string, error) { - - kptfile, err := internalpkg.DecodeKptfile(strings.NewReader(kptfileContents)) - if err != nil { - return "", fmt.Errorf("cannot parse Kptfile: %w", err) - } - - // populate the cloneFrom values so we know where the package came from - kptfile.UpstreamLock = &lock - kptfile.Upstream = &upstream - if name != "" { - kptfile.Name = name - } - - b, err := yaml.MarshalWithOptions(kptfile, &yaml.EncoderOptions{SeqIndent: yaml.WideSequenceStyle}) - if err != nil { - return "", fmt.Errorf("cannot save Kptfile: %w", err) - } - - return string(b), nil -} - -func UpdateName(kptfileContents string, name string) (string, error) { - kptfile, err := internalpkg.DecodeKptfile(strings.NewReader(kptfileContents)) - if err != nil { - return "", fmt.Errorf("cannot parse Kptfile: %w", err) - } - - // update the name of the package - kptfile.Name = name - - b, err := yaml.MarshalWithOptions(kptfile, &yaml.EncoderOptions{SeqIndent: yaml.WideSequenceStyle}) - if err != nil { - return "", fmt.Errorf("cannot save Kptfile: %w", err) - } - - return string(b), nil -} - -// TODO: accept a virtual filesystem -func UpdateKptfileUpstream(name string, contents map[string]string, upstream kptfilev1.Upstream, lock kptfilev1.UpstreamLock) error { - kptfile, found := contents[kptfilev1.KptFileName] - if !found { - return fmt.Errorf("package %q is missing Kptfile", name) - } - - kptfile, err := UpdateUpstream(kptfile, name, upstream, lock) - if err != nil { - return fmt.Errorf("failed to update package upstream: %w", err) - } - - contents[kptfilev1.KptFileName] = kptfile - return nil -} - -func UpdateKptfileName(name string, contents map[string]string) error { - kptfile, found := contents[kptfilev1.KptFileName] - if !found { - return fmt.Errorf("package %q is missing Kptfile", name) - } - - kptfile, err := UpdateName(kptfile, name) - if err != nil { - return fmt.Errorf("failed to update package upstream: %w", err) - } - - contents[kptfilev1.KptFileName] = kptfile - return nil -} diff --git a/porch/pkg/kpt/eval.go b/porch/pkg/kpt/eval.go deleted file mode 100644 index 0b21a9b272..0000000000 --- a/porch/pkg/kpt/eval.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2022 The kpt 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. - -package kpt - -import ( - "context" - "io" - - kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/pkg/fn" - "github.com/GoogleContainerTools/kpt/porch/pkg/kpt/internal" - "sigs.k8s.io/kustomize/kyaml/fn/framework" - "sigs.k8s.io/kustomize/kyaml/kio" -) - -func NewSimpleFunctionRuntime() FunctionRuntime { - return &runtime{} -} - -type runtime struct { -} - -var _ FunctionRuntime = &runtime{} - -func (e *runtime) GetRunner(ctx context.Context, funct *kptfilev1.Function) (fn.FunctionRunner, error) { - processor := internal.FindProcessor(funct.Image) - if processor == nil { - return nil, &fn.NotFoundError{Function: *funct} - } - - return &runner{ - ctx: ctx, - processor: processor, - }, nil -} - -func (e *runtime) Close() error { - return nil -} - -type runner struct { - ctx context.Context - processor framework.ResourceListProcessorFunc -} - -var _ fn.FunctionRunner = &runner{} - -func (fr *runner) Run(r io.Reader, w io.Writer) error { - rw := &kio.ByteReadWriter{ - Reader: r, - Writer: w, - KeepReaderAnnotations: true, - } - - return framework.Execute(fr.processor, rw) -} diff --git a/porch/pkg/kpt/eval_test.go b/porch/pkg/kpt/eval_test.go deleted file mode 100644 index 0b7454bae8..0000000000 --- a/porch/pkg/kpt/eval_test.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2022 The kpt 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. - -package kpt - -import ( - "bytes" - "context" - "path" - "testing" - - "github.com/GoogleContainerTools/kpt/internal/fnruntime" - v1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -func ReadResourceList(t *testing.T, pkgdir string, config *yaml.RNode) []byte { - r := &kio.LocalPackageReader{ - PackagePath: pkgdir, - WrapBareSeqNode: true, - } - - var rl bytes.Buffer - w := &kio.ByteWriter{ - Writer: &rl, - KeepReaderAnnotations: true, - WrappingKind: kio.ResourceListKind, - WrappingAPIVersion: kio.ResourceListAPIVersion, - FunctionConfig: config, - } - if err := (kio.Pipeline{Inputs: []kio.Reader{r}, Outputs: []kio.Writer{w}}).Execute(); err != nil { - t.Fatalf("Failed to load package %q", pkgdir) - return nil - } else { - return rl.Bytes() - } -} - -func TestSetLabels(t *testing.T) { - r := &runtime{} - runner, err := r.GetRunner(context.Background(), &v1.Function{ - Image: "gcr.io/kpt-fn/set-labels:v0.1.5", - }) - if err != nil { - t.Errorf("GetRunner failed: %v", err) - } - - config, err := fnruntime.NewConfigMap(map[string]string{ - "label-key": "label-value", - }) - if err != nil { - t.Fatalf("Failed to create function config map: %v", err) - } - - input := ReadResourceList(t, path.Join(".", "testdata", "bucket"), config) - var output bytes.Buffer - if err := runner.Run(bytes.NewReader(input), &output); err != nil { - t.Errorf("Eval failed: %v", err) - } - - t.Log(output.String()) - - reader := kio.ByteReader{Reader: &output} - result, err := reader.Read() - if err != nil { - t.Errorf("Reading results failed") - } - - if got, want := len(result), 1; got != want { - t.Errorf("Expected single resource in the result. got %d", got) - } - for _, n := range result { - labels := n.GetLabels() - if got, ok := labels["label-key"]; !ok { - t.Error("label 'label-key' was not set") - } else if want := "label-value"; got != want { - t.Errorf("unexpected label-key value; got %q, want %q", got, want) - } - } -} diff --git a/porch/pkg/kpt/fnruntime.go b/porch/pkg/kpt/fnruntime.go deleted file mode 100644 index c553fb2357..0000000000 --- a/porch/pkg/kpt/fnruntime.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2022 The kpt 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. - -package kpt - -import ( - "io" - - "github.com/GoogleContainerTools/kpt/pkg/fn" -) - -type FunctionRuntime interface { - fn.FunctionRuntime - io.Closer -} diff --git a/porch/pkg/kpt/fs_test.go b/porch/pkg/kpt/fs_test.go deleted file mode 100644 index 490b58b197..0000000000 --- a/porch/pkg/kpt/fs_test.go +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright 2022 The kpt 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. - -package kpt - -import ( - "testing" - - "github.com/GoogleContainerTools/kpt/internal/fnruntime" - "github.com/GoogleContainerTools/kpt/internal/util/render" - "github.com/GoogleContainerTools/kpt/pkg/printer/fake" - "sigs.k8s.io/kustomize/kyaml/filesys" -) - -func TestMemFS(t *testing.T) { - fs := filesys.MakeFsInMemory() - - if err := fs.MkdirAll("a/b/c/"); err != nil { - t.Errorf("MkdirAll(\"a/b/c/\") failed %v", err) - } - if err := fs.MkdirAll("/d/e/f"); err != nil { - t.Errorf("MkdirAll(\"/d/e/f\") failed: %v", err) - } - if err := fs.WriteFile("/a/b/c/foo.txt", []byte("Hello World")); err != nil { - t.Errorf("Failed to write file: %v", err) - } - if res, err := fs.ReadFile("/a/b/c/foo.txt"); err != nil { - t.Errorf("Failed to read file: %v", err) - } else if got, want := string(res), "Hello World"; got != want { - t.Errorf("unexpected file contents: got %q, want %q", got, want) - } -} - -func TestMemFSRenderBasicPipeline(t *testing.T) { - resources := `apiVersion: apps/v1 -kind: Deployment -metadata: - name: nginx-deployment -spec: - replicas: 3 ---- -apiVersion: custom.io/v1 -kind: Custom -metadata: - name: custom -spec: - image: nginx:1.2.3` - - kptfile := `apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: app -pipeline: - mutators: - - image: gcr.io/kpt-fn/set-namespace:v0.4.1 - configMap: - namespace: staging - - image: gcr.io/kpt-fn/set-labels:v0.1.5 - configMap: - tier: backend` - - expectedResources := `apiVersion: apps/v1 -kind: Deployment -metadata: - name: nginx-deployment - namespace: staging - labels: - tier: backend -spec: - replicas: 3 ---- -apiVersion: custom.io/v1 -kind: Custom -metadata: - name: custom - namespace: staging - labels: - tier: backend -spec: - image: nginx:1.2.3 -` - - fs := filesys.MakeFsInMemory() - if err := fs.MkdirAll("a/b/c"); err != nil { - t.Errorf(`MkdirAll("a/b/c") failed %v`, err) - } - if err := fs.WriteFile("/a/b/c/resources.yaml", []byte(resources)); err != nil { - t.Errorf("Failed to write file: %v", err) - } - if err := fs.WriteFile("/a/b/c/Kptfile", []byte(kptfile)); err != nil { - t.Errorf("Failed to write file: %v", err) - } - r := render.Renderer{ - PkgPath: "/a/b/c", - FileSystem: fs, - Runtime: &runtime{}, - } - r.RunnerOptions.InitDefaults() - r.RunnerOptions.ImagePullPolicy = fnruntime.IfNotPresentPull - _, err := r.Execute(fake.CtxWithDefaultPrinter()) - if err != nil { - t.Errorf("Failed to render: %v", err) - } - - if res, err := fs.ReadFile("/a/b/c/resources.yaml"); err != nil { - t.Errorf("Failed to read file: %v", err) - } else if got, want := string(res), expectedResources; got != want { - t.Errorf("unexpected file contents: got %q, want %q", got, want) - } -} - -func TestMemFSRenderSubpkgs(t *testing.T) { - appResources := `apiVersion: apps/v1 -kind: Deployment -metadata: - name: nginx-deployment -spec: - replicas: 3 ---- -apiVersion: custom.io/v1 -kind: Custom -metadata: - name: custom -spec: - image: nginx:1.2.3` - - appKptfile := `apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: app-with-db -pipeline: - mutators: - - image: gcr.io/kpt-fn/set-namespace:v0.4.1 - configMap: - namespace: staging - - image: gcr.io/kpt-fn/set-labels:v0.1.5 - configMap: - tier: db` - - dbResources := `apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: db -spec: - replicas: 3` - dbKptfile := `apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: db -pipeline: - mutators: - - image: gcr.io/kpt-fn/set-namespace:v0.4.1 - configMap: - namespace: db - - image: gcr.io/kpt-fn/set-labels:v0.1.5 - configMap: - app: backend` - - expectedAppResources := `apiVersion: apps/v1 -kind: Deployment -metadata: - name: nginx-deployment - namespace: staging - labels: - tier: db -spec: - replicas: 3 ---- -apiVersion: custom.io/v1 -kind: Custom -metadata: - name: custom - namespace: staging - labels: - tier: db -spec: - image: nginx:1.2.3 -` - expectedDbResources := `apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: db - namespace: staging - labels: - app: backend - tier: db -spec: - replicas: 3 -` - fs := filesys.MakeFsInMemory() - if err := fs.MkdirAll("app/db"); err != nil { - t.Errorf(`MkdirAll("app/db") failed %v`, err) - } - if err := fs.WriteFile("/app/resources.yaml", []byte(appResources)); err != nil { - t.Errorf("Failed to write file: %v", err) - } - if err := fs.WriteFile("/app/Kptfile", []byte(appKptfile)); err != nil { - t.Errorf("Failed to write file: %v", err) - } - if err := fs.WriteFile("/app/db/resources.yaml", []byte(dbResources)); err != nil { - t.Errorf("Failed to write file: %v", err) - } - if err := fs.WriteFile("/app/db/Kptfile", []byte(dbKptfile)); err != nil { - t.Errorf("Failed to write file: %v", err) - } - - r := render.Renderer{ - PkgPath: "/app", - FileSystem: fs, - Runtime: &runtime{}, - } - r.RunnerOptions.InitDefaults() - r.RunnerOptions.ImagePullPolicy = fnruntime.IfNotPresentPull - - _, err := r.Execute(fake.CtxWithDefaultPrinter()) - if err != nil { - t.Errorf("Failed to render: %v", err) - } - - if res, err := fs.ReadFile("/app/resources.yaml"); err != nil { - t.Errorf("Failed to read file: %v", err) - } else if got, want := string(res), expectedAppResources; got != want { - println(got) - t.Errorf("unexpected file contents: got %q, want %q", got, want) - } - - if res, err := fs.ReadFile("/app/db/resources.yaml"); err != nil { - t.Errorf("Failed to read file: %v", err) - } else if got, want := string(res), expectedDbResources; got != want { - t.Errorf("unexpected file contents: got %q, want %q", got, want) - } -} diff --git a/porch/pkg/kpt/internal/apply-setters.go b/porch/pkg/kpt/internal/apply-setters.go deleted file mode 100644 index 2dab0f1063..0000000000 --- a/porch/pkg/kpt/internal/apply-setters.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2022 The kpt 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. - -package internal - -import ( - "fmt" - - function "github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/apply-setters/applysetters" - "sigs.k8s.io/kustomize/kyaml/fn/framework" -) - -func applySetters(rl *framework.ResourceList) error { - if rl.FunctionConfig == nil { - return nil // nothing to do - } - - var fn function.ApplySetters - function.Decode(rl.FunctionConfig, &fn) - if items, err := fn.Filter(rl.Items); err != nil { - return fmt.Errorf("apply-setter evaluation failed: %w", err) - } else { - rl.Items = items - } - return nil -} diff --git a/porch/pkg/kpt/internal/doc.go b/porch/pkg/kpt/internal/doc.go deleted file mode 100644 index f69bfb60c6..0000000000 --- a/porch/pkg/kpt/internal/doc.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2022 The kpt 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. - -// internal package containing implementation details of the package -// manipulation primitives. -package internal diff --git a/porch/pkg/kpt/internal/functions.go b/porch/pkg/kpt/internal/functions.go deleted file mode 100644 index 7e5683f6e7..0000000000 --- a/porch/pkg/kpt/internal/functions.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2022 The kpt 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. - -package internal - -import ( - "sigs.k8s.io/kustomize/kyaml/fn/framework" -) - -var functions map[string]framework.ResourceListProcessorFunc = map[string]framework.ResourceListProcessorFunc{ - "gcr.io/kpt-fn/apply-setters:v0.2.0": applySetters, - "gcr.io/kpt-fn/set-labels:v0.1.5": setLabels, - "gcr.io/kpt-fn/set-namespace:v0.4.1": setNamespace, -} - -func FindProcessor(image string) framework.ResourceListProcessorFunc { - return functions[image] -} diff --git a/porch/pkg/kpt/internal/set-labels.go b/porch/pkg/kpt/internal/set-labels.go deleted file mode 100644 index c3c34912e6..0000000000 --- a/porch/pkg/kpt/internal/set-labels.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2022 The kpt 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. - -package internal - -import ( - "errors" - - "sigs.k8s.io/kustomize/kyaml/fn/framework" - kyaml "sigs.k8s.io/kustomize/kyaml/yaml" -) - -func setLabels(rl *framework.ResourceList) error { - if rl.FunctionConfig == nil { - return nil // Done, nothing to do - } - - var labels map[string]string - if validGVK(rl.FunctionConfig, "v1", "ConfigMap") { - labels = rl.FunctionConfig.GetDataMap() - } else { - return errors.New("invalid set-labels function config; expected v1/ConfigMap") - } - - for _, n := range rl.Items { - l := n.GetLabels() - for k, v := range labels { - l[k] = v - } - n.SetLabels(l) - } - - return nil -} - -func validGVK(rn *kyaml.RNode, apiVersion, kind string) bool { - meta, err := rn.GetMeta() - if err != nil { - return false - } - if meta.APIVersion != apiVersion || meta.Kind != kind { - return false - } - return true -} diff --git a/porch/pkg/kpt/internal/set-namespace.go b/porch/pkg/kpt/internal/set-namespace.go deleted file mode 100644 index 65953e9080..0000000000 --- a/porch/pkg/kpt/internal/set-namespace.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2022 The kpt 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. - -package internal - -import ( - "fmt" - - "sigs.k8s.io/kustomize/kyaml/fn/framework" -) - -// Simple implementation of set-namespace kpt function, primarily for testing. -func setNamespace(rl *framework.ResourceList) error { - if rl.FunctionConfig == nil { - return nil // nothing to do - } - - if !validGVK(rl.FunctionConfig, "v1", "ConfigMap") { - return fmt.Errorf("invalid set-namespace function config type: %s/%s; expected v1/ConfigMap", rl.FunctionConfig.GetApiVersion(), rl.FunctionConfig.GetKind()) - } - - data := rl.FunctionConfig.GetDataMap() - if data == nil { - return nil // nothing to do - } - - namespace, ok := data["namespace"] - if !ok { - return nil // nothing to do - } - - for _, n := range rl.Items { - n.SetNamespace(namespace) - } - - return nil -} diff --git a/porch/pkg/kpt/pkgupdate.go b/porch/pkg/kpt/pkgupdate.go deleted file mode 100644 index 8c1bb5e65d..0000000000 --- a/porch/pkg/kpt/pkgupdate.go +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2022 The kpt 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. - -package kpt - -import ( - "context" - "fmt" - "os" - "path/filepath" - - internalpkg "github.com/GoogleContainerTools/kpt/internal/pkg" - "github.com/GoogleContainerTools/kpt/internal/util/fetch" - "github.com/GoogleContainerTools/kpt/internal/util/git" - "github.com/GoogleContainerTools/kpt/internal/util/update" - kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/pkg/kptfile/kptfileutil" - "github.com/GoogleContainerTools/kpt/pkg/printer" - "k8s.io/klog/v2" -) - -// PkgUpdateOpts are options for invoking kpt PkgUpdate -type PkgUpdateOpts struct { - Strategy string -} - -// PkgUpdate is a wrapper around `kpt pkg update`, running it against the package in packageDir -func PkgUpdate(ctx context.Context, ref string, packageDir string, opts PkgUpdateOpts) error { - // TODO: Printer should be a logr - pr := printer.New(os.Stdout, os.Stderr) - ctx = printer.WithContext(ctx, pr) - - // This code is based on the kpt pkg update code. - - fsys := os.DirFS(packageDir) - - f, err := fsys.Open("Kptfile") - if err != nil { - return fmt.Errorf("error opening kptfile: %w", err) - } - defer f.Close() - - kf, err := internalpkg.DecodeKptfile(f) - if err != nil { - return fmt.Errorf("error parsing kptfile: %w", err) - } - - if kf.Upstream == nil || kf.Upstream.Git == nil { - return fmt.Errorf("package must have an upstream reference") //errors.E(op, u.Pkg.UniquePath, - // fmt.Errorf("package must have an upstream reference")) - } - // originalRootKfRef := rootKf.Upstream.Git.Ref - if ref != "" { - kf.Upstream.Git.Ref = ref - } - // if u.Strategy != "" { - // rootKf.Upstream.UpdateStrategy = u.Strategy - // } - if err = kptfileutil.WriteFile(packageDir, kf); err != nil { - return err // errors.E(op, u.Pkg.UniquePath, err) - } - - // var updatedDigest string - var updatedRepoSpec git.RepoSpec - var updatedDir string - var originDir string - switch kf.Upstream.Type { - case kptfilev1.GitOrigin: - g := kf.Upstream.Git - upstream := &git.RepoSpec{OrgRepo: g.Repo, Path: g.Directory, Ref: g.Ref} - klog.Infof("Fetching upstream from %s@%s\n", upstream.OrgRepo, upstream.Ref) - // pr.Printf("Fetching upstream from %s@%s\n", kf.Upstream.Git.Repo, kf.Upstream.Git.Ref) - // if err := fetch.ClonerUsingGitExec(ctx, updated); err != nil { - // return errors.E(op, p.UniquePath, err) - // } - updated := *upstream - if err := fetch.NewCloner(&updated).ClonerUsingGitExec(ctx); err != nil { - return err - } - defer os.RemoveAll(updated.AbsPath()) - updatedDir = updated.AbsPath() - updatedRepoSpec = updated - - // var origin repoClone - if kf.UpstreamLock != nil { - gLock := kf.UpstreamLock.Git - originRepoSpec := &git.RepoSpec{OrgRepo: gLock.Repo, Path: gLock.Directory, Ref: gLock.Commit} - klog.Infof("Fetching origin from %s@%s\n", originRepoSpec.OrgRepo, originRepoSpec.Ref) - // pr.Printf("Fetching origin from %s@%s\n", kf.Upstream.Git.Repo, kf.Upstream.Git.Ref) - // if err := fetch.ClonerUsingGitExec(ctx, originRepoSpec); err != nil { - // return errors.E(op, p.UniquePath, err) - // } - if err := fetch.NewCloner(originRepoSpec).ClonerUsingGitExec(ctx); err != nil { - return err //errors.E(op, p.UniquePath, err) - } - originDir = originRepoSpec.AbsPath() - } else { - dir, err := os.MkdirTemp("", "kpt-empty-") - if err != nil { - return fmt.Errorf("failed to create tempdir: %w", err) - } - originDir = dir - // origin, err = newNilRepoClone() - // if err != nil { - // return errors.E(op, p.UniquePath, err) - // } - } - defer os.RemoveAll(originDir) - - // case kptfilev1.OciOrigin: - // options := &[]crane.Option{crane.WithAuthFromKeychain(gcrane.Keychain)} - // updatedDir, err = ioutil.TempDir("", "kpt-get-") - // if err != nil { - // return errors.E(op, errors.Internal, fmt.Errorf("error creating temp directory: %w", err)) - // } - // defer os.RemoveAll(updatedDir) - - // if err = fetch.ClonerUsingOciPull(ctx, kf.Upstream.Oci.Image, &updatedDigest, updatedDir, options); err != nil { - // return errors.E(op, p.UniquePath, err) - // } - - // if kf.UpstreamLock != nil { - // originDir, err = ioutil.TempDir("", "kpt-get-") - // if err != nil { - // return errors.E(op, errors.Internal, fmt.Errorf("error creating temp directory: %w", err)) - // } - // defer os.RemoveAll(originDir) - - // if err = fetch.ClonerUsingOciPull(ctx, kf.UpstreamLock.Oci.Image, nil, originDir, options); err != nil { - // return errors.E(op, p.UniquePath, err) - // } - // } else { - // origin, err := newNilRepoClone() - // if err != nil { - // return errors.E(op, p.UniquePath, err) - // } - // originDir = origin.AbsPath() - // defer os.RemoveAll(originDir) - // } - } - - // s := stack.New() - // s.Push(".") - - // for s.Len() > 0 { - { - // relPath := s.Pop() - relPath := "." - localPath := filepath.Join(packageDir, relPath) - updatedPath := filepath.Join(updatedDir, relPath) - originPath := filepath.Join(originDir, relPath) - isRoot := false - if relPath == "." { - isRoot = true - } - - // if err := u.updatePackage(ctx, relPath, localPath, updatedPath, originPath, isRoot); err != nil { - // return errors.E(op, p.UniquePath, err) - // } - - updateOptions := update.Options{ - RelPackagePath: relPath, - LocalPath: localPath, - UpdatedPath: updatedPath, - OriginPath: originPath, - IsRoot: isRoot, - } - updater := update.ResourceMergeUpdater{} - if err := updater.Update(updateOptions); err != nil { - return err - } - - // paths, err := pkgutil.FindSubpackagesForPaths(pkg.Remote, false, - // localPath, updatedPath, originPath) - // if err != nil { - // return errors.E(op, p.UniquePath, err) - // } - // for _, path := range paths { - // s.Push(filepath.Join(relPath, path)) - // } - } - - if err := kptfileutil.UpdateUpstreamLockFromGit(packageDir, &updatedRepoSpec); err != nil { - return err // errors.E(op, p.UniquePath, err) - } - - return nil -} diff --git a/porch/pkg/kpt/render.go b/porch/pkg/kpt/render.go deleted file mode 100644 index 572bee802e..0000000000 --- a/porch/pkg/kpt/render.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2022 The kpt 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. - -package kpt - -import ( - "context" - "fmt" - "io" - "os" - - "github.com/GoogleContainerTools/kpt/internal/fnruntime" - "github.com/GoogleContainerTools/kpt/internal/pkg" - "github.com/GoogleContainerTools/kpt/internal/util/render" - fnresult "github.com/GoogleContainerTools/kpt/pkg/api/fnresult/v1" - "github.com/GoogleContainerTools/kpt/pkg/fn" - "github.com/GoogleContainerTools/kpt/pkg/printer" - "k8s.io/klog/v2" - "sigs.k8s.io/kustomize/kyaml/filesys" -) - -func NewRenderer(runnerOptions fnruntime.RunnerOptions) fn.Renderer { - return &renderer{runnerOptions: runnerOptions} -} - -type renderer struct { - runnerOptions fnruntime.RunnerOptions -} - -var _ fn.Renderer = &renderer{} - -func (r *renderer) Render(ctx context.Context, pkg filesys.FileSystem, opts fn.RenderOptions) (*fnresult.ResultList, error) { - rr := render.Renderer{ - PkgPath: opts.PkgPath, - Runtime: opts.Runtime, - FileSystem: pkg, - RunnerOptions: r.runnerOptions, - } - return rr.Execute(printer.WithContext(ctx, &packagePrinter{})) -} - -type packagePrinter struct{} - -var _ printer.Printer = &packagePrinter{} - -func (p *packagePrinter) PrintPackage(pkg *pkg.Pkg, leadingNewline bool) { - p.Printf("Package %q: ", pkg.DisplayPath) -} - -func (p *packagePrinter) Printf(format string, args ...interface{}) { - klog.Infof(format, args...) -} - -func (p *packagePrinter) OptPrintf(opt *printer.Options, format string, args ...interface{}) { - if opt == nil { - p.Printf(format, args...) - return - } - var prefix string - if !opt.PkgDisplayPath.Empty() { - prefix = fmt.Sprintf("Package %q: ", string(opt.PkgDisplayPath)) - } else if !opt.PkgPath.Empty() { - prefix = fmt.Sprintf("Package %q: ", string(opt.PkgPath)) - } - p.Printf(prefix+format, args...) -} - -func (p *packagePrinter) OutStream() io.Writer { - return os.Stdout -} - -func (p *packagePrinter) ErrStream() io.Writer { - return os.Stderr -} diff --git a/porch/pkg/kpt/render_test.go b/porch/pkg/kpt/render_test.go deleted file mode 100644 index 08c5ffb726..0000000000 --- a/porch/pkg/kpt/render_test.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2022 The kpt 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. - -package kpt - -import ( - "bytes" - "os" - "path/filepath" - "testing" - - "github.com/GoogleContainerTools/kpt/internal/util/render" - "github.com/GoogleContainerTools/kpt/pkg/printer/fake" - "github.com/google/go-cmp/cmp" - "sigs.k8s.io/kustomize/kyaml/filesys" -) - -func readFile(t *testing.T, path string) []byte { - if data, err := os.ReadFile(path); err != nil { - t.Fatalf("Cannot read file %q", err) - return nil - } else { - return data - } -} - -func TestRender(t *testing.T) { - testdata, err := filepath.Abs(filepath.Join(".", "testdata")) - if err != nil { - t.Fatalf("Cannot compute absolute path for ./testdata: %v", err) - } - - for _, test := range []struct { - name string - pkg string - want string - }{ - { - name: "render-with-function-config", - pkg: "simple-bucket", - want: "expected.txt", - }, - { - name: "render-with-inline-config", - pkg: "simple-bucket", - want: "expected.txt", - }, - } { - t.Run(test.name, func(t *testing.T) { - var output bytes.Buffer - r := render.Renderer{ - PkgPath: filepath.Join(testdata, test.name, test.pkg), - Runtime: &runtime{}, - FileSystem: filesys.FileSystemOrOnDisk{}, - Output: &output, - } - r.RunnerOptions.InitDefaults() - - if _, err := r.Execute(fake.CtxWithDefaultPrinter()); err != nil { - t.Errorf("Render failed: %v", err) - } - - got := output.String() - want := readFile(t, filepath.Join(testdata, test.name, test.want)) - - if diff := cmp.Diff(string(want), string(got)); diff != "" { - t.Errorf("Unexpected result (-want, +got): %s", diff) - } - }) - } -} diff --git a/porch/pkg/kpt/testdata/bucket/bucket.yaml b/porch/pkg/kpt/testdata/bucket/bucket.yaml deleted file mode 100644 index 2a3a59d7df..0000000000 --- a/porch/pkg/kpt/testdata/bucket/bucket.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2022 The kpt 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. - -# Comment -apiVersion: storage.cnrm.cloud.google.com/v1beta1 -kind: StorageBucket -metadata: - name: blueprints-project-bucket - namespace: config-control -spec: - storageClass: standard diff --git a/porch/pkg/kpt/testdata/render-with-function-config/expected.txt b/porch/pkg/kpt/testdata/render-with-function-config/expected.txt deleted file mode 100644 index 9d731e1b6e..0000000000 --- a/porch/pkg/kpt/testdata/render-with-function-config/expected.txt +++ /dev/null @@ -1,94 +0,0 @@ -apiVersion: config.kubernetes.io/v1 -kind: ResourceList -items: -# Copyright 2022 The kpt 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. -- apiVersion: kpt.dev/v1 - kind: Kptfile - metadata: - name: simple-bucket - annotations: - blueprints.cloud.google.com/title: Google Cloud Storage Bucket blueprint - config.kubernetes.io/index: '0' - config.kubernetes.io/path: 'Kptfile' - internal.config.kubernetes.io/index: '0' - internal.config.kubernetes.io/path: 'Kptfile' - internal.config.kubernetes.io/seqindent: 'wide' - info: - description: A Google Cloud Storage bucket - pipeline: - mutators: - - image: gcr.io/kpt-fn/apply-setters:v0.2.0 - configPath: setters.yaml -# Copyright 2022 The kpt 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. -- apiVersion: storage.cnrm.cloud.google.com/v1beta1 - kind: StorageBucket - metadata: # kpt-merge: config-control/blueprints-project-bucket - name: updated-project-id-updated-bucket-name # kpt-set: ${project-id}-${name} - namespace: updated-namespace # kpt-set: ${namespace} - annotations: - cnrm.cloud.google.com/force-destroy: "false" - cnrm.cloud.google.com/project-id: updated-project-id # kpt-set: ${project-id} - cnrm.cloud.google.com/blueprint: 'kpt-fn' - config.kubernetes.io/index: '0' - config.kubernetes.io/path: 'bucket.yaml' - internal.config.kubernetes.io/index: '0' - internal.config.kubernetes.io/path: 'bucket.yaml' - internal.config.kubernetes.io/seqindent: 'compact' - spec: - storageClass: updated-storage-class # kpt-set: ${storage-class} - uniformBucketLevelAccess: true - versioning: - enabled: false -# Copyright 2022 The kpt 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. -- apiVersion: v1 - kind: ConfigMap - metadata: # kpt-merge: /setters - name: setters - annotations: - config.kubernetes.io/local-config: "true" - config.kubernetes.io/index: '0' - config.kubernetes.io/path: 'setters.yaml' - internal.config.kubernetes.io/index: '0' - internal.config.kubernetes.io/path: 'setters.yaml' - internal.config.kubernetes.io/seqindent: 'compact' - data: - name: updated-bucket-name - namespace: updated-namespace - project-id: updated-project-id - storage-class: updated-storage-class diff --git a/porch/pkg/kpt/testdata/render-with-function-config/simple-bucket/Kptfile b/porch/pkg/kpt/testdata/render-with-function-config/simple-bucket/Kptfile deleted file mode 100644 index 459ca2778b..0000000000 --- a/porch/pkg/kpt/testdata/render-with-function-config/simple-bucket/Kptfile +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: simple-bucket - annotations: - blueprints.cloud.google.com/title: Google Cloud Storage Bucket blueprint -info: - description: A Google Cloud Storage bucket -pipeline: - mutators: - - image: gcr.io/kpt-fn/apply-setters:v0.2.0 - configPath: setters.yaml diff --git a/porch/pkg/kpt/testdata/render-with-function-config/simple-bucket/bucket.yaml b/porch/pkg/kpt/testdata/render-with-function-config/simple-bucket/bucket.yaml deleted file mode 100644 index 5a5f3a2263..0000000000 --- a/porch/pkg/kpt/testdata/render-with-function-config/simple-bucket/bucket.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: storage.cnrm.cloud.google.com/v1beta1 -kind: StorageBucket -metadata: # kpt-merge: config-control/blueprints-project-bucket - name: updated-project-id-updated-bucket-name # kpt-set: ${project-id}-${name} - namespace: updated-namespace # kpt-set: ${namespace} - annotations: - cnrm.cloud.google.com/force-destroy: "false" - cnrm.cloud.google.com/project-id: updated-project-id # kpt-set: ${project-id} - cnrm.cloud.google.com/blueprint: 'kpt-fn' -spec: - storageClass: updated-storage-class # kpt-set: ${storage-class} - uniformBucketLevelAccess: true - versioning: - enabled: false diff --git a/porch/pkg/kpt/testdata/render-with-function-config/simple-bucket/setters.yaml b/porch/pkg/kpt/testdata/render-with-function-config/simple-bucket/setters.yaml deleted file mode 100644 index bc86e701e7..0000000000 --- a/porch/pkg/kpt/testdata/render-with-function-config/simple-bucket/setters.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: v1 -kind: ConfigMap -metadata: # kpt-merge: /setters - name: setters - annotations: - config.kubernetes.io/local-config: "true" -data: - name: updated-bucket-name - namespace: updated-namespace - project-id: updated-project-id - storage-class: updated-storage-class diff --git a/porch/pkg/kpt/testdata/render-with-inline-config/expected.txt b/porch/pkg/kpt/testdata/render-with-inline-config/expected.txt deleted file mode 100644 index f8829d7a2e..0000000000 --- a/porch/pkg/kpt/testdata/render-with-inline-config/expected.txt +++ /dev/null @@ -1,56 +0,0 @@ -apiVersion: config.kubernetes.io/v1 -kind: ResourceList -items: -- apiVersion: kpt.dev/v1 - kind: Kptfile - metadata: - name: simple-bucket - annotations: - blueprints.cloud.google.com/title: Google Cloud Storage Bucket blueprint - config.kubernetes.io/index: '0' - config.kubernetes.io/path: 'Kptfile' - internal.config.kubernetes.io/index: '0' - internal.config.kubernetes.io/path: 'Kptfile' - internal.config.kubernetes.io/seqindent: 'wide' - info: - description: A Google Cloud Storage bucket - pipeline: - mutators: - - image: gcr.io/kpt-fn/apply-setters:v0.2.0 - configMap: - name: updated-bucket-name - namespace: updated-namespace - project-id: updated-project-id - storage-class: updated-storage-class -# Copyright 2022 The kpt 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. -- apiVersion: storage.cnrm.cloud.google.com/v1beta1 - kind: StorageBucket - metadata: # kpt-merge: config-control/blueprints-project-bucket - name: updated-project-id-updated-bucket-name # kpt-set: ${project-id}-${name} - namespace: updated-namespace # kpt-set: ${namespace} - annotations: - cnrm.cloud.google.com/force-destroy: "false" - cnrm.cloud.google.com/project-id: updated-project-id # kpt-set: ${project-id} - cnrm.cloud.google.com/blueprint: 'kpt-fn' - config.kubernetes.io/index: '0' - config.kubernetes.io/path: 'bucket.yaml' - internal.config.kubernetes.io/index: '0' - internal.config.kubernetes.io/path: 'bucket.yaml' - internal.config.kubernetes.io/seqindent: 'compact' - spec: - storageClass: updated-storage-class # kpt-set: ${storage-class} - uniformBucketLevelAccess: true - versioning: - enabled: false diff --git a/porch/pkg/kpt/testdata/render-with-inline-config/simple-bucket/Kptfile b/porch/pkg/kpt/testdata/render-with-inline-config/simple-bucket/Kptfile deleted file mode 100644 index 3b8830b62e..0000000000 --- a/porch/pkg/kpt/testdata/render-with-inline-config/simple-bucket/Kptfile +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: kpt.dev/v1 -kind: Kptfile -metadata: - name: simple-bucket - annotations: - blueprints.cloud.google.com/title: Google Cloud Storage Bucket blueprint -info: - description: A Google Cloud Storage bucket -pipeline: - mutators: - - image: gcr.io/kpt-fn/apply-setters:v0.2.0 - configMap: - name: updated-bucket-name - namespace: updated-namespace - project-id: updated-project-id - storage-class: updated-storage-class diff --git a/porch/pkg/kpt/testdata/render-with-inline-config/simple-bucket/bucket.yaml b/porch/pkg/kpt/testdata/render-with-inline-config/simple-bucket/bucket.yaml deleted file mode 100644 index 5a5f3a2263..0000000000 --- a/porch/pkg/kpt/testdata/render-with-inline-config/simple-bucket/bucket.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2022 The kpt 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. - -apiVersion: storage.cnrm.cloud.google.com/v1beta1 -kind: StorageBucket -metadata: # kpt-merge: config-control/blueprints-project-bucket - name: updated-project-id-updated-bucket-name # kpt-set: ${project-id}-${name} - namespace: updated-namespace # kpt-set: ${namespace} - annotations: - cnrm.cloud.google.com/force-destroy: "false" - cnrm.cloud.google.com/project-id: updated-project-id # kpt-set: ${project-id} - cnrm.cloud.google.com/blueprint: 'kpt-fn' -spec: - storageClass: updated-storage-class # kpt-set: ${storage-class} - uniformBucketLevelAccess: true - versioning: - enabled: false diff --git a/porch/pkg/meta/fake/memorystore.go b/porch/pkg/meta/fake/memorystore.go deleted file mode 100644 index e0570bed5a..0000000000 --- a/porch/pkg/meta/fake/memorystore.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2022 The kpt 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. - -package fake - -import ( - "context" - - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/meta" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" -) - -// MemoryMetadataStore is an in-memory implementation of the MetadataStore interface. It -// means metadata about packagerevisions will be stored in memory, which is useful for testing. -type MemoryMetadataStore struct { - Metas []meta.PackageRevisionMeta -} - -var _ meta.MetadataStore = &MemoryMetadataStore{} - -func (m *MemoryMetadataStore) Get(ctx context.Context, namespacedName types.NamespacedName) (meta.PackageRevisionMeta, error) { - for _, meta := range m.Metas { - if meta.Name == namespacedName.Name && meta.Namespace == namespacedName.Namespace { - return meta, nil - } - } - return meta.PackageRevisionMeta{}, apierrors.NewNotFound( - schema.GroupResource{Group: "config.kpt.dev", Resource: "packagerevisions"}, - namespacedName.Name, - ) -} - -func (m *MemoryMetadataStore) List(ctx context.Context, repo *configapi.Repository) ([]meta.PackageRevisionMeta, error) { - return m.Metas, nil -} - -func (m *MemoryMetadataStore) Create(ctx context.Context, pkgRevMeta meta.PackageRevisionMeta, repoName string, pkgRevUID types.UID) (meta.PackageRevisionMeta, error) { - for _, m := range m.Metas { - if m.Name == pkgRevMeta.Name && m.Namespace == pkgRevMeta.Namespace { - return m, apierrors.NewAlreadyExists( - schema.GroupResource{Group: "config.kpt.dev", Resource: "packagerevisions"}, - m.Name, - ) - } - } - m.Metas = append(m.Metas, pkgRevMeta) - return pkgRevMeta, nil -} - -func (m *MemoryMetadataStore) Update(ctx context.Context, pkgRevMeta meta.PackageRevisionMeta) (meta.PackageRevisionMeta, error) { - i := -1 - for j, m := range m.Metas { - if m.Name == pkgRevMeta.Name && m.Namespace == pkgRevMeta.Namespace { - i = j - } - } - if i < 0 { - return meta.PackageRevisionMeta{}, apierrors.NewNotFound( - schema.GroupResource{Group: "config.porch.kpt.dev", Resource: "packagerevisions"}, - pkgRevMeta.Name, - ) - } - m.Metas[i] = pkgRevMeta - return pkgRevMeta, nil -} - -func (m *MemoryMetadataStore) Delete(ctx context.Context, namespacedName types.NamespacedName, _ bool) (meta.PackageRevisionMeta, error) { - var metas []meta.PackageRevisionMeta - found := false - var deletedMeta meta.PackageRevisionMeta - for _, m := range m.Metas { - if m.Name == namespacedName.Name && m.Namespace == namespacedName.Namespace { - found = true - deletedMeta = m - } else { - metas = append(metas, m) - } - } - if !found { - return meta.PackageRevisionMeta{}, apierrors.NewNotFound( - schema.GroupResource{Group: "config.kpt.dev", Resource: "packagerevisions"}, - namespacedName.Name, - ) - } - m.Metas = metas - return deletedMeta, nil -} diff --git a/porch/pkg/meta/store.go b/porch/pkg/meta/store.go deleted file mode 100644 index 17ca50bbea..0000000000 --- a/porch/pkg/meta/store.go +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright 2022 The kpt 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. - -package meta - -import ( - "context" - - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - internalapi "github.com/GoogleContainerTools/kpt/porch/internal/api/porchinternal/v1alpha1" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/trace" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/klog/v2" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -var tracer = otel.Tracer("meta") - -const ( - PkgRevisionRepoLabel = "internal.porch.kpt.dev/repository" - PkgRevisionFinalizer = "internal.porch.kpt.dev/packagerevision" -) - -var ( - packageRevisionGVK = porchapi.SchemeGroupVersion.WithKind("PackageRevision") -) - -// MetadataStore is the store for keeping metadata about PackageRevisions. Typical -// examples of metadata we want to keep is labels, annotations, owner references, and -// finalizers. -type MetadataStore interface { - Get(ctx context.Context, namespacedName types.NamespacedName) (PackageRevisionMeta, error) - List(ctx context.Context, repo *configapi.Repository) ([]PackageRevisionMeta, error) - Create(ctx context.Context, pkgRevMeta PackageRevisionMeta, repoName string, pkgRevUID types.UID) (PackageRevisionMeta, error) - Update(ctx context.Context, pkgRevMeta PackageRevisionMeta) (PackageRevisionMeta, error) - Delete(ctx context.Context, namespacedName types.NamespacedName, clearFinalizer bool) (PackageRevisionMeta, error) -} - -// PackageRevisionMeta contains metadata about a specific PackageRevision. The -// PackageRevision is identified by the name and namespace. -type PackageRevisionMeta struct { - Name string - Namespace string - Labels map[string]string - Annotations map[string]string - Finalizers []string - OwnerReferences []metav1.OwnerReference - DeletionTimestamp *metav1.Time -} - -var _ MetadataStore = &crdMetadataStore{} - -func NewCrdMetadataStore(coreClient client.Client) *crdMetadataStore { - return &crdMetadataStore{ - coreClient: coreClient, - } -} - -// crdMetadataStore is an implementation of the MetadataStore interface that -// stores metadata in a CRD. -type crdMetadataStore struct { - coreClient client.Client -} - -func (c *crdMetadataStore) Get(ctx context.Context, namespacedName types.NamespacedName) (PackageRevisionMeta, error) { - ctx, span := tracer.Start(ctx, "crdMetadataStore::Get", trace.WithAttributes()) - defer span.End() - - var internalPkgRev internalapi.PackageRev - err := c.coreClient.Get(ctx, namespacedName, &internalPkgRev) - if err != nil { - return PackageRevisionMeta{}, err - } - - return toPackageRevisionMeta(&internalPkgRev), nil -} - -func (c *crdMetadataStore) List(ctx context.Context, repo *configapi.Repository) ([]PackageRevisionMeta, error) { - ctx, span := tracer.Start(ctx, "crdMetadataStore::List", trace.WithAttributes()) - defer span.End() - - var internalPkgRevList internalapi.PackageRevList - err := c.coreClient.List(ctx, &internalPkgRevList, client.InNamespace(repo.Namespace), client.MatchingLabels(map[string]string{PkgRevisionRepoLabel: repo.Name})) - if err != nil { - return nil, err - } - var pkgRevMetas []PackageRevisionMeta - for _, ipr := range internalPkgRevList.Items { - pkgRevMetas = append(pkgRevMetas, toPackageRevisionMeta(&ipr)) - } - return pkgRevMetas, nil -} - -func (c *crdMetadataStore) Create(ctx context.Context, pkgRevMeta PackageRevisionMeta, repoName string, pkgRevUID types.UID) (PackageRevisionMeta, error) { - ctx, span := tracer.Start(ctx, "crdMetadataStore::Create", trace.WithAttributes()) - defer span.End() - - labels := pkgRevMeta.Labels - if labels == nil { - labels = make(map[string]string) - } - labels[PkgRevisionRepoLabel] = repoName - - ownerReferences := append(pkgRevMeta.OwnerReferences, metav1.OwnerReference{ - APIVersion: packageRevisionGVK.GroupVersion().String(), - Kind: packageRevisionGVK.Kind, - Name: pkgRevMeta.Name, - UID: pkgRevUID, - }) - - finalizers := append(pkgRevMeta.Finalizers, PkgRevisionFinalizer) - - internalPkgRev := internalapi.PackageRev{ - ObjectMeta: metav1.ObjectMeta{ - Name: pkgRevMeta.Name, - Namespace: pkgRevMeta.Namespace, - Labels: labels, - Annotations: pkgRevMeta.Annotations, - Finalizers: finalizers, - OwnerReferences: ownerReferences, - }, - } - klog.Infof("Creating packagerev %s/%s", internalPkgRev.Namespace, internalPkgRev.Name) - if err := c.coreClient.Create(ctx, &internalPkgRev); err != nil { - if apierrors.IsAlreadyExists(err) { - return c.Update(ctx, pkgRevMeta) - } - return PackageRevisionMeta{}, err - } - return toPackageRevisionMeta(&internalPkgRev), nil -} - -func (c *crdMetadataStore) Update(ctx context.Context, pkgRevMeta PackageRevisionMeta) (PackageRevisionMeta, error) { - ctx, span := tracer.Start(ctx, "crdMetadataStore::Update", trace.WithAttributes()) - defer span.End() - - var internalPkgRev internalapi.PackageRev - namespacedName := types.NamespacedName{ - Name: pkgRevMeta.Name, - Namespace: pkgRevMeta.Namespace, - } - err := c.coreClient.Get(ctx, namespacedName, &internalPkgRev) - if err != nil { - return PackageRevisionMeta{}, err - } - - // Copy updated labels to the CR and add the repository label - // that is only used on the CR. - var labels map[string]string - if pkgRevMeta.Labels != nil { - labels = pkgRevMeta.Labels - } else { - labels = make(map[string]string) - } - labels[PkgRevisionRepoLabel] = internalPkgRev.Labels[PkgRevisionRepoLabel] - internalPkgRev.Labels = labels - internalPkgRev.Annotations = pkgRevMeta.Annotations - - // Copy update ownerReferences to the CR and make sure to also - // add the ownerReferences pointing to the PackageRevision. - ownerReferences := pkgRevMeta.OwnerReferences - for _, or := range internalPkgRev.OwnerReferences { - if isPackageRevOwnerRef(or, internalPkgRev.Name) { - ownerReferences = append(ownerReferences, or) - } - } - internalPkgRev.OwnerReferences = ownerReferences - internalPkgRev.Finalizers = append(pkgRevMeta.Finalizers, PkgRevisionFinalizer) - - klog.Infof("Updating packagerev %s/%s", internalPkgRev.Namespace, internalPkgRev.Name) - if err := c.coreClient.Update(ctx, &internalPkgRev); err != nil { - return PackageRevisionMeta{}, err - } - return toPackageRevisionMeta(&internalPkgRev), nil -} - -func (c *crdMetadataStore) Delete(ctx context.Context, namespacedName types.NamespacedName, clearFinalizers bool) (PackageRevisionMeta, error) { - ctx, span := tracer.Start(ctx, "crdMetadataStore::Delete", trace.WithAttributes()) - defer span.End() - - var internalPkgRev internalapi.PackageRev - err := c.coreClient.Get(ctx, namespacedName, &internalPkgRev) - if err != nil { - return PackageRevisionMeta{}, err - } - - if clearFinalizers { - internalPkgRev.Finalizers = []string{} - if err = c.coreClient.Update(ctx, &internalPkgRev); err != nil { - return PackageRevisionMeta{}, err - } - } - - klog.Infof("Deleting packagerev %s/%s", internalPkgRev.Namespace, internalPkgRev.Name) - if err := c.coreClient.Delete(ctx, &internalPkgRev); err != nil { - return PackageRevisionMeta{}, err - } - return toPackageRevisionMeta(&internalPkgRev), nil -} - -func toPackageRevisionMeta(internalPkgRev *internalapi.PackageRev) PackageRevisionMeta { - labels := internalPkgRev.Labels - delete(labels, PkgRevisionRepoLabel) - - var ownerReferences []metav1.OwnerReference - for _, or := range internalPkgRev.OwnerReferences { - // Don't include ownerReference to the PackageRevision itself. It is - // only used by Porch internally. - if !isPackageRevOwnerRef(or, internalPkgRev.Name) { - ownerReferences = append(ownerReferences, or) - } - } - - var finalizers []string - for _, f := range internalPkgRev.Finalizers { - if f != PkgRevisionFinalizer { - finalizers = append(finalizers, f) - } - } - - return PackageRevisionMeta{ - Name: internalPkgRev.Name, - Namespace: internalPkgRev.Namespace, - Labels: labels, - Annotations: internalPkgRev.Annotations, - Finalizers: finalizers, - OwnerReferences: ownerReferences, - DeletionTimestamp: internalPkgRev.DeletionTimestamp, - } -} - -func isPackageRevOwnerRef(or metav1.OwnerReference, pkgRevName string) bool { - return or.APIVersion == packageRevisionGVK.GroupVersion().String() && - or.Kind == packageRevisionGVK.Kind && - or.Name == pkgRevName -} diff --git a/porch/pkg/objects/extract.go b/porch/pkg/objects/extract.go deleted file mode 100644 index c4dc75663f..0000000000 --- a/porch/pkg/objects/extract.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2023 The kpt 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. - -package objects - -import ( - "fmt" - "path" - "strings" - "unicode" - - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/klog/v2" - "sigs.k8s.io/yaml" -) - -type Parser struct { - IncludeLocalConfig bool -} - -func (p Parser) AsUnstructureds(resources map[string]string) ([]*unstructured.Unstructured, error) { - objectList, err := p.AsObjectList(resources) - if err != nil { - return nil, err - } - unstructureds, err := objectList.AsUnstructured() - if err != nil { - return nil, err - } - return unstructureds, nil -} - -func (p Parser) AsObjectList(resources map[string]string) (*ObjectList, error) { - var items []*Object - - for filePath, fileContents := range resources { - ext := path.Ext(filePath) - ext = strings.ToLower(ext) - - parse := false - switch ext { - case ".yaml", ".yml": - parse = true - - default: - klog.Warningf("ignoring non-yaml file %s", filePath) - } - - if !parse { - continue - } - // TODO: Use https://github.com/kubernetes-sigs/kustomize/blob/a5b61016bb40c30dd1b0a78290b28b2330a0383e/kyaml/kio/byteio_reader.go#L170 or similar? - for _, s := range strings.Split(fileContents, "\n---\n") { - if isWhitespace(s) { - continue - } - - raw := []byte(s) - u := &unstructured.Unstructured{} - if err := yaml.Unmarshal(raw, &u); err != nil { - return nil, fmt.Errorf("error parsing yaml from %s: %w", filePath, err) - } - - annotations := u.GetAnnotations() - - if !p.IncludeLocalConfig { - s := annotations["config.kubernetes.io/local-config"] - if s == "true" { - continue - } - } - - obj := &Object{ - filePath: filePath, - raw: raw, - u: u, - } - - // TODO: sync with kpt logic; skip objects marked with the local-only annotation - items = append(items, obj) - } - } - - return &ObjectList{Items: items}, nil -} - -func isWhitespace(s string) bool { - for _, r := range s { - if !unicode.IsSpace(r) { - return false - } - } - return true -} diff --git a/porch/pkg/objects/object.go b/porch/pkg/objects/object.go deleted file mode 100644 index 17fbb2f47d..0000000000 --- a/porch/pkg/objects/object.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2023 The kpt 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. - -package objects - -import ( - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" -) - -type Object struct { - filePath string - raw []byte - u *unstructured.Unstructured -} - -func (o *Object) AsUnstructured() (*unstructured.Unstructured, error) { - return o.u, nil -} diff --git a/porch/pkg/objects/objectlist.go b/porch/pkg/objects/objectlist.go deleted file mode 100644 index c0bb7f6d1e..0000000000 --- a/porch/pkg/objects/objectlist.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2023 The kpt 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. - -package objects - -import ( - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" -) - -type ObjectList struct { - Items []*Object -} - -func (o *ObjectList) AsUnstructured() ([]*unstructured.Unstructured, error) { - var out []*unstructured.Unstructured - for _, o := range o.Items { - u, err := o.AsUnstructured() - if err != nil { - return nil, err - } - out = append(out, u) - } - return out, nil -} diff --git a/porch/pkg/oci/doc.go b/porch/pkg/oci/doc.go deleted file mode 100644 index 425f97c995..0000000000 --- a/porch/pkg/oci/doc.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2022 The kpt 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. - -// OCI Repository Adapter -package oci diff --git a/porch/pkg/oci/function.go b/porch/pkg/oci/function.go deleted file mode 100644 index 504f12cf26..0000000000 --- a/porch/pkg/oci/function.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2022 The kpt 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. - -package oci - -import ( - "fmt" - "strings" - "time" - - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/google/go-containerregistry/pkg/name" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -const ( - ociImagePrefix = "dev.kpt.fn.meta." - FunctionTypesKey = ociImagePrefix + "types" - DescriptionKey = ociImagePrefix + "description" - DocumentationURLKey = ociImagePrefix + "documentationurl" - keywordsKey = ociImagePrefix + "keywords" - - fnConfigMetaPrefix = ociImagePrefix + "fnconfig." - // experimental: this field is very likely to be changed in the future. - ConfigMapFnKey = fnConfigMetaPrefix + "configmap.requiredfields" -) - -func AnnotationToSlice(annotation string) []string { - vals := strings.Split(annotation, ",") - var result []string - for _, val := range vals { - result = append(result, strings.TrimSpace(val)) - } - return result -} - -type functionMeta struct { - FunctionTypes []string - Description string - DocumentationUrl string - Keywords []string - // experimental: this field is very likely to be changed in the future. - FunctionConfigs []functionConfig -} - -// experimental: this struct is very likely to be changed in the future. -type functionConfig struct { - metav1.TypeMeta - RequiredFields []string -} - -type ociFunction struct { - ref name.Reference - tag name.Reference - name string - version string - created time.Time - meta *functionMeta - parent *ociRepository -} - -var _ repository.Function = &ociFunction{} - -// LINT.IfChange(Name) -func (f *ociFunction) Name() string { - return fmt.Sprintf("%s:%s:%s", f.parent.name, f.name, f.version) - // LINT.ThenChange(internal/fnruntime/container.go AddDefaultImagePathPrefix) -} - -func (f *ociFunction) GetFunction() (*v1alpha1.Function, error) { - var functionTypes []v1alpha1.FunctionType - for _, fnType := range f.meta.FunctionTypes { - switch { - case fnType == string(v1alpha1.FunctionTypeMutator): - functionTypes = append(functionTypes, v1alpha1.FunctionTypeMutator) - case fnType == string(v1alpha1.FunctionTypeValidator): - functionTypes = append(functionTypes, v1alpha1.FunctionTypeValidator) - default: - // unrecognized custom FunctionType - } - } - var fnConfigs []v1alpha1.FunctionConfig - for _, metaFnConfig := range f.meta.FunctionConfigs { - fnConfigs = append(fnConfigs, v1alpha1.FunctionConfig{ - TypeMeta: metaFnConfig.TypeMeta, - RequiredFields: metaFnConfig.RequiredFields, - }) - } - return &v1alpha1.Function{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Name: f.Name(), - Namespace: f.parent.namespace, - UID: "", - CreationTimestamp: metav1.Time{ - Time: f.created, - }, - }, - Spec: v1alpha1.FunctionSpec{ - Image: f.tag.Name(), - RepositoryRef: v1alpha1.RepositoryRef{ - Name: f.parent.name, - }, - FunctionTypes: functionTypes, - Description: f.meta.Description, - DocumentationUrl: f.meta.DocumentationUrl, - Keywords: f.meta.Keywords, - FunctionConfigs: fnConfigs, - }, - Status: v1alpha1.FunctionStatus{}, - }, nil -} - -func (f *ociFunction) GetCRD() (*configapi.Function, error) { - var functionTypes []configapi.FunctionType - for _, fnType := range f.meta.FunctionTypes { - switch { - case fnType == string(v1alpha1.FunctionTypeMutator): - functionTypes = append(functionTypes, configapi.FunctionTypeMutator) - case fnType == string(v1alpha1.FunctionTypeValidator): - functionTypes = append(functionTypes, configapi.FunctionTypeValidator) - default: - // unrecognized custom FunctionType - } - } - var fnConfigs []configapi.FunctionConfig - for _, metaFnConfig := range f.meta.FunctionConfigs { - fnConfigs = append(fnConfigs, configapi.FunctionConfig{ - TypeMeta: metaFnConfig.TypeMeta, - RequiredFields: metaFnConfig.RequiredFields, - }) - } - - name := fmt.Sprintf("%s.%s.%s", f.parent.name, f.name, f.version) - - return &configapi.Function{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: f.parent.namespace, - }, - Spec: configapi.FunctionSpec{ - Image: f.tag.Name(), - RepositoryRef: configapi.RepositoryRef{ - Name: f.parent.name, - }, - FunctionTypes: functionTypes, - Description: f.meta.Description, - DocumentationUrl: f.meta.DocumentationUrl, - Keywords: f.meta.Keywords, - FunctionConfigs: fnConfigs, - }, - }, nil -} - -// RepositoryStr is the repository part of the resource name, -// typically slash-separated. Last segment is the base function name. -func parseFunctionName(repositoryStr string) string { - slash := strings.LastIndex(repositoryStr, "/") - return repositoryStr[slash+1:] -} diff --git a/porch/pkg/oci/loader.go b/porch/pkg/oci/loader.go deleted file mode 100644 index 710cd28e4b..0000000000 --- a/porch/pkg/oci/loader.go +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright 2022 The kpt 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. - -package oci - -import ( - "archive/tar" - "context" - "encoding/json" - "fmt" - "io" - "io/fs" - "path/filepath" - "strings" - - "github.com/GoogleContainerTools/kpt/pkg/oci" - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/google/go-containerregistry/pkg/v1/mutate" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/trace" - "k8s.io/klog/v2" -) - -const ( - annotationKeyLifecycle = "kpt.dev/lifecycle" - annotationKeyRevision = "kpt.dev/revision" -) - -var tracer = otel.Tracer("oci") - -func (r *ociRepository) getLifecycle(ctx context.Context, imageRef oci.ImageDigestName) (v1alpha1.PackageRevisionLifecycle, error) { - ctx, span := tracer.Start(ctx, "ociRepository::getLifecycle", trace.WithAttributes( - attribute.Stringer("image", imageRef), - )) - defer span.End() - - ociImage, err := r.storage.ToRemoteImage(ctx, imageRef) - if err != nil { - return "", err - } - - manifest, err := r.storage.CachedManifest(ctx, ociImage) - if err != nil { - return "", fmt.Errorf("error fetching manifest for image: %w", err) - } - - lifecycleValue := manifest.Annotations[annotationKeyLifecycle] - switch lifecycleValue { - case "", string(v1alpha1.PackageRevisionLifecycleDraft): - return v1alpha1.PackageRevisionLifecycleDraft, nil - case string(v1alpha1.PackageRevisionLifecycleProposed): - return v1alpha1.PackageRevisionLifecycleProposed, nil - case string(v1alpha1.PackageRevisionLifecyclePublished): - return v1alpha1.PackageRevisionLifecyclePublished, nil - case string(v1alpha1.PackageRevisionLifecycleDeletionProposed): - return v1alpha1.PackageRevisionLifecycleDeletionProposed, nil - default: - return "", fmt.Errorf("unknown package revision lifecycle %q", lifecycleValue) - } -} - -func (r *ociRepository) getRevisionNumber(ctx context.Context, imageRef oci.ImageDigestName) (string, error) { - ctx, span := tracer.Start(ctx, "ociRepository::getRevision", trace.WithAttributes( - attribute.Stringer("image", imageRef), - )) - defer span.End() - - ociImage, err := r.storage.ToRemoteImage(ctx, imageRef) - if err != nil { - return "", err - } - - manifest, err := r.storage.CachedManifest(ctx, ociImage) - if err != nil { - return "", fmt.Errorf("error fetching manifest for image: %w", err) - } - - return manifest.Annotations[annotationKeyRevision], nil -} - -func (r *ociRepository) loadTasks(ctx context.Context, imageRef oci.ImageDigestName) ([]api.Task, error) { - ctx, span := tracer.Start(ctx, "ociRepository::loadTasks", trace.WithAttributes( - attribute.Stringer("image", imageRef), - )) - defer span.End() - - configFile, err := r.storage.CachedConfigFile(ctx, imageRef) - if err != nil { - return nil, fmt.Errorf("error fetching config for image: %w", err) - } - - var tasks []api.Task - for i := range configFile.History { - history := &configFile.History[i] - command := history.CreatedBy - if strings.HasPrefix(command, "kpt:") { - task := api.Task{} - b := []byte(strings.TrimPrefix(command, "kpt:")) - if err := json.Unmarshal(b, &task); err != nil { - klog.Warningf("failed to unmarshal task command %q: %w", command, err) - continue - } - tasks = append(tasks, task) - } else { - klog.Warningf("unknown task command in history %q", command) - } - } - - return tasks, nil -} - -func LookupImageTag(ctx context.Context, s *oci.Storage, imageName oci.ImageTagName) (*oci.ImageDigestName, error) { - ctx, span := tracer.Start(ctx, "Storage::LookupImageTag", trace.WithAttributes( - attribute.Stringer("image", imageName), - )) - defer span.End() - - ociImage, err := s.ToRemoteImage(ctx, imageName) - if err != nil { - return nil, err - } - - digest, err := ociImage.Digest() - if err != nil { - return nil, err - } - - return &oci.ImageDigestName{ - Image: imageName.Image, - Digest: digest.String(), - }, nil -} - -func LoadResources(ctx context.Context, s *oci.Storage, imageName *oci.ImageDigestName) (*repository.PackageResources, error) { - ctx, span := tracer.Start(ctx, "Storage::LoadResources", trace.WithAttributes( - attribute.Stringer("image", imageName), - )) - defer span.End() - - if imageName.Digest == "" { - // New package; no digest yet - return &repository.PackageResources{ - Contents: map[string]string{}, - }, nil - } - - fetcher := func() (io.ReadCloser, error) { - ociImage, err := s.ToRemoteImage(ctx, imageName) - if err != nil { - return nil, err - } - - reader := mutate.Extract(ociImage) - return reader, nil - } - - // We need the per-digest cache here because otherwise we have to make a network request to look up the manifest in remote.Image - // (this could be cached by the go-containerregistry library, for some reason it is not...) - // TODO: Is there then any real reason to _also_ have the image-layer cache? - f, err := oci.WithCacheFile(filepath.Join(s.GetCacheDir(), "resources", imageName.Digest), fetcher) - if err != nil { - return nil, err - } - defer f.Close() - - tarReader := tar.NewReader(f) - - // TODO: Check hash here? Or otherwise handle error? - resources, err := loadResourcesFromTar(ctx, tarReader) - if err != nil { - return nil, err - } - return resources, nil -} - -func loadResourcesFromTar(ctx context.Context, tarReader *tar.Reader) (*repository.PackageResources, error) { - resources := &repository.PackageResources{ - Contents: map[string]string{}, - } - - for { - hdr, err := tarReader.Next() - if err == io.EOF { - break - } - if err != nil { - return nil, err - } - path := hdr.Name - fileType := hdr.FileInfo().Mode().Type() - switch fileType { - case fs.ModeDir: - // Ignored - case fs.ModeSymlink: - // We probably don't want to support this; feels high-risk, low-reward - return nil, fmt.Errorf("package cannot contain symlink (%q)", path) - case 0: - b, err := io.ReadAll(tarReader) - if err != nil { - return nil, fmt.Errorf("error reading %q from image: %w", path, err) - } - resources.Contents[path] = string(b) - - default: - return nil, fmt.Errorf("package cannot unsupported entry type for %q (%v)", path, fileType) - - } - } - - return resources, nil -} diff --git a/porch/pkg/oci/mutate.go b/porch/pkg/oci/mutate.go deleted file mode 100644 index 502cf7526f..0000000000 --- a/porch/pkg/oci/mutate.go +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright 2022 The kpt 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. - -package oci - -import ( - "archive/tar" - "bytes" - "compress/gzip" - "context" - "encoding/json" - "fmt" - "io" - "path" - "strconv" - "time" - - "github.com/GoogleContainerTools/kpt/pkg/oci" - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/google/go-containerregistry/pkg/gcrane" - "github.com/google/go-containerregistry/pkg/name" - v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/google/go-containerregistry/pkg/v1/empty" - "github.com/google/go-containerregistry/pkg/v1/mutate" - "github.com/google/go-containerregistry/pkg/v1/remote" - "github.com/google/go-containerregistry/pkg/v1/stream" - "go.opentelemetry.io/otel/trace" - "k8s.io/apimachinery/pkg/types" - "k8s.io/klog/v2" -) - -func (r *ociRepository) CreatePackageRevision(ctx context.Context, obj *api.PackageRevision) (repository.PackageDraft, error) { - base := empty.Image - - packageName := obj.Spec.PackageName - ociRepo, err := name.NewRepository(path.Join(r.spec.Registry, packageName)) - if err != nil { - return nil, err - } - - if err := repository.ValidateWorkspaceName(obj.Spec.WorkspaceName); err != nil { - return nil, fmt.Errorf("failed to create packagerevision: %w", err) - } - - // digestName := ImageDigestName{} - return &ociPackageDraft{ - packageName: packageName, - parent: r, - tasks: []api.Task{}, - base: base, - tag: ociRepo.Tag(string(obj.Spec.WorkspaceName)), - lifecycle: v1alpha1.PackageRevisionLifecycleDraft, - }, nil -} - -func (r *ociRepository) UpdatePackageRevision(ctx context.Context, old repository.PackageRevision) (repository.PackageDraft, error) { - oldPackage := old.(*ociPackageRevision) - packageName := oldPackage.packageName - workspace := oldPackage.workspaceName - // digestName := oldPackage.digestName - - ociRepo, err := name.NewRepository(path.Join(r.spec.Registry, packageName)) - if err != nil { - return nil, err - } - - // TODO: Authentication must be set up correctly. Do we use: - // * Provided Service account? - // * Workload identity? - // * Caller credentials (is this possible with k8s apiserver)? - options := []remote.Option{ - remote.WithAuthFromKeychain(gcrane.Keychain), - remote.WithContext(ctx), - } - - ref := ociRepo.Tag(string(workspace)) - - base, err := remote.Image(ref, options...) - if err != nil { - return nil, fmt.Errorf("error fetching image %q: %w", ref, err) - } - - return &ociPackageDraft{ - packageName: packageName, - parent: r, - tasks: []api.Task{}, - base: base, - tag: ref, - lifecycle: oldPackage.Lifecycle(), - }, nil -} - -type ociPackageDraft struct { - packageName string - - created time.Time - - parent *ociRepository - - tasks []api.Task - - base v1.Image - tag name.Tag - addendums []mutate.Addendum - - lifecycle v1alpha1.PackageRevisionLifecycle // New value of the package revision lifecycle -} - -var _ repository.PackageDraft = (*ociPackageDraft)(nil) - -func (p *ociPackageDraft) UpdateResources(ctx context.Context, new *api.PackageRevisionResources, task *api.Task) error { - ctx, span := tracer.Start(ctx, "ociPackageDraft::UpdateResources", trace.WithAttributes()) - defer span.End() - - buf := bytes.NewBuffer(nil) - writer := tar.NewWriter(buf) - - // TODO: write only changes. - for k, v := range new.Spec.Resources { - b := ([]byte)(v) - blen := len(b) - - if err := writer.WriteHeader(&tar.Header{ - Name: k, - Size: int64(blen), - Mode: 0644, - ModTime: p.created, - AccessTime: p.created, - ChangeTime: p.created, - }); err != nil { - return fmt.Errorf("failed to write oci package tar header: %w", err) - } - - if n, err := writer.Write(b); err != nil { - return fmt.Errorf("failed to write oci package tar contents: %w", err) - } else if n != blen { - return fmt.Errorf("failed to write complete oci package tar content: %d of %d", n, blen) - } - } - - if err := writer.Close(); err != nil { - return fmt.Errorf("failed to finalize oci package tar content: %w", err) - } - - layer := stream.NewLayer(io.NopCloser(buf), stream.WithCompressionLevel(gzip.BestCompression)) - if err := remote.WriteLayer(p.tag.Repository, layer, remote.WithAuthFromKeychain(gcrane.Keychain)); err != nil { - return fmt.Errorf("failed to write remote layer: %w", err) - } - - taskJSON, err := json.Marshal(*task) - if err != nil { - return fmt.Errorf("failed to marshal task %T to json: %w", task, err) - } - - digest, err := layer.Digest() - if err != nil { - return fmt.Errorf("failed to get layer digets: %w", err) - } - - remoteLayer, err := remote.Layer( - p.tag.Context().Digest(digest.String()), - remote.WithAuthFromKeychain(gcrane.Keychain)) - if err != nil { - return fmt.Errorf("failed to create remote layer from digest: %w", err) - } - - p.addendums = append(p.addendums, mutate.Addendum{ - Layer: remoteLayer, - History: v1.History{ - Author: "kool kat", - Created: v1.Time{Time: p.created}, - CreatedBy: "kpt:" + string(taskJSON), - }, - }) - - p.tasks = append(p.tasks, *task) - - return nil -} - -func (p *ociPackageDraft) UpdateLifecycle(ctx context.Context, new api.PackageRevisionLifecycle) error { - p.lifecycle = new - return nil -} - -// Finish round of updates. -func (p *ociPackageDraft) Close(ctx context.Context) (repository.PackageRevision, error) { - ctx, span := tracer.Start(ctx, "ociPackageDraft::Close", trace.WithAttributes()) - defer span.End() - - ref := p.tag - option := remote.WithAuthFromKeychain(gcrane.Keychain) - - klog.Infof("pushing %s", ref) - - revision := "" - addendums := append([]mutate.Addendum{}, p.addendums...) - if p.lifecycle != "" { - if len(addendums) == 0 { - return nil, fmt.Errorf("cannot create empty layer") - // TODO: How do we create an empty layer ... failed to append image layers: unable to add a nil layer to the image - // Maybe https://github.com/google/go-containerregistry/blob/fc6ff852e45e4bfd4fe41e03d992118687d3ec21/pkg/v1/static/static_test.go#L28-L29 - // addendums = append(addendums, mutate.Addendum{ - // Annotations: map[string]string{ - // annotationKeyLifecycle: string(p.lifecycle), - // }, - // }) - } else { - addendum := &addendums[len(addendums)-1] - if addendum.Annotations == nil { - addendum.Annotations = make(map[string]string) - } - addendum.Annotations[annotationKeyLifecycle] = string(p.lifecycle) - - if v1alpha1.LifecycleIsPublished(p.lifecycle) { - r := p.parent - // Finalize the package revision. Assign it a revision number of latest + 1. - revisions, err := r.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{ - Package: p.packageName, - }) - if err != nil { - return nil, err - } - var revs []string - for _, rev := range revisions { - if api.LifecycleIsPublished(rev.Lifecycle()) { - revs = append(revs, rev.Key().Revision) - } - } - nextRevisionNumber, err := repository.NextRevisionNumber(revs) - if err != nil { - return nil, err - } - addendum.Annotations[annotationKeyRevision] = nextRevisionNumber - revision = nextRevisionNumber - } - } - } - - base := p.base - if base == nil { - base = empty.Image - } - img, err := mutate.Append(base, addendums...) - if err != nil { - return nil, fmt.Errorf("failed to append image layers: %w", err) - } - - // TODO: We have a race condition here; there's no way to indicate that we want to create / not update an existing tag - if err := remote.Write(ref, img, option); err != nil { - return nil, fmt.Errorf("failed to push image %s: %w", ref, err) - } - - // TODO: remote.Write should return the digest etc that was pushed - desc, err := remote.Get(ref, option) - if err != nil { - return nil, fmt.Errorf("error getting metadata for %s: %w", ref, err) - } - klog.Infof("desc %s", string(desc.Manifest)) - - digestName := oci.ImageDigestName{ - Image: ref.Name(), - Digest: desc.Digest.String(), - } - - configFile, err := p.parent.storage.CachedConfigFile(ctx, digestName) - if err != nil { - return nil, fmt.Errorf("error getting config file: %w", err) - } - - return p.parent.buildPackageRevision(ctx, digestName, p.packageName, v1alpha1.WorkspaceName(p.tag.TagStr()), revision, configFile.Created.Time) -} - -func constructResourceVersion(t time.Time) string { - return strconv.FormatInt(t.UnixNano(), 10) -} - -func constructUID(ref string) types.UID { - return types.UID("uid:" + ref) -} - -func (r *ociRepository) DeletePackageRevision(ctx context.Context, old repository.PackageRevision) error { - oldPackage := old.(*ociPackageRevision) - packageName := oldPackage.packageName - workspace := oldPackage.workspaceName - - ociRepo, err := name.NewRepository(path.Join(r.spec.Registry, packageName)) - if err != nil { - return err - } - - // TODO: Authentication must be set up correctly. Do we use: - // * Provided Service account? - // * Workload identity? - // * Caller credentials (is this possible with k8s apiserver)? - options := []remote.Option{ - remote.WithAuthFromKeychain(gcrane.Keychain), - remote.WithContext(ctx), - } - - ref := ociRepo.Tag(string(workspace)) - - klog.Infof("deleting %s", ref) - - if err := remote.Delete(ref, options...); err != nil { - return fmt.Errorf("error deleting image %q: %w", ref, err) - } - - return nil -} - -func (r *ociRepository) CreatePackage(ctx context.Context, obj *v1alpha1.Package) (repository.Package, error) { - return nil, fmt.Errorf("CreatePackage not supported for OCI packages") -} - -func (r *ociRepository) DeletePackage(ctx context.Context, obj repository.Package) error { - return fmt.Errorf("DeletePackage not supported for OCI packages") -} diff --git a/porch/pkg/oci/oci.go b/porch/pkg/oci/oci.go deleted file mode 100644 index fac7ccf5cc..0000000000 --- a/porch/pkg/oci/oci.go +++ /dev/null @@ -1,562 +0,0 @@ -// Copyright 2022 The kpt 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. - -package oci - -import ( - "bytes" - "context" - "crypto/sha1" - "crypto/sha256" - "encoding/hex" - "fmt" - "strings" - "time" - - "github.com/GoogleContainerTools/kpt/internal/pkg" - kptfile "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/pkg/oci" - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/google/go-containerregistry/pkg/gcrane" - "github.com/google/go-containerregistry/pkg/name" - v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/google/go-containerregistry/pkg/v1/google" - "github.com/google/go-containerregistry/pkg/v1/remote" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/klog/v2" -) - -func OpenRepository(name string, namespace string, content configapi.RepositoryContent, spec *configapi.OciRepository, deployment bool, storage *oci.Storage) (repository.Repository, error) { - return &ociRepository{ - name: name, - namespace: namespace, - content: content, - spec: *spec.DeepCopy(), - deployment: deployment, - storage: storage, - }, nil - -} - -type ociRepository struct { - name string - namespace string - content configapi.RepositoryContent - spec configapi.OciRepository - deployment bool - - storage *oci.Storage -} - -var _ repository.Repository = &ociRepository{} -var _ repository.FunctionRepository = &ociRepository{} - -func (r *ociRepository) Close() error { - return nil -} - -// there is probably a more efficient way to do this -func (r *ociRepository) Version(ctx context.Context) (string, error) { - ctx, span := tracer.Start(ctx, "ociRepository::Version") - defer span.End() - - if r.content != configapi.RepositoryContentPackage { - return "", nil - } - - ociRepo, err := name.NewRepository(r.spec.Registry) - if err != nil { - return "", err - } - - options := r.storage.CreateOptions(ctx) - - tags, err := google.List(ociRepo, options...) - if err != nil { - return "", err - } - - klog.Infof("tags: %#v", tags) - - b := bytes.Buffer{} - for _, childName := range tags.Children { - path := fmt.Sprintf("%s/%s", r.spec.Registry, childName) - child, err := name.NewRepository(path, name.StrictValidation) - if err != nil { - klog.Warningf("Cannot create nested repository %q: %v", path, err) - continue - } - - childTags, err := google.List(child, options...) - if err != nil { - klog.Warningf("Cannot list nested repository %q: %v", path, err) - continue - } - - // klog.Infof("childTags: %#v", childTags) - - for digest, m := range childTags.Manifests { - b.WriteString(digest) - mb, err := m.MarshalJSON() - if err != nil { - return "", err - } - b.Write(mb) - } - } - hash := sha256.Sum256(b.Bytes()) - return hex.EncodeToString(hash[:]), nil -} - -func (r *ociRepository) ListPackageRevisions(ctx context.Context, filter repository.ListPackageRevisionFilter) ([]repository.PackageRevision, error) { - if r.content != configapi.RepositoryContentPackage { - return []repository.PackageRevision{}, nil - } - - ctx, span := tracer.Start(ctx, "ociRepository::ListPackageRevisions") - defer span.End() - - ociRepo, err := name.NewRepository(r.spec.Registry) - if err != nil { - return nil, err - } - - options := r.storage.CreateOptions(ctx) - - tags, err := google.List(ociRepo, options...) - if err != nil { - return nil, err - } - - klog.Infof("tags: %#v", tags) - - var result []repository.PackageRevision - for _, childName := range tags.Children { - path := fmt.Sprintf("%s/%s", r.spec.Registry, childName) - child, err := name.NewRepository(path, name.StrictValidation) - if err != nil { - klog.Warningf("Cannot create nested repository %q: %v", path, err) - continue - } - - childTags, err := google.List(child, options...) - if err != nil { - klog.Warningf("Cannot list nested repository %q: %v", path, err) - continue - } - - // klog.Infof("childTags: %#v", childTags) - - for digest, m := range childTags.Manifests { - for _, tag := range m.Tags { - created := m.Created - if created.IsZero() { - created = m.Uploaded - } - - // ref := child.Tag(tag) - // ref := child.Digest(digest) - - p := &ociPackageRevision{ - // tagName: ImageTagName{ - // Image: child.Name(), - // Tag: tag, - // }, - digestName: oci.ImageDigestName{ - Image: child.Name(), - Digest: digest, - }, - packageName: childName, - workspaceName: v1alpha1.WorkspaceName(tag), - created: created, - parent: r, - resourceVersion: constructResourceVersion(m.Created), - } - p.uid = constructUID(p.packageName + ":" + string(p.workspaceName)) - - lifecycle, err := r.getLifecycle(ctx, p.digestName) - if err != nil { - return nil, err - } - p.lifecycle = lifecycle - - revision, err := r.getRevisionNumber(ctx, p.digestName) - if err != nil { - return nil, err - } - p.revision = revision - - tasks, err := r.loadTasks(ctx, p.digestName) - if err != nil { - return nil, err - } - p.tasks = tasks - - if filter.Matches(p) { - result = append(result, p) - } - } - } - } - - return result, nil -} - -func (r *ociRepository) ListPackages(ctx context.Context, filter repository.ListPackageFilter) ([]repository.Package, error) { - return nil, fmt.Errorf("ListPackages not supported for OCI packages") -} - -func (r *ociRepository) buildPackageRevision(ctx context.Context, name oci.ImageDigestName, packageName string, - workspace v1alpha1.WorkspaceName, revision string, created time.Time) (repository.PackageRevision, error) { - if r.content != configapi.RepositoryContentPackage { - return nil, fmt.Errorf("repository is not a package repo, type is %v", r.content) - } - - ctx, span := tracer.Start(ctx, "ociRepository::buildPackageRevision") - defer span.End() - - // for backwards compatibility with packages that existed before porch supported - // workspaces, we populate the workspaceName as the revision number if it is empty - if workspace == "" { - workspace = v1alpha1.WorkspaceName(revision) - } - - p := &ociPackageRevision{ - digestName: name, - packageName: packageName, - workspaceName: workspace, - revision: revision, - created: created, - parent: r, - resourceVersion: constructResourceVersion(created), - } - p.uid = constructUID(p.packageName + ":" + string(p.workspaceName)) - - lifecycle, err := r.getLifecycle(ctx, p.digestName) - if err != nil { - return nil, err - } - p.lifecycle = lifecycle - - tasks, err := r.loadTasks(ctx, p.digestName) - if err != nil { - return nil, err - } - p.tasks = tasks - - return p, nil -} - -func GetFunctionMeta(reference string, ctx context.Context) (*functionMeta, error) { - ref, err := name.ParseReference(reference) - if err != nil { - return nil, fmt.Errorf("parse image reference %v: %v", reference, err) - } - image, err := remote.Image(ref, remote.WithAuthFromKeychain(gcrane.Keychain), remote.WithContext(ctx)) - if err != nil { - return nil, fmt.Errorf("pull remote image %v: %v", reference, err) - } - manifest, err := image.Manifest() - if err != nil { - return nil, fmt.Errorf("get manifest from image %v: %v", reference, err) - } - return &functionMeta{ - FunctionTypes: GetSliceFromAnnotation(FunctionTypesKey, manifest), - Description: GetSingleFromAnnotation(DescriptionKey, manifest), - DocumentationUrl: GetSingleFromAnnotation(DocumentationURLKey, manifest), - Keywords: GetSliceFromAnnotation(keywordsKey, manifest), - FunctionConfigs: GetDefaultFunctionConfig(manifest), - }, nil -} - -func GetDefaultFunctionConfig(manifest *v1.Manifest) []functionConfig { - val, ok := manifest.Annotations[ConfigMapFnKey] - if !ok { - return nil - } - return []functionConfig{ - { - TypeMeta: metav1.TypeMeta{ - Kind: "ConfigMap", - APIVersion: "v1", - }, - RequiredFields: AnnotationToSlice(val), - }, - } -} - -func GetSliceFromAnnotation(key string, manifest *v1.Manifest) []string { - slice, ok := manifest.Annotations[key] - if !ok { - return nil - } - return AnnotationToSlice(slice) -} - -func GetSingleFromAnnotation(key string, manifest *v1.Manifest) string { - if val, ok := manifest.Annotations[key]; ok { - return val - } - return fmt.Sprintf("annotation %v unset", key) -} - -func (r *ociRepository) ListFunctions(ctx context.Context) ([]repository.Function, error) { - // Repository whose content type is not Function contains no Function resources. - if r.content != configapi.RepositoryContentFunction { - klog.Infof("Repository %q doesn't contain functions; contains %s", r.name, r.content) - return []repository.Function{}, nil - } - - ctx, span := tracer.Start(ctx, "ociRepository::ListFunctions") - defer span.End() - - ociRepo, err := name.NewRepository(r.spec.Registry) - if err != nil { - return nil, err - } - - options := r.storage.CreateOptions(ctx) - - result := []repository.Function{} - - err = google.Walk(ociRepo, func(repo name.Repository, tags *google.Tags, err error) error { - if err != nil { - klog.Warningf(" Walk %s encountered error: %v", repo, err) - return err - } - - if tags == nil { - return nil - } - - if cl := len(tags.Children); cl > 0 { - // Expect no manifests or tags - if ml, tl := len(tags.Manifests), len(tags.Tags); ml != 0 || tl != 0 { - return fmt.Errorf("OCI repository with children (%d) as well as Manifests (%d) or Tags (%d)", cl, ml, tl) - } - return nil - } - - functionName := parseFunctionName(repo.RepositoryStr()) - - for digest, manifest := range tags.Manifests { - // Only consider tagged images. - for _, tag := range manifest.Tags { - - created := manifest.Created - if created.IsZero() { - created = manifest.Uploaded - } - meta, err := GetFunctionMeta(repo.Digest(digest).Name(), ctx) - if err != nil { - klog.Warningf(" pull function %v error: %w", functionName, err) - continue - } - result = append(result, &ociFunction{ - ref: repo.Digest(digest), - tag: repo.Tag(tag), - name: functionName, - version: tag, - meta: meta, - created: created, - parent: r, - }) - } - } - - return nil - }, options...) - if err != nil { - return nil, err - } - - return result, nil -} - -type ociPackageRevision struct { - digestName oci.ImageDigestName - packageName string - revision string - workspaceName v1alpha1.WorkspaceName - created time.Time - resourceVersion string - uid types.UID - - parent *ociRepository - tasks []v1alpha1.Task - - lifecycle v1alpha1.PackageRevisionLifecycle -} - -func (p *ociPackageRevision) CachedIdentifier() repository.CachedIdentifier { - return repository.CachedIdentifier{Key: p.packageName + ":" + string(p.workspaceName), Version: p.resourceVersion} -} - -var _ repository.PackageRevision = &ociPackageRevision{} - -func (p *ociPackageRevision) GetResources(ctx context.Context) (*v1alpha1.PackageRevisionResources, error) { - resources, err := LoadResources(ctx, p.parent.storage, &p.digestName) - if err != nil { - return nil, err - } - - key := p.Key() - - return &v1alpha1.PackageRevisionResources{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevisionResources", - APIVersion: v1alpha1.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: p.KubeObjectName(), - Namespace: p.parent.namespace, - CreationTimestamp: metav1.Time{ - Time: p.created, - }, - ResourceVersion: p.resourceVersion, - UID: p.uid, - }, - Spec: v1alpha1.PackageRevisionResourcesSpec{ - PackageName: key.Package, - WorkspaceName: key.WorkspaceName, - Revision: key.Revision, - RepositoryName: key.Repository, - - Resources: resources.Contents, - }, - }, nil -} - -func (p *ociPackageRevision) KubeObjectName() string { - hash := sha1.Sum([]byte(fmt.Sprintf("%s:%s:%s", p.parent.name, p.packageName, p.workspaceName))) - return p.parent.name + "-" + hex.EncodeToString(hash[:]) -} - -func (p *ociPackageRevision) KubeObjectNamespace() string { - return p.parent.namespace -} - -func (p *ociPackageRevision) UID() types.UID { - return p.uid -} - -func (p *ociPackageRevision) ResourceVersion() string { - return p.resourceVersion -} - -func (p *ociPackageRevision) Key() repository.PackageRevisionKey { - return repository.PackageRevisionKey{ - Repository: p.parent.name, - Package: p.packageName, - Revision: p.revision, - WorkspaceName: p.workspaceName, - } -} - -func (p *ociPackageRevision) GetPackageRevision(ctx context.Context) (*v1alpha1.PackageRevision, error) { - key := p.Key() - - kf, err := p.GetKptfile(ctx) - if err != nil { - return nil, err - } - - return &v1alpha1.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: v1alpha1.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: p.KubeObjectName(), - Namespace: p.parent.namespace, - CreationTimestamp: metav1.Time{ - Time: p.created, - }, - ResourceVersion: p.resourceVersion, - UID: p.uid, - }, - Spec: v1alpha1.PackageRevisionSpec{ - PackageName: key.Package, - RepositoryName: key.Repository, - Revision: key.Revision, - WorkspaceName: key.WorkspaceName, - - Lifecycle: p.Lifecycle(), - Tasks: p.tasks, - ReadinessGates: repository.ToApiReadinessGates(kf), - }, - Status: v1alpha1.PackageRevisionStatus{ - // TODO: UpstreamLock, - Deployment: p.parent.deployment, - Conditions: repository.ToApiConditions(kf), - }, - }, nil -} - -func (p *ociPackageRevision) GetKptfile(ctx context.Context) (kptfile.KptFile, error) { - resources, err := LoadResources(ctx, p.parent.storage, &p.digestName) - if err != nil { - return kptfile.KptFile{}, fmt.Errorf("error loading package resources for %v: %w", p.digestName, err) - } - kfString, found := resources.Contents[kptfile.KptFileName] - if !found { - return kptfile.KptFile{}, fmt.Errorf("packagerevision does not have a Kptfile") - } - kf, err := pkg.DecodeKptfile(strings.NewReader(kfString)) - if err != nil { - return kptfile.KptFile{}, fmt.Errorf("error decoding Kptfile: %w", err) - } - return *kf, nil -} - -func (p *ociPackageRevision) GetUpstreamLock(context.Context) (kptfile.Upstream, kptfile.UpstreamLock, error) { - return kptfile.Upstream{}, kptfile.UpstreamLock{}, fmt.Errorf("UpstreamLock is not supported for OCI packages (%s)", p.KubeObjectName()) -} - -func (p *ociPackageRevision) GetLock() (kptfile.Upstream, kptfile.UpstreamLock, error) { - return kptfile.Upstream{}, kptfile.UpstreamLock{}, fmt.Errorf("Lock is not supported for OCI packages (%s)", p.KubeObjectName()) -} - -func (p *ociPackageRevision) Lifecycle() v1alpha1.PackageRevisionLifecycle { - return p.lifecycle -} - -// UpdateLifecycle should update the package revision lifecycle from DeletionProposed to Published or vice versa. -// -// This function is currently only partially implemented; it still needs to store whether the package has been -// proposed for deletion somewhere in OCI, probably as another OCI image with a "deletionProposed" tag. -func (p *ociPackageRevision) UpdateLifecycle(ctx context.Context, new v1alpha1.PackageRevisionLifecycle) error { - old := p.Lifecycle() - - if old == v1alpha1.PackageRevisionLifecyclePublished { - if new != v1alpha1.PackageRevisionLifecycleDeletionProposed { - return fmt.Errorf("invalid new lifecycle value: %q", new) - } - - // TODO: Create a "deletionProposed" OCI image tag. - p.lifecycle = v1alpha1.PackageRevisionLifecycleDeletionProposed - } - if old == v1alpha1.PackageRevisionLifecycleDeletionProposed { - if new != v1alpha1.PackageRevisionLifecyclePublished { - return fmt.Errorf("invalid new lifecycle value: %q", new) - } - - // TODO: Delete the "deletionProposed" OCI image tag. - p.lifecycle = v1alpha1.PackageRevisionLifecyclePublished - } - return nil -} diff --git a/porch/pkg/registry/porch/background.go b/porch/pkg/registry/porch/background.go deleted file mode 100644 index 642725593c..0000000000 --- a/porch/pkg/registry/porch/background.go +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - "fmt" - "time" - - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/cache" - "k8s.io/apimachinery/pkg/api/meta" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/klog/v2" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -func RunBackground(ctx context.Context, coreClient client.WithWatch, cache *cache.Cache) { - b := background{ - coreClient: coreClient, - cache: cache, - } - go b.run(ctx) -} - -// background manages background tasks -type background struct { - coreClient client.WithWatch - cache *cache.Cache -} - -const ( - minReconnectDelay = 1 * time.Second - maxReconnectDelay = 30 * time.Second -) - -// run will run until ctx is done -func (b *background) run(ctx context.Context) { - klog.Infof("Background routine starting ...") - - // Repository watch. - var events <-chan watch.Event - var watcher watch.Interface - var bookmark string - defer func() { - if watcher != nil { - watcher.Stop() - } - }() - - reconnect := newBackoffTimer(minReconnectDelay, maxReconnectDelay) - defer reconnect.Stop() - - // Start ticker - ticker := time.NewTicker(1 * time.Minute) - defer ticker.Stop() - -loop: - for { - select { - case <-reconnect.channel(): - var err error - klog.Infof("Starting watch ... ") - var obj configapi.RepositoryList - watcher, err = b.coreClient.Watch(ctx, &obj, &client.ListOptions{ - Raw: &v1.ListOptions{ - AllowWatchBookmarks: true, - ResourceVersion: bookmark, - }, - }) - if err != nil { - klog.Errorf("Cannot start watch: %v; will retry", err) - reconnect.backoff() - } else { - klog.Infof("Watch successfully started.") - events = watcher.ResultChan() - } - - case event, eventOk := <-events: - if !eventOk { - klog.Errorf("Watch event stream closed. Will restart watch from bookmark %q", bookmark) - watcher.Stop() - events = nil - watcher = nil - - // Initiate reconnect - reconnect.reset() - } else if repository, ok := event.Object.(*configapi.Repository); ok { - if event.Type == watch.Bookmark { - bookmark = repository.ResourceVersion - klog.Infof("Bookmark: %q", bookmark) - } else { - if err := b.updateCache(ctx, event.Type, repository); err != nil { - klog.Warningf("error updating cache: %v", err) - } - } - } else { - klog.V(5).Infof("Received unexpected watch event Object: %T", event.Object) - } - - case t := <-ticker.C: - klog.Infof("Background task %s", t) - if err := b.runOnce(ctx); err != nil { - klog.Errorf("Periodic repository refresh failed: %v", err) - } - - case <-ctx.Done(): - if ctx.Err() != nil { - klog.V(2).Infof("exiting background poller, because context is done: %v", ctx.Err()) - } else { - klog.Infof("Background routine exiting; context done") - } - break loop - } - } -} - -func (b *background) updateCache(ctx context.Context, event watch.EventType, repository *configapi.Repository) error { - switch event { - case watch.Added: - klog.Infof("Repository added: %s:%s", repository.ObjectMeta.Namespace, repository.ObjectMeta.Name) - return b.cacheRepository(ctx, repository) - case watch.Modified: - klog.Infof("Repository modified: %s:%s", repository.ObjectMeta.Namespace, repository.ObjectMeta.Name) - // TODO: implement - case watch.Deleted: - klog.Infof("Repository deleted: %s:%s", repository.ObjectMeta.Namespace, repository.ObjectMeta.Name) - shared, err := b.isSharedRepository(ctx, repository) - if err != nil { - return err - } - // Only close the repository if no other k8s repository resources references - // the same underlying git/oci repo. - if !shared { - return b.cache.CloseRepository(repository) - } - return nil - default: - klog.Warning("Unhandled watch event type: %s", event) - } - return nil -} - -// isSharedRepository checks if the underlying git/oci repo of the provided -// k8s repository is also used by another repository. -func (b *background) isSharedRepository(ctx context.Context, repo *configapi.Repository) (bool, error) { - var obj configapi.RepositoryList - if err := b.coreClient.List(ctx, &obj); err != nil { - return false, err - } - for _, r := range obj.Items { - if r.Name == repo.Name && r.Namespace == repo.Namespace { - continue - } - if r.Spec.Type != repo.Spec.Type { - continue - } - switch r.Spec.Type { - case configapi.RepositoryTypeOCI: - if r.Spec.Oci.Registry == repo.Spec.Oci.Registry { - return true, nil - } - case configapi.RepositoryTypeGit: - if r.Spec.Git.Repo == repo.Spec.Git.Repo && r.Spec.Git.Directory == repo.Spec.Git.Directory { - return true, nil - } - default: - return false, fmt.Errorf("type %q not supported", r.Spec.Type) - } - } - return false, nil -} - -func (b *background) runOnce(ctx context.Context) error { - klog.Infof("background-refreshing repositories") - var repositories configapi.RepositoryList - if err := b.coreClient.List(ctx, &repositories); err != nil { - return fmt.Errorf("error listing repository objects: %w", err) - } - - for i := range repositories.Items { - repo := &repositories.Items[i] - - if err := b.cacheRepository(ctx, repo); err != nil { - klog.Errorf("Failed to cache repository: %v", err) - } - } - - return nil -} - -func (b *background) cacheRepository(ctx context.Context, repo *configapi.Repository) error { - var condition v1.Condition - if _, err := b.cache.OpenRepository(ctx, repo); err == nil { - condition = v1.Condition{ - Type: configapi.RepositoryReady, - Status: v1.ConditionTrue, - ObservedGeneration: repo.Generation, - LastTransitionTime: v1.Now(), - Reason: configapi.ReasonReady, - } - } else { - condition = v1.Condition{ - Type: configapi.RepositoryReady, - Status: v1.ConditionFalse, - ObservedGeneration: repo.Generation, - LastTransitionTime: v1.Now(), - Reason: configapi.ReasonError, - Message: err.Error(), - } - } - - meta.SetStatusCondition(&repo.Status.Conditions, condition) - if err := b.coreClient.Status().Update(ctx, repo); err != nil { - return fmt.Errorf("error updating repository status: %w", err) - } - return nil -} - -type backoffTimer struct { - min, max, curr time.Duration - timer *time.Timer -} - -func newBackoffTimer(min, max time.Duration) *backoffTimer { - return &backoffTimer{ - min: min, - max: max, - timer: time.NewTimer(min), - } -} - -func (t *backoffTimer) Stop() bool { - return t.timer.Stop() -} - -func (t *backoffTimer) channel() <-chan time.Time { - return t.timer.C -} - -func (t *backoffTimer) reset() bool { - t.curr = t.min - return t.timer.Reset(t.curr) -} - -func (t *backoffTimer) backoff() bool { - curr := t.curr * 2 - if curr > t.max { - curr = t.max - } - t.curr = curr - return t.timer.Reset(curr) -} diff --git a/porch/pkg/registry/porch/errors.go b/porch/pkg/registry/porch/errors.go deleted file mode 100644 index f2b2372cfe..0000000000 --- a/porch/pkg/registry/porch/errors.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - "fmt" - "net/http" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - genericapirequest "k8s.io/apiserver/pkg/endpoints/request" -) - -type errNotAcceptable struct { - resource schema.GroupResource -} - -func (e errNotAcceptable) Error() string { - return fmt.Sprintf("%s does not support Table format", e.resource) -} - -func (e errNotAcceptable) Status() metav1.Status { - return metav1.Status{ - Status: metav1.StatusFailure, - Message: e.Error(), - Reason: metav1.StatusReasonNotAcceptable, - Code: http.StatusNotAcceptable, - } -} - -func newResourceNotAcceptableError(ctx context.Context, resource schema.GroupResource) error { - if info, ok := genericapirequest.RequestInfoFrom(ctx); ok { - resource = schema.GroupResource{ - Group: info.APIGroup, - Resource: info.Resource, - } - } - return errNotAcceptable{ - resource: resource, - } -} diff --git a/porch/pkg/registry/porch/fieldselector.go b/porch/pkg/registry/porch/fieldselector.go deleted file mode 100644 index 16b61364a0..0000000000 --- a/porch/pkg/registry/porch/fieldselector.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "fmt" - - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/selection" -) - -// convertPackageRevisionFieldSelector is the schema conversion function for normalizing the the FieldSelector for PackageRevision -func convertPackageFieldSelector(label, value string) (internalLabel, internalValue string, err error) { - switch label { - case "metadata.name": - return label, value, nil - case "metadata.namespace": - return label, value, nil - case "spec.packageName", "spec.repository": - return label, value, nil - default: - return "", "", fmt.Errorf("%q is not a known field selector", label) - } -} - -// convertPackageRevisionFieldSelector is the schema conversion function for normalizing the the FieldSelector for PackageRevision -func convertPackageRevisionFieldSelector(label, value string) (internalLabel, internalValue string, err error) { - switch label { - case "metadata.name": - return label, value, nil - case "metadata.namespace": - return label, value, nil - case "spec.revision", "spec.packageName", "spec.repository": - return label, value, nil - default: - return "", "", fmt.Errorf("%q is not a known field selector", label) - } -} - -// convertPackageRevisionResourcesFieldSelector is the schema conversion function for normalizing the the FieldSelector for PackageRevisionResources -func convertPackageRevisionResourcesFieldSelector(label, value string) (internalLabel, internalValue string, err error) { - return convertPackageRevisionFieldSelector(label, value) -} - -// packageRevisionFilter filters packages, extending repository.ListPackageRevisionFilter -type packageRevisionFilter struct { - repository.ListPackageRevisionFilter - - // Namespace filters by the namespace of the objects - Namespace string - - // Repository restricts to repositories with the given name. - Repository string -} - -// packageFilter filters packages, extending repository.ListPackageFilter -type packageFilter struct { - repository.ListPackageFilter - - // Namespace filters by the namespace of the objects - Namespace string - - // Repository restricts to repositories with the given name. - Repository string -} - -// parsePackageFieldSelector parses client-provided fields.Selector into a packageFilter -func parsePackageFieldSelector(fieldSelector fields.Selector) (packageFilter, error) { - var filter packageFilter - - if fieldSelector == nil { - return filter, nil - } - - requirements := fieldSelector.Requirements() - for _, requirement := range requirements { - - switch requirement.Operator { - case selection.Equals, selection.DoesNotExist: - if requirement.Value == "" { - return filter, apierrors.NewBadRequest(fmt.Sprintf("unsupported fieldSelector value %q for field %q with operator %q", requirement.Value, requirement.Field, requirement.Operator)) - } - default: - return filter, apierrors.NewBadRequest(fmt.Sprintf("unsupported fieldSelector operator %q for field %q", requirement.Operator, requirement.Field)) - } - - switch requirement.Field { - case "metadata.name": - filter.KubeObjectName = requirement.Value - - case "metadata.namespace": - filter.Namespace = requirement.Value - - case "spec.packageName": - filter.Package = requirement.Value - case "spec.repository": - filter.Repository = requirement.Value - - default: - return filter, apierrors.NewBadRequest(fmt.Sprintf("unknown fieldSelector field %q", requirement.Field)) - } - } - - return filter, nil -} - -// parsePackageRevisionFieldSelector parses client-provided fields.Selector into a packageRevisionFilter -func parsePackageRevisionFieldSelector(fieldSelector fields.Selector) (packageRevisionFilter, error) { - var filter packageRevisionFilter - - if fieldSelector == nil { - return filter, nil - } - - requirements := fieldSelector.Requirements() - for _, requirement := range requirements { - - switch requirement.Operator { - case selection.Equals, selection.DoesNotExist: - if requirement.Value == "" { - return filter, apierrors.NewBadRequest(fmt.Sprintf("unsupported fieldSelector value %q for field %q with operator %q", requirement.Value, requirement.Field, requirement.Operator)) - } - default: - return filter, apierrors.NewBadRequest(fmt.Sprintf("unsupported fieldSelector operator %q for field %q", requirement.Operator, requirement.Field)) - } - - switch requirement.Field { - case "metadata.name": - filter.KubeObjectName = requirement.Value - - case "metadata.namespace": - filter.Namespace = requirement.Value - - case "spec.revision": - filter.Revision = requirement.Value - case "spec.packageName": - filter.Package = requirement.Value - case "spec.repository": - filter.Repository = requirement.Value - - default: - return filter, apierrors.NewBadRequest(fmt.Sprintf("unknown fieldSelector field %q", requirement.Field)) - } - } - - return filter, nil -} - -// parsePackageRevisionResourcesFieldSelector parses client-provided fields.Selector into a packageRevisionFilter -func parsePackageRevisionResourcesFieldSelector(fieldSelector fields.Selector) (packageRevisionFilter, error) { - // TOOD: This is a little weird, because we don't have the same fields on PackageRevisionResources. - // But we probably should have the key fields - return parsePackageRevisionFieldSelector(fieldSelector) -} diff --git a/porch/pkg/registry/porch/functions.go b/porch/pkg/registry/porch/functions.go deleted file mode 100644 index 32474f1348..0000000000 --- a/porch/pkg/registry/porch/functions.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - "fmt" - "strings" - - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/engine" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/apiserver/pkg/registry/rest" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -type functions struct { - rest.TableConvertor - - cad engine.CaDEngine - coreClient client.Client -} - -var _ rest.Storage = &functions{} -var _ rest.Scoper = &functions{} -var _ rest.Lister = &functions{} -var _ rest.Getter = &functions{} - -func (f *functions) New() runtime.Object { - return &v1alpha1.Function{} -} - -func (f *functions) Destroy() {} - -func (f *functions) NamespaceScoped() bool { - return true -} - -func (f *functions) NewList() runtime.Object { - return &v1alpha1.FunctionList{} -} - -// List selects resources in the storage which match to the selector. 'options' can be nil. -func (f *functions) List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) { - var opts []client.ListOption - if ns, ok := request.NamespaceFrom(ctx); ok { - opts = append(opts, client.InNamespace(ns)) - } - - var repositories configapi.RepositoryList - if err := f.coreClient.List(ctx, &repositories, opts...); err != nil { - return nil, fmt.Errorf("failed to list registered repositories: %w", err) - } - - result := &v1alpha1.FunctionList{} - - for i := range repositories.Items { - repo := &repositories.Items[i] - fns, err := f.cad.ListFunctions(ctx, repo) - if err != nil { - return nil, fmt.Errorf("failed to list repository %s functions: %w", repositories.Items[i].Name, err) - } - for _, f := range fns { - api, err := f.GetFunction() - if err != nil { - return nil, fmt.Errorf("failed to get function details %s: %w", f.Name(), err) - } - result.Items = append(result.Items, *api) - } - } - - return result, nil -} - -func (f *functions) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { - var repositoryKey client.ObjectKey - if ns, ok := request.NamespaceFrom(ctx); !ok { - return nil, apierrors.NewBadRequest("namespace must be specified") - } else { - repositoryKey.Namespace = ns - } - - if fn, err := parseFunctionName(name); err != nil { - return nil, apierrors.NewNotFound(schema.GroupResource(v1alpha1.FunctionGVR.GroupResource()), name) - } else { - repositoryKey.Name = fn.repository - } - - var repository configapi.Repository - if err := f.coreClient.Get(ctx, repositoryKey, &repository); err != nil { - if apierrors.IsNotFound(err) { - return nil, apierrors.NewNotFound(schema.GroupResource(v1alpha1.FunctionGVR.GroupResource()), name) - } - return nil, fmt.Errorf("error getting repository %s: %w", repositoryKey, err) - } - - // TODO: implement get to avoid listing - fns, err := f.cad.ListFunctions(ctx, &repository) - if err != nil { - return nil, fmt.Errorf("failed to list repository %s functions: %w", repository.Name, err) - } - - for _, f := range fns { - if f.Name() == name { - return f.GetFunction() - } - } - - return nil, apierrors.NewNotFound(schema.GroupResource(v1alpha1.FunctionGVR.GroupResource()), name) -} - -type functionName struct { - repository, name, version string -} - -func parseFunctionName(name string) (functionName, error) { - var result functionName - - parts := strings.SplitN(name, ":", 3) - if len(parts) != 3 { - return result, fmt.Errorf("invalid name %q; expect name in the format ::", name) - } - - result.repository = parts[0] - result.name = parts[1] - result.version = parts[2] - - return result, nil -} diff --git a/porch/pkg/registry/porch/name.go b/porch/pkg/registry/porch/name.go deleted file mode 100644 index b200421b03..0000000000 --- a/porch/pkg/registry/porch/name.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "fmt" - "strings" -) - -func ParseRepositoryName(name string) (string, error) { - lastDash := strings.LastIndex(name, "-") - if lastDash < 0 { - return "", fmt.Errorf("malformed package revision name; expected at least one hyphen: %q", name) - } - return name[:lastDash], nil -} diff --git a/porch/pkg/registry/porch/package.go b/porch/pkg/registry/porch/package.go deleted file mode 100644 index aa225570b9..0000000000 --- a/porch/pkg/registry/porch/package.go +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - "fmt" - - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/engine" - "go.opentelemetry.io/otel/trace" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - genericapirequest "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/apiserver/pkg/registry/rest" - "k8s.io/klog/v2" -) - -type packages struct { - packageCommon - rest.TableConvertor -} - -var _ rest.Storage = &packages{} -var _ rest.Lister = &packages{} -var _ rest.Getter = &packages{} -var _ rest.Scoper = &packages{} -var _ rest.Creater = &packages{} -var _ rest.Updater = &packages{} -var _ rest.GracefulDeleter = &packages{} - -func (r *packages) New() runtime.Object { - return &api.Package{} -} - -func (r *packages) Destroy() {} - -func (r *packages) NewList() runtime.Object { - return &api.PackageList{} -} - -func (r *packages) NamespaceScoped() bool { - return true -} - -// List selects resources in the storage which match to the selector. 'options' can be nil. -func (r *packages) List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) { - ctx, span := tracer.Start(ctx, "packages::List", trace.WithAttributes()) - defer span.End() - - result := &api.PackageList{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageList", - APIVersion: api.SchemeGroupVersion.Identifier(), - }, - } - - filter, err := parsePackageFieldSelector(options.FieldSelector) - if err != nil { - return nil, err - } - - if err := r.packageCommon.listPackages(ctx, filter, func(p *engine.Package) error { - item := p.GetPackage() - result.Items = append(result.Items, *item) - return nil - }); err != nil { - return nil, err - } - - return result, nil -} - -// Get implements the Getter interface -func (r *packages) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { - ctx, span := tracer.Start(ctx, "packages::Get", trace.WithAttributes()) - defer span.End() - - pkg, err := r.getPackage(ctx, name) - if err != nil { - return nil, err - } - - obj := pkg.GetPackage() - return obj, nil -} - -// Create implements the Creater interface. -func (r *packages) Create(ctx context.Context, runtimeObject runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) { - ctx, span := tracer.Start(ctx, "packages::Create", trace.WithAttributes()) - defer span.End() - - ns, namespaced := genericapirequest.NamespaceFrom(ctx) - if !namespaced { - return nil, apierrors.NewBadRequest("namespace must be specified") - } - - obj, ok := runtimeObject.(*api.Package) - if !ok { - return nil, apierrors.NewBadRequest(fmt.Sprintf("expected Package object, got %T", runtimeObject)) - } - - // TODO: Accpept some form of client-provided name, for example using GenerateName - // and figure out where we can store it (in Kptfile?). Porch can then append unique - // suffix to the names while respecting client-provided value as well. - if obj.Name != "" { - klog.Warningf("Client provided metadata.name %q", obj.Name) - } - - repositoryName := obj.Spec.RepositoryName - if repositoryName == "" { - return nil, apierrors.NewBadRequest("spec.repository is required") - } - - repositoryObj, err := r.packageCommon.getRepositoryObj(ctx, types.NamespacedName{Name: repositoryName, Namespace: ns}) - if err != nil { - return nil, err - } - - fieldErrors := r.createStrategy.Validate(ctx, runtimeObject) - if len(fieldErrors) > 0 { - return nil, apierrors.NewInvalid(api.SchemeGroupVersion.WithKind("Package").GroupKind(), obj.Name, fieldErrors) - } - - rev, err := r.cad.CreatePackage(ctx, repositoryObj, obj) - if err != nil { - return nil, apierrors.NewInternalError(err) - } - - created := rev.GetPackage() - return created, nil -} - -// Update implements the Updater interface. - -// Update finds a resource in the storage and updates it. Some implementations -// may allow updates creates the object - they should set the created boolean -// to true. -func (r *packages) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { - ctx, span := tracer.Start(ctx, "packages::Update", trace.WithAttributes()) - defer span.End() - - return r.packageCommon.updatePackage(ctx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options) -} - -// Delete implements the GracefulDeleter interface. -// Delete finds a resource in the storage and deletes it. -// The delete attempt is validated by the deleteValidation first. -// If options are provided, the resource will attempt to honor them or return an invalid -// request error. -// Although it can return an arbitrary error value, IsNotFound(err) is true for the -// returned error value err when the specified resource is not found. -// Delete *may* return the object that was deleted, or a status object indicating additional -// information about deletion. -// It also returns a boolean which is set to true if the resource was instantly -// deleted or false if it will be deleted asynchronously. -func (r *packages) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { - ctx, span := tracer.Start(ctx, "packages::Delete", trace.WithAttributes()) - defer span.End() - - // TODO: Verify options are empty? - - ns, namespaced := genericapirequest.NamespaceFrom(ctx) - if !namespaced { - return nil, false, apierrors.NewBadRequest("namespace must be specified") - } - - oldPackage, err := r.packageCommon.getPackage(ctx, name) - if err != nil { - return nil, false, err - } - - oldObj := oldPackage.GetPackage() - repositoryObj, err := r.packageCommon.validateDelete(ctx, deleteValidation, oldObj, name, ns) - if err != nil { - return nil, false, err - } - - if err := r.cad.DeletePackage(ctx, repositoryObj, oldPackage); err != nil { - return nil, false, apierrors.NewInternalError(err) - } - - // TODO: Should we do an async delete? - return oldObj, true, nil -} diff --git a/porch/pkg/registry/porch/packagecommon.go b/porch/pkg/registry/porch/packagecommon.go deleted file mode 100644 index 6dd26a5580..0000000000 --- a/porch/pkg/registry/porch/packagecommon.go +++ /dev/null @@ -1,466 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - "fmt" - - unversionedapi "github.com/GoogleContainerTools/kpt/porch/api/porch" - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/engine" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - apierrors "k8s.io/apimachinery/pkg/api/errors" - 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/types" - genericapirequest "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/apiserver/pkg/registry/rest" - "k8s.io/klog/v2" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -type packageCommon struct { - // scheme holds our scheme, for type conversions etc - scheme *runtime.Scheme - - cad engine.CaDEngine - // coreClient is a client back to the core kubernetes API server, useful for querying CRDs etc - coreClient client.Client - gr schema.GroupResource - updateStrategy SimpleRESTUpdateStrategy - createStrategy SimpleRESTCreateStrategy -} - -func (r *packageCommon) listPackageRevisions(ctx context.Context, filter packageRevisionFilter, selector labels.Selector, callback func(p *engine.PackageRevision) error) error { - var opts []client.ListOption - if ns, namespaced := genericapirequest.NamespaceFrom(ctx); namespaced { - opts = append(opts, client.InNamespace(ns)) - - if filter.Namespace != "" && ns != filter.Namespace { - return fmt.Errorf("conflicting namespaces specified: %q and %q", ns, filter.Namespace) - } - } - - // TODO: Filter on filter.Repository? - var repositories configapi.RepositoryList - if err := r.coreClient.List(ctx, &repositories, opts...); err != nil { - return fmt.Errorf("error listing repository objects: %w", err) - } - - for i := range repositories.Items { - repositoryObj := &repositories.Items[i] - - if filter.Repository != "" && filter.Repository != repositoryObj.GetName() { - continue - } - - revisions, err := r.cad.ListPackageRevisions(ctx, repositoryObj, filter.ListPackageRevisionFilter) - if err != nil { - klog.Warningf("error listing package revisions from repository %s/%s: %s", repositoryObj.GetNamespace(), repositoryObj.GetName(), err) - continue - } - for _, rev := range revisions { - apiPkgRev, err := rev.GetPackageRevision(ctx) - if err != nil { - return err - } - - if selector != nil && !selector.Matches(labels.Set(apiPkgRev.Labels)) { - continue - } - - if err := callback(rev); err != nil { - return err - } - } - } - return nil -} - -func (r *packageCommon) listPackages(ctx context.Context, filter packageFilter, callback func(p *engine.Package) error) error { - var opts []client.ListOption - if ns, namespaced := genericapirequest.NamespaceFrom(ctx); namespaced { - opts = append(opts, client.InNamespace(ns)) - - if filter.Namespace != "" && ns != filter.Namespace { - return fmt.Errorf("conflicting namespaces specified: %q and %q", ns, filter.Namespace) - } - } - - // TODO: Filter on filter.Repository? - var repositories configapi.RepositoryList - if err := r.coreClient.List(ctx, &repositories, opts...); err != nil { - return fmt.Errorf("error listing repository objects: %w", err) - } - - for i := range repositories.Items { - repositoryObj := &repositories.Items[i] - - if filter.Repository != "" && filter.Repository != repositoryObj.GetName() { - continue - } - - revisions, err := r.cad.ListPackages(ctx, repositoryObj, filter.ListPackageFilter) - if err != nil { - klog.Warningf("error listing packages from repository %s/%s: %s", repositoryObj.GetNamespace(), repositoryObj.GetName(), err) - continue - } - for _, rev := range revisions { - if err := callback(rev); err != nil { - return err - } - } - } - return nil -} - -func (r *packageCommon) watchPackages(ctx context.Context, filter packageRevisionFilter, callback engine.ObjectWatcher) error { - if err := r.cad.ObjectCache().WatchPackageRevisions(ctx, filter.ListPackageRevisionFilter, callback); err != nil { - return err - } - - return nil -} - -func (r *packageCommon) getRepositoryObjFromName(ctx context.Context, name string) (*configapi.Repository, error) { - ns, namespaced := genericapirequest.NamespaceFrom(ctx) - if !namespaced { - return nil, fmt.Errorf("namespace must be specified") - } - repositoryName, err := ParseRepositoryName(name) - if err != nil { - return nil, apierrors.NewNotFound(r.gr, name) - } - - return r.getRepositoryObj(ctx, types.NamespacedName{Name: repositoryName, Namespace: ns}) -} - -func (r *packageCommon) getRepositoryObj(ctx context.Context, repositoryID types.NamespacedName) (*configapi.Repository, error) { - var repositoryObj configapi.Repository - if err := r.coreClient.Get(ctx, repositoryID, &repositoryObj); err != nil { - if apierrors.IsNotFound(err) { - return nil, apierrors.NewNotFound(configapi.TypeRepository.GroupResource(), repositoryID.Name) - } - return nil, apierrors.NewInternalError(fmt.Errorf("error getting repository %v: %w", repositoryID, err)) - } - return &repositoryObj, nil -} - -func (r *packageCommon) getRepoPkgRev(ctx context.Context, name string) (*engine.PackageRevision, error) { - repositoryObj, err := r.getRepositoryObjFromName(ctx, name) - if err != nil { - return nil, err - } - revisions, err := r.cad.ListPackageRevisions(ctx, repositoryObj, repository.ListPackageRevisionFilter{KubeObjectName: name}) - if err != nil { - return nil, err - } - for _, rev := range revisions { - if rev.KubeObjectName() == name { - return rev, nil - } - } - - return nil, apierrors.NewNotFound(r.gr, name) -} - -func (r *packageCommon) getPackage(ctx context.Context, name string) (*engine.Package, error) { - repositoryObj, err := r.getRepositoryObjFromName(ctx, name) - if err != nil { - return nil, err - } - - revisions, err := r.cad.ListPackages(ctx, repositoryObj, repository.ListPackageFilter{KubeObjectName: name}) - if err != nil { - return nil, err - } - for _, rev := range revisions { - if rev.KubeObjectName() == name { - return rev, nil - } - } - - return nil, apierrors.NewNotFound(r.gr, name) -} - -// Common implementation of PackageRevision update logic. -func (r *packageCommon) updatePackageRevision(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { - // TODO: Is this all boilerplate?? - - ns, namespaced := genericapirequest.NamespaceFrom(ctx) - if !namespaced { - return nil, false, apierrors.NewBadRequest("namespace must be specified") - } - - // isCreate tracks whether this is an update that creates an object (this happens in server-side apply) - isCreate := false - - oldRepoPkgRev, err := r.getRepoPkgRev(ctx, name) - if err != nil { - if forceAllowCreate && apierrors.IsNotFound(err) { - // For server-side apply, we can create the object here - isCreate = true - } else { - return nil, false, err - } - } - - var oldApiPkgRev runtime.Object // We have to be runtime.Object (and not *api.PackageRevision) or else nil-checks fail (because a nil object is not a nil interface) - if !isCreate { - oldApiPkgRev, err = oldRepoPkgRev.GetPackageRevision(ctx) - if err != nil { - return nil, false, err - } - } - - newRuntimeObj, err := objInfo.UpdatedObject(ctx, oldApiPkgRev) - if err != nil { - klog.Infof("update failed to construct UpdatedObject: %v", err) - return nil, false, err - } - - // This type conversion is necessary because mutations work with unversioned types - // (mostly for historical reasons). So the server-side-apply library returns an unversioned object. - if unversioned, isUnversioned := newRuntimeObj.(*unversionedapi.PackageRevision); isUnversioned { - klog.Warningf("converting from unversioned to versioned object") - typed := &api.PackageRevision{} - if err := r.scheme.Convert(unversioned, typed, nil); err != nil { - return nil, false, fmt.Errorf("failed to convert %T to %T: %w", unversioned, typed, err) - } - newRuntimeObj = typed - } - - if err := r.validateUpdate(ctx, newRuntimeObj, oldApiPkgRev, isCreate, createValidation, - updateValidation, "PackageRevision", name); err != nil { - return nil, false, err - } - - newApiPkgRev, ok := newRuntimeObj.(*api.PackageRevision) - if !ok { - return nil, false, apierrors.NewBadRequest(fmt.Sprintf("expected PackageRevision object, got %T", newRuntimeObj)) - } - - repositoryName, err := ParseRepositoryName(name) - if err != nil { - return nil, false, apierrors.NewBadRequest(fmt.Sprintf("invalid name %q", name)) - } - if isCreate { - repositoryName = newApiPkgRev.Spec.RepositoryName - if repositoryName == "" { - return nil, false, apierrors.NewBadRequest(fmt.Sprintf("invalid repositoryName %q", name)) - } - } - - var repositoryObj configapi.Repository - repositoryID := types.NamespacedName{Namespace: ns, Name: repositoryName} - if err := r.coreClient.Get(ctx, repositoryID, &repositoryObj); err != nil { - if apierrors.IsNotFound(err) { - return nil, false, apierrors.NewNotFound(configapi.TypeRepository.GroupResource(), repositoryID.Name) - } - return nil, false, apierrors.NewInternalError(fmt.Errorf("error getting repository %v: %w", repositoryID, err)) - } - - var parentPackage *engine.PackageRevision - if newApiPkgRev.Spec.Parent != nil && newApiPkgRev.Spec.Parent.Name != "" { - p, err := r.getRepoPkgRev(ctx, newApiPkgRev.Spec.Parent.Name) - if err != nil { - return nil, false, fmt.Errorf("cannot get parent package %q: %w", newApiPkgRev.Spec.Parent.Name, err) - } - parentPackage = p - } - - if !isCreate { - rev, err := r.cad.UpdatePackageRevision(ctx, &repositoryObj, oldRepoPkgRev, oldApiPkgRev.(*api.PackageRevision), newApiPkgRev, parentPackage) - if err != nil { - return nil, false, apierrors.NewInternalError(err) - } - - updated, err := rev.GetPackageRevision(ctx) - if err != nil { - return nil, false, apierrors.NewInternalError(err) - } - - return updated, false, nil - } else { - rev, err := r.cad.CreatePackageRevision(ctx, &repositoryObj, newApiPkgRev, parentPackage) - if err != nil { - klog.Infof("error creating package: %v", err) - return nil, false, apierrors.NewInternalError(err) - } - createdApiPkgRev, err := rev.GetPackageRevision(ctx) - if err != nil { - return nil, false, apierrors.NewInternalError(err) - } - - return createdApiPkgRev, true, nil - } -} - -// Common implementation of Package update logic. -func (r *packageCommon) updatePackage(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { - // TODO: Is this all boilerplate?? - - ns, namespaced := genericapirequest.NamespaceFrom(ctx) - if !namespaced { - return nil, false, apierrors.NewBadRequest("namespace must be specified") - } - - // isCreate tracks whether this is an update that creates an object (this happens in server-side apply) - isCreate := false - - oldPackage, err := r.getPackage(ctx, name) - if err != nil { - if forceAllowCreate && apierrors.IsNotFound(err) { - // For server-side apply, we can create the object here - isCreate = true - } else { - return nil, false, err - } - } - - var oldRuntimeObj runtime.Object // We have to be runtime.Object (and not *api.PackageRevision) or else nil-checks fail (because a nil object is not a nil interface) - if !isCreate { - oldRuntimeObj = oldPackage.GetPackage() - } - - newRuntimeObj, err := objInfo.UpdatedObject(ctx, oldRuntimeObj) - if err != nil { - klog.Infof("update failed to construct UpdatedObject: %v", err) - return nil, false, err - } - - // This type conversion is necessary because mutations work with unversioned types - // (mostly for historical reasons). So the server-side-apply library returns an unversioned object. - if unversioned, isUnversioned := newRuntimeObj.(*unversionedapi.PackageRevision); isUnversioned { - klog.Warningf("converting from unversioned to versioned object") - typed := &api.PackageRevision{} - if err := r.scheme.Convert(unversioned, typed, nil); err != nil { - return nil, false, fmt.Errorf("failed to convert %T to %T: %w", unversioned, typed, err) - } - newRuntimeObj = typed - } - - if err := r.validateUpdate(ctx, newRuntimeObj, oldRuntimeObj, isCreate, createValidation, - updateValidation, "Package", name); err != nil { - return nil, false, err - } - - newObj, ok := newRuntimeObj.(*api.Package) - if !ok { - return nil, false, apierrors.NewBadRequest(fmt.Sprintf("expected Package object, got %T", newRuntimeObj)) - } - - repositoryName, err := ParseRepositoryName(name) - if err != nil { - return nil, false, apierrors.NewBadRequest(fmt.Sprintf("invalid name %q", name)) - } - if isCreate { - repositoryName = newObj.Spec.RepositoryName - if repositoryName == "" { - return nil, false, apierrors.NewBadRequest(fmt.Sprintf("invalid repositoryName %q", name)) - } - } - - var repositoryObj configapi.Repository - repositoryID := types.NamespacedName{Namespace: ns, Name: repositoryName} - if err := r.coreClient.Get(ctx, repositoryID, &repositoryObj); err != nil { - if apierrors.IsNotFound(err) { - return nil, false, apierrors.NewNotFound(configapi.TypeRepository.GroupResource(), repositoryID.Name) - } - return nil, false, apierrors.NewInternalError(fmt.Errorf("error getting repository %v: %w", repositoryID, err)) - } - - if !isCreate { - rev, err := r.cad.UpdatePackage(ctx, &repositoryObj, oldPackage, oldRuntimeObj.(*api.Package), newObj) - if err != nil { - return nil, false, apierrors.NewInternalError(err) - } - - updated := rev.GetPackage() - - return updated, false, nil - } else { - rev, err := r.cad.CreatePackage(ctx, &repositoryObj, newObj) - if err != nil { - klog.Infof("error creating package: %v", err) - return nil, false, apierrors.NewInternalError(err) - } - - created := rev.GetPackage() - return created, true, nil - } -} - -func (r *packageCommon) validateDelete(ctx context.Context, deleteValidation rest.ValidateObjectFunc, obj runtime.Object, - repoName string, ns string) (*configapi.Repository, error) { - if deleteValidation != nil { - err := deleteValidation(ctx, obj) - if err != nil { - klog.Infof("delete failed validation: %v", err) - return nil, err - } - } - repositoryName, err := ParseRepositoryName(repoName) - if err != nil { - return nil, apierrors.NewBadRequest(fmt.Sprintf("invalid name %q", repoName)) - } - repositoryObj, err := r.getRepositoryObj(ctx, types.NamespacedName{Name: repositoryName, Namespace: ns}) - if err != nil { - return nil, err - } - return repositoryObj, nil -} - -func (r *packageCommon) validateUpdate(ctx context.Context, newRuntimeObj runtime.Object, oldRuntimeObj runtime.Object, create bool, - createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, kind string, name string) error { - r.updateStrategy.PrepareForUpdate(ctx, newRuntimeObj, oldRuntimeObj) - - if create { - if createValidation != nil { - err := createValidation(ctx, newRuntimeObj) - if err != nil { - klog.Infof("update failed create validation: %v", err) - return err - } - } - - fieldErrors := r.createStrategy.Validate(ctx, newRuntimeObj) - if len(fieldErrors) > 0 { - return apierrors.NewInvalid(api.SchemeGroupVersion.WithKind(kind).GroupKind(), name, fieldErrors) - } - } - - if !create { - if updateValidation != nil { - err := updateValidation(ctx, newRuntimeObj, oldRuntimeObj) - if err != nil { - klog.Infof("update failed validation: %v", err) - return err - } - } - - fieldErrors := r.updateStrategy.ValidateUpdate(ctx, newRuntimeObj, oldRuntimeObj) - if len(fieldErrors) > 0 { - return apierrors.NewInvalid(api.SchemeGroupVersion.WithKind(kind).GroupKind(), name, fieldErrors) - } - } - - r.updateStrategy.Canonicalize(newRuntimeObj) - return nil -} diff --git a/porch/pkg/registry/porch/packagerevision.go b/porch/pkg/registry/porch/packagerevision.go deleted file mode 100644 index c0ae6f6d9d..0000000000 --- a/porch/pkg/registry/porch/packagerevision.go +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - "fmt" - - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/engine" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/trace" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - genericapirequest "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/apiserver/pkg/registry/rest" - "k8s.io/klog/v2" -) - -var tracer = otel.Tracer("apiserver") - -type packageRevisions struct { - packageCommon - rest.TableConvertor -} - -var _ rest.Storage = &packageRevisions{} -var _ rest.Lister = &packageRevisions{} -var _ rest.Getter = &packageRevisions{} -var _ rest.Scoper = &packageRevisions{} -var _ rest.Creater = &packageRevisions{} -var _ rest.Updater = &packageRevisions{} -var _ rest.GracefulDeleter = &packageRevisions{} -var _ rest.Watcher = &packageRevisions{} - -func (r *packageRevisions) New() runtime.Object { - return &api.PackageRevision{} -} - -func (r *packageRevisions) Destroy() {} - -func (r *packageRevisions) NewList() runtime.Object { - return &api.PackageRevisionList{} -} - -func (r *packageRevisions) NamespaceScoped() bool { - return true -} - -// List selects resources in the storage which match to the selector. 'options' can be nil. -func (r *packageRevisions) List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) { - ctx, span := tracer.Start(ctx, "packageRevisions::List", trace.WithAttributes()) - defer span.End() - - result := &api.PackageRevisionList{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevisionList", - APIVersion: api.SchemeGroupVersion.Identifier(), - }, - } - - filter, err := parsePackageRevisionFieldSelector(options.FieldSelector) - if err != nil { - return nil, err - } - - if err := r.packageCommon.listPackageRevisions(ctx, filter, options.LabelSelector, func(p *engine.PackageRevision) error { - item, err := p.GetPackageRevision(ctx) - if err != nil { - return err - } - result.Items = append(result.Items, *item) - return nil - }); err != nil { - return nil, err - } - - return result, nil -} - -// Get implements the Getter interface -func (r *packageRevisions) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { - ctx, span := tracer.Start(ctx, "packageRevisions::Get", trace.WithAttributes()) - defer span.End() - - repoPkgRev, err := r.getRepoPkgRev(ctx, name) - if err != nil { - return nil, err - } - - apiPkgRev, err := repoPkgRev.GetPackageRevision(ctx) - if err != nil { - return nil, err - } - - return apiPkgRev, nil -} - -// Create implements the Creater interface. -func (r *packageRevisions) Create(ctx context.Context, runtimeObject runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) { - ctx, span := tracer.Start(ctx, "packageRevisions::Create", trace.WithAttributes()) - defer span.End() - - ns, namespaced := genericapirequest.NamespaceFrom(ctx) - if !namespaced { - return nil, apierrors.NewBadRequest("namespace must be specified") - } - - newApiPkgRev, ok := runtimeObject.(*api.PackageRevision) - if !ok { - return nil, apierrors.NewBadRequest(fmt.Sprintf("expected PackageRevision object, got %T", runtimeObject)) - } - - // TODO: Accept some form of client-provided name, for example using GenerateName - // and figure out where we can store it (in Kptfile?). Porch can then append unique - // suffix to the names while respecting client-provided value as well. - if newApiPkgRev.Name != "" { - klog.Warningf("Client provided metadata.name %q", newApiPkgRev.Name) - } - - repositoryName := newApiPkgRev.Spec.RepositoryName - if repositoryName == "" { - return nil, apierrors.NewBadRequest("spec.repositoryName is required") - } - - repositoryObj, err := r.packageCommon.getRepositoryObj(ctx, types.NamespacedName{Name: repositoryName, Namespace: ns}) - if err != nil { - return nil, err - } - - fieldErrors := r.createStrategy.Validate(ctx, runtimeObject) - if len(fieldErrors) > 0 { - return nil, apierrors.NewInvalid(api.SchemeGroupVersion.WithKind("PackageRevision").GroupKind(), newApiPkgRev.Name, fieldErrors) - } - - var parentPackage *engine.PackageRevision - if newApiPkgRev.Spec.Parent != nil && newApiPkgRev.Spec.Parent.Name != "" { - p, err := r.packageCommon.getRepoPkgRev(ctx, newApiPkgRev.Spec.Parent.Name) - if err != nil { - return nil, fmt.Errorf("cannot get parent package %q: %w", newApiPkgRev.Spec.Parent.Name, err) - } - parentPackage = p - } - - createdRepoPkgRev, err := r.cad.CreatePackageRevision(ctx, repositoryObj, newApiPkgRev, parentPackage) - if err != nil { - return nil, apierrors.NewInternalError(err) - } - - createdApiPkgRev, err := createdRepoPkgRev.GetPackageRevision(ctx) - if err != nil { - return nil, apierrors.NewInternalError(err) - } - - return createdApiPkgRev, nil -} - -// Update implements the Updater interface. - -// Update finds a resource in the storage and updates it. Some implementations -// may allow updates creates the object - they should set the created boolean -// to true. -func (r *packageRevisions) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { - ctx, span := tracer.Start(ctx, "packageRevisions::Update", trace.WithAttributes()) - defer span.End() - - return r.packageCommon.updatePackageRevision(ctx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options) -} - -// Delete implements the GracefulDeleter interface. -// Delete finds a resource in the storage and deletes it. -// The delete attempt is validated by the deleteValidation first. -// If options are provided, the resource will attempt to honor them or return an invalid -// request error. -// Although it can return an arbitrary error value, IsNotFound(err) is true for the -// returned error value err when the specified resource is not found. -// Delete *may* return the object that was deleted, or a status object indicating additional -// information about deletion. -// It also returns a boolean which is set to true if the resource was instantly -// deleted or false if it will be deleted asynchronously. -func (r *packageRevisions) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { - ctx, span := tracer.Start(ctx, "packageRevisions::Delete", trace.WithAttributes()) - defer span.End() - - ns, namespaced := genericapirequest.NamespaceFrom(ctx) - if !namespaced { - return nil, false, apierrors.NewBadRequest("namespace must be specified") - } - - repoPkgRev, err := r.packageCommon.getRepoPkgRev(ctx, name) - if err != nil { - return nil, false, err - } - - apiPkgRev, err := repoPkgRev.GetPackageRevision(ctx) - if err != nil { - return nil, false, apierrors.NewInternalError(err) - } - - repositoryObj, err := r.packageCommon.validateDelete(ctx, deleteValidation, apiPkgRev, name, ns) - if err != nil { - return nil, false, err - } - - if err := r.cad.DeletePackageRevision(ctx, repositoryObj, repoPkgRev); err != nil { - return nil, false, apierrors.NewInternalError(err) - } - - // TODO: Should we do an async delete? - return apiPkgRev, true, nil -} diff --git a/porch/pkg/registry/porch/packagerevision_approval_test.go b/porch/pkg/registry/porch/packagerevision_approval_test.go deleted file mode 100644 index 8538894982..0000000000 --- a/porch/pkg/registry/porch/packagerevision_approval_test.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "testing" - - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" -) - -func TestApprovalUpdateStrategy(t *testing.T) { - s := packageRevisionApprovalStrategy{} - - type testCase struct { - old api.PackageRevisionLifecycle - valid []api.PackageRevisionLifecycle - invalid []api.PackageRevisionLifecycle - } - - for _, tc := range []testCase{ - { - old: "", - valid: []api.PackageRevisionLifecycle{}, - invalid: []api.PackageRevisionLifecycle{"", "Wrong", api.PackageRevisionLifecycleDraft, api.PackageRevisionLifecycleProposed, api.PackageRevisionLifecyclePublished, api.PackageRevisionLifecycleDeletionProposed}, - }, - { - old: "Wrong", - valid: []api.PackageRevisionLifecycle{}, - invalid: []api.PackageRevisionLifecycle{"", "Wrong", api.PackageRevisionLifecycleDraft, api.PackageRevisionLifecycleProposed, api.PackageRevisionLifecyclePublished, api.PackageRevisionLifecycleDeletionProposed}, - }, - { - old: api.PackageRevisionLifecycleDraft, - valid: []api.PackageRevisionLifecycle{}, - invalid: []api.PackageRevisionLifecycle{"", "Wrong", api.PackageRevisionLifecycleDraft, api.PackageRevisionLifecycleProposed, api.PackageRevisionLifecyclePublished, api.PackageRevisionLifecycleDeletionProposed}, - }, - { - old: api.PackageRevisionLifecyclePublished, - valid: []api.PackageRevisionLifecycle{api.PackageRevisionLifecycleDeletionProposed}, - invalid: []api.PackageRevisionLifecycle{"", "Wrong", api.PackageRevisionLifecycleDraft, api.PackageRevisionLifecycleProposed, api.PackageRevisionLifecyclePublished}, - }, - { - old: api.PackageRevisionLifecycleDeletionProposed, - valid: []api.PackageRevisionLifecycle{api.PackageRevisionLifecyclePublished}, - invalid: []api.PackageRevisionLifecycle{"", "Wrong", api.PackageRevisionLifecycleDraft, api.PackageRevisionLifecycleProposed, api.PackageRevisionLifecycleDeletionProposed}, - }, - { - old: api.PackageRevisionLifecycleProposed, - valid: []api.PackageRevisionLifecycle{api.PackageRevisionLifecycleDraft, api.PackageRevisionLifecyclePublished}, - invalid: []api.PackageRevisionLifecycle{"", "Wrong", api.PackageRevisionLifecycleProposed, api.PackageRevisionLifecycleDeletionProposed}, - }, - } { - for _, new := range tc.valid { - testValidateUpdate(t, s, tc.old, new, true) - } - for _, new := range tc.invalid { - testValidateUpdate(t, s, tc.old, new, false) - } - } -} diff --git a/porch/pkg/registry/porch/packagerevision_test.go b/porch/pkg/registry/porch/packagerevision_test.go deleted file mode 100644 index 40efead016..0000000000 --- a/porch/pkg/registry/porch/packagerevision_test.go +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - "testing" - - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestUpdateStrategyForLifecycle(t *testing.T) { - type testCase struct { - old api.PackageRevisionLifecycle - valid []api.PackageRevisionLifecycle - invalid []api.PackageRevisionLifecycle - } - - s := packageRevisionStrategy{} - - for _, tc := range []testCase{ - { - old: "", - valid: []api.PackageRevisionLifecycle{"", api.PackageRevisionLifecycleDraft, api.PackageRevisionLifecycleProposed}, - invalid: []api.PackageRevisionLifecycle{"Wrong", api.PackageRevisionLifecyclePublished}, - }, - { - old: api.PackageRevisionLifecycleDraft, - valid: []api.PackageRevisionLifecycle{"", api.PackageRevisionLifecycleDraft, api.PackageRevisionLifecycleProposed}, - invalid: []api.PackageRevisionLifecycle{"Wrong", api.PackageRevisionLifecyclePublished}, - }, - { - old: api.PackageRevisionLifecycleProposed, - valid: []api.PackageRevisionLifecycle{"", api.PackageRevisionLifecycleDraft, api.PackageRevisionLifecycleProposed}, - invalid: []api.PackageRevisionLifecycle{"Wrong", api.PackageRevisionLifecyclePublished}, - }, - { - old: api.PackageRevisionLifecyclePublished, - valid: []api.PackageRevisionLifecycle{api.PackageRevisionLifecyclePublished}, - invalid: []api.PackageRevisionLifecycle{"", "Wrong", api.PackageRevisionLifecycleDraft, api.PackageRevisionLifecycleProposed}, - }, - { - old: "Wrong", - valid: []api.PackageRevisionLifecycle{}, - invalid: []api.PackageRevisionLifecycle{"", "Wrong", api.PackageRevisionLifecycleDraft, api.PackageRevisionLifecycleProposed, api.PackageRevisionLifecyclePublished}, - }, - } { - for _, new := range tc.valid { - testValidateUpdate(t, s, tc.old, new, true) - } - for _, new := range tc.invalid { - testValidateUpdate(t, s, tc.old, new, false) - } - } -} - -func TestUpdateStrategy(t *testing.T) { - s := packageRevisionStrategy{} - - testCases := map[string]struct { - old *api.PackageRevision - new *api.PackageRevision - valid bool - }{ - "spec can be updated for draft": { - old: &api.PackageRevision{ - Spec: api.PackageRevisionSpec{ - Lifecycle: api.PackageRevisionLifecycleDraft, - Tasks: []api.Task{ - { - Type: api.TaskTypeInit, - Init: &api.PackageInitTaskSpec{ - Description: "This is a test", - }, - }, - }, - }, - }, - new: &api.PackageRevision{ - Spec: api.PackageRevisionSpec{ - Lifecycle: api.PackageRevisionLifecycleDraft, - Tasks: []api.Task{ - { - Type: api.TaskTypeInit, - Init: &api.PackageInitTaskSpec{ - Description: "This is a test", - }, - }, - { - Type: api.TaskTypePatch, - Patch: &api.PackagePatchTaskSpec{}, - }, - }, - }, - }, - valid: true, - }, - "spec can not be updated for published": { - old: &api.PackageRevision{ - Spec: api.PackageRevisionSpec{ - Lifecycle: api.PackageRevisionLifecyclePublished, - Tasks: []api.Task{ - { - Type: api.TaskTypeInit, - Init: &api.PackageInitTaskSpec{ - Description: "This is a test", - }, - }, - }, - }, - }, - new: &api.PackageRevision{ - Spec: api.PackageRevisionSpec{ - Lifecycle: api.PackageRevisionLifecyclePublished, - Tasks: []api.Task{ - { - Type: api.TaskTypeInit, - Init: &api.PackageInitTaskSpec{ - Description: "This is a test", - }, - }, - { - Type: api.TaskTypePatch, - Patch: &api.PackagePatchTaskSpec{}, - }, - }, - }, - }, - valid: false, - }, - "labels can be updated for published": { - old: &api.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "foo": "bar", - }, - }, - Spec: api.PackageRevisionSpec{ - Lifecycle: api.PackageRevisionLifecyclePublished, - }, - }, - new: &api.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "bar": "foo", - }, - }, - Spec: api.PackageRevisionSpec{ - Lifecycle: api.PackageRevisionLifecyclePublished, - }, - }, - valid: true, - }, - "annotations can be updated for published": { - old: &api.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{ - "foo": "bar", - }, - }, - Spec: api.PackageRevisionSpec{ - Lifecycle: api.PackageRevisionLifecyclePublished, - }, - }, - new: &api.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{ - "bar": "foo", - }, - }, - Spec: api.PackageRevisionSpec{ - Lifecycle: api.PackageRevisionLifecyclePublished, - }, - }, - valid: true, - }, - } - - for tn := range testCases { - tc := testCases[tn] - t.Run(tn, func(t *testing.T) { - ctx := context.Background() - allErrs := s.ValidateUpdate(ctx, tc.new, tc.old) - - if tc.valid { - if len(allErrs) > 0 { - t.Errorf("Update failed unexpectedly: %v", allErrs.ToAggregate().Error()) - } - } else { - if len(allErrs) == 0 { - t.Error("Update should fail but didn't") - } - } - }) - } -} diff --git a/porch/pkg/registry/porch/packagerevisionresources.go b/porch/pkg/registry/porch/packagerevisionresources.go deleted file mode 100644 index 0821a7ac46..0000000000 --- a/porch/pkg/registry/porch/packagerevisionresources.go +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - "fmt" - - "k8s.io/apimachinery/pkg/runtime/schema" - - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/engine" - "go.opentelemetry.io/otel/trace" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - genericapirequest "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/apiserver/pkg/registry/rest" - "k8s.io/klog/v2" -) - -type packageRevisionResources struct { - rest.TableConvertor - - packageCommon -} - -var _ rest.Storage = &packageRevisionResources{} -var _ rest.Lister = &packageRevisionResources{} -var _ rest.Getter = &packageRevisionResources{} -var _ rest.Scoper = &packageRevisionResources{} -var _ rest.Updater = &packageRevisionResources{} - -func (r *packageRevisionResources) New() runtime.Object { - return &api.PackageRevisionResources{} -} - -func (r *packageRevisionResources) Destroy() {} - -func (r *packageRevisionResources) NewList() runtime.Object { - return &api.PackageRevisionResourcesList{} -} - -func (r *packageRevisionResources) NamespaceScoped() bool { - return true -} - -// List selects resources in the storage which match to the selector. 'options' can be nil. -func (r *packageRevisionResources) List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) { - ctx, span := tracer.Start(ctx, "packageRevisionResources::List", trace.WithAttributes()) - defer span.End() - - result := &api.PackageRevisionResourcesList{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevisionResourcesList", - APIVersion: api.SchemeGroupVersion.Identifier(), - }, - } - - filter, err := parsePackageRevisionResourcesFieldSelector(options.FieldSelector) - if err != nil { - return nil, err - } - - if err := r.packageCommon.listPackageRevisions(ctx, filter, options.LabelSelector, func(p *engine.PackageRevision) error { - apiPkgResources, err := p.GetResources(ctx) - if err != nil { - return err - } - result.Items = append(result.Items, *apiPkgResources) - return nil - }); err != nil { - return nil, err - } - - return result, nil -} - -// Get implements the Getter interface -func (r *packageRevisionResources) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { - ctx, span := tracer.Start(ctx, "packageRevisionResources::Get", trace.WithAttributes()) - defer span.End() - - pkg, err := r.packageCommon.getRepoPkgRev(ctx, name) - if err != nil { - return nil, err - } - - apiPkgResources, err := pkg.GetResources(ctx) - if err != nil { - return nil, err - } - return apiPkgResources, nil -} - -// Update finds a resource in the storage and updates it. Some implementations -// may allow updates creates the object - they should set the created boolean -// to true. -func (r *packageRevisionResources) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { - ctx, span := tracer.Start(ctx, "packageRevisionResources::Update", trace.WithAttributes()) - defer span.End() - - ns, namespaced := genericapirequest.NamespaceFrom(ctx) - if !namespaced { - return nil, false, apierrors.NewBadRequest("namespace must be specified") - } - - oldRepoPkgRev, err := r.packageCommon.getRepoPkgRev(ctx, name) - if err != nil { - return nil, false, err - } - - oldApiPkgRevResources, err := oldRepoPkgRev.GetResources(ctx) - if err != nil { - klog.Infof("update failed to retrieve old object: %v", err) - return nil, false, err - } - - newRuntimeObj, err := objInfo.UpdatedObject(ctx, oldApiPkgRevResources) - if err != nil { - klog.Infof("update failed to construct UpdatedObject: %v", err) - return nil, false, err - } - newObj, ok := newRuntimeObj.(*api.PackageRevisionResources) - if !ok { - return nil, false, apierrors.NewBadRequest(fmt.Sprintf("expected PackageRevisionResources object, got %T", newRuntimeObj)) - } - - if updateValidation != nil { - err := updateValidation(ctx, newObj, oldApiPkgRevResources) - if err != nil { - klog.Infof("update failed validation: %v", err) - return nil, false, err - } - } - - repositoryName, err := ParseRepositoryName(name) - if err != nil { - return nil, false, apierrors.NewBadRequest(fmt.Sprintf("invalid name %q", name)) - } - - var repositoryObj v1alpha1.Repository - repositoryID := types.NamespacedName{Namespace: ns, Name: repositoryName} - if err := r.coreClient.Get(ctx, repositoryID, &repositoryObj); err != nil { - if apierrors.IsNotFound(err) { - return nil, false, apierrors.NewNotFound(schema.GroupResource(api.PackageRevisionResourcesGVR.GroupResource()), repositoryID.Name) - } - return nil, false, apierrors.NewInternalError(fmt.Errorf("error getting repository %v: %w", repositoryID, err)) - } - - rev, renderStatus, err := r.cad.UpdatePackageResources(ctx, &repositoryObj, oldRepoPkgRev, oldApiPkgRevResources, newObj) - if err != nil { - return nil, false, apierrors.NewInternalError(err) - } - - created, err := rev.GetResources(ctx) - if err != nil { - return nil, false, apierrors.NewInternalError(err) - } - if renderStatus != nil { - created.Status.RenderStatus = *renderStatus - } - - return created, false, nil -} diff --git a/porch/pkg/registry/porch/packagerevisions_approval.go b/porch/pkg/registry/porch/packagerevisions_approval.go deleted file mode 100644 index 20e8b4ce26..0000000000 --- a/porch/pkg/registry/porch/packagerevisions_approval.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - "fmt" - "strings" - - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/validation/field" - "k8s.io/apiserver/pkg/registry/rest" -) - -type packageRevisionsApproval struct { - common packageCommon -} - -var _ rest.Storage = &packageRevisionsApproval{} -var _ rest.Scoper = &packageRevisionsApproval{} -var _ rest.Getter = &packageRevisionsApproval{} -var _ rest.Updater = &packageRevisionsApproval{} - -// New returns an empty object that can be used with Create and Update after request data has been put into it. -// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object) -func (a *packageRevisionsApproval) New() runtime.Object { - return &api.PackageRevision{} -} - -func (a *packageRevisionsApproval) Destroy() {} - -// NamespaceScoped returns true if the storage is namespaced -func (a *packageRevisionsApproval) NamespaceScoped() bool { - return true -} - -func (a *packageRevisionsApproval) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { - pkg, err := a.common.getRepoPkgRev(ctx, name) - if err != nil { - return nil, err - } - return pkg.GetPackageRevision(ctx) -} - -// Update finds a resource in the storage and updates it. Some implementations -// may allow updates creates the object - they should set the created boolean -// to true. -func (a *packageRevisionsApproval) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { - allowCreate := false // do not allow create on update - return a.common.updatePackageRevision(ctx, name, objInfo, createValidation, updateValidation, allowCreate, options) -} - -type packageRevisionApprovalStrategy struct{} - -func (s packageRevisionApprovalStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { -} - -func (s packageRevisionApprovalStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { - allErrs := field.ErrorList{} - oldRevision := old.(*api.PackageRevision) - newRevision := obj.(*api.PackageRevision) - - switch lifecycle := oldRevision.Spec.Lifecycle; lifecycle { - - case api.PackageRevisionLifecyclePublished: - if newRevision.Spec.Lifecycle != api.PackageRevisionLifecycleDeletionProposed { - allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "lifecycle"), lifecycle, - fmt.Sprintf("package with %s lifecycle value can only be updated to 'ProposeDeletion'", lifecycle))) - } - - case api.PackageRevisionLifecycleDeletionProposed: - if newRevision.Spec.Lifecycle != api.PackageRevisionLifecyclePublished { - allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "lifecycle"), lifecycle, - fmt.Sprintf("package with %s lifecycle value can only be updated to 'Published'", lifecycle))) - } - - case api.PackageRevisionLifecycleProposed: - // valid - - default: - allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "lifecycle"), lifecycle, - fmt.Sprintf("cannot approve package with %s lifecycle value; only Proposed packages can be approved", lifecycle))) - } - - switch lifecycle := newRevision.Spec.Lifecycle; lifecycle { - // TODO: signal rejection of the approval differently than by returning to draft? - case api.PackageRevisionLifecycleDraft, api.PackageRevisionLifecyclePublished: - // valid - - case api.PackageRevisionLifecycleDeletionProposed: - if oldRevision.Spec.Lifecycle != api.PackageRevisionLifecyclePublished { - allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "lifecycle"), lifecycle, - fmt.Sprintf("cannot update lifecycle %s; only Published packages require approval for deletion", lifecycle))) - } - - default: - allErrs = append(allErrs, - field.Invalid(field.NewPath("spec", "lifecycle"), lifecycle, fmt.Sprintf("value for approval can be only one of %s", - strings.Join([]string{ - string(api.PackageRevisionLifecycleDraft), - string(api.PackageRevisionLifecyclePublished), - }, ",")), - )) - } - return allErrs -} - -func (s packageRevisionApprovalStrategy) Canonicalize(obj runtime.Object) {} - -var _ SimpleRESTCreateStrategy = packageRevisionApprovalStrategy{} - -// Validate returns an ErrorList with validation errors or nil. Validate -// is invoked after default fields in the object have been filled in -// before the object is persisted. This method should not mutate the -// object. -func (s packageRevisionApprovalStrategy) Validate(ctx context.Context, runtimeObj runtime.Object) field.ErrorList { - allErrs := field.ErrorList{} - - // obj := runtimeObj.(*api.PackageRevision) - - return allErrs -} diff --git a/porch/pkg/registry/porch/reference.go b/porch/pkg/registry/porch/reference.go deleted file mode 100644 index 09993bd7df..0000000000 --- a/porch/pkg/registry/porch/reference.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - - "github.com/GoogleContainerTools/kpt/porch/pkg/engine" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -func NewReferenceResolver(coreClient client.Reader) engine.ReferenceResolver { - return &referenceResolver{ - coreClient: coreClient, - } -} - -type referenceResolver struct { - coreClient client.Reader -} - -var _ engine.ReferenceResolver = &referenceResolver{} - -func (r *referenceResolver) ResolveReference(ctx context.Context, namespace, name string, result engine.Object) error { - return r.coreClient.Get(ctx, client.ObjectKey{ - Namespace: namespace, - Name: name, - }, result) -} diff --git a/porch/pkg/registry/porch/rest.go b/porch/pkg/registry/porch/rest.go deleted file mode 100644 index 4301367eee..0000000000 --- a/porch/pkg/registry/porch/rest.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/validation/field" -) - -// SimpleRESTUpdateStrategy is similar to rest.RESTUpdateStrategy, though only contains -// methods currently required. -type SimpleRESTUpdateStrategy interface { - PrepareForUpdate(ctx context.Context, obj, old runtime.Object) - ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList - Canonicalize(obj runtime.Object) -} - -// SimpleRESTCreateStrategy is similar to rest.RESTCreateStrategy, though only contains -// methods currently required. -type SimpleRESTCreateStrategy interface { - // Validate returns an ErrorList with validation errors or nil. Validate - // is invoked after default fields in the object have been filled in - // before the object is persisted. This method should not mutate the - // object. - Validate(ctx context.Context, obj runtime.Object) field.ErrorList -} - -type NoopUpdateStrategy struct{} - -func (s NoopUpdateStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {} -func (s NoopUpdateStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { - return nil -} -func (s NoopUpdateStrategy) Canonicalize(obj runtime.Object) {} diff --git a/porch/pkg/registry/porch/secret.go b/porch/pkg/registry/porch/secret.go deleted file mode 100644 index b306b24b62..0000000000 --- a/porch/pkg/registry/porch/secret.go +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - "fmt" - "time" - - "github.com/GoogleContainerTools/kpt/porch/pkg/registry/porch/wi" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/go-git/go-git/v5/plumbing/transport" - "github.com/go-git/go-git/v5/plumbing/transport/http" - "golang.org/x/oauth2" - stsv1 "google.golang.org/api/sts/v1" - core "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - corev1client "k8s.io/client-go/kubernetes/typed/core/v1" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - // Values for scret types supported by porch. - BasicAuthType = core.SecretTypeBasicAuth - WorkloadIdentityAuthType = "kpt.dev/workload-identity-auth" - - // Annotation used to specify the gsa for a ksa. - WIGCPSAAnnotation = "iam.gke.io/gcp-service-account" -) - -func NewCredentialResolver(coreClient client.Reader, resolverChain []Resolver) repository.CredentialResolver { - return &secretResolver{ - coreClient: coreClient, - resolverChain: resolverChain, - } -} - -type secretResolver struct { - resolverChain []Resolver - coreClient client.Reader -} - -type Resolver interface { - Resolve(ctx context.Context, secret core.Secret) (repository.Credential, bool, error) -} - -var _ repository.CredentialResolver = &secretResolver{} - -func (r *secretResolver) ResolveCredential(ctx context.Context, namespace, name string) (repository.Credential, error) { - var secret core.Secret - if err := r.coreClient.Get(ctx, client.ObjectKey{ - Namespace: namespace, - Name: name, - }, &secret); err != nil { - return nil, fmt.Errorf("cannot resolve credentials in a secret %s/%s: %w", namespace, name, err) - } - - for _, resolver := range r.resolverChain { - cred, found, err := resolver.Resolve(ctx, secret) - if err != nil { - return nil, fmt.Errorf("error resolving credential: %w", err) - } - if found { - return cred, nil - } - } - return nil, &NoMatchingResolverError{ - Type: string(secret.Type), - } -} - -type NoMatchingResolverError struct { - Type string -} - -func (e *NoMatchingResolverError) Error() string { - return fmt.Sprintf("no resolver for secret with type %s", e.Type) -} - -func (e *NoMatchingResolverError) Is(err error) bool { - nmre, ok := err.(*NoMatchingResolverError) - if !ok { - return false - } - return nmre.Type == e.Type -} - -func NewBasicAuthResolver() Resolver { - return &BasicAuthResolver{} -} - -var _ Resolver = &BasicAuthResolver{} - -type BasicAuthResolver struct{} - -func (b *BasicAuthResolver) Resolve(_ context.Context, secret core.Secret) (repository.Credential, bool, error) { - if secret.Type != BasicAuthType { - return nil, false, nil - } - - return &BasicAuthCredential{ - Username: string(secret.Data["username"]), - Password: string(secret.Data["password"]), - }, true, nil -} - -type BasicAuthCredential struct { - Username string - Password string -} - -var _ repository.Credential = &BasicAuthCredential{} - -func (b *BasicAuthCredential) Valid() bool { - return true -} - -func (b *BasicAuthCredential) ToAuthMethod() transport.AuthMethod { - return &http.BasicAuth{ - Username: string(b.Username), - Password: string(b.Password), - } -} - -func NewGcloudWIResolver(corev1Client *corev1client.CoreV1Client, stsClient *stsv1.Service) Resolver { - return &GcloudWIResolver{ - coreV1Client: corev1Client, - exchanger: wi.NewWITokenExchanger(corev1Client, stsClient), - circuitBreaker: &circuitBreaker{ - duration: 5 * time.Second, // We always wait at least 5 seconds before trying again. - factor: 2, // We double the wait time for every consecutive failure. - maxDuration: 5 * time.Minute, // Max wait time is 5 minutes. - }, - } -} - -var _ Resolver = &GcloudWIResolver{} - -type GcloudWIResolver struct { - coreV1Client *corev1client.CoreV1Client - exchanger *wi.WITokenExchanger - circuitBreaker *circuitBreaker -} - -var porchKSA = types.NamespacedName{ - Name: "porch-server", - Namespace: "porch-system", -} - -func (g *GcloudWIResolver) Resolve(ctx context.Context, secret core.Secret) (repository.Credential, bool, error) { - if secret.Type != WorkloadIdentityAuthType { - return nil, false, nil - } - - var token *oauth2.Token - err := g.circuitBreaker.do(func() error { - var tokenErr error - token, tokenErr = g.getToken(ctx) - return tokenErr - }) - if err != nil { - return nil, true, err - } - return &GcloudWICredential{ - token: token, - }, true, nil -} - -func (g *GcloudWIResolver) getToken(ctx context.Context) (*oauth2.Token, error) { - gsa, err := g.lookupGSAEmail(ctx, porchKSA.Name, porchKSA.Namespace) - if err != nil { - return nil, err - } - - token, err := g.exchanger.Exchange(ctx, porchKSA, gsa) - if err != nil { - return nil, err - } - - return token, nil -} - -func (g *GcloudWIResolver) lookupGSAEmail(ctx context.Context, name, namespace string) (string, error) { - sa, err := g.coreV1Client.ServiceAccounts(namespace).Get(ctx, name, v1.GetOptions{}) - if err != nil { - if apierrors.IsNotFound(err) { - return "", fmt.Errorf("porch service account %s/%s not found", namespace, name) - } - return "", fmt.Errorf("error looking up porch service account %s/%s: %w", namespace, name, err) - } - gsa, found := sa.Annotations[WIGCPSAAnnotation] - if !found { - return "", fmt.Errorf("%s annotation not found on porch sa", WIGCPSAAnnotation) - } - return gsa, nil -} - -type GcloudWICredential struct { - token *oauth2.Token -} - -var _ repository.Credential = &GcloudWICredential{} - -func (b *GcloudWICredential) Valid() bool { - timeLeft := time.Until(b.token.Expiry) - return timeLeft > 5*time.Minute -} - -func (b *GcloudWICredential) ToAuthMethod() transport.AuthMethod { - return &http.BasicAuth{ - Username: "token", // username doesn't matter here. - Password: string(b.token.AccessToken), - } -} - -// circuitBreaker makes sure that failing operations are retried -// using exponential backoff. -type circuitBreaker struct { - // duration defines how long to wait after the first failure. - duration time.Duration - // factor is multiplied with the previous wait time after a failure. - factor float64 - // maxDuration is the maximum wait time we require. - maxDuration time.Duration - - open bool - delay time.Duration - expiration time.Time - lastErr error -} - -func (cb *circuitBreaker) do(action func() error) error { - if cb.open { - // If the circuit breaker is open and the required amount of - // time hasn't passed yet, we don't retry but instead return - // and error wrapping the error from the last attempt. - if time.Now().Before(cb.expiration) { - return &CircuitBreakerError{ - Err: cb.lastErr, - } - } - } - - err := action() - if err != nil { - // After an error, we determine delay before we allow - // another attempt. - if !cb.open { - cb.delay = cb.duration - } else { - cb.delay = cb.delay * time.Duration(cb.factor) - } - if cb.delay > cb.maxDuration { - cb.delay = cb.maxDuration - } - // Set the new expiration in the future. - cb.expiration = time.Now().Add(cb.delay) - cb.open = true - cb.lastErr = err - return err - } - // If the opration succeeded, reset the circuit breaker. - cb.open = false - cb.delay = 0 - cb.lastErr = nil - return nil -} - -type CircuitBreakerError struct { - Err error -} - -func (cbe *CircuitBreakerError) Error() string { - return fmt.Sprintf("circuit breaker is open. Last error: %s", cbe.Err.Error()) -} - -func (cbe *CircuitBreakerError) Unwrap() error { - return cbe.Err -} diff --git a/porch/pkg/registry/porch/secret_test.go b/porch/pkg/registry/porch/secret_test.go deleted file mode 100644 index 85478c630f..0000000000 --- a/porch/pkg/registry/porch/secret_test.go +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - "fmt" - "testing" - "time" - - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/stretchr/testify/assert" - core "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - secretName = "secret" - secretNamespace = "porch-system" -) - -func TestCredentialResolver(t *testing.T) { - secretNotFoundError := apierrors.NewNotFound(schema.GroupResource{Resource: "secrets"}, "secret") - - testCases := map[string]struct { - readerSecret *core.Secret - readerErr error - - resolverCredential repository.Credential - resolverResolved bool - resolverErr error - - expectedCredential repository.Credential - expectedErr error - }{ - "no secret found": { - readerErr: secretNotFoundError, - expectedErr: secretNotFoundError, - }, - "secret is of type kubernetes.io/basic-auth": { - readerSecret: &core.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: secretName, - Namespace: secretNamespace, - }, - Type: core.SecretTypeBasicAuth, - Data: map[string][]byte{ - "username": []byte("username"), - "password": []byte("password"), - }, - }, - expectedCredential: &BasicAuthCredential{ - Username: "username", - Password: "password", - }, - }, - "no resolver for secret type": { - readerSecret: &core.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: secretName, - Namespace: secretNamespace, - }, - Type: "notSupported", - Data: map[string][]byte{}, - }, - expectedErr: &NoMatchingResolverError{ - Type: "notSupported", - }, - }, - } - - for tn := range testCases { - tc := testCases[tn] - t.Run(tn, func(t *testing.T) { - reader := &fakeReader{ - expectedSecret: tc.readerSecret, - expectedErr: tc.readerErr, - } - credResolver := NewCredentialResolver(reader, []Resolver{ - NewBasicAuthResolver(), - &fakeResolver{ - credential: tc.resolverCredential, - resolved: tc.resolverResolved, - err: tc.resolverErr, - }, - }) - - cred, err := credResolver.ResolveCredential(context.Background(), secretNamespace, secretName) - - assert.ErrorIs(t, err, tc.expectedErr) - assert.Equal(t, tc.expectedCredential, cred) - - }) - } -} - -type fakeReader struct { - expectedSecret *core.Secret - expectedErr error -} - -func (f *fakeReader) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { - if f.expectedErr != nil { - return f.expectedErr - } - in, ok := obj.(*core.Secret) - if !ok { - return fmt.Errorf("object is not of type *core.Secret") - } - f.expectedSecret.DeepCopyInto(in) - return nil -} - -func (f *fakeReader) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { - return nil -} - -type fakeResolver struct { - credential repository.Credential - resolved bool - err error -} - -func (fr *fakeResolver) Resolve(ctx context.Context, secret core.Secret) (repository.Credential, bool, error) { - return fr.credential, fr.resolved, fr.err -} - -func TestCircuitBreaker(t *testing.T) { - cb := &circuitBreaker{ - duration: 2 * time.Second, - factor: 4, - maxDuration: 10 * time.Second, - } - - ticker := time.NewTicker(500 * time.Millisecond) - timer := time.NewTimer(5 * time.Second) - - actionCounter := 0 -loop: - for { - select { - case <-ticker.C: - _ = cb.do(func() error { - actionCounter++ - return fmt.Errorf("error") - }) - case <-timer.C: - ticker.Stop() - timer.Stop() - break loop - } - } - if got, want := actionCounter, 2; got != want { - t.Errorf("expected function to be called %d times, but got %d", want, got) - } -} diff --git a/porch/pkg/registry/porch/storage.go b/porch/pkg/registry/porch/storage.go deleted file mode 100644 index 7d02adf0ba..0000000000 --- a/porch/pkg/registry/porch/storage.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "github.com/GoogleContainerTools/kpt/porch/api/porch" - apiv1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/engine" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/runtime/serializer" - "k8s.io/apiserver/pkg/registry/rest" - genericapiserver "k8s.io/apiserver/pkg/server" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -func NewRESTStorage(scheme *runtime.Scheme, codecs serializer.CodecFactory, cad engine.CaDEngine, coreClient client.WithWatch) (genericapiserver.APIGroupInfo, error) { - packages := &packages{ - TableConvertor: packageTableConvertor, - packageCommon: packageCommon{ - scheme: scheme, - cad: cad, - gr: porch.Resource("packages"), - coreClient: coreClient, - updateStrategy: packageStrategy{}, - createStrategy: packageStrategy{}, - }, - } - - packageRevisions := &packageRevisions{ - TableConvertor: packageRevisionTableConvertor, - packageCommon: packageCommon{ - scheme: scheme, - cad: cad, - gr: porch.Resource("packagerevisions"), - coreClient: coreClient, - updateStrategy: packageRevisionStrategy{}, - createStrategy: packageRevisionStrategy{}, - }, - } - - packageRevisionsApproval := &packageRevisionsApproval{ - common: packageCommon{ - scheme: scheme, - cad: cad, - coreClient: coreClient, - gr: porch.Resource("packagerevisions"), - updateStrategy: packageRevisionApprovalStrategy{}, - createStrategy: packageRevisionApprovalStrategy{}, - }, - } - - packageRevisionResources := &packageRevisionResources{ - TableConvertor: packageRevisionResourcesTableConvertor, - packageCommon: packageCommon{ - scheme: scheme, - cad: cad, - gr: porch.Resource("packagerevisionresources"), - coreClient: coreClient, - }, - } - - functions := &functions{ - TableConvertor: rest.NewDefaultTableConvertor(porch.Resource("functions")), - cad: cad, - coreClient: coreClient, - } - - group := genericapiserver.NewDefaultAPIGroupInfo(porch.GroupName, scheme, metav1.ParameterCodec, codecs) - - group.VersionedResourcesStorageMap = map[string]map[string]rest.Storage{ - apiv1alpha1.SchemeGroupVersion.Version: { - "packages": packages, - "packagerevisions": packageRevisions, - "packagerevisions/approval": packageRevisionsApproval, - "packagerevisionresources": packageRevisionResources, - "functions": functions, - }, - } - - { - gvk := schema.GroupVersionKind{ - Group: apiv1alpha1.GroupName, - Version: apiv1alpha1.SchemeGroupVersion.Version, - Kind: "Package", - } - - scheme.AddFieldLabelConversionFunc(gvk, convertPackageFieldSelector) - } - { - gvk := schema.GroupVersionKind{ - Group: apiv1alpha1.GroupName, - Version: apiv1alpha1.SchemeGroupVersion.Version, - Kind: "PackageRevision", - } - - scheme.AddFieldLabelConversionFunc(gvk, convertPackageRevisionFieldSelector) - } - { - gvk := schema.GroupVersionKind{ - Group: apiv1alpha1.GroupName, - Version: apiv1alpha1.SchemeGroupVersion.Version, - Kind: "PackageRevisionResources", - } - - scheme.AddFieldLabelConversionFunc(gvk, convertPackageRevisionResourcesFieldSelector) - } - - return group, nil -} diff --git a/porch/pkg/registry/porch/strategy.go b/porch/pkg/registry/porch/strategy.go deleted file mode 100644 index 9228751467..0000000000 --- a/porch/pkg/registry/porch/strategy.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - "fmt" - "strings" - - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/validation/field" -) - -// PackageRevisions Update Strategy - -type packageRevisionStrategy struct{} - -var _ SimpleRESTUpdateStrategy = packageRevisionStrategy{} - -func (s packageRevisionStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { -} - -func (s packageRevisionStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { - allErrs := field.ErrorList{} - oldRevision := old.(*api.PackageRevision) - newRevision := obj.(*api.PackageRevision) - - // Verify that the new lifecycle value is valid. - switch lifecycle := newRevision.Spec.Lifecycle; lifecycle { - case "", api.PackageRevisionLifecycleDraft, api.PackageRevisionLifecycleProposed, api.PackageRevisionLifecyclePublished, api.PackageRevisionLifecycleDeletionProposed: - // valid - default: - allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "lifecycle"), lifecycle, fmt.Sprintf("value can be only updated to %s", - strings.Join([]string{ - string(api.PackageRevisionLifecycleDraft), - string(api.PackageRevisionLifecycleProposed), - string(api.PackageRevisionLifecyclePublished), - string(api.PackageRevisionLifecycleDeletionProposed), - }, ",")), - )) - } - - switch lifecycle := oldRevision.Spec.Lifecycle; lifecycle { - case "", api.PackageRevisionLifecycleDraft, api.PackageRevisionLifecycleProposed: - // Packages in a draft or proposed state can only be updated to draft or proposed. - newLifecycle := newRevision.Spec.Lifecycle - if !(newLifecycle == api.PackageRevisionLifecycleDraft || - newLifecycle == api.PackageRevisionLifecycleProposed || - newLifecycle == "") { - allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "lifecycle"), lifecycle, fmt.Sprintf("value can be only updated to %s", - strings.Join([]string{ - string(api.PackageRevisionLifecycleDraft), - string(api.PackageRevisionLifecycleProposed), - }, ",")), - )) - } - case api.PackageRevisionLifecyclePublished, api.PackageRevisionLifecycleDeletionProposed: - // We don't allow any updates to the spec for packagerevision that have been published. That includes updates of the lifecycle. But - // we allow updates to metadata and status. The only exception is that the lifecycle - // can change between Published and DeletionProposed and vice versa. - newLifecycle := newRevision.Spec.Lifecycle - if api.LifecycleIsPublished(newLifecycle) { - // copy the lifecycle value over before calling reflect.DeepEqual to allow comparison - // of all other fields without error - newRevision.Spec.Lifecycle = oldRevision.Spec.Lifecycle - } - if !equality.Semantic.DeepEqual(oldRevision.Spec, newRevision.Spec) { - allErrs = append(allErrs, field.Invalid(field.NewPath("spec"), newRevision.Spec, fmt.Sprintf("spec can only update package with lifecycle value one of %s", - strings.Join([]string{ - string(api.PackageRevisionLifecycleDraft), - string(api.PackageRevisionLifecycleProposed), - }, ",")), - )) - } - newRevision.Spec.Lifecycle = newLifecycle - default: - allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "lifecycle"), lifecycle, fmt.Sprintf("can only update package with lifecycle value one of %s", - strings.Join([]string{ - string(api.PackageRevisionLifecycleDraft), - string(api.PackageRevisionLifecycleProposed), - string(api.PackageRevisionLifecyclePublished), - string(api.PackageRevisionLifecycleDeletionProposed), - }, ",")), - )) - } - - return allErrs -} - -func (s packageRevisionStrategy) Canonicalize(obj runtime.Object) { - pr := obj.(*api.PackageRevision) - if pr.Spec.Lifecycle == "" { - // Set default - pr.Spec.Lifecycle = api.PackageRevisionLifecycleDraft - } -} - -var _ SimpleRESTCreateStrategy = packageRevisionStrategy{} - -// Validate returns an ErrorList with validation errors or nil. Validate -// is invoked after default fields in the object have been filled in -// before the object is persisted. This method should not mutate the -// object. -func (s packageRevisionStrategy) Validate(ctx context.Context, runtimeObj runtime.Object) field.ErrorList { - allErrs := field.ErrorList{} - - obj := runtimeObj.(*api.PackageRevision) - - switch lifecycle := obj.Spec.Lifecycle; lifecycle { - case "", api.PackageRevisionLifecycleDraft: - // valid - - default: - allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "lifecycle"), lifecycle, fmt.Sprintf("value can be only created as %s", - strings.Join([]string{ - string(api.PackageRevisionLifecycleDraft), - }, ",")), - )) - } - - return allErrs -} - -// Package Update Strategy - -type packageStrategy struct{} - -var _ SimpleRESTUpdateStrategy = packageStrategy{} - -func (s packageStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { -} - -func (s packageStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { - return nil -} - -func (s packageStrategy) Canonicalize(obj runtime.Object) { -} - -var _ SimpleRESTCreateStrategy = packageStrategy{} - -// Validate returns an ErrorList with validation errors or nil. Validate -// is invoked after default fields in the object have been filled in -// before the object is persisted. This method should not mutate the -// object. -func (s packageStrategy) Validate(ctx context.Context, runtimeObj runtime.Object) field.ErrorList { - return nil -} diff --git a/porch/pkg/registry/porch/table.go b/porch/pkg/registry/porch/table.go deleted file mode 100644 index 726f07529e..0000000000 --- a/porch/pkg/registry/porch/table.go +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - - "github.com/GoogleContainerTools/kpt/porch/api/porch" - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apiserver/pkg/registry/rest" -) - -type tableConvertor struct { - resource schema.GroupResource - // cells creates a single row of cells of the table from a runtime.Object - cells func(obj runtime.Object) []interface{} - // columns stores column definitions for the table convertor - columns []metav1.TableColumnDefinition -} - -var _ rest.TableConvertor = tableConvertor{} - -// ConvertToTable implements rest.TableConvertor -func (c tableConvertor) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { - var table metav1.Table - - fn := func(obj runtime.Object) error { - cells := c.cells(obj) - if cells == nil || len(cells) == 0 { - return newResourceNotAcceptableError(ctx, c.resource) - } - table.Rows = append(table.Rows, metav1.TableRow{ - Cells: cells, - Object: runtime.RawExtension{Object: obj}, - }) - return nil - } - - // Create table rows - switch { - case meta.IsListType(object): - if err := meta.EachListItem(object, fn); err != nil { - return nil, err - } - default: - if err := fn(object); err != nil { - return nil, err - } - } - - // Populate table metadata - table.APIVersion = metav1.SchemeGroupVersion.Identifier() - table.Kind = "Table" - if l, err := meta.ListAccessor(object); err == nil { - table.ResourceVersion = l.GetResourceVersion() - table.SelfLink = l.GetSelfLink() - table.Continue = l.GetContinue() - table.RemainingItemCount = l.GetRemainingItemCount() - } else if c, err := meta.CommonAccessor(object); err == nil { - table.ResourceVersion = c.GetResourceVersion() - table.SelfLink = c.GetSelfLink() - } - if opt, ok := tableOptions.(*metav1.TableOptions); !ok || !opt.NoHeaders { - table.ColumnDefinitions = c.columns - } - - return &table, nil -} - -var ( - packageTableConvertor = tableConvertor{ - resource: porch.Resource("packages"), - cells: func(obj runtime.Object) []interface{} { - pr, ok := obj.(*api.Package) - if !ok { - return nil - } - return []interface{}{ - pr.Name, - pr.Spec.PackageName, - pr.Spec.RepositoryName, - pr.Status.LatestRevision, - } - }, - columns: []metav1.TableColumnDefinition{ - {Name: "Name", Type: "string"}, - {Name: "Package", Type: "string"}, - {Name: "Repository", Type: "string"}, - {Name: "Latest Revision", Type: "string"}, - }, - } - - packageRevisionTableConvertor = tableConvertor{ - resource: porch.Resource("packagerevisions"), - cells: func(obj runtime.Object) []interface{} { - pr, ok := obj.(*api.PackageRevision) - if !ok { - return nil - } - return []interface{}{ - pr.Name, - pr.Spec.PackageName, - pr.Spec.WorkspaceName, - pr.Spec.Revision, - isLatest(pr), - pr.Spec.Lifecycle, - pr.Spec.RepositoryName, - } - }, - columns: []metav1.TableColumnDefinition{ - {Name: "Name", Type: "string"}, - {Name: "Package", Type: "string"}, - {Name: "WorkspaceName", Type: "string"}, - {Name: "Revision", Type: "string"}, - {Name: "Latest", Type: "boolean"}, - {Name: "Lifecycle", Type: "string"}, - {Name: "Repository", Type: "string"}, - }, - } - - packageRevisionResourcesTableConvertor = tableConvertor{ - resource: porch.Resource("packagerevisionresources"), - cells: func(obj runtime.Object) []interface{} { - pr, ok := obj.(*api.PackageRevisionResources) - if !ok { - return nil - } - return []interface{}{ - pr.Name, - pr.Spec.PackageName, - pr.Spec.WorkspaceName, - pr.Spec.Revision, - pr.Spec.RepositoryName, - len(pr.Spec.Resources), - } - }, - columns: []metav1.TableColumnDefinition{ - {Name: "Name", Type: "string"}, - {Name: "Package", Type: "string"}, - {Name: "WorkspaceName", Type: "string"}, - {Name: "Revision", Type: "string"}, - {Name: "Repository", Type: "string"}, - {Name: "Files", Type: "integer"}, - }, - } -) - -func isLatest(pr *api.PackageRevision) bool { - val, ok := pr.Labels[api.LatestPackageRevisionKey] - return ok && val == api.LatestPackageRevisionValue -} diff --git a/porch/pkg/registry/porch/testing.go b/porch/pkg/registry/porch/testing.go deleted file mode 100644 index 2d2f47e186..0000000000 --- a/porch/pkg/registry/porch/testing.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - "fmt" - "testing" - - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" -) - -func testValidateUpdate(t *testing.T, s SimpleRESTUpdateStrategy, old, new api.PackageRevisionLifecycle, valid bool) { - ctx := context.Background() - t.Run(fmt.Sprintf("%s-%s", old, new), func(t *testing.T) { - oldRev := &api.PackageRevision{ - Spec: api.PackageRevisionSpec{ - Lifecycle: old, - }, - } - newRev := &api.PackageRevision{ - Spec: api.PackageRevisionSpec{ - Lifecycle: new, - }, - } - - allErrs := s.ValidateUpdate(ctx, newRev, oldRev) - - if valid { - if len(allErrs) > 0 { - t.Errorf("Update %s -> %s failed unexpectedly: %v", old, new, allErrs.ToAggregate().Error()) - } - } else { - if len(allErrs) == 0 { - t.Errorf("Update %s -> %s should fail but didn't", old, new) - } - } - }) -} diff --git a/porch/pkg/registry/porch/userinfo.go b/porch/pkg/registry/porch/userinfo.go deleted file mode 100644 index f5c72a4125..0000000000 --- a/porch/pkg/registry/porch/userinfo.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "k8s.io/apiserver/pkg/authentication/user" - "k8s.io/apiserver/pkg/endpoints/request" -) - -type ApiserverUserInfoProvider struct{} - -var _ repository.UserInfoProvider = &ApiserverUserInfoProvider{} - -func (p *ApiserverUserInfoProvider) GetUserInfo(ctx context.Context) *repository.UserInfo { - userinfo, ok := request.UserFrom(ctx) - if !ok { - return nil - } - - name := userinfo.GetName() - if name == "" { - return nil - } - - for _, group := range userinfo.GetGroups() { - if group == user.AllAuthenticated { - return &repository.UserInfo{ - Name: name, // k8s authentication only provides single name; use it for both values for now. - Email: name, - } - } - } - - return nil -} diff --git a/porch/pkg/registry/porch/userinfo_test.go b/porch/pkg/registry/porch/userinfo_test.go deleted file mode 100644 index 26dac47e43..0000000000 --- a/porch/pkg/registry/porch/userinfo_test.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - "testing" - - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/google/go-cmp/cmp" - "k8s.io/apiserver/pkg/authentication/user" - "k8s.io/apiserver/pkg/endpoints/request" -) - -func TestApiserverProvider(t *testing.T) { - - uip := &ApiserverUserInfoProvider{} - - for _, tc := range []struct { - name string - groups []string - - want *repository.UserInfo - }{ - { - want: nil, - }, - { - name: "user1@domain.com", - groups: []string{}, - want: nil, - }, - { - name: "user2@domain.com", - groups: []string{user.AllUnauthenticated, user.Anonymous}, - want: nil, - }, - { - name: "", - groups: []string{user.AllAuthenticated}, - want: nil, - }, - { - name: "user3@domain.com", - groups: []string{user.AllAuthenticated}, - want: &repository.UserInfo{ - Name: "user3@domain.com", - Email: "user3@domain.com", - }, - }, - } { - di := &user.DefaultInfo{ - Name: tc.name, - UID: "uuid", - Groups: tc.groups, - Extra: map[string][]string{}, - } - - ctx := request.WithUser(context.Background(), di) - - if got, want := uip.GetUserInfo(ctx), tc.want; !cmp.Equal(got, want) { - t.Errorf("GetUserInfo: got %v, want %v; diff (-want,+got): %s", got, want, cmp.Diff(want, got)) - } - } -} - -func TestEmptyUserInfo(t *testing.T) { - uip := &ApiserverUserInfoProvider{} - - if got, want := uip.GetUserInfo(context.Background()), (*repository.UserInfo)(nil); got != want { - t.Errorf("GetUserInfo with empty context: got %v, want %v", got, want) - } -} diff --git a/porch/pkg/registry/porch/watch.go b/porch/pkg/registry/porch/watch.go deleted file mode 100644 index d1487cf8a2..0000000000 --- a/porch/pkg/registry/porch/watch.go +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - "fmt" - "sync" - - "github.com/GoogleContainerTools/kpt/porch/pkg/engine" - "github.com/GoogleContainerTools/kpt/porch/pkg/meta" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "go.opentelemetry.io/otel/trace" - metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/watch" - genericapirequest "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/klog/v2" -) - -// Watch supports watching for changes. -func (r *packageRevisions) Watch(ctx context.Context, options *metainternalversion.ListOptions) (watch.Interface, error) { - // 'label' selects on labels; 'field' selects on the object's fields. Not all fields - // are supported; an error should be returned if 'field' tries to select on a field that - // isn't supported. 'resourceVersion' allows for continuing/starting a watch at a - // particular version. - - ctx, span := tracer.Start(ctx, "packageRevisions::Watch", trace.WithAttributes()) - defer span.End() - - filter, err := parsePackageRevisionFieldSelector(options.FieldSelector) - if err != nil { - return nil, err - } - - if ns, namespaced := genericapirequest.NamespaceFrom(ctx); namespaced { - if filter.Namespace != "" && ns != filter.Namespace { - return nil, fmt.Errorf("conflicting namespaces specified: %q and %q", ns, filter.Namespace) - } - filter.Namespace = ns - } - - ctx, cancel := context.WithCancel(ctx) - - w := &watcher{ - cancel: cancel, - resultChan: make(chan watch.Event, 64), - } - - go w.listAndWatch(ctx, r, filter, options.LabelSelector) - - return w, nil -} - -// watcher implements watch.Interface, and holds the state for an active watch. -type watcher struct { - cancel func() - resultChan chan watch.Event - - // mutex that protects the eventCallback and done fields - // from concurrent access. - mutex sync.Mutex - eventCallback func(eventType watch.EventType, pr engine.PackageRevision) bool - done bool - totalSent int -} - -var _ watch.Interface = &watcher{} - -// Stop stops watching. Will close the channel returned by ResultChan(). Releases -// any resources used by the watch. -func (w *watcher) Stop() { - w.cancel() -} - -// ResultChan returns a chan which will receive all the events. If an error occurs -// or Stop() is called, the implementation will close this channel and -// release any resources used by the watch. -func (w *watcher) ResultChan() <-chan watch.Event { - return w.resultChan -} - -type packageReader interface { - watchPackages(ctx context.Context, filter packageRevisionFilter, callback engine.ObjectWatcher) error - listPackageRevisions(ctx context.Context, filter packageRevisionFilter, selector labels.Selector, callback func(p *engine.PackageRevision) error) error -} - -// listAndWatch implements watch by doing a list, then sending any observed changes. -// This is not a compliant implementation of watch, but it is a good-enough start for most controllers. -// One trick is that we start the watch _before_ we perform the list, so we don't miss changes that happen immediately after the list. -func (w *watcher) listAndWatch(ctx context.Context, r packageReader, filter packageRevisionFilter, selector labels.Selector) { - if err := w.listAndWatchInner(ctx, r, filter, selector); err != nil { - // TODO: We need to populate the object on this error - klog.Warningf("sending error to watch stream: %v", err) - ev := watch.Event{ - Type: watch.Error, - } - w.resultChan <- ev - } - w.cancel() - close(w.resultChan) -} - -func (w *watcher) listAndWatchInner(ctx context.Context, r packageReader, filter packageRevisionFilter, selector labels.Selector) error { - errorResult := make(chan error, 4) - - var backlog []watch.Event - // Make sure we hold the lock when setting the eventCallback, as it - // will be read by other goroutines when events happen. - w.mutex.Lock() - w.eventCallback = func(eventType watch.EventType, pr engine.PackageRevision) bool { - if w.done { - return false - } - obj, err := pr.GetPackageRevision(ctx) - if err != nil { - w.done = true - errorResult <- err - return false - } - - backlog = append(backlog, watch.Event{ - Type: eventType, - Object: obj, - }) - - return true - } - w.mutex.Unlock() - - if err := r.watchPackages(ctx, filter, w); err != nil { - return err - } - - sentAdd := 0 - // TODO: Only if rv == 0? - if err := r.listPackageRevisions(ctx, filter, selector, func(p *engine.PackageRevision) error { - obj, err := p.GetPackageRevision(ctx) - if err != nil { - w.mutex.Lock() - w.done = true - w.mutex.Unlock() - return err - } - // TODO: Check resource version? - ev := watch.Event{ - Type: watch.Added, - Object: obj, - } - sentAdd += 1 - w.sendWatchEvent(ev) - return nil - }); err != nil { - w.mutex.Lock() - w.done = true - w.mutex.Unlock() - return err - } - - // Repeatedly flush the backlog until we catch up - sentBacklog := 0 - for { - w.mutex.Lock() - chunk := backlog - backlog = nil - w.mutex.Unlock() - - if len(chunk) == 0 { - break - } - - for _, ev := range chunk { - // TODO: Check resource version? - sentBacklog += 1 - w.sendWatchEvent(ev) - } - } - - w.mutex.Lock() - // Pick up anything that squeezed in - sentNewBacklog := 0 - for _, ev := range backlog { - // TODO: Check resource version? - - sentNewBacklog += 1 - w.sendWatchEvent(ev) - } - - klog.Infof("watch %p: moving watch into streaming mode after sentAdd %d, sentBacklog %d, sentNewBacklog %d", w, sentAdd, sentBacklog, sentNewBacklog) - w.eventCallback = func(eventType watch.EventType, pr engine.PackageRevision) bool { - if w.done { - return false - } - obj, err := pr.GetPackageRevision(ctx) - if err != nil { - w.done = true - errorResult <- err - return false - } - // TODO: Check resource version? - ev := watch.Event{ - Type: eventType, - Object: obj, - } - w.sendWatchEvent(ev) - return true - } - w.mutex.Unlock() - - select { - case <-ctx.Done(): - w.mutex.Lock() - defer w.mutex.Unlock() - w.done = true - return ctx.Err() - - case err := <-errorResult: - w.mutex.Lock() - defer w.mutex.Unlock() - w.done = true - return err - } - -} - -func (w *watcher) sendWatchEvent(ev watch.Event) { - // TODO: Handle the case that the watch channel is full? - w.resultChan <- ev - w.totalSent += 1 - if (w.totalSent % 100) == 0 { - klog.Infof("watch %p: total sent: %d", w, w.totalSent) - } -} - -// OnPackageRevisionChange is the callback called when a PackageRevision changes. -func (w *watcher) OnPackageRevisionChange(eventType watch.EventType, pr repository.PackageRevision, objMeta meta.PackageRevisionMeta) bool { - w.mutex.Lock() - defer w.mutex.Unlock() - - return w.eventCallback(eventType, *engine.ToPackageRevision(pr, objMeta)) -} diff --git a/porch/pkg/registry/porch/watch_test.go b/porch/pkg/registry/porch/watch_test.go deleted file mode 100644 index f1dcac7a04..0000000000 --- a/porch/pkg/registry/porch/watch_test.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2022 The kpt 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. - -package porch - -import ( - "context" - "sync" - "testing" - "time" - - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/engine" - "github.com/GoogleContainerTools/kpt/porch/pkg/engine/fake" - "github.com/GoogleContainerTools/kpt/porch/pkg/meta" - metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/watch" -) - -func TestWatcherClose(t *testing.T) { - ctx := context.Background() - ctx, cancelFunc := context.WithCancel(ctx) - - w := &watcher{ - cancel: cancelFunc, - resultChan: make(chan watch.Event, 64), - } - - r := &fakePackageReader{} - r.Add(1) - var filter packageRevisionFilter - options := &metainternalversion.ListOptions{} - - go w.listAndWatch(ctx, r, filter, options.LabelSelector) - - // Just make sure someone is pulling events of the result channel. - go func() { - for range w.resultChan { - // do nothing - } - }() - - // Wait until the callback has been set in the fakePackageReader - r.Wait() - - // Create lots of watch events for the next 2 seconds. - timer := time.NewTimer(2 * time.Second) - go func() { - ch := make(chan struct{}) - close(ch) - for { - select { - case <-ch: - pkgRev := &fake.PackageRevision{ - PackageRevision: &v1alpha1.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Labels: make(map[string]string), - }, - }, - } - if cont := r.callback.OnPackageRevisionChange(watch.Modified, pkgRev, meta.PackageRevisionMeta{}); !cont { - return - } - case <-timer.C: - return - } - } - }() - - // Close the watcher while watch events are being sent. - <-time.NewTimer(1 * time.Second).C - cancelFunc() - <-timer.C -} - -type fakePackageReader struct { - sync.WaitGroup - callback engine.ObjectWatcher -} - -func (f *fakePackageReader) watchPackages(ctx context.Context, filter packageRevisionFilter, callback engine.ObjectWatcher) error { - f.callback = callback - f.Done() - return nil -} - -func (f *fakePackageReader) listPackageRevisions(ctx context.Context, filter packageRevisionFilter, selector labels.Selector, callback func(p *engine.PackageRevision) error) error { - return nil -} diff --git a/porch/pkg/registry/porch/wi/wi.go b/porch/pkg/registry/porch/wi/wi.go deleted file mode 100644 index 13f64f71a8..0000000000 --- a/porch/pkg/registry/porch/wi/wi.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2022 The kpt 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. - -package wi - -import ( - "context" - "fmt" - "os" - "strings" - - "github.com/GoogleContainerTools/kpt/porch/pkg/tokenexchange/gcptokensource" - "github.com/GoogleContainerTools/kpt/porch/pkg/tokenexchange/ksaimpersonationtokensource" - "github.com/GoogleContainerTools/kpt/porch/pkg/tokenexchange/ksatokensource" - "golang.org/x/oauth2" - stsv1 "google.golang.org/api/sts/v1" - "k8s.io/apimachinery/pkg/types" - corev1client "k8s.io/client-go/kubernetes/typed/core/v1" - "k8s.io/klog/v2" -) - -func NewWITokenExchanger(corev1Client *corev1client.CoreV1Client, stsClient *stsv1.Service) *WITokenExchanger { - return &WITokenExchanger{ - corev1Client: corev1Client, - stsClient: stsClient, - } -} - -type WITokenExchanger struct { - corev1Client *corev1client.CoreV1Client - stsClient *stsv1.Service -} - -func (w *WITokenExchanger) Exchange(ctx context.Context, ksa types.NamespacedName, gsa string) (*oauth2.Token, error) { - workloadIdentityPool, identityProvider, err := w.findWorkloadIdentityPool(ctx, ksa) - if err != nil { - return nil, err - } - - impersonated := ksaimpersonationtokensource.New(w.corev1Client, ksa, []string{workloadIdentityPool}) - - ksaToken := ksatokensource.New(w.stsClient, impersonated, workloadIdentityPool, identityProvider) - - var scopes []string - gcpToken := gcptokensource.New(gsa, scopes, ksaToken) - - token, err := gcpToken.Token() - if err != nil { - return nil, fmt.Errorf("unable to get token: %w", err) - } - - return token, nil -} - -func (w *WITokenExchanger) findWorkloadIdentityPool(ctx context.Context, kubeServiceAccount types.NamespacedName) (string, string, error) { - accessToken := "" - - // First, see if we have a valid token mounted locally in our pod - { - const tokenFilePath = "/var/run/secrets/kubernetes.io/serviceaccount/token" - - tokenBytes, err := os.ReadFile(tokenFilePath) - if err != nil { - if os.IsNotExist(err) { - klog.V(2).Infof("token file not found at %q", tokenFilePath) - } else { - klog.Warningf("error reading token file from %q: %v", tokenFilePath, err) - } - } else { - klog.Infof("found token at %q", tokenFilePath) - accessToken = string(tokenBytes) - } - } - - // We could also query the kube apiserver at /.well-known/openid-configuration - // kubectl get --raw /.well-known/openid-configuration - // {"issuer":"https://container.googleapis.com/v1/projects/example-project-id/locations/us-central1/clusters/krmapihost-control","jwks_uri":"https://172.16.0.130:443/openid/v1/jwks","response_types_supported":["id_token"],"subject_types_supported":["public"],"id_token_signing_alg_values_supported":["RS256"]} - - if accessToken == "" { - // We get a token for our own service account, so we can extract the issuer - klog.Infof("token not found at well-known path, requesting token from apiserver") - impersonated := ksaimpersonationtokensource.New(w.corev1Client, kubeServiceAccount, nil /* unspecified/default audience */) - - token, err := impersonated.Token() - if err != nil { - return "", "", fmt.Errorf("failed to get kube token for %s: %w", kubeServiceAccount, err) - } else { - accessToken = token.AccessToken - } - } - - issuer, err := ksatokensource.ExtractIssuer(accessToken) - if err != nil { - return "", "", err - } - - if strings.HasPrefix(issuer, "https://container.googleapis.com/") { - path := strings.TrimPrefix(issuer, "https://container.googleapis.com/") - tokens := strings.Split(path, "/") - for i := 0; i+1 < len(tokens); i++ { - if tokens[i] == "projects" { - workloadIdentityPool := tokens[i+1] + ".svc.id.goog" - klog.Infof("inferred workloadIdentityPool as %q", workloadIdentityPool) - return workloadIdentityPool, issuer, nil - } - } - return "", "", fmt.Errorf("could not extract project from issue %q", issuer) - } else { - return "", "", fmt.Errorf("unknown issuer %q", issuer) - } -} diff --git a/porch/pkg/repository/repository.go b/porch/pkg/repository/repository.go deleted file mode 100644 index 858ef95859..0000000000 --- a/porch/pkg/repository/repository.go +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright 2022 The kpt 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. - -package repository - -import ( - "context" - "fmt" - - kptfile "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - "github.com/go-git/go-git/v5/plumbing/transport" - "k8s.io/apimachinery/pkg/types" -) - -// TODO: "sigs.k8s.io/kustomize/kyaml/filesys" FileSystem? -type PackageResources struct { - Contents map[string]string -} - -type PackageRevisionKey struct { - Repository, Package, Revision string - WorkspaceName v1alpha1.WorkspaceName -} - -func (n PackageRevisionKey) String() string { - return fmt.Sprintf("Repository: %q, Package: %q, Revision: %q, WorkspaceName: %q", - n.Repository, n.Package, n.Revision, string(n.WorkspaceName)) -} - -type PackageKey struct { - Repository, Package string -} - -func (n PackageKey) String() string { - return fmt.Sprintf("Repository: %q, Package: %q", n.Repository, n.Package) -} - -// CachedIdentier is a used by a cache and underlying storage -// implementation to avoid unnecessary reloads -type CachedIdentifier struct { - // Key uniquely identifies the resource in the underlying storage - Key string - - // Version uniquely identifies the version of the resource in the underlying storage - Version string -} - -type PackageRevisionCacheEntry struct { - Version string - PackageRevision PackageRevision -} - -type PackageRevisionCache map[string]PackageRevisionCacheEntry - -type packageCacheKey struct{} - -func ContextWithPackageRevisionCache(ctx context.Context, cache PackageRevisionCache) context.Context { - return context.WithValue(ctx, packageCacheKey{}, cache) -} - -func PackageRevisionCacheFromContext(ctx context.Context) PackageRevisionCache { - cache, ok := ctx.Value(packageCacheKey{}).(PackageRevisionCache) - if !ok { - cache = make(PackageRevisionCache) - } - return cache -} - -// PackageRevision is an abstract package version. -// We have a single object for both Revision and Resources, because conceptually they are one object. -// The best way we've found (so far) to represent them in k8s is as two resources, but they map to the same object. -// Interesting reading: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#differing-representations -type PackageRevision interface { - // KubeObjectName returns an encoded name for the object that should be unique. - // More "readable" values are returned by Key() - KubeObjectName() string - - // KubeObjectNamespace returns the namespace in which the PackageRevision - // belongs. - KubeObjectNamespace() string - - // UID returns a unique identifier for the PackageRevision. - UID() types.UID - - // Key returns the "primary key" of the package. - Key() PackageRevisionKey - - // CachedIdentier returns a unique identifer for this package revision and version - CachedIdentifier() CachedIdentifier - - // Lifecycle returns the current lifecycle state of the package. - Lifecycle() v1alpha1.PackageRevisionLifecycle - - // UpdateLifecycle updates the desired lifecycle of the package. This can only - // be used for Published package revisions to go from Published to DeletionProposed - // or vice versa. Draft revisions should use PackageDraft.UpdateLifecycle. - UpdateLifecycle(ctx context.Context, new v1alpha1.PackageRevisionLifecycle) error - - // GetPackageRevision returns the PackageRevision ("DRY") API representation of this package-revision - GetPackageRevision(context.Context) (*v1alpha1.PackageRevision, error) - - // GetResources returns the PackageRevisionResources ("WET") API representation of this package-revision - // TODO: return PackageResources or filesystem abstraction? - GetResources(context.Context) (*v1alpha1.PackageRevisionResources, error) - - // GetUpstreamLock returns the kpt lock information. - GetUpstreamLock(context.Context) (kptfile.Upstream, kptfile.UpstreamLock, error) - - // GetKptfile returns the Kptfile for hte package - GetKptfile(context.Context) (kptfile.KptFile, error) - - // GetLock returns the current revision's lock information. - // This will be the upstream info for downstream revisions. - GetLock() (kptfile.Upstream, kptfile.UpstreamLock, error) - - // ResourceVersion returns the Kube resource version of the package - ResourceVersion() string -} - -// Package is an abstract package. -type Package interface { - // KubeObjectName returns an encoded name for the object that should be unique. - // More "readable" values are returned by Key() - KubeObjectName() string - - // Key returns the "primary key" of the package. - Key() PackageKey - - // GetPackage returns the object representing this package - GetPackage() *v1alpha1.Package - - // GetLatestRevision returns the name of the package revision that is the "latest" package - // revision belonging to this package - GetLatestRevision() string -} - -type PackageDraft interface { - UpdateResources(ctx context.Context, new *v1alpha1.PackageRevisionResources, task *v1alpha1.Task) error - // Updates desired lifecycle of the package. The lifecycle is applied on Close. - UpdateLifecycle(ctx context.Context, new v1alpha1.PackageRevisionLifecycle) error - // Finish round of updates. - Close(ctx context.Context) (PackageRevision, error) -} - -// Function is an abstract function. -type Function interface { - Name() string - GetFunction() (*v1alpha1.Function, error) - GetCRD() (*configapi.Function, error) -} - -// ListPackageRevisionFilter is a predicate for filtering PackageRevision objects; -// only matching PackageRevision objects will be returned. -type ListPackageRevisionFilter struct { - // KubeObjectName matches the generated kubernetes object name. - KubeObjectName string - - // Package matches the name of the package (spec.package) - Package string - - // WorkspaceName matches the description of the package (spec.workspaceName) - WorkspaceName v1alpha1.WorkspaceName - - // Revision matches the revision of the package (spec.revision) - Revision string -} - -// Matches returns true if the provided PackageRevision satisfies the conditions in the filter. -func (f *ListPackageRevisionFilter) Matches(p PackageRevision) bool { - if f.Package != "" && f.Package != p.Key().Package { - return false - } - if f.Revision != "" && f.Revision != p.Key().Revision { - return false - } - if f.WorkspaceName != "" && f.WorkspaceName != p.Key().WorkspaceName { - return false - } - if f.KubeObjectName != "" && f.KubeObjectName != p.KubeObjectName() { - return false - } - return true -} - -// ListPackageFilter is a predicate for filtering Package objects; -// only matching Package objects will be returned. -type ListPackageFilter struct { - // KubeObjectName matches the generated kubernetes object name. - KubeObjectName string - - // Package matches the name of the package (spec.package) - Package string -} - -// Matches returns true if the provided Package satisfies the conditions in the filter. -func (f *ListPackageFilter) Matches(p Package) bool { - if f.Package != "" && f.Package != p.Key().Package { - return false - } - if f.KubeObjectName != "" && f.KubeObjectName != p.KubeObjectName() { - return false - } - return true -} - -// Repository is the interface for interacting with packages in repositories -// TODO: we may need interface to manage repositories too. Stay tuned. -type Repository interface { - // ListPackageRevisions lists the existing package revisions in the repository - ListPackageRevisions(ctx context.Context, filter ListPackageRevisionFilter) ([]PackageRevision, error) - - // CreatePackageRevision creates a new package revision - CreatePackageRevision(ctx context.Context, obj *v1alpha1.PackageRevision) (PackageDraft, error) - - // DeletePackageRevision deletes a package revision - DeletePackageRevision(ctx context.Context, old PackageRevision) error - - // UpdatePackageRevision updates a package - UpdatePackageRevision(ctx context.Context, old PackageRevision) (PackageDraft, error) - - // ListPackages lists all packages in the repository - ListPackages(ctx context.Context, filter ListPackageFilter) ([]Package, error) - - // CreatePackage creates a new package - CreatePackage(ctx context.Context, obj *v1alpha1.Package) (Package, error) - - // DeletePackage deletes a package - DeletePackage(ctx context.Context, old Package) error - - // Version returns a string that is guaranteed to be different if any change has been made to the repo contents - Version(ctx context.Context) (string, error) - - // Close cleans up any resources associated with the repository - Close() error -} - -type FunctionRepository interface { - // TODO: Should repository understand functions, or just packages (and function is just a package in an OCI repo?) - ListFunctions(ctx context.Context) ([]Function, error) -} - -// The definitions below would be more appropriately located in a package usable by any Porch component. -// They are located in repository package because repository is one such package though thematically -// they rather belong to a package of their own. - -type Credential interface { - Valid() bool - ToAuthMethod() transport.AuthMethod -} - -type CredentialResolver interface { - ResolveCredential(ctx context.Context, namespace, name string) (Credential, error) -} - -type UserInfo struct { - Name string - Email string -} - -// UserInfoProvider providers name of the authenticated user on whose behalf the request -// is being processed. -type UserInfoProvider interface { - // GetUserInfo returns the information about the user on whose behalf the request is being - // processed, if any. If user cannot be determnined, returns nil. - GetUserInfo(ctx context.Context) *UserInfo -} diff --git a/porch/pkg/repository/util.go b/porch/pkg/repository/util.go deleted file mode 100644 index 5180ac47e4..0000000000 --- a/porch/pkg/repository/util.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2022 The kpt 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. - -package repository - -import ( - "fmt" - "regexp" - "strconv" - "strings" - - kptfile "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - api "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "golang.org/x/mod/semver" -) - -func ToApiReadinessGates(kf kptfile.KptFile) []api.ReadinessGate { - var readinessGates []api.ReadinessGate - if kf.Info != nil { - for _, rg := range kf.Info.ReadinessGates { - readinessGates = append(readinessGates, api.ReadinessGate{ - ConditionType: rg.ConditionType, - }) - } - } - return readinessGates -} - -func ToApiConditions(kf kptfile.KptFile) []api.Condition { - var conditions []api.Condition - if kf.Status != nil && kf.Status.Conditions != nil { - for _, s := range kf.Status.Conditions { - conditions = append(conditions, api.Condition{ - Type: s.Type, - Status: toApiConditionStatus(s.Status), - Reason: s.Reason, - Message: s.Message, - }) - } - } - return conditions -} - -func toApiConditionStatus(s kptfile.ConditionStatus) api.ConditionStatus { - switch s { - case kptfile.ConditionTrue: - return api.ConditionTrue - case kptfile.ConditionFalse: - return api.ConditionFalse - case kptfile.ConditionUnknown: - return api.ConditionUnknown - default: - panic(fmt.Errorf("unknown condition status: %v", s)) - } -} - -func NextRevisionNumber(revs []string) (string, error) { - // Computes the next revision number as the latest revision number + 1. - // This function only understands strict versioning format, e.g. v1, v2, etc. It will - // ignore all revision numbers it finds that do not adhere to this format. - // If there are no published revisions (in the recognized format), the revision - // number returned here will be "v1". - latestRev := "v0" - for _, currentRev := range revs { - if !semver.IsValid(currentRev) { - // ignore this revision - continue - } - // collect the major version. i.e. if we find that the latest published - // version is v3.1.1, we will end up returning v4 - currentRev = semver.Major(currentRev) - - switch cmp := semver.Compare(currentRev, latestRev); { - case cmp == 0: - // Same revision. - case cmp < 0: - // current < latest; no change - case cmp > 0: - // current > latest; update latest - latestRev = currentRev - } - - } - - i, err := strconv.Atoi(latestRev[1:]) - if err != nil { - return "", err - } - i++ - next := "v" + strconv.Itoa(i) - return next, nil -} - -// ValidateWorkspaceName validates WorkspaceName. It must: -// - be at least 1 and at most 63 characters long -// - contain only lowercase alphanumeric characters or '-' -// - start and end with an alphanumeric character. -// -// '/ ' should never be allowed, because we use '/' to -// delimit branch names (e.g. the 'drafts/' prefix). -func ValidateWorkspaceName(workspace v1alpha1.WorkspaceName) error { - wn := string(workspace) - if len(wn) > 63 || len(wn) == 0 { - return fmt.Errorf("workspaceName %q must be at least 1 and at most 63 characters long", wn) - } - if strings.HasPrefix(wn, "-") || strings.HasSuffix(wn, "-") { - return fmt.Errorf("workspaceName %q must start and end with an alphanumeric character", wn) - } - - match, err := regexp.MatchString(`^[a-z0-9-]+$`, wn) - if err != nil { - return err - } - if !match { - return fmt.Errorf("workspaceName %q must be comprised only of lowercase alphanumeric characters and '-'", wn) - } - - return nil -} diff --git a/porch/pkg/repository/util_test.go b/porch/pkg/repository/util_test.go deleted file mode 100644 index b7df196e51..0000000000 --- a/porch/pkg/repository/util_test.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2022 The kpt 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. - -package repository - -import ( - "fmt" - "testing" - - v1alpha1 "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/stretchr/testify/assert" -) - -func TestValidateWorkspaceName(t *testing.T) { - testCases := map[string]struct { - workspace string - expectedErr error - }{ - "empty string": { - workspace: "", - expectedErr: fmt.Errorf("workspaceName %q must be at least 1 and at most 63 characters long", ""), - }, - - "64 characters long": { - workspace: "abcedfhglaasdkfuaweoihfjghldhsgufhgaakjsdhaflkasdjflksadjfsalsdk", - expectedErr: fmt.Errorf("workspaceName %q must be at least 1 and at most 63 characters long", "abcedfhglaasdkfuaweoihfjghldhsgufhgaakjsdhaflkasdjflksadjfsalsdk"), - }, - - "63 characters long": { - workspace: "abcedfhglaasdkfuaweoihfjghldhsgufhgaakjsdhaflkasdjflksadjfsalsk", - expectedErr: nil, - }, - - "starts with -": { - workspace: "-hello", - expectedErr: fmt.Errorf("workspaceName %q must start and end with an alphanumeric character", "-hello"), - }, - - "ends with -": { - workspace: "hello-", - expectedErr: fmt.Errorf("workspaceName %q must start and end with an alphanumeric character", "hello-"), - }, - - "has - in the middle": { - workspace: "hel-lo-wor-ld", - expectedErr: nil, - }, - - "has uppercase alphanumeric characters": { - workspace: "hElLo", - expectedErr: fmt.Errorf("workspaceName %q must be comprised only of lowercase alphanumeric characters and '-'", "hElLo"), - }, - - "has other characters": { - workspace: "hel lo", - expectedErr: fmt.Errorf("workspaceName %q must be comprised only of lowercase alphanumeric characters and '-'", "hel lo"), - }, - } - - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - got := ValidateWorkspaceName(v1alpha1.WorkspaceName(tc.workspace)) - assert.Equal(t, tc.expectedErr, got) - }) - } -} diff --git a/porch/pkg/tokenexchange/gcptokensource/gcptokensource.go b/porch/pkg/tokenexchange/gcptokensource/gcptokensource.go deleted file mode 100644 index b1ecf7ef9f..0000000000 --- a/porch/pkg/tokenexchange/gcptokensource/gcptokensource.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2022 The kpt 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. - -package gcptokensource - -import ( - "context" - "fmt" - "time" - - iamv1 "cloud.google.com/go/iam/credentials/apiv1" - "github.com/golang/protobuf/ptypes" - "golang.org/x/oauth2" - "google.golang.org/api/option" - iampb "google.golang.org/genproto/googleapis/iam/credentials/v1" - "k8s.io/klog/v2" -) - -// New returns an oauth2.TokenSource that exchanges tokens from ts for tokens -// that authenticate as GCP Service Accounts. -func New(gcpServiceAccount string, scopes []string, tokenSource oauth2.TokenSource) oauth2.TokenSource { - // The cloud-platform scope is always required for the token exchange. - scopes = append(scopes, "https://www.googleapis.com/auth/cloud-platform") - return &gcpTokenSource{ - gcpServiceAccount: gcpServiceAccount, - scopes: scopes, - tokenSource: tokenSource, - } -} - -// gcpTokenSource produces tokens that authenticate as GCP ServiceAccounts. -type gcpTokenSource struct { - gcpServiceAccount string - scopes []string - tokenSource oauth2.TokenSource -} - -// ensure gcpTokenSource implements oauth2.TokenSource -var _ oauth2.TokenSource = &gcpTokenSource{} - -// Token exchanges the input token for a GCP SA token. -func (ts *gcpTokenSource) Token() (*oauth2.Token, error) { - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - // use the provided token source to make the request - c, err := iamv1.NewIamCredentialsClient(ctx, option.WithTokenSource(ts.tokenSource)) - if err != nil { - return nil, fmt.Errorf("failed to construct IAM client: %w", err) - } - resp, err := c.GenerateAccessToken(ctx, - &iampb.GenerateAccessTokenRequest{ - Name: "projects/-/serviceAccounts/" + ts.gcpServiceAccount, - Scope: ts.scopes, - }) - if err != nil { - return nil, fmt.Errorf("token exchange for GCP serviceaccount %q failed: %w", ts.gcpServiceAccount, err) - } - - klog.Infof("got GCP token for %v", ts.gcpServiceAccount) - - expiry, err := ptypes.Timestamp(resp.ExpireTime) - if err != nil { - return nil, fmt.Errorf("failed to parse expire time on returned token: %w", err) - } - return &oauth2.Token{ - AccessToken: resp.AccessToken, - Expiry: expiry, - }, nil -} diff --git a/porch/pkg/tokenexchange/ksaimpersonationtokensource/ksaimpersonation.go b/porch/pkg/tokenexchange/ksaimpersonationtokensource/ksaimpersonation.go deleted file mode 100644 index f840315f91..0000000000 --- a/porch/pkg/tokenexchange/ksaimpersonationtokensource/ksaimpersonation.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2022 The kpt 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. - -package ksaimpersonationtokensource - -import ( - "context" - "fmt" - "time" - - "golang.org/x/oauth2" - authenticationv1 "k8s.io/api/authentication/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - corev1client "k8s.io/client-go/kubernetes/typed/core/v1" - "k8s.io/klog/v2" -) - -// New returns an oauth2.TokenSource that exchanges the KSA token at ksaTokenPath -// for a GCP access token. -func New(corev1Client corev1client.CoreV1Interface, serviceAccount types.NamespacedName, audiences []string) oauth2.TokenSource { - return &ksaImpersonationTokenSource{ - corev1Client: corev1Client, - serviceAccount: serviceAccount, - audiences: audiences, - } -} - -// ksaImpersonationTokenSource implements oauth2.TokenSource for exchanging KSA tokens for -// GCP tokens. It can be wrapped in a ReuseTokenSource to cache tokens until -// expiry. -type ksaImpersonationTokenSource struct { - corev1Client corev1client.CoreV1Interface - - // serviceAccount is the name of the serviceAccount to impersonate - serviceAccount types.NamespacedName - - // audiences is the set of audiences to request - audiences []string -} - -// ksaTokenSource implements oauth2.TokenSource -var _ oauth2.TokenSource = &ksaImpersonationTokenSource{} - -// Token exchanges a KSA token for a GCP access token, returning the GCP token. -func (ts *ksaImpersonationTokenSource) Token() (*oauth2.Token, error) { - tokenRequest := &authenticationv1.TokenRequest{ - Spec: authenticationv1.TokenRequestSpec{ - Audiences: ts.audiences, - }, - } - - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - klog.V(2).Infof("getting token for kubernetes serviceaccount %v", ts.serviceAccount) - response, err := ts.corev1Client.ServiceAccounts(ts.serviceAccount.Namespace).CreateToken(ctx, ts.serviceAccount.Name, tokenRequest, metav1.CreateOptions{}) - if err != nil { - return nil, fmt.Errorf("failed to CreateToken for %s: %w", ts.serviceAccount, err) - } - - exchangeTime := time.Now() - - serviceAccountToken := &oauth2.Token{ - AccessToken: response.Status.Token, - TokenType: "Bearer", - } - - if response.Spec.ExpirationSeconds != nil { - serviceAccountToken.Expiry = exchangeTime.Add(time.Duration(*response.Spec.ExpirationSeconds) * time.Second) - } else { - klog.Warningf("service account token did not include expirationSeconds") - serviceAccountToken.Expiry = exchangeTime - } - - return serviceAccountToken, nil -} diff --git a/porch/pkg/tokenexchange/ksatokensource/ksatokensource.go b/porch/pkg/tokenexchange/ksatokensource/ksatokensource.go deleted file mode 100644 index b716031e6d..0000000000 --- a/porch/pkg/tokenexchange/ksatokensource/ksatokensource.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2022 The kpt 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. - -package ksatokensource - -import ( - "context" - "encoding/base64" - "encoding/json" - "fmt" - "strings" - "time" - - "golang.org/x/oauth2" - stsv1 "google.golang.org/api/sts/v1" -) - -// New returns an oauth2.TokenSource that exchanges the KSA token from ksaToken -// for a GCP access token. -func New(stsService *stsv1.Service, ksaToken oauth2.TokenSource, workloadIdentityPool, identityProvider string) oauth2.TokenSource { - return &ksaTokenSource{ - ksaToken: ksaToken, - workloadIdentityPool: workloadIdentityPool, - identityProvider: identityProvider, - stsService: stsService, - } -} - -// ksaTokenSource implements oauth2.TokenSource for exchanging KSA tokens for -// GCP tokens. It can be wrapped in a ReuseTokenSource to cache tokens until -// expiry. -type ksaTokenSource struct { - // ksaToken is the source of the kubernetes serviceaccount token. - ksaToken oauth2.TokenSource - // workloadIdentityPool is the Workload Identity Pool to use when exchanging the KSA - // token for a GCP token. - workloadIdentityPool string - // identityProvider is the Identity Provider to use when exchanging the KSA - // token for a GCP token. - identityProvider string - - stsService *stsv1.Service -} - -// ksaTokenSource implements oauth2.TokenSource -var _ oauth2.TokenSource = &ksaTokenSource{} - -// Token exchanges a KSA token for a GCP access token, returning the GCP token. -func (ts *ksaTokenSource) Token() (*oauth2.Token, error) { - ksaToken, err := ts.ksaToken.Token() - if err != nil { - return nil, err - } - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - exchangeTime := time.Now() - workloadIdentityPool := ts.workloadIdentityPool - identityProvider := ts.identityProvider - - audience := fmt.Sprintf("identitynamespace:%s:%s", workloadIdentityPool, identityProvider) - - request := &stsv1.GoogleIdentityStsV1ExchangeTokenRequest{ - GrantType: "urn:ietf:params:oauth:grant-type:token-exchange", - SubjectTokenType: "urn:ietf:params:oauth:token-type:jwt", - SubjectToken: ksaToken.AccessToken, - RequestedTokenType: "urn:ietf:params:oauth:token-type:access_token", - Audience: audience, - Scope: "https://www.googleapis.com/auth/iam", - } - - response, err := ts.stsService.V1.Token(request).Context(ctx).Do() - if err != nil { - return nil, fmt.Errorf("failed to get federated token from STS: %w", err) - } - - token := &oauth2.Token{ - AccessToken: response.AccessToken, - TokenType: response.TokenType, - Expiry: exchangeTime.Add(time.Duration(response.ExpiresIn) * time.Second), - } - return token, nil - -} - -// ExtractIsssuer will extract the issuer field from the provided JWT token -func ExtractIssuer(jwtToken string) (string, error) { - return ExtractJWTString(jwtToken, "iss") -} - -// ExtractJWTString extracts the named field from the provided JWT token. -func ExtractJWTString(jwtToken string, key string) (string, error) { - tokens := strings.Split(jwtToken, ".") - if len(tokens) != 3 { - // Don't log the token as it may be sensitive - return "", fmt.Errorf("error getting identity provider from JWT (unexpected number of tokens)") - } - b, err := base64.RawURLEncoding.DecodeString(tokens[1]) - if err != nil { - // Don't log the token as it may be sensitive - return "", fmt.Errorf("error getting identity provider from JWT (cannot decode base64)") - } - m := make(map[string]interface{}) - if err := json.Unmarshal(b, &m); err != nil { - // Don't log the token as it may be sensitive - return "", fmt.Errorf("error getting identity provider from JWT (cannot decode json)") - } - val := m[key] - if val == nil { - // Don't log the token as it may be sensitive - return "", fmt.Errorf("error getting identity provider from JWT (key %q not found)", key) - } - s, ok := val.(string) - if !ok { - // Don't log the token as it may be sensitive - return "", fmt.Errorf("error getting identity provider from JWT (key %q was not string)", key) - } - return s, nil -} diff --git a/porch/pkg/tokenexchange/membership/membership.go b/porch/pkg/tokenexchange/membership/membership.go deleted file mode 100644 index 9d43d2b0b9..0000000000 --- a/porch/pkg/tokenexchange/membership/membership.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2022 The kpt 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. - -package membership - -import ( - "context" - "encoding/json" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/dynamic" -) - -var ( - gvr = schema.GroupVersionResource{ - Group: "hub.gke.io", - Version: "v1", - Resource: "memberships", - } -) - -// Membership is the object created by hub when a cluster is registered to hub. -type Membership struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - Spec MembershipSpec `json:"spec,omitempty"` -} - -type MembershipSpec struct { - Owner MembershipOwner `json:"owner,omitempty"` - WorkloadIdentityPool string `json:"workload_identity_pool,omitempty"` - IdentityProvider string `json:"identity_provider,omitempty"` -} - -type MembershipOwner struct { - ID string `json:"id,omitempty"` -} - -// Get gets and returns the Membership named "membership" from the cluster. -func Get(ctx context.Context, client dynamic.Interface) (*Membership, error) { - cr, err := client.Resource(gvr).Get(ctx, "membership", metav1.GetOptions{}) - if err != nil { - return nil, err - } - // round-trip through JSON is a convenient way to get at structured content - b, err := cr.MarshalJSON() - if err != nil { - return nil, err - } - membership := &Membership{} - if err := json.Unmarshal(b, membership); err != nil { - return nil, err - } - return membership, nil -} diff --git a/porch/pkg/util/util.go b/porch/pkg/util/util.go deleted file mode 100644 index db829cb9c3..0000000000 --- a/porch/pkg/util/util.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2023 The kpt 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. - -package util - -import ( - "crypto/sha1" - "encoding/hex" - "fmt" -) - -// KubernetesName returns the passed id if it less than maxLen, otherwise -// a truncated version of id with a unique hash of length hashLen appended -// with length maxLen. maxLen must be at least 5 + hashLen, and hashLen -// must be at least 4. -func KubernetesName(id string, hashLen, maxLen int) string { - if hashLen < 4 { - hashLen = 4 - } - if maxLen < hashLen+5 { - maxLen = hashLen + 5 - } - - if len(id) <= maxLen { - return id - } - - hash := sha1.Sum([]byte(id)) - stubIdx := maxLen - hashLen - 1 - return fmt.Sprintf("%s-%s", id[:stubIdx], hex.EncodeToString(hash[:])[:hashLen]) -} diff --git a/porch/pkg/util/util_test.go b/porch/pkg/util/util_test.go deleted file mode 100644 index 4c2fabc94a..0000000000 --- a/porch/pkg/util/util_test.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2022 The kpt 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. - -package util - -import ( - "testing" - - "github.com/google/go-cmp/cmp" -) - -func TestKubernetesName(t *testing.T) { - testCases := map[string]struct { - id string - hashLen int - maxLen int - expected string - }{ - "short-id": { - id: "my-k8s-object-name", - hashLen: 4, - maxLen: 20, - expected: "my-k8s-object-name", - }, - "long-id": { - id: "my-kubernetes-object-name", - hashLen: 4, - maxLen: 20, - expected: "my-kubernetes-o-71d0", - }, - "long-id, long-hash": { - id: "my-kubernetes-object-name", - hashLen: 8, - maxLen: 20, - expected: "my-kubernet-71d0e1e4", - }, - "maxLen too small": { - id: "my-kubernetes-object-name", - hashLen: 8, - maxLen: 8, - expected: "my-k-71d0e1e4", - }, - "hashLen too small": { - id: "my-kubernetes-object-name", - hashLen: 3, - maxLen: 20, - expected: "my-kubernetes-o-71d0", - }, - } - - for tn, tc := range testCases { - t.Run(tn, func(t *testing.T) { - if diff := cmp.Diff(tc.expected, KubernetesName(tc.id, tc.hashLen, tc.maxLen)); diff != "" { - t.Errorf("unexpected diff (+got,-want): %s", diff) - } - }) - } -} diff --git a/porch/porch.code-workspace b/porch/porch.code-workspace deleted file mode 100644 index f90fdd25c2..0000000000 --- a/porch/porch.code-workspace +++ /dev/null @@ -1,27 +0,0 @@ -{ - "folders": [ - { - "path": "api" - }, - { - "name": "hello-server", - "path": "examples/apps/hello-server" - }, - { - "name": "porch", - "path": "." - }, - { - "name": "kpt", - "path": ".." - }, - { - "name": "controllers", - "path": "controllers" - }, - { - "name": "rollouts", - "path": "../rollouts" - } - ] -} diff --git a/porch/scripts/boilerplate.go.txt b/porch/scripts/boilerplate.go.txt deleted file mode 100644 index f6a75f137f..0000000000 --- a/porch/scripts/boilerplate.go.txt +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2023 The kpt 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. diff --git a/porch/scripts/create-deployment-blueprint.sh b/porch/scripts/create-deployment-blueprint.sh deleted file mode 100755 index 576cdc544a..0000000000 --- a/porch/scripts/create-deployment-blueprint.sh +++ /dev/null @@ -1,248 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2022 The kpt 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. - -# Stricter error handling -set -e # Exit on error -set -u # Must predefine variables -set -o pipefail # Check errors in piped commands - -PORCH_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )" - -function error() { - cat < "${FN_CONFIG}" << EOF -apiVersion: fn.kpt.dev/v1alpha1 -kind: SetImage -metadata: - name: my-func-config -image: - name: ${OLD} - newName: ${IMG} - newTag: ${TAG} -additionalImageFields: -- group: apps - version: v1 - kind: Deployment - path: spec/template/spec/containers[]/env[]/value -EOF - - trap "rm -f ${FN_CONFIG}" EXIT - - kpt fn eval "${DESTINATION}" --image set-image:v0.1.1 --fn-config "${FN_CONFIG}" || echo "kpt fn eval failed" -} - -function customize-sa { - local NAME="${1}" - local SA="${2}" - - kpt fn eval "${DESTINATION}" --image set-annotations:v0.1.4 \ - --match-api-version=v1 \ - --match-kind=ServiceAccount \ - "--match-name=${NAME}" \ - --match-namespace=porch-system -- \ - "${SA}" -} - -function customize-container-env { - local ENV_KEY="${1}" - local ENV_VAL="${2}" - - # TODO: This is terrible. Do we have a good way to handle this with kpt? - sed "/env:/a\ - name: ${ENV_KEY}\n value: ${ENV_VAL}\n" -i "${DESTINATION}/9-controllers.yaml" -} - -function main() { - # Repository CRD - cp "./api/porchconfig/v1alpha1/config.porch.kpt.dev_functions.yaml" \ - "${DESTINATION}/0-functions.yaml" - cp "./api/porchconfig/v1alpha1/config.porch.kpt.dev_repositories.yaml" \ - "${DESTINATION}/0-repositories.yaml" - cp "./internal/api/porchinternal/v1alpha1/config.porch.kpt.dev_packagerevs.yaml" \ - "${DESTINATION}/0-packagerevs.yaml" - - # Porch Deployment Config - cp ${PORCH_DIR}/deployments/porch/*.yaml "${PORCH_DIR}/deployments/porch/Kptfile" "${DESTINATION}" - # Copy Porch controller manager rbac - cp ${PORCH_DIR}/controllers/config/rbac/role.yaml "${DESTINATION}/9-porch-controller-clusterrole.yaml" - - IFS=',' read -ra RECONCILERS <<< "$ENABLED_RECONCILERS" - for i in "${RECONCILERS[@]}"; do - if [[ -f "${PORCH_DIR}/controllers/config/crd/bases/config.porch.kpt.dev_${i}.yaml" ]]; then - # Copy over the CRD (if it exists) - cp "${PORCH_DIR}/controllers/config/crd/bases/config.porch.kpt.dev_${i}.yaml" \ - "${DESTINATION}/0-${i}.yaml" - fi - # Update the porch-controllers Deployment env variables to enable the reconciler. - customize-container-env \ - "ENABLE_${i^^}" \ - "\"true\"" - # Copy over the rbac rules for the reconciler - cp "${PORCH_DIR}/controllers/${i}/config/rbac/role.yaml" \ - "${DESTINATION}/9-porch-controller-${i}-clusterrole.yaml" - # Copy over the rbac rules for the reconciler - cp "${PORCH_DIR}/controllers/${i}/config/rbac/rolebinding.yaml" \ - "${DESTINATION}/9-porch-controller-${i}-clusterrolebinding.yaml" - done - - customize-image \ - "gcr.io/example-google-project-id/porch-function-runner:latest" \ - "${FUNCTION_IMAGE}" - customize-image \ - "gcr.io/example-google-project-id/porch-server:latest" \ - "${SERVER_IMAGE}" - customize-image \ - "gcr.io/example-google-project-id/porch-controllers:latest" \ - "${CONTROLLERS_IMAGE}" - customize-image-in-env \ - "gcr.io/example-google-project-id/porch-wrapper-server:latest" \ - "${WRAPPER_SERVER_IMAGE}" - - if [ -n "${CONTROLLERS_SA}" ]; then - customize-sa "porch-controllers" "${CONTROLLERS_SA}" - fi - - if [ -n "${SERVER_SA}" ]; then - customize-sa "porch-server" "${SERVER_SA}" - fi - - if [ -n "${FUNCTION_RUNNER_SA}" ]; then - # TODO: Rename serviceaccount for consistency (avoid abbreviations?) - customize-sa "porch-fn-runner" "${FUNCTION_RUNNER_SA}" - fi -} - -validate -main diff --git a/porch/scripts/create-deployment-package.sh b/porch/scripts/create-deployment-package.sh deleted file mode 100755 index 9db36d869e..0000000000 --- a/porch/scripts/create-deployment-package.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash - -# Copyright 2022 The kpt 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. - -set -ex - -kubectl apply -f - < .git/description -) - diff --git a/porch/scripts/install-etcd.sh b/porch/scripts/install-etcd.sh deleted file mode 100755 index 7c7b39ad9f..0000000000 --- a/porch/scripts/install-etcd.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2022 The kpt 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. - - -ETCD_VER=v3.5.1 -DOWNLOAD_URL="https://github.com/etcd-io/etcd/releases/download" - -function install-etcd-linux() { - echo "You will be asked for sudo password ..." - sudo -v - curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz | sudo tar -C /usr/local/bin --strip-components 1 -xvz "${DIR}/etcdctl" "${DIR}/etcdutl" "${DIR}/etcd" -} - -function install-etcd-darwin() { - echo "You will be asked for sudo password ..." - sudo -v - DIR=$(mktemp -d) - - curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-darwin-amd64.zip -o "${DIR}/etcd-${ETCD_VER}-darwin-amd64.zip" - unzip -d "${DIR}" "${DIR}/etcd-${ETCD_VER}-darwin-amd64.zip" - sudo mv ${DIR}/etcd-${ETCD_VER}-darwin-amd64/{etcd,etcdctl,etcdutl} /usr/local/bin - rm -rf ${DIR} -} - -OS=$(uname -s) -case "${OS}" in - Linux) - install-etcd-linux - ;; - - Darwin) - install-etcd-darwin - ;; - - *) echo "Unrecognized OS: ${OS}" - exit 1 - ;; -esac diff --git a/porch/scripts/install-gcrane.sh b/porch/scripts/install-gcrane.sh deleted file mode 100755 index d110ee239a..0000000000 --- a/porch/scripts/install-gcrane.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2022 The kpt 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. - - -VERSION="v0.7.0" -DOWNLOAD_URL="https://github.com/google/go-containerregistry/releases/download" -URL="${DOWNLOAD_URL}/${VERSION}/go-containerregistry_$(uname -s)_x86_64.tar.gz" -sudo -v -curl -L ${URL} | sudo tar -C /usr/local/bin -xvz "gcrane" "crane" diff --git a/porch/scripts/install-protoc.sh b/porch/scripts/install-protoc.sh deleted file mode 100755 index ddbcd3ba93..0000000000 --- a/porch/scripts/install-protoc.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -# Copyright 2022 The kpt 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. - -VERSION="3.19.4" -OS=$(uname -s) -MACHINE=$(uname -m) - -case "${OS}" in - Linux) PLATFORM="linux" - ;; - Darwin) PLATFORM="osx" - ;; - *) echo "Unrecognized OS: %{OS}" - exit 1 - ;; -esac - -function cleanup() { - [[ -z "${TMPDIR}" ]] || { rm -rf "${TMPDIR}" || true ; } -} -trap cleanup EXIT - -TMPDIR=$(mktemp -d) -ARCHIVE="protoc-${VERSION}-${PLATFORM}-${MACHINE}.zip" -URL="https://github.com/protocolbuffers/protobuf/releases/download/v${VERSION}/${ARCHIVE}" - -curl -L "${URL}" -o "${TMPDIR}/${ARCHIVE}" - -echo "You may be asked for sudo password..." -sudo -v -sudo unzip -o -q -d /usr/local "${TMPDIR}/${ARCHIVE}" -x "readme.txt" -cd /usr/local ; sudo unzip -Z1 "${TMPDIR}/${ARCHIVE}" | grep -v "readme.txt" | sudo xargs chmod +r -sudo chmod +rx \ - /usr/local/bin/protoc \ - /usr/local/include/google \ - /usr/local/include/google/protobuf \ - /usr/local/include/google/protobuf/compiler diff --git a/porch/scripts/tar-test-repo.sh b/porch/scripts/tar-test-repo.sh deleted file mode 100755 index 87119ebf30..0000000000 --- a/porch/scripts/tar-test-repo.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2022 The kpt 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. - -function error() { - echo "$@" - exit 1 -} - -if [[ $# -ne 2 ]]; then - error "Invalid # of arguments; ${#}. 2 expected: GIT_DIRECTORY OUTPUT_TAR_FILE" -fi - -GIT_DIRECTORY="${1}" -OUTPUT_TAR_FILE="${2}" - -if [ -d "${GIT_DIRECTORY}" ]; then - - tar -c -v -f "${OUTPUT_TAR_FILE}" -C "${GIT_DIRECTORY}" --owner=porch:0 --group=porch:0 \ - --sort=name --mtime='PST 2022-02-02' \ - --exclude '.git/logs' \ - --exclude '.git/COMMIT_EDITMSG' \ - --exclude '.git/ORIG_HEAD' \ - --exclude '.git/info/exclude' \ - .git - -else - error "${GIT_DIRECTORY} doesn't exist" -fi diff --git a/porch/scripts/verify-fix-all.sh b/porch/scripts/verify-fix-all.sh deleted file mode 100755 index b674d39984..0000000000 --- a/porch/scripts/verify-fix-all.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2022 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. - -set -o nounset -o errexit -o pipefail - -GREEN='\033[0;32m' -RED='\033[0;31m' -NC='\033[0m' # No Color - -REPO_ROOT="$(git rev-parse --show-toplevel)" - -make -C "${REPO_ROOT}/porch" fix-all - -changes=$(git status --porcelain || true) -if [ -n "${changes}" ]; then - echo - echo -e "${RED}ERROR: required changes detected, please run 'make -C porch fix-all'${NC}" - echo - echo -e "${RED}FILE CHANGES:${NC}" - printf "%s" "${changes}\n" - echo - echo -e "${RED}GIT DIFF:${NC}" - git --no-pager diff - exit 1 -else - echo -e "${GREEN}SUCCESS: No changes required${NC}" -fi diff --git a/porch/test/Dockerfile b/porch/test/Dockerfile deleted file mode 100644 index 7bc47a2ea6..0000000000 --- a/porch/test/Dockerfile +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2022 The kpt 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. - - -FROM golang:1.21.6-bookworm as builder - -WORKDIR /go/src/github.com/GoogleContainerTools/kpt - -# cache deps before building and copying source so that we don't need to re-download as much -# and so that source changes don't invalidate our downloaded layer - -COPY go.mod go.sum ./ -COPY porch/go.mod porch/go.sum porch/ -COPY porch/api/go.mod porch/api/go.sum porch/api/ - -RUN echo "Downloading root modules ..." \ - && go mod download -RUN echo "Downloading porch modules ..." \ - && cd porch && go mod download -RUN echo "Downloading api modules ..." \ - && cd porch/api && go mod download - -# Prebuild some library dependencies to warm the cache -RUN cd porch/; go build -v \ - k8s.io/klog/v2 \ - github.com/go-git/go-git/v5 - -COPY internal internal -COPY pkg pkg -COPY porch/api porch/api -COPY porch/controllers porch/controllers -COPY porch/pkg porch/pkg -COPY porch/test porch/test - -RUN cd porch/test; go build -v -o /git-server ./git - -FROM debian:bookworm-slim -RUN apt update && apt install -y ca-certificates && rm -rf /var/lib/apt && rm -rf /var/cache/apt -COPY --from=builder /git-server /git-server -ENTRYPOINT ["/git-server", "--port=8080"] diff --git a/porch/test/Makefile b/porch/test/Makefile deleted file mode 100644 index cf2e48b085..0000000000 --- a/porch/test/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 The kpt 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. - -GCP_PROJECT_ID ?= $(shell gcloud config get-value project) -IMAGE_TAG ?= latest -IMAGE_REPO ?= gcr.io/$(GCP_PROJECT_ID) -IMAGE_NAME ?= test-git-server - -.PHONY: build-image -build-image: - docker buildx build --load --tag $(IMAGE_REPO)/$(IMAGE_NAME):$(IMAGE_TAG) -f $(CURDIR)/Dockerfile ../.. - -.PHONY: push-image -push-image: - docker buildx build --push --tag $(IMAGE_REPO)/$(IMAGE_NAME):$(IMAGE_TAG) -f $(CURDIR)/Dockerfile ../.. diff --git a/porch/test/e2e/e2e_test.go b/porch/test/e2e/e2e_test.go deleted file mode 100644 index be1b3d01dd..0000000000 --- a/porch/test/e2e/e2e_test.go +++ /dev/null @@ -1,2713 +0,0 @@ -// Copyright 2022 The kpt 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. - -package e2e - -import ( - "context" - "fmt" - "os" - "path/filepath" - "reflect" - "strings" - "testing" - "time" - - kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - internalapi "github.com/GoogleContainerTools/kpt/porch/internal/api/porchinternal/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - "github.com/google/go-cmp/cmp" - "github.com/stretchr/testify/assert" - coreapi "k8s.io/api/core/v1" - corev1 "k8s.io/api/core/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/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/wait" - _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -const ( - testBlueprintsRepo = "https://github.com/platkrm/test-blueprints.git" - kptRepo = "https://github.com/GoogleContainerTools/kpt.git" -) - -var ( - packageRevisionGVK = porchapi.SchemeGroupVersion.WithKind("PackageRevision") - configMapGVK = corev1.SchemeGroupVersion.WithKind("ConfigMap") -) - -func TestE2E(t *testing.T) { - e2e := os.Getenv("E2E") - if e2e == "" { - t.Skip("set E2E to run this test") - } - - Run(&PorchSuite{}, t) -} - -func Run(suite interface{}, t *testing.T) { - sv := reflect.ValueOf(suite) - st := reflect.TypeOf(suite) - ctx := context.Background() - - t.Run(st.Elem().Name(), func(t *testing.T) { - var ts *TestSuite = sv.Elem().FieldByName("TestSuite").Addr().Interface().(*TestSuite) - - ts.T = t - if init, ok := suite.(Initializer); ok { - init.Initialize(ctx) - } - - for i, max := 0, st.NumMethod(); i < max; i++ { - m := st.Method(i) - if strings.HasPrefix(m.Name, "Test") { - t.Run(m.Name, func(t *testing.T) { - ts.T = t - m.Func.Call([]reflect.Value{sv, reflect.ValueOf(ctx)}) - }) - } - } - }) -} - -type PorchSuite struct { - TestSuite - - gitConfig GitConfig -} - -var _ Initializer = &PorchSuite{} - -func (p *PorchSuite) Initialize(ctx context.Context) { - p.TestSuite.Initialize(ctx) - p.gitConfig = p.CreateGitRepo() -} - -func (p *PorchSuite) GitConfig(repoID string) GitConfig { - config := p.gitConfig - config.Repo = config.Repo + "/" + repoID - return config -} - -func (t *PorchSuite) TestGitRepository(ctx context.Context) { - // Register the repository as 'git' - t.registerMainGitRepositoryF(ctx, "git") - - // Create Package Revision - pr := &porchapi.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: "test-bucket", - WorkspaceName: "workspace", - RepositoryName: "git", - Tasks: []porchapi.Task{ - { - Type: "clone", - Clone: &porchapi.PackageCloneTaskSpec{ - Upstream: porchapi.UpstreamPackage{ - Type: "git", - Git: &porchapi.GitPackage{ - Repo: "https://github.com/GoogleCloudPlatform/blueprints.git", - Ref: "bucket-blueprint-v0.4.3", - Directory: "catalog/bucket", - }, - }, - }, - }, - { - Type: "eval", - Eval: &porchapi.FunctionEvalTaskSpec{ - Image: "gcr.io/kpt-fn/set-namespace:v0.4.1", - ConfigMap: map[string]string{ - "namespace": "bucket-namespace", - }, - }, - }, - }, - }, - } - t.CreateF(ctx, pr) - - // Get package resources - var resources porchapi.PackageRevisionResources - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &resources) - - bucket, ok := resources.Spec.Resources["bucket.yaml"] - if !ok { - t.Errorf("'bucket.yaml' not found among package resources") - } - node, err := yaml.Parse(bucket) - if err != nil { - t.Errorf("yaml.Parse(\"bucket.yaml\") failed: %v", err) - } - if got, want := node.GetNamespace(), "bucket-namespace"; got != want { - t.Errorf("StorageBucket namespace: got %q, want %q", got, want) - } -} - -func (t *PorchSuite) TestGitRepositoryWithReleaseTagsAndDirectory(ctx context.Context) { - t.registerGitRepositoryF(ctx, kptRepo, "kpt-repo", "package-examples") - - var list porchapi.PackageRevisionList - t.ListF(ctx, &list, client.InNamespace(t.namespace)) - - for _, pr := range list.Items { - if strings.HasPrefix(pr.Spec.PackageName, "package-examples") { - t.Errorf("package name %q should not include repo directory %q as prefix", pr.Spec.PackageName, "package-examples") - } - } -} - -func (t *PorchSuite) TestCloneFromUpstream(ctx context.Context) { - // Register Upstream Repository - t.registerGitRepositoryF(ctx, testBlueprintsRepo, "test-blueprints", "") - - var list porchapi.PackageRevisionList - t.ListE(ctx, &list, client.InNamespace(t.namespace)) - - basens := MustFindPackageRevision(t.T, &list, repository.PackageRevisionKey{Repository: "test-blueprints", Package: "basens", Revision: "v1"}) - - // Register the repository as 'downstream' - t.registerMainGitRepositoryF(ctx, "downstream") - - // Create PackageRevision from upstream repo - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: "istions", - WorkspaceName: "test-workspace", - RepositoryName: "downstream", - Tasks: []porchapi.Task{ - { - Type: porchapi.TaskTypeClone, - Clone: &porchapi.PackageCloneTaskSpec{ - Upstream: porchapi.UpstreamPackage{ - UpstreamRef: &porchapi.PackageRevisionRef{ - Name: basens.Name, - }, - }, - }, - }, - }, - }, - } - - t.CreateF(ctx, pr) - - // Get istions resources - var istions porchapi.PackageRevisionResources - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &istions) - - kptfile := t.ParseKptfileF(&istions) - - if got, want := kptfile.Name, "istions"; got != want { - t.Errorf("istions package Kptfile.metadata.name: got %q, want %q", got, want) - } - if kptfile.UpstreamLock == nil { - t.Fatalf("istions package upstreamLock is missing") - } - if kptfile.UpstreamLock.Git == nil { - t.Errorf("istions package upstreamLock.git is missing") - } - if kptfile.UpstreamLock.Git.Commit == "" { - t.Errorf("isions package upstreamLock.gkti.commit is missing") - } - - // Remove commit from comparison - got := kptfile.UpstreamLock - got.Git.Commit = "" - - want := &kptfilev1.UpstreamLock{ - Type: kptfilev1.GitOrigin, - Git: &kptfilev1.GitLock{ - Repo: testBlueprintsRepo, - Directory: "basens", - Ref: "basens/v1", - }, - } - if !cmp.Equal(want, got) { - t.Errorf("unexpected upstreamlock returned (-want, +got) %s", cmp.Diff(want, got)) - } - - // Check Upstream - if got, want := kptfile.Upstream, (&kptfilev1.Upstream{ - Type: kptfilev1.GitOrigin, - Git: &kptfilev1.Git{ - Repo: testBlueprintsRepo, - Directory: "basens", - Ref: "basens/v1", - }, - }); !cmp.Equal(want, got) { - t.Errorf("unexpected upstream returned (-want, +got) %s", cmp.Diff(want, got)) - } -} - -func (t *PorchSuite) TestInitEmptyPackage(ctx context.Context) { - // Create a new package via init, no task specified - const ( - repository = "git" - packageName = "empty-package" - revision = "v1" - workspace = "test-workspace" - description = "empty-package description" - ) - - // Register the repository - t.registerMainGitRepositoryF(ctx, repository) - - // Create a new package (via init) - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: "empty-package", - WorkspaceName: workspace, - RepositoryName: repository, - }, - } - t.CreateF(ctx, pr) - - // Get the package - var newPackage porchapi.PackageRevisionResources - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &newPackage) - - kptfile := t.ParseKptfileF(&newPackage) - if got, want := kptfile.Name, "empty-package"; got != want { - t.Fatalf("New package name: got %q, want %q", got, want) - } - if got, want := kptfile.Info, (&kptfilev1.PackageInfo{ - Description: description, - }); !cmp.Equal(want, got) { - t.Fatalf("unexpected %s/%s package info (-want, +got) %s", newPackage.Namespace, newPackage.Name, cmp.Diff(want, got)) - } -} - -func (t *PorchSuite) TestInitTaskPackage(ctx context.Context) { - const ( - repository = "git" - packageName = "new-package" - revision = "v1" - workspace = "test-workspace" - description = "New Package" - site = "https://kpt.dev/new-package" - ) - keywords := []string{"test"} - - // Register the repository - t.registerMainGitRepositoryF(ctx, repository) - - // Create a new package (via init) - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: "new-package", - WorkspaceName: workspace, - RepositoryName: repository, - Tasks: []porchapi.Task{ - { - Type: porchapi.TaskTypeInit, - Init: &porchapi.PackageInitTaskSpec{ - Description: description, - Keywords: keywords, - Site: site, - }, - }, - }, - }, - } - t.CreateF(ctx, pr) - - // Get the package - var newPackage porchapi.PackageRevisionResources - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &newPackage) - - kptfile := t.ParseKptfileF(&newPackage) - if got, want := kptfile.Name, "new-package"; got != want { - t.Fatalf("New package name: got %q, want %q", got, want) - } - if got, want := kptfile.Info, (&kptfilev1.PackageInfo{ - Site: site, - Description: description, - Keywords: keywords, - }); !cmp.Equal(want, got) { - t.Fatalf("unexpected %s/%s package info (-want, +got) %s", newPackage.Namespace, newPackage.Name, cmp.Diff(want, got)) - } -} - -func (t *PorchSuite) TestCloneIntoDeploymentRepository(ctx context.Context) { - const downstreamRepository = "deployment" - const downstreamPackage = "istions" - const downstreamRevision = "v2" - const downstreamWorkspace = "test-workspace" - - // Register the deployment repository - t.registerMainGitRepositoryF(ctx, downstreamRepository, withDeployment()) - - // Register the upstream repository - t.registerGitRepositoryF(ctx, testBlueprintsRepo, "test-blueprints", "") - - var upstreamPackages porchapi.PackageRevisionList - t.ListE(ctx, &upstreamPackages, client.InNamespace(t.namespace)) - upstreamPackage := MustFindPackageRevision(t.T, &upstreamPackages, repository.PackageRevisionKey{ - Repository: "test-blueprints", - Package: "basens", - Revision: "v1", - WorkspaceName: "v1", - }) - - // Create PackageRevision from upstream repo - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: downstreamPackage, - WorkspaceName: downstreamWorkspace, - RepositoryName: downstreamRepository, - Tasks: []porchapi.Task{ - { - Type: porchapi.TaskTypeClone, - Clone: &porchapi.PackageCloneTaskSpec{ - Upstream: porchapi.UpstreamPackage{ - UpstreamRef: &porchapi.PackageRevisionRef{ - Name: upstreamPackage.Name, // Package to be cloned - }, - }, - }, - }, - }, - }, - } - t.CreateF(ctx, pr) - - // Get istions resources - var istions porchapi.PackageRevisionResources - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &istions) - - kptfile := t.ParseKptfileF(&istions) - - if got, want := kptfile.Name, "istions"; got != want { - t.Errorf("istions package Kptfile.metadata.name: got %q, want %q", got, want) - } - if kptfile.UpstreamLock == nil { - t.Fatalf("istions package upstreamLock is missing") - } - if kptfile.UpstreamLock.Git == nil { - t.Errorf("istions package upstreamLock.git is missing") - } - if kptfile.UpstreamLock.Git.Commit == "" { - t.Errorf("isions package upstreamLock.gkti.commit is missing") - } - - // Remove commit from comparison - got := kptfile.UpstreamLock - got.Git.Commit = "" - - want := &kptfilev1.UpstreamLock{ - Type: kptfilev1.GitOrigin, - Git: &kptfilev1.GitLock{ - Repo: testBlueprintsRepo, - Directory: "basens", - Ref: "basens/v1", - }, - } - if !cmp.Equal(want, got) { - t.Errorf("unexpected upstreamlock returned (-want, +got) %s", cmp.Diff(want, got)) - } - - // Check Upstream - if got, want := kptfile.Upstream, (&kptfilev1.Upstream{ - Type: kptfilev1.GitOrigin, - Git: &kptfilev1.Git{ - Repo: testBlueprintsRepo, - Directory: "basens", - Ref: "basens/v1", - }, - }); !cmp.Equal(want, got) { - t.Errorf("unexpected upstream returned (-want, +got) %s", cmp.Diff(want, got)) - } - - // Check generated context - var configmap coreapi.ConfigMap - t.FindAndDecodeF(&istions, "package-context.yaml", &configmap) - if got, want := configmap.Name, "kptfile.kpt.dev"; got != want { - t.Errorf("package context name: got %s, want %s", got, want) - } - if got, want := configmap.Data["name"], "istions"; got != want { - t.Errorf("package context 'data.name': got %s, want %s", got, want) - } -} - -func (t *PorchSuite) TestEditPackageRevision(ctx context.Context) { - const ( - repository = "edit-test" - packageName = "simple-package" - otherPackageName = "other-package" - workspace = "workspace" - workspace2 = "workspace2" - ) - - t.registerMainGitRepositoryF(ctx, repository) - - // Create a new package (via init) - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: packageName, - WorkspaceName: workspace, - RepositoryName: repository, - }, - } - t.CreateF(ctx, pr) - - // Create a new revision, but with a different package as the source. - // This is not allowed. - invalidEditPR := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: otherPackageName, - WorkspaceName: workspace2, - RepositoryName: repository, - Tasks: []porchapi.Task{ - { - Type: porchapi.TaskTypeEdit, - Edit: &porchapi.PackageEditTaskSpec{ - Source: &porchapi.PackageRevisionRef{ - Name: pr.Name, - }, - }, - }, - }, - }, - } - if err := t.client.Create(ctx, invalidEditPR); err == nil { - t.Fatalf("Expected error for source revision being from different package") - } - - // Create a new revision of the package with a source that is a revision - // of the same package. - editPR := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: packageName, - WorkspaceName: workspace2, - RepositoryName: repository, - Tasks: []porchapi.Task{ - { - Type: porchapi.TaskTypeEdit, - Edit: &porchapi.PackageEditTaskSpec{ - Source: &porchapi.PackageRevisionRef{ - Name: pr.Name, - }, - }, - }, - }, - }, - } - if err := t.client.Create(ctx, editPR); err == nil { - t.Fatalf("Expected error for source revision not being published") - } - - // Publish the source package to make it a valid source for edit. - pr.Spec.Lifecycle = porchapi.PackageRevisionLifecycleProposed - t.UpdateF(ctx, pr) - - // Approve the package - pr.Spec.Lifecycle = porchapi.PackageRevisionLifecyclePublished - t.UpdateApprovalF(ctx, pr, metav1.UpdateOptions{}) - - // Create a new revision with the edit task. - t.CreateF(ctx, editPR) - - // Check its task list - var pkgRev porchapi.PackageRevision - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: editPR.Name, - }, &pkgRev) - tasks := pkgRev.Spec.Tasks - for _, tsk := range tasks { - t.Logf("Task: %s", tsk.Type) - } - assert.Equal(t, 2, len(tasks)) -} - -// Test will initialize an empty package, update its resources, adding a function -// to the Kptfile's pipeline, and then check that the package was re-rendered. -func (t *PorchSuite) TestUpdateResources(ctx context.Context) { - const ( - repository = "re-render-test" - packageName = "simple-package" - workspace = "workspace" - ) - - t.registerMainGitRepositoryF(ctx, repository) - - // Create a new package (via init) - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: packageName, - WorkspaceName: workspace, - RepositoryName: repository, - }, - } - t.CreateF(ctx, pr) - - // Get the package resources - var newPackage porchapi.PackageRevisionResources - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &newPackage) - - // Add function into a pipeline - kptfile := t.ParseKptfileF(&newPackage) - if kptfile.Pipeline == nil { - kptfile.Pipeline = &kptfilev1.Pipeline{} - } - kptfile.Pipeline.Mutators = append(kptfile.Pipeline.Mutators, kptfilev1.Function{ - Image: "gcr.io/kpt-fn/set-annotations:v0.1.4", - ConfigMap: map[string]string{ - "color": "red", - "fruit": "apple", - }, - Name: "set-annotations", - }) - t.SaveKptfileF(&newPackage, kptfile) - - // Add a new resource - filename := filepath.Join("testdata", "update-resources", "add-config-map.yaml") - cm, err := os.ReadFile(filename) - if err != nil { - t.Fatalf("Failed to read ConfigMap from %q: %v", filename, err) - } - newPackage.Spec.Resources["config-map.yaml"] = string(cm) - t.UpdateF(ctx, &newPackage) - - updated, ok := newPackage.Spec.Resources["config-map.yaml"] - if !ok { - t.Fatalf("Updated config map config-map.yaml not found") - } - - renderStatus := newPackage.Status.RenderStatus - assert.Empty(t, renderStatus.Err, "render error must be empty for successful render operation.") - assert.Zero(t, renderStatus.Result.ExitCode, "exit code must be zero for successful render operation.") - assert.True(t, len(renderStatus.Result.Items) > 0) - - golden := filepath.Join("testdata", "update-resources", "want-config-map.yaml") - if diff := t.CompareGoldenFileYAML(golden, updated); diff != "" { - t.Errorf("Unexpected updated confg map contents: (-want,+got): %s", diff) - } -} - -// Test will initialize an empty package, and then make a call to update the resources -// without actually making any changes. This test is ensuring that no additional -// tasks get added. -func (t *PorchSuite) TestUpdateResourcesEmptyPatch(ctx context.Context) { - const ( - repository = "empty-patch-test" - packageName = "simple-package" - workspace = "workspace" - ) - - t.registerMainGitRepositoryF(ctx, repository) - - // Create a new package (via init) - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: packageName, - WorkspaceName: workspace, - RepositoryName: repository, - }, - } - t.CreateF(ctx, pr) - - // Check its task list - var newPackage porchapi.PackageRevision - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &newPackage) - tasksBeforeUpdate := newPackage.Spec.Tasks - assert.Equal(t, 2, len(tasksBeforeUpdate)) - - // Get the package resources - var newPackageResources porchapi.PackageRevisionResources - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &newPackageResources) - - // "Update" the package resources, without changing anything - t.UpdateF(ctx, &newPackageResources) - - // Check the task list - var newPackageUpdated porchapi.PackageRevision - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &newPackageUpdated) - tasksAfterUpdate := newPackageUpdated.Spec.Tasks - assert.Equal(t, 2, len(tasksAfterUpdate)) - - assert.True(t, reflect.DeepEqual(tasksBeforeUpdate, tasksAfterUpdate)) -} - -func (t *PorchSuite) TestFunctionRepository(ctx context.Context) { - repo := &configapi.Repository{ - ObjectMeta: metav1.ObjectMeta{ - Name: "function-repository", - Namespace: t.namespace, - }, - Spec: configapi.RepositorySpec{ - Description: "Test Function Repository", - Type: configapi.RepositoryTypeOCI, - Content: configapi.RepositoryContentFunction, - Oci: &configapi.OciRepository{ - Registry: "gcr.io/kpt-fn", - }, - }, - } - t.CreateF(ctx, repo) - - t.Cleanup(func() { - t.DeleteL(ctx, &configapi.Repository{ - ObjectMeta: metav1.ObjectMeta{ - Name: repo.Name, - Namespace: repo.Namespace, - }, - }) - }) - - // Make sure the repository is ready before we test to (hopefully) - // avoid flakiness. - t.waitUntilRepositoryReady(ctx, repo.Name, repo.Namespace) - - // Wait here for the repository to be cached in porch. We wait - // first one minute, since Porch waits 1 minute before it syncs - // the repo for the first time. Then wait another minute so that - // the sync has (hopefully) finished. - // TODO(mortent): We need a better solution for this. This is only - // temporary to fix the current flakiness with the e2e tests. - <-time.NewTimer(2 * time.Minute).C - - list := &porchapi.FunctionList{} - t.ListE(ctx, list, client.InNamespace(t.namespace)) - - if got := len(list.Items); got == 0 { - t.Errorf("Found no functions in gcr.io/kpt-fn repository; expected at least one") - } -} - -func (t *PorchSuite) TestPublicGitRepository(ctx context.Context) { - t.registerGitRepositoryF(ctx, testBlueprintsRepo, "demo-blueprints", "") - - var list porchapi.PackageRevisionList - t.ListE(ctx, &list, client.InNamespace(t.namespace)) - - if got := len(list.Items); got == 0 { - t.Errorf("Found no package revisions in %s; expected at least one", testBlueprintsRepo) - } -} - -func (t *PorchSuite) TestProposeApprove(ctx context.Context) { - const ( - repository = "lifecycle" - packageName = "test-package" - workspace = "workspace" - ) - - // Register the repository - t.registerMainGitRepositoryF(ctx, repository) - - // Create a new package (via init) - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: packageName, - WorkspaceName: workspace, - RepositoryName: repository, - Tasks: []porchapi.Task{ - { - Type: porchapi.TaskTypeInit, - Init: &porchapi.PackageInitTaskSpec{}, - }, - }, - }, - } - t.CreateF(ctx, pr) - - var pkg porchapi.PackageRevision - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &pkg) - - // Propose the package revision to be finalized - pkg.Spec.Lifecycle = porchapi.PackageRevisionLifecycleProposed - t.UpdateF(ctx, &pkg) - - var proposed porchapi.PackageRevision - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &proposed) - - if got, want := proposed.Spec.Lifecycle, porchapi.PackageRevisionLifecycleProposed; got != want { - t.Fatalf("Proposed package lifecycle value: got %s, want %s", got, want) - } - - // Approve using Update should fail. - proposed.Spec.Lifecycle = porchapi.PackageRevisionLifecyclePublished - if err := t.client.Update(ctx, &proposed); err == nil { - t.Fatalf("Finalization of a package via Update unexpectedly succeeded") - } - - // Approve the package - proposed.Spec.Lifecycle = porchapi.PackageRevisionLifecyclePublished - approved := t.UpdateApprovalF(ctx, &proposed, metav1.UpdateOptions{}) - if got, want := approved.Spec.Lifecycle, porchapi.PackageRevisionLifecyclePublished; got != want { - t.Fatalf("Approved package lifecycle value: got %s, want %s", got, want) - } - - // Check its revision number - if got, want := approved.Spec.Revision, "v1"; got != want { - t.Fatalf("Approved package revision value: got %s, want %s", got, want) - } -} - -func (t *PorchSuite) TestDeleteDraft(ctx context.Context) { - const ( - repository = "delete-draft" - packageName = "test-delete-draft" - revision = "v1" - workspace = "test-workspace" - ) - - // Register the repository - t.registerMainGitRepositoryF(ctx, repository) - - // Create a draft package - created := t.createPackageDraftF(ctx, repository, packageName, workspace) - - // Check the package exists - var draft porchapi.PackageRevision - t.mustExist(ctx, client.ObjectKey{Namespace: t.namespace, Name: created.Name}, &draft) - - // Delete the package - t.DeleteE(ctx, &porchapi.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - Name: created.Name, - }, - }) - - t.mustNotExist(ctx, &draft) -} - -func (t *PorchSuite) TestDeleteProposed(ctx context.Context) { - const ( - repository = "delete-proposed" - packageName = "test-delete-proposed" - revision = "v1" - workspace = "workspace" - ) - - // Register the repository - t.registerMainGitRepositoryF(ctx, repository) - - // Create a draft package - created := t.createPackageDraftF(ctx, repository, packageName, workspace) - - // Check the package exists - var pkg porchapi.PackageRevision - t.mustExist(ctx, client.ObjectKey{Namespace: t.namespace, Name: created.Name}, &pkg) - - // Propose the package revision to be finalized - pkg.Spec.Lifecycle = porchapi.PackageRevisionLifecycleProposed - t.UpdateF(ctx, &pkg) - - // Delete the package - t.DeleteE(ctx, &porchapi.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - Name: created.Name, - }, - }) - - t.mustNotExist(ctx, &pkg) -} - -func (t *PorchSuite) TestDeleteFinal(ctx context.Context) { - const ( - repository = "delete-final" - packageName = "test-delete-final" - workspace = "workspace" - ) - - // Register the repository - t.registerMainGitRepositoryF(ctx, repository) - - // Create a draft package - created := t.createPackageDraftF(ctx, repository, packageName, workspace) - - // Check the package exists - var pkg porchapi.PackageRevision - t.mustExist(ctx, client.ObjectKey{Namespace: t.namespace, Name: created.Name}, &pkg) - - // Propose the package revision to be finalized - pkg.Spec.Lifecycle = porchapi.PackageRevisionLifecycleProposed - t.UpdateF(ctx, &pkg) - - pkg.Spec.Lifecycle = porchapi.PackageRevisionLifecyclePublished - t.UpdateApprovalF(ctx, &pkg, metav1.UpdateOptions{}) - - t.mustExist(ctx, client.ObjectKey{Namespace: t.namespace, Name: created.Name}, &pkg) - - // Try to delete the package. This should fail because it hasn't been proposed for deletion. - t.DeleteL(ctx, &porchapi.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - Name: created.Name, - }, - }) - t.mustExist(ctx, client.ObjectKey{Namespace: t.namespace, Name: created.Name}, &pkg) - - // Propose deletion and then delete the package - pkg.Spec.Lifecycle = porchapi.PackageRevisionLifecycleDeletionProposed - t.UpdateApprovalF(ctx, &pkg, metav1.UpdateOptions{}) - - t.DeleteE(ctx, &porchapi.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - Name: created.Name, - }, - }) - - t.mustNotExist(ctx, &pkg) -} - -func (t *PorchSuite) TestProposeDeleteAndUndo(ctx context.Context) { - const ( - repository = "test-propose-delete-and-undo" - packageName = "test-propose-delete-and-undo" - workspace = "workspace" - ) - - // Register the repository - t.registerMainGitRepositoryF(ctx, repository) - - // Create a draft package - created := t.createPackageDraftF(ctx, repository, packageName, workspace) - - // Check the package exists - var pkg porchapi.PackageRevision - t.mustExist(ctx, client.ObjectKey{Namespace: t.namespace, Name: created.Name}, &pkg) - - // Propose the package revision to be finalized - pkg.Spec.Lifecycle = porchapi.PackageRevisionLifecycleProposed - t.UpdateF(ctx, &pkg) - - pkg.Spec.Lifecycle = porchapi.PackageRevisionLifecyclePublished - t.UpdateApprovalF(ctx, &pkg, metav1.UpdateOptions{}) - t.mustExist(ctx, client.ObjectKey{Namespace: t.namespace, Name: created.Name}, &pkg) - - t.waitUntilMainBranchPackageRevisionExists(ctx, packageName) - - var list porchapi.PackageRevisionList - t.ListF(ctx, &list, client.InNamespace(t.namespace)) - - for i := range list.Items { - pkgRev := list.Items[i] - t.Run(fmt.Sprintf("revision %s", pkgRev.Spec.Revision), func(newT *testing.T) { - // This is a bit awkward, we should find a better way to allow subtests - // with our custom implmentation of t. - oldT := t.T - t.T = newT - defer func() { - t.T = oldT - }() - - // Propose deletion - pkgRev.Spec.Lifecycle = porchapi.PackageRevisionLifecycleDeletionProposed - t.UpdateApprovalF(ctx, &pkgRev, metav1.UpdateOptions{}) - - // Undo proposal of deletion - pkgRev.Spec.Lifecycle = porchapi.PackageRevisionLifecyclePublished - t.UpdateApprovalF(ctx, &pkgRev, metav1.UpdateOptions{}) - - // Try to delete the package. This should fail because the lifecycle should be changed back to Published. - t.DeleteL(ctx, &porchapi.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - Name: pkgRev.Name, - }, - }) - t.mustExist(ctx, client.ObjectKey{Namespace: t.namespace, Name: pkgRev.Name}, &pkgRev) - - // Propose deletion and then delete the package - pkgRev.Spec.Lifecycle = porchapi.PackageRevisionLifecycleDeletionProposed - t.UpdateApprovalF(ctx, &pkgRev, metav1.UpdateOptions{}) - - t.DeleteE(ctx, &porchapi.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - Name: pkgRev.Name, - }, - }) - - t.mustNotExist(ctx, &pkgRev) - }) - } -} - -func (t *PorchSuite) TestDeleteAndRecreate(ctx context.Context) { - const ( - repository = "delete-and-recreate" - packageName = "test-delete-and-recreate" - revision = "v1" - workspace = "work" - ) - - // Register the repository - t.registerMainGitRepositoryF(ctx, repository) - - // Create a draft package - created := t.createPackageDraftF(ctx, repository, packageName, workspace) - - // Check the package exists - var pkg porchapi.PackageRevision - t.mustExist(ctx, client.ObjectKey{Namespace: t.namespace, Name: created.Name}, &pkg) - - // Propose the package revision to be finalized - pkg.Spec.Lifecycle = porchapi.PackageRevisionLifecycleProposed - t.UpdateF(ctx, &pkg) - - pkg.Spec.Lifecycle = porchapi.PackageRevisionLifecyclePublished - t.UpdateApprovalF(ctx, &pkg, metav1.UpdateOptions{}) - - t.mustExist(ctx, client.ObjectKey{Namespace: t.namespace, Name: created.Name}, &pkg) - - // Propose deletion and then delete the package - pkg.Spec.Lifecycle = porchapi.PackageRevisionLifecycleDeletionProposed - t.UpdateApprovalF(ctx, &pkg, metav1.UpdateOptions{}) - - t.DeleteE(ctx, &porchapi.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - Name: created.Name, - }, - }) - - t.mustNotExist(ctx, &pkg) - - // Recreate the package with the same name and workspace - created = t.createPackageDraftF(ctx, repository, packageName, workspace) - - // Check the package exists - t.mustExist(ctx, client.ObjectKey{Namespace: t.namespace, Name: created.Name}, &pkg) - - // Ensure that there is only one init task in the package revision history - foundInitTask := false - for _, task := range pkg.Spec.Tasks { - if task.Type == porchapi.TaskTypeInit { - if foundInitTask { - t.Fatalf("found two init tasks in recreated package revision") - } - foundInitTask = true - } - } - t.Logf("successfully recreated package revision %q", packageName) -} - -func (t *PorchSuite) TestDeleteFromMain(ctx context.Context) { - const ( - repository = "delete-main" - packageNameFirst = "test-delete-main-first" - packageNameSecond = "test-delete-main-second" - workspace = "workspace" - ) - - // Register the repository - t.registerMainGitRepositoryF(ctx, repository) - - // Create the first draft package - createdFirst := t.createPackageDraftF(ctx, repository, packageNameFirst, workspace) - - // Check the package exists - var pkgFirst porchapi.PackageRevision - t.mustExist(ctx, client.ObjectKey{Namespace: t.namespace, Name: createdFirst.Name}, &pkgFirst) - - // Propose the package revision to be finalized - pkgFirst.Spec.Lifecycle = porchapi.PackageRevisionLifecycleProposed - t.UpdateF(ctx, &pkgFirst) - - pkgFirst.Spec.Lifecycle = porchapi.PackageRevisionLifecyclePublished - t.UpdateApprovalF(ctx, &pkgFirst, metav1.UpdateOptions{}) - - t.mustExist(ctx, client.ObjectKey{Namespace: t.namespace, Name: createdFirst.Name}, &pkgFirst) - - // Create the second draft package - createdSecond := t.createPackageDraftF(ctx, repository, packageNameSecond, workspace) - - // Check the package exists - var pkgSecond porchapi.PackageRevision - t.mustExist(ctx, client.ObjectKey{Namespace: t.namespace, Name: createdSecond.Name}, &pkgSecond) - - // Propose the package revision to be finalized - pkgSecond.Spec.Lifecycle = porchapi.PackageRevisionLifecycleProposed - t.UpdateF(ctx, &pkgSecond) - - pkgSecond.Spec.Lifecycle = porchapi.PackageRevisionLifecyclePublished - t.UpdateApprovalF(ctx, &pkgSecond, metav1.UpdateOptions{}) - - t.mustExist(ctx, client.ObjectKey{Namespace: t.namespace, Name: createdSecond.Name}, &pkgSecond) - - // We need to wait for the sync for the "main" revisions to get created - time.Sleep(75 * time.Second) - - var list porchapi.PackageRevisionList - t.ListE(ctx, &list, client.InNamespace(t.namespace)) - - var firstPkgRevFromMain porchapi.PackageRevision - var secondPkgRevFromMain porchapi.PackageRevision - - for _, pkgrev := range list.Items { - if pkgrev.Spec.PackageName == packageNameFirst && pkgrev.Spec.Revision == "main" { - firstPkgRevFromMain = pkgrev - } - if pkgrev.Spec.PackageName == packageNameSecond && pkgrev.Spec.Revision == "main" { - secondPkgRevFromMain = pkgrev - } - } - - // Propose deletion of both main packages - firstPkgRevFromMain.Spec.Lifecycle = porchapi.PackageRevisionLifecycleDeletionProposed - t.UpdateApprovalF(ctx, &firstPkgRevFromMain, metav1.UpdateOptions{}) - secondPkgRevFromMain.Spec.Lifecycle = porchapi.PackageRevisionLifecycleDeletionProposed - t.UpdateApprovalF(ctx, &secondPkgRevFromMain, metav1.UpdateOptions{}) - - // Delete the first package revision from main - t.DeleteE(ctx, &porchapi.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - Name: firstPkgRevFromMain.Name, - }, - }) - - // We need to wait for the sync - time.Sleep(75 * time.Second) - - // Delete the second package revision from main - t.DeleteE(ctx, &porchapi.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - Name: secondPkgRevFromMain.Name, - }, - }) - - // Propose and delete the original package revisions (cleanup) - t.ListE(ctx, &list, client.InNamespace(t.namespace)) - for _, pkgrev := range list.Items { - pkgrev.Spec.Lifecycle = porchapi.PackageRevisionLifecycleDeletionProposed - t.UpdateApprovalF(ctx, &pkgrev, metav1.UpdateOptions{}) - t.DeleteE(ctx, &porchapi.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - Name: pkgrev.Name, - }, - }) - } -} - -func (t *PorchSuite) TestCloneLeadingSlash(ctx context.Context) { - const ( - repository = "clone-ls" - packageName = "test-clone-ls" - revision = "v1" - workspace = "workspace" - ) - - t.registerMainGitRepositoryF(ctx, repository) - - // Clone the package. Use leading slash in the directory (regression test) - new := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: packageName, - WorkspaceName: workspace, - RepositoryName: repository, - Tasks: []porchapi.Task{ - { - Type: porchapi.TaskTypeClone, - Clone: &porchapi.PackageCloneTaskSpec{ - Upstream: porchapi.UpstreamPackage{ - Type: porchapi.RepositoryTypeGit, - Git: &porchapi.GitPackage{ - Repo: "https://github.com/platkrm/test-blueprints", - Ref: "basens/v1", - Directory: "/basens", - }, - }, - Strategy: porchapi.ResourceMerge, - }, - }, - }, - }, - } - - t.CreateF(ctx, new) - - var pr porchapi.PackageRevision - t.mustExist(ctx, client.ObjectKey{Namespace: t.namespace, Name: new.Name}, &pr) -} - -func (t *PorchSuite) TestPackageUpdate(ctx context.Context) { - const ( - gitRepository = "package-update" - ) - - t.registerGitRepositoryF(ctx, testBlueprintsRepo, "test-blueprints", "") - - var list porchapi.PackageRevisionList - t.ListE(ctx, &list, client.InNamespace(t.namespace)) - - basensV1 := MustFindPackageRevision(t.T, &list, repository.PackageRevisionKey{Repository: "test-blueprints", Package: "basens", Revision: "v1"}) - basensV2 := MustFindPackageRevision(t.T, &list, repository.PackageRevisionKey{Repository: "test-blueprints", Package: "basens", Revision: "v2"}) - - // Register the repository as 'downstream' - t.registerMainGitRepositoryF(ctx, gitRepository) - - // Create PackageRevision from upstream repo - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: "testns", - WorkspaceName: "test-workspace", - RepositoryName: gitRepository, - Tasks: []porchapi.Task{ - { - Type: porchapi.TaskTypeClone, - Clone: &porchapi.PackageCloneTaskSpec{ - Upstream: porchapi.UpstreamPackage{ - UpstreamRef: &porchapi.PackageRevisionRef{ - Name: basensV1.Name, - }, - }, - }, - }, - }, - }, - } - - t.CreateF(ctx, pr) - - var revisionResources porchapi.PackageRevisionResources - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &revisionResources) - - filename := filepath.Join("testdata", "update-resources", "add-config-map.yaml") - cm, err := os.ReadFile(filename) - if err != nil { - t.Fatalf("Failed to read ConfigMap from %q: %v", filename, err) - } - revisionResources.Spec.Resources["config-map.yaml"] = string(cm) - t.UpdateF(ctx, &revisionResources) - - var newrr porchapi.PackageRevisionResources - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &newrr) - - by, _ := yaml.Marshal(&newrr) - t.Logf("PRR: %s", string(by)) - - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, pr) - - upstream := pr.Spec.Tasks[0].Clone.Upstream.DeepCopy() - upstream.UpstreamRef.Name = basensV2.Name - pr.Spec.Tasks = append(pr.Spec.Tasks, porchapi.Task{ - Type: porchapi.TaskTypeUpdate, - Update: &porchapi.PackageUpdateTaskSpec{ - Upstream: *upstream, - }, - }) - - t.UpdateE(ctx, pr, &client.UpdateOptions{}) - - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &revisionResources) - - if _, found := revisionResources.Spec.Resources["resourcequota.yaml"]; !found { - t.Errorf("Updated package should contain 'resourcequota.yaml` file") - } - -} - -func (t *PorchSuite) TestRegisterRepository(ctx context.Context) { - const ( - repository = "register" - ) - t.registerMainGitRepositoryF(ctx, repository, - withContent(configapi.RepositoryContentPackage), - withType(configapi.RepositoryTypeGit), - withDeployment()) - - var repo configapi.Repository - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: repository, - }, &repo) - - if got, want := repo.Spec.Content, configapi.RepositoryContentPackage; got != want { - t.Errorf("Repo Content: got %q, want %q", got, want) - } - if got, want := repo.Spec.Type, configapi.RepositoryTypeGit; got != want { - t.Errorf("Repo Type: got %q, want %q", got, want) - } - if got, want := repo.Spec.Deployment, true; got != want { - t.Errorf("Repo Deployment: got %t, want %t", got, want) - } -} - -func (t *PorchSuite) TestBuiltinFunctionEvaluator(ctx context.Context) { - // Register the repository as 'git-fn' - t.registerMainGitRepositoryF(ctx, "git-builtin-fn") - - // Create Package Revision - pr := &porchapi.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: "test-builtin-fn-bucket", - WorkspaceName: "test-workspace", - RepositoryName: "git-builtin-fn", - Tasks: []porchapi.Task{ - { - Type: "clone", - Clone: &porchapi.PackageCloneTaskSpec{ - Upstream: porchapi.UpstreamPackage{ - Type: "git", - Git: &porchapi.GitPackage{ - Repo: "https://github.com/GoogleCloudPlatform/blueprints.git", - Ref: "bucket-blueprint-v0.4.3", - Directory: "catalog/bucket", - }, - }, - }, - }, - { - Type: "eval", - Eval: &porchapi.FunctionEvalTaskSpec{ - // - Image: "gcr.io/kpt-fn/starlark:v0.4.3", - ConfigMap: map[string]string{ - "source": `for resource in ctx.resource_list["items"]: - resource["metadata"]["annotations"]["foo"] = "bar"`, - }, - }, - }, - { - Type: "eval", - Eval: &porchapi.FunctionEvalTaskSpec{ - Image: "gcr.io/kpt-fn/set-namespace:v0.4.1", - ConfigMap: map[string]string{ - "namespace": "bucket-namespace", - }, - }, - }, - // TODO: add test for apply-replacements, we can't do it now because FunctionEvalTaskSpec doesn't allow - // non-ConfigMap functionConfig due to a code generator issue when dealing with unstructured. - }, - }, - } - t.CreateF(ctx, pr) - - // Get package resources - var resources porchapi.PackageRevisionResources - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &resources) - - bucket, ok := resources.Spec.Resources["bucket.yaml"] - if !ok { - t.Errorf("'bucket.yaml' not found among package resources") - } - node, err := yaml.Parse(bucket) - if err != nil { - t.Errorf("yaml.Parse(\"bucket.yaml\") failed: %v", err) - } - if got, want := node.GetNamespace(), "bucket-namespace"; got != want { - t.Errorf("StorageBucket namespace: got %q, want %q", got, want) - } - annotations := node.GetAnnotations() - if val, found := annotations["foo"]; !found || val != "bar" { - t.Errorf("StorageBucket annotations should contain foo=bar, but got %v", annotations) - } -} - -func (t *PorchSuite) TestExecFunctionEvaluator(ctx context.Context) { - // Register the repository as 'git-fn' - t.registerMainGitRepositoryF(ctx, "git-fn") - - // Create Package Revision - pr := &porchapi.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: "test-fn-bucket", - WorkspaceName: "test-workspace", - RepositoryName: "git-fn", - Tasks: []porchapi.Task{ - { - Type: "clone", - Clone: &porchapi.PackageCloneTaskSpec{ - Upstream: porchapi.UpstreamPackage{ - Type: "git", - Git: &porchapi.GitPackage{ - Repo: "https://github.com/GoogleCloudPlatform/blueprints.git", - Ref: "bucket-blueprint-v0.4.3", - Directory: "catalog/bucket", - }, - }, - }, - }, - { - Type: "eval", - Eval: &porchapi.FunctionEvalTaskSpec{ - Image: "gcr.io/kpt-fn/starlark:v0.3.0", - ConfigMap: map[string]string{ - "source": `# set the namespace on all resources -for resource in ctx.resource_list["items"]: - # mutate the resource - resource["metadata"]["namespace"] = "bucket-namespace"`, - }, - }, - }, - { - Type: "eval", - Eval: &porchapi.FunctionEvalTaskSpec{ - Image: "gcr.io/kpt-fn/set-annotations:v0.1.4", - ConfigMap: map[string]string{ - "foo": "bar", - }, - }, - }, - }, - }, - } - t.CreateF(ctx, pr) - - // Get package resources - var resources porchapi.PackageRevisionResources - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &resources) - - bucket, ok := resources.Spec.Resources["bucket.yaml"] - if !ok { - t.Errorf("'bucket.yaml' not found among package resources") - } - node, err := yaml.Parse(bucket) - if err != nil { - t.Errorf("yaml.Parse(\"bucket.yaml\") failed: %v", err) - } - if got, want := node.GetNamespace(), "bucket-namespace"; got != want { - t.Errorf("StorageBucket namespace: got %q, want %q", got, want) - } - annotations := node.GetAnnotations() - if val, found := annotations["foo"]; !found || val != "bar" { - t.Errorf("StorageBucket annotations should contain foo=bar, but got %v", annotations) - } -} - -func (t *PorchSuite) TestPodFunctionEvaluatorWithDistrolessImage(ctx context.Context) { - if t.local { - t.Skipf("Skipping due to not having pod evalutor in local mode") - } - - t.registerMainGitRepositoryF(ctx, "git-fn-distroless") - - // Create Package Revision - pr := &porchapi.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: "test-fn-redis-bucket", - WorkspaceName: "test-description", - RepositoryName: "git-fn-distroless", - Tasks: []porchapi.Task{ - { - Type: "clone", - Clone: &porchapi.PackageCloneTaskSpec{ - Upstream: porchapi.UpstreamPackage{ - Type: "git", - Git: &porchapi.GitPackage{ - Repo: "https://github.com/GoogleCloudPlatform/blueprints.git", - Ref: "redis-bucket-blueprint-v0.3.2", - Directory: "catalog/redis-bucket", - }, - }, - }, - }, - { - Type: "patch", - Patch: &porchapi.PackagePatchTaskSpec{ - Patches: []porchapi.PatchSpec{ - { - File: "configmap.yaml", - Contents: `apiVersion: v1 -kind: ConfigMap -metadata: - name: kptfile.kpt.dev -data: - name: bucket-namespace -`, - PatchType: porchapi.PatchTypeCreateFile, - }, - }, - }, - }, - { - Type: "eval", - Eval: &porchapi.FunctionEvalTaskSpec{ - // This image is a mirror of gcr.io/cad-demo-sdk/set-namespace@sha256:462e44020221e72e3eb337ee59bc4bc3e5cb50b5ed69d377f55e05bec3a93d11 - // which uses gcr.io/distroless/base-debian11:latest as the base image. - Image: "gcr.io/kpt-fn-demo/set-namespace:v0.1.0", - }, - }, - }, - }, - } - t.CreateF(ctx, pr) - - // Get package resources - var resources porchapi.PackageRevisionResources - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &resources) - - bucket, ok := resources.Spec.Resources["bucket.yaml"] - if !ok { - t.Errorf("'bucket.yaml' not found among package resources") - } - node, err := yaml.Parse(bucket) - if err != nil { - t.Errorf("yaml.Parse(\"bucket.yaml\") failed: %v", err) - } - if got, want := node.GetNamespace(), "bucket-namespace"; got != want { - t.Errorf("StorageBucket namespace: got %q, want %q", got, want) - } -} - -func (t *PorchSuite) TestPodEvaluator(ctx context.Context) { - if t.local { - t.Skipf("Skipping due to not having pod evalutor in local mode") - } - - const ( - generateFolderImage = "gcr.io/kpt-fn/generate-folders:v0.1.1" // This function is a TS based function. - setAnnotationsImage = "gcr.io/kpt-fn/set-annotations:v0.1.3" // set-annotations:v0.1.3 is an older version that porch maps it neither to built-in nor exec. - ) - - // Register the repository as 'git-fn' - t.registerMainGitRepositoryF(ctx, "git-fn-pod") - - // Create Package Revision - pr := &porchapi.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: "test-fn-pod-hierarchy", - WorkspaceName: "workspace-1", - RepositoryName: "git-fn-pod", - Tasks: []porchapi.Task{ - { - Type: "clone", - Clone: &porchapi.PackageCloneTaskSpec{ - Upstream: porchapi.UpstreamPackage{ - Type: "git", - Git: &porchapi.GitPackage{ - Repo: "https://github.com/GoogleCloudPlatform/blueprints.git", - Ref: "783380ce4e6c3f21e9e90055b3a88bada0410154", - Directory: "catalog/hierarchy/simple", - }, - }, - }, - }, - // Testing pod evaluator with TS function - { - Type: "eval", - Eval: &porchapi.FunctionEvalTaskSpec{ - Image: generateFolderImage, - }, - }, - // Testing pod evaluator with golang function - { - Type: "eval", - Eval: &porchapi.FunctionEvalTaskSpec{ - Image: setAnnotationsImage, - ConfigMap: map[string]string{ - "test-key": "test-val", - }, - }, - }, - }, - }, - } - t.CreateF(ctx, pr) - - // Get package resources - var resources porchapi.PackageRevisionResources - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &resources) - - counter := 0 - for name, obj := range resources.Spec.Resources { - if strings.HasPrefix(name, "hierarchy/") { - counter++ - node, err := yaml.Parse(obj) - if err != nil { - t.Errorf("failed to parse Folder object: %v", err) - } - if node.GetAnnotations()["test-key"] != "test-val" { - t.Errorf("Folder should contain annotation `test-key:test-val`, the annotations we got: %v", node.GetAnnotations()) - } - } - } - if counter != 4 { - t.Errorf("expected 4 Folder objects, but got %v", counter) - } - - // Get the fn runner pods and delete them. - podList := &coreapi.PodList{} - t.ListF(ctx, podList, client.InNamespace("porch-fn-system")) - for _, pod := range podList.Items { - img := pod.Spec.Containers[0].Image - if img == generateFolderImage || img == setAnnotationsImage { - t.DeleteF(ctx, &pod) - } - } - - // Create another Package Revision - pr2 := &porchapi.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: "test-fn-pod-hierarchy", - WorkspaceName: "workspace-2", - RepositoryName: "git-fn-pod", - Tasks: []porchapi.Task{ - { - Type: "clone", - Clone: &porchapi.PackageCloneTaskSpec{ - Upstream: porchapi.UpstreamPackage{ - Type: "git", - Git: &porchapi.GitPackage{ - Repo: "https://github.com/GoogleCloudPlatform/blueprints.git", - Ref: "783380ce4e6c3f21e9e90055b3a88bada0410154", - Directory: "catalog/hierarchy/simple", - }, - }, - }, - }, - // Testing pod evaluator with TS function - { - Type: "eval", - Eval: &porchapi.FunctionEvalTaskSpec{ - Image: generateFolderImage, - }, - }, - // Testing pod evaluator with golang function - { - Type: "eval", - Eval: &porchapi.FunctionEvalTaskSpec{ - Image: setAnnotationsImage, - ConfigMap: map[string]string{ - "new-test-key": "new-test-val", - }, - }, - }, - }, - }, - } - t.CreateF(ctx, pr2) - - // Get package resources - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr2.Name, - }, &resources) - - counter = 0 - for name, obj := range resources.Spec.Resources { - if strings.HasPrefix(name, "hierarchy/") { - counter++ - node, err := yaml.Parse(obj) - if err != nil { - t.Errorf("failed to parse Folder object: %v", err) - } - if node.GetAnnotations()["new-test-key"] != "new-test-val" { - t.Errorf("Folder should contain annotation `test-key:test-val`, the annotations we got: %v", node.GetAnnotations()) - } - } - } - if counter != 4 { - t.Errorf("expected 4 Folder objects, but got %v", counter) - } -} - -func (t *PorchSuite) TestPodEvaluatorWithFailure(ctx context.Context) { - if t.local { - t.Skipf("Skipping due to not having pod evalutor in local mode") - } - - t.registerMainGitRepositoryF(ctx, "git-fn-pod-failure") - - // Create Package Revision - pr := &porchapi.PackageRevision{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: "test-fn-pod-bucket", - WorkspaceName: "workspace", - RepositoryName: "git-fn-pod-failure", - Tasks: []porchapi.Task{ - { - Type: "clone", - Clone: &porchapi.PackageCloneTaskSpec{ - Upstream: porchapi.UpstreamPackage{ - Type: "git", - Git: &porchapi.GitPackage{ - Repo: "https://github.com/GoogleCloudPlatform/blueprints.git", - Ref: "bucket-blueprint-v0.4.3", - Directory: "catalog/bucket", - }, - }, - }, - }, - { - Type: "eval", - Eval: &porchapi.FunctionEvalTaskSpec{ - // This function is expect to fail due to not knowing schema for some CRDs. - Image: "gcr.io/kpt-fn/kubeval:v0.2.0", - }, - }, - }, - }, - } - err := t.client.Create(ctx, pr) - expectedErrMsg := "Validating arbitrary CRDs is not supported" - if err == nil || !strings.Contains(err.Error(), expectedErrMsg) { - t.Fatalf("expected the error to contain %q, but got %v", expectedErrMsg, err) - } -} - -func (t *PorchSuite) TestRepositoryError(ctx context.Context) { - const ( - repositoryName = "repo-with-error" - ) - t.CreateF(ctx, &configapi.Repository{ - TypeMeta: metav1.TypeMeta{ - Kind: configapi.TypeRepository.Kind, - APIVersion: configapi.TypeRepository.APIVersion(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: repositoryName, - Namespace: t.namespace, - }, - Spec: configapi.RepositorySpec{ - Description: "Repository With Error", - Type: configapi.RepositoryTypeGit, - Content: configapi.RepositoryContentPackage, - Git: &configapi.GitRepository{ - // Use `incalid` domain: https://www.rfc-editor.org/rfc/rfc6761#section-6.4 - Repo: "https://repo.invalid/repository.git", - }, - }, - }) - t.Cleanup(func() { - t.DeleteL(ctx, &configapi.Repository{ - ObjectMeta: metav1.ObjectMeta{ - Name: repositoryName, - Namespace: t.namespace, - }, - }) - }) - - giveUp := time.Now().Add(60 * time.Second) - - for { - if time.Now().After(giveUp) { - t.Errorf("Timed out waiting for Repository Condition") - break - } - - time.Sleep(5 * time.Second) - - var repository configapi.Repository - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: repositoryName, - }, &repository) - - available := meta.FindStatusCondition(repository.Status.Conditions, configapi.RepositoryReady) - if available == nil { - // Condition not yet set - t.Logf("Repository condition not yet available") - continue - } - - if got, want := available.Status, metav1.ConditionFalse; got != want { - t.Errorf("Repository Available Condition Status; got %q, want %q", got, want) - } - if got, want := available.Reason, configapi.ReasonError; got != want { - t.Errorf("Repository Available Condition Reason: got %q, want %q", got, want) - } - break - } -} - -func (t *PorchSuite) TestNewPackageRevisionLabels(ctx context.Context) { - const ( - repository = "pkg-rev-labels" - labelKey1 = "kpt.dev/label" - labelVal1 = "foo" - labelKey2 = "kpt.dev/other-label" - labelVal2 = "bar" - annoKey1 = "kpt.dev/anno" - annoVal1 = "foo" - annoKey2 = "kpt.dev/other-anno" - annoVal2 = "bar" - ) - - t.registerMainGitRepositoryF(ctx, repository) - - // Create a package with labels and annotations. - pr := porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - Labels: map[string]string{ - labelKey1: labelVal1, - }, - Annotations: map[string]string{ - annoKey1: annoVal1, - annoKey2: annoVal2, - }, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: "new-package", - WorkspaceName: "workspace", - RepositoryName: repository, - Tasks: []porchapi.Task{ - { - Type: porchapi.TaskTypeInit, - Init: &porchapi.PackageInitTaskSpec{ - Description: "this is a test", - }, - }, - }, - }, - } - t.CreateF(ctx, &pr) - t.validateLabelsAndAnnos(ctx, pr.Name, - map[string]string{ - labelKey1: labelVal1, - }, - map[string]string{ - annoKey1: annoVal1, - annoKey2: annoVal2, - }, - ) - - // Propose the package. - pr.Spec.Lifecycle = porchapi.PackageRevisionLifecycleProposed - t.UpdateF(ctx, &pr) - - // retrieve the updated object - t.GetF(ctx, client.ObjectKey{ - Namespace: pr.Namespace, - Name: pr.Name, - }, &pr) - - t.validateLabelsAndAnnos(ctx, pr.Name, - map[string]string{ - labelKey1: labelVal1, - }, - map[string]string{ - annoKey1: annoVal1, - annoKey2: annoVal2, - }, - ) - - // Approve the package - pr.Spec.Lifecycle = porchapi.PackageRevisionLifecyclePublished - _ = t.UpdateApprovalF(ctx, &pr, metav1.UpdateOptions{}) - t.validateLabelsAndAnnos(ctx, pr.Name, - map[string]string{ - labelKey1: labelVal1, - porchapi.LatestPackageRevisionKey: porchapi.LatestPackageRevisionValue, - }, - map[string]string{ - annoKey1: annoVal1, - annoKey2: annoVal2, - }, - ) - - // retrieve the updated object - t.GetF(ctx, client.ObjectKey{ - Namespace: pr.Namespace, - Name: pr.Name, - }, &pr) - - // Update the labels and annotations on the approved package. - delete(pr.ObjectMeta.Labels, labelKey1) - pr.ObjectMeta.Labels[labelKey2] = labelVal2 - delete(pr.ObjectMeta.Annotations, annoKey2) - pr.Spec.Revision = "v1" - t.UpdateF(ctx, &pr) - t.validateLabelsAndAnnos(ctx, pr.Name, - map[string]string{ - labelKey2: labelVal2, - porchapi.LatestPackageRevisionKey: porchapi.LatestPackageRevisionValue, - }, - map[string]string{ - annoKey1: annoVal1, - }, - ) - - // Create PackageRevision from upstream repo. Labels and annotations should - // not be retained from upstream. - clonedPr := porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: "cloned-package", - WorkspaceName: "workspace", - RepositoryName: repository, - Tasks: []porchapi.Task{ - { - Type: porchapi.TaskTypeClone, - Clone: &porchapi.PackageCloneTaskSpec{ - Upstream: porchapi.UpstreamPackage{ - UpstreamRef: &porchapi.PackageRevisionRef{ - Name: pr.Name, // Package to be cloned - }, - }, - }, - }, - }, - }, - } - t.CreateF(ctx, &clonedPr) - t.validateLabelsAndAnnos(ctx, clonedPr.Name, - map[string]string{}, - map[string]string{}, - ) -} - -func (t *PorchSuite) TestRegisteredPackageRevisionLabels(ctx context.Context) { - const ( - labelKey = "kpt.dev/label" - labelVal = "foo" - annoKey = "kpt.dev/anno" - annoVal = "foo" - ) - - t.registerGitRepositoryF(ctx, testBlueprintsRepo, "test-blueprints", "") - - var list porchapi.PackageRevisionList - t.ListE(ctx, &list, client.InNamespace(t.namespace)) - - basens := MustFindPackageRevision(t.T, &list, repository.PackageRevisionKey{Repository: "test-blueprints", Package: "basens", Revision: "v1"}) - if basens.ObjectMeta.Labels == nil { - basens.ObjectMeta.Labels = make(map[string]string) - } - basens.ObjectMeta.Labels[labelKey] = labelVal - if basens.ObjectMeta.Annotations == nil { - basens.ObjectMeta.Annotations = make(map[string]string) - } - basens.ObjectMeta.Annotations[annoKey] = annoVal - t.UpdateF(ctx, basens) - - t.validateLabelsAndAnnos(ctx, basens.Name, - map[string]string{ - labelKey: labelVal, - }, - map[string]string{ - annoKey: annoVal, - }, - ) -} - -func (t *PorchSuite) TestPackageRevisionGCWithOwner(ctx context.Context) { - const ( - repository = "pkgrevgcwithowner" - workspace = "pkgrevgcwithowner-workspace" - description = "empty-package description" - cmName = "foo" - ) - - t.registerMainGitRepositoryF(ctx, repository) - - // Create a new package (via init) - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: packageRevisionGVK.Kind, - APIVersion: packageRevisionGVK.GroupVersion().String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: "empty-package", - WorkspaceName: workspace, - RepositoryName: repository, - }, - } - t.CreateF(ctx, pr) - - cm := &corev1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - Kind: configMapGVK.Kind, - APIVersion: configMapGVK.GroupVersion().String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: cmName, - Namespace: t.namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: porchapi.SchemeGroupVersion.String(), - Kind: packageRevisionGVK.Kind, - Name: pr.Name, - UID: pr.UID, - }, - }, - }, - Data: map[string]string{ - "foo": "bar", - }, - } - t.CreateF(ctx, cm) - - t.DeleteF(ctx, pr) - t.waitUntilObjectDeleted( - ctx, - packageRevisionGVK, - types.NamespacedName{ - Name: pr.Name, - Namespace: pr.Namespace, - }, - 10*time.Second, - ) - t.waitUntilObjectDeleted( - ctx, - configMapGVK, - types.NamespacedName{ - Name: cm.Name, - Namespace: cm.Namespace, - }, - 10*time.Second, - ) -} - -func (t *PorchSuite) TestPackageRevisionGCAsOwner(ctx context.Context) { - const ( - repository = "pkgrevgcasowner" - workspace = "pkgrevgcasowner-workspace" - description = "empty-package description" - cmName = "foo" - ) - - t.registerMainGitRepositoryF(ctx, repository) - - cm := &corev1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - Kind: configMapGVK.Kind, - APIVersion: configMapGVK.GroupVersion().String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: cmName, - Namespace: t.namespace, - }, - Data: map[string]string{ - "foo": "bar", - }, - } - t.CreateF(ctx, cm) - - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: packageRevisionGVK.Kind, - APIVersion: packageRevisionGVK.GroupVersion().String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "v1", - Kind: "ConfigMap", - Name: cm.Name, - UID: cm.UID, - }, - }, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: "empty-package", - WorkspaceName: workspace, - RepositoryName: repository, - }, - } - t.CreateF(ctx, pr) - - t.DeleteF(ctx, cm) - t.waitUntilObjectDeleted( - ctx, - configMapGVK, - types.NamespacedName{ - Name: cm.Name, - Namespace: cm.Namespace, - }, - 10*time.Second, - ) - t.waitUntilObjectDeleted( - ctx, - packageRevisionGVK, - types.NamespacedName{ - Name: pr.Name, - Namespace: pr.Namespace, - }, - 10*time.Second, - ) -} - -func (t *PorchSuite) TestPackageRevisionOwnerReferences(ctx context.Context) { - const ( - repository = "pkgrevownerrefs" - workspace = "pkgrevownerrefs-workspace" - description = "empty-package description" - cmName = "foo" - ) - - t.registerMainGitRepositoryF(ctx, repository) - - cm := &corev1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - Kind: configMapGVK.Kind, - APIVersion: configMapGVK.GroupVersion().String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: cmName, - Namespace: t.namespace, - }, - Data: map[string]string{ - "foo": "bar", - }, - } - t.CreateF(ctx, cm) - - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: packageRevisionGVK.Kind, - APIVersion: packageRevisionGVK.GroupVersion().String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: "empty-package", - WorkspaceName: workspace, - RepositoryName: repository, - }, - } - t.CreateF(ctx, pr) - t.validateOwnerReferences(ctx, pr.Name, []metav1.OwnerReference{}) - - ownerRef := metav1.OwnerReference{ - APIVersion: "v1", - Kind: "ConfigMap", - Name: cm.Name, - UID: cm.UID, - } - pr.ObjectMeta.OwnerReferences = []metav1.OwnerReference{ownerRef} - t.UpdateF(ctx, pr) - t.validateOwnerReferences(ctx, pr.Name, []metav1.OwnerReference{ownerRef}) - - pr.ObjectMeta.OwnerReferences = []metav1.OwnerReference{} - t.UpdateF(ctx, pr) - t.validateOwnerReferences(ctx, pr.Name, []metav1.OwnerReference{}) -} - -func (t *PorchSuite) TestPackageRevisionFinalizers(ctx context.Context) { - const ( - repository = "pkgrevfinalizers" - workspace = "pkgrevfinalizers-workspace" - description = "empty-package description" - ) - - t.registerMainGitRepositoryF(ctx, repository) - - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: packageRevisionGVK.Kind, - APIVersion: packageRevisionGVK.GroupVersion().String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: "empty-package", - WorkspaceName: workspace, - RepositoryName: repository, - }, - } - t.CreateF(ctx, pr) - t.validateFinalizers(ctx, pr.Name, []string{}) - - pr.Finalizers = append(pr.Finalizers, "foo-finalizer") - t.UpdateF(ctx, pr) - t.validateFinalizers(ctx, pr.Name, []string{"foo-finalizer"}) - - t.DeleteF(ctx, pr) - t.validateFinalizers(ctx, pr.Name, []string{"foo-finalizer"}) - - pr.Finalizers = []string{} - t.UpdateF(ctx, pr) - t.waitUntilObjectDeleted(ctx, packageRevisionGVK, types.NamespacedName{ - Name: pr.Name, - Namespace: pr.Namespace, - }, 10*time.Second) -} - -func (t *PorchSuite) validateFinalizers(ctx context.Context, name string, finalizers []string) { - var pr porchapi.PackageRevision - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: name, - }, &pr) - - if len(finalizers) != len(pr.Finalizers) { - diff := cmp.Diff(finalizers, pr.Finalizers) - t.Errorf("Expected %d finalizers, but got %s", len(finalizers), diff) - } - - for _, finalizer := range finalizers { - var found bool - for _, f := range pr.Finalizers { - if f == finalizer { - found = true - } - } - if !found { - t.Errorf("Expected finalizer %v, but didn't find it", finalizer) - } - } -} - -func (t *PorchSuite) validateOwnerReferences(ctx context.Context, name string, ownerRefs []metav1.OwnerReference) { - var pr porchapi.PackageRevision - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: name, - }, &pr) - - if len(ownerRefs) != len(pr.OwnerReferences) { - diff := cmp.Diff(ownerRefs, pr.OwnerReferences) - t.Errorf("Expected %d ownerReferences, but got %s", len(ownerRefs), diff) - } - - for _, ownerRef := range ownerRefs { - var found bool - for _, or := range pr.OwnerReferences { - if or == ownerRef { - found = true - } - } - if !found { - t.Errorf("Expected ownerRef %v, but didn't find it", ownerRef) - } - } -} - -func (t *PorchSuite) validateLabelsAndAnnos(ctx context.Context, name string, labels, annos map[string]string) { - var pr porchapi.PackageRevision - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: name, - }, &pr) - - actualLabels := pr.ObjectMeta.Labels - actualAnnos := pr.ObjectMeta.Annotations - - // Make this check to handle empty vs nil maps - if !(len(labels) == 0 && len(actualLabels) == 0) { - if diff := cmp.Diff(actualLabels, labels); diff != "" { - t.Errorf("Unexpected result (-want, +got): %s", diff) - } - } - - if !(len(annos) == 0 && len(actualAnnos) == 0) { - if diff := cmp.Diff(actualAnnos, annos); diff != "" { - t.Errorf("Unexpected result (-want, +got): %s", diff) - } - } -} - -func (t *PorchSuite) registerGitRepositoryF(ctx context.Context, repo, name, directory string) { - t.CreateF(ctx, &configapi.Repository{ - TypeMeta: metav1.TypeMeta{ - Kind: "Repository", - APIVersion: configapi.GroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: t.namespace, - }, - Spec: configapi.RepositorySpec{ - Type: configapi.RepositoryTypeGit, - Content: configapi.RepositoryContentPackage, - Git: &configapi.GitRepository{ - Repo: repo, - Branch: "main", - Directory: directory, - }, - }, - }) - - t.Cleanup(func() { - t.DeleteL(ctx, &configapi.Repository{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: t.namespace, - }, - }) - }) - - // Make sure the repository is ready before we test to (hopefully) - // avoid flakiness. - t.waitUntilRepositoryReady(ctx, name, t.namespace) -} - -type repositoryOption func(*configapi.Repository) - -func (t *PorchSuite) registerMainGitRepositoryF(ctx context.Context, name string, opts ...repositoryOption) { - repoID := t.namespace + "-" + name - config := t.GitConfig(repoID) - - var secret string - // Create auth secret if necessary - if config.Username != "" || config.Password != "" { - secret = fmt.Sprintf("%s-auth", name) - immutable := true - t.CreateF(ctx, &coreapi.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: secret, - Namespace: t.namespace, - }, - Immutable: &immutable, - Data: map[string][]byte{ - "username": []byte(config.Username), - "password": []byte(config.Password), - }, - Type: coreapi.SecretTypeBasicAuth, - }) - - t.Cleanup(func() { - t.DeleteE(ctx, &coreapi.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: secret, - Namespace: t.namespace, - }, - }) - }) - } - - repository := &configapi.Repository{ - TypeMeta: metav1.TypeMeta{ - Kind: "Repository", - APIVersion: configapi.GroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: t.namespace, - }, - Spec: configapi.RepositorySpec{ - Description: "Porch Test Repository Description", - Type: configapi.RepositoryTypeGit, - Content: configapi.RepositoryContentPackage, - Git: &configapi.GitRepository{ - Repo: config.Repo, - Branch: config.Branch, - Directory: config.Directory, - SecretRef: configapi.SecretRef{ - Name: secret, - }, - }, - }, - } - - // Apply options - for _, o := range opts { - o(repository) - } - - // Register repository - t.CreateF(ctx, repository) - - t.Cleanup(func() { - t.DeleteE(ctx, &configapi.Repository{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: t.namespace, - }, - }) - t.waitUntilRepositoryDeleted(ctx, name, t.namespace) - t.waitUntilAllPackagesDeleted(ctx, name) - }) -} - -func withDeployment() repositoryOption { - return func(r *configapi.Repository) { - r.Spec.Deployment = true - } -} - -func withType(t configapi.RepositoryType) repositoryOption { - return func(r *configapi.Repository) { - r.Spec.Type = t - } -} - -func withContent(content configapi.RepositoryContent) repositoryOption { - return func(r *configapi.Repository) { - r.Spec.Content = content - } -} - -// Creates an empty package draft by initializing an empty package -func (t *PorchSuite) createPackageDraftF(ctx context.Context, repository, name, workspace string) *porchapi.PackageRevision { - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: name, - WorkspaceName: porchapi.WorkspaceName(workspace), - RepositoryName: repository, - Tasks: []porchapi.Task{ - { - Type: porchapi.TaskTypeInit, - Init: &porchapi.PackageInitTaskSpec{}, - }, - }, - }, - } - t.CreateF(ctx, pr) - return pr -} - -func (t *PorchSuite) mustExist(ctx context.Context, key client.ObjectKey, obj client.Object) { - t.GetF(ctx, key, obj) - if got, want := obj.GetName(), key.Name; got != want { - t.Errorf("%T.Name: got %q, want %q", obj, got, want) - } - if got, want := obj.GetNamespace(), key.Namespace; got != want { - t.Errorf("%T.Namespace: got %q, want %q", obj, got, want) - } -} - -func (t *PorchSuite) mustNotExist(ctx context.Context, obj client.Object) { - switch err := t.client.Get(ctx, client.ObjectKeyFromObject(obj), obj); { - case err == nil: - t.Errorf("No error returned getting a deleted package; expected error") - case !apierrors.IsNotFound(err): - t.Errorf("Expected NotFound error. got %v", err) - } -} - -// waitUntilRepositoryReady waits for up to 10 seconds for the repository with the -// provided name and namespace is ready, i.e. the Ready condition is true. -// It also queries for Functions and PackageRevisions, to ensure these are also -// ready - this is an artifact of the way we've implemented the aggregated apiserver, -// where the first fetch will block on the cache loading. Wait up to two minutes for the -// package revisions and functions. -func (t *PorchSuite) waitUntilRepositoryReady(ctx context.Context, name, namespace string) { - nn := types.NamespacedName{ - Name: name, - Namespace: namespace, - } - var innerErr error - err := wait.PollImmediateWithContext(ctx, time.Second, 10*time.Second, func(ctx context.Context) (bool, error) { - var repo configapi.Repository - if err := t.client.Get(ctx, nn, &repo); err != nil { - innerErr = err - return false, nil - } - for _, c := range repo.Status.Conditions { - if c.Type == configapi.RepositoryReady { - return c.Status == metav1.ConditionTrue, nil - } - } - return false, nil - }) - if err != nil { - t.Errorf("Repository not ready after wait: %v", innerErr) - } - - // While we're using an aggregated apiserver, make sure we can query the generated objects - if err := wait.PollImmediateWithContext(ctx, time.Second, 120*time.Second, func(ctx context.Context) (bool, error) { - var revisions porchapi.PackageRevisionList - if err := t.client.List(ctx, &revisions, client.InNamespace(nn.Namespace)); err != nil { - innerErr = err - return false, nil - } - return true, nil - }); err != nil { - t.Errorf("unable to query PackageRevisions after wait: %v", innerErr) - } - - // Check for functions also (until we move them to CRDs) - if err := wait.PollImmediateWithContext(ctx, time.Second, 120*time.Second, func(ctx context.Context) (bool, error) { - var functions porchapi.FunctionList - if err := t.client.List(ctx, &functions, client.InNamespace(nn.Namespace)); err != nil { - innerErr = err - return false, nil - } - return true, nil - }); err != nil { - t.Errorf("unable to query Functions after wait: %v", innerErr) - } - -} - -func (t *PorchSuite) waitUntilRepositoryDeleted(ctx context.Context, name, namespace string) { - err := wait.PollImmediateWithContext(ctx, time.Second, 20*time.Second, func(ctx context.Context) (done bool, err error) { - var repo configapi.Repository - nn := types.NamespacedName{ - Name: name, - Namespace: namespace, - } - if err := t.client.Get(ctx, nn, &repo); err != nil { - if apierrors.IsNotFound(err) { - return true, nil - } - return false, nil - } - return false, nil - }) - if err != nil { - t.Fatalf("Repository %s/%s not deleted", namespace, name) - } -} - -func (t *PorchSuite) waitUntilAllPackagesDeleted(ctx context.Context, repoName string) { - err := wait.PollImmediateWithContext(ctx, time.Second, 60*time.Second, func(ctx context.Context) (done bool, err error) { - var pkgRevList porchapi.PackageRevisionList - if err := t.client.List(ctx, &pkgRevList); err != nil { - t.Logf("error listing packages: %v", err) - return false, nil - } - for _, pkgRev := range pkgRevList.Items { - if strings.HasPrefix(fmt.Sprintf("%s-", pkgRev.Name), repoName) { - t.Logf("Found package %s from repo %s", pkgRev.Name, repoName) - return false, nil - } - } - - var internalPkgRevList internalapi.PackageRevList - if err := t.client.List(ctx, &internalPkgRevList); err != nil { - t.Logf("error list internal packages: %v", err) - return false, nil - } - for _, internalPkgRev := range internalPkgRevList.Items { - if strings.HasPrefix(fmt.Sprintf("%s-", internalPkgRev.Name), repoName) { - t.Logf("Found internalPkg %s from repo %s", internalPkgRev.Name, repoName) - return false, nil - } - } - return true, nil - }) - if err != nil { - t.Fatalf("Packages from repo %s still remains", repoName) - } -} - -func (t *PorchSuite) waitUntilObjectDeleted(ctx context.Context, gvk schema.GroupVersionKind, namespacedName types.NamespacedName, d time.Duration) { - var innerErr error - err := wait.PollImmediateWithContext(ctx, time.Second, d, func(ctx context.Context) (bool, error) { - var u unstructured.Unstructured - u.SetGroupVersionKind(gvk) - if err := t.client.Get(ctx, namespacedName, &u); err != nil { - if apierrors.IsNotFound(err) { - return true, nil - } - innerErr = err - return false, err - } - return false, nil - }) - if err != nil { - t.Errorf("Object %s not deleted after %s: %v", namespacedName.String(), d.String(), innerErr) - } -} - -func (t *PorchSuite) waitUntilMainBranchPackageRevisionExists(ctx context.Context, pkgName string) { - err := wait.PollImmediateWithContext(ctx, time.Second, 120*time.Second, func(ctx context.Context) (done bool, err error) { - var pkgRevList porchapi.PackageRevisionList - if err := t.client.List(ctx, &pkgRevList); err != nil { - t.Logf("error listing packages: %v", err) - return false, nil - } - for _, pkgRev := range pkgRevList.Items { - pkgName := pkgRev.Spec.PackageName - pkgRevision := pkgRev.Spec.Revision - if pkgRevision == "main" && - pkgName == pkgRev.Spec.PackageName { - return true, nil - } - } - return false, nil - }) - if err != nil { - t.Fatalf("Main branch package revision for %s not found", pkgName) - } -} diff --git a/porch/test/e2e/suite.go b/porch/test/e2e/suite.go deleted file mode 100644 index 28c53db424..0000000000 --- a/porch/test/e2e/suite.go +++ /dev/null @@ -1,731 +0,0 @@ -// Copyright 2022 The kpt 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. - -package e2e - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "net" - "net/http" - "os" - "strings" - "sync" - "testing" - "time" - - internalpkg "github.com/GoogleContainerTools/kpt/internal/pkg" - kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" - porchtest "github.com/GoogleContainerTools/kpt/pkg/test/porch" - porchclient "github.com/GoogleContainerTools/kpt/porch/api/generated/clientset/versioned" - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - configapi "github.com/GoogleContainerTools/kpt/porch/api/porchconfig/v1alpha1" - internalapi "github.com/GoogleContainerTools/kpt/porch/internal/api/porchinternal/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/git" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - gogit "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/object" - "github.com/google/go-cmp/cmp" - appsv1 "k8s.io/api/apps/v1" - coreapi "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/intstr" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" - aggregatorv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/config" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -const ( - // TODO: accept a flag? - PorchTestConfigFile = "porch-test-config.yaml" - updateGoldenFiles = "UPDATE_GOLDEN_FILES" -) - -type GitConfig struct { - Repo string `json:"repo"` - Branch string `json:"branch"` - Directory string `json:"directory"` - Username string `json:"username"` - Password Password `json:"password"` -} - -type OciConfig struct { - Registry string `json:"registry"` -} - -type Password string - -func (p Password) String() string { - return "*************" -} - -type TestSuite struct { - *testing.T - kubeconfig *rest.Config - client client.Client - - // Strongly-typed client handy for reading e.g. pod logs - kubeClient kubernetes.Interface - - clientset porchclient.Interface - - namespace string // K8s namespace for this test run - local bool // Tests running against local dev porch -} - -type Initializer interface { - Initialize(ctx context.Context) -} - -var _ Initializer = &TestSuite{} - -func (t *TestSuite) Initialize(ctx context.Context) { - cfg, err := config.GetConfig() - if err != nil { - t.Skipf("Skipping test suite - cannot obtain k8s client config: %v", err) - } - - t.Logf("Testing against server: %q", cfg.Host) - cfg.UserAgent = "Porch Test" - t.Logf("using timeout %v", cfg.Timeout) - - scheme := createClientScheme(t.T) - - if c, err := client.New(cfg, client.Options{ - Scheme: scheme, - }); err != nil { - t.Fatalf("Failed to initialize k8s client (%s): %v", cfg.Host, err) - } else { - t.client = c - t.kubeconfig = cfg - } - - if kubeClient, err := kubernetes.NewForConfig(cfg); err != nil { - t.Fatalf("failed to initialize kubernetes clientset: %v", err) - } else { - t.kubeClient = kubeClient - } - - if cs, err := porchclient.NewForConfig(cfg); err != nil { - t.Fatalf("Failed to initialize Porch clientset: %v", err) - } else { - t.clientset = cs - } - - t.local = t.IsUsingDevPorch() - - namespace := fmt.Sprintf("porch-test-%d", time.Now().UnixMicro()) - t.CreateF(ctx, &coreapi.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: namespace, - }, - }) - - t.namespace = namespace - c := t.client - t.Cleanup(func() { - if err := c.Delete(ctx, &coreapi.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: namespace, - }, - }); err != nil { - t.Errorf("Failed to clean up namespace %q: %v", namespace, err) - } else { - t.Logf("Successfully cleaned up namespace %q", namespace) - } - }) -} - -func (t *TestSuite) IsUsingDevPorch() bool { - porch := aggregatorv1.APIService{} - ctx := context.TODO() - t.GetF(ctx, client.ObjectKey{ - Name: "v1alpha1.porch.kpt.dev", - }, &porch) - service := coreapi.Service{} - t.GetF(ctx, client.ObjectKey{ - Namespace: porch.Spec.Service.Namespace, - Name: porch.Spec.Service.Name, - }, &service) - - return service.Spec.Type == coreapi.ServiceTypeExternalName && service.Spec.ExternalName == "host.docker.internal" -} - -func (t *TestSuite) CreateGitRepo() GitConfig { - if t.IsUsingDevPorch() { - // Create Git server on the local machine. - t.Logf("using dev porch; creating local git server") - return createLocalGitServer(t.T) - } else { - // Deploy Git server via k8s client. - t.Logf("not using dev porch; creating git server in cluster") - return t.createInClusterGitServer(context.TODO()) - } -} - -type ErrorHandler func(format string, args ...interface{}) - -func (t *TestSuite) get(ctx context.Context, key client.ObjectKey, obj client.Object, eh ErrorHandler) { - if err := t.client.Get(ctx, key, obj); err != nil { - eh("failed to get resource %s %s/%s: %v", obj.GetObjectKind().GroupVersionKind(), key.Name, key.Namespace, err) - } -} - -func (c *TestSuite) list(ctx context.Context, list client.ObjectList, opts []client.ListOption, eh ErrorHandler) { - if err := c.client.List(ctx, list, opts...); err != nil { - eh("failed to list resources %s %+v: %v", list.GetObjectKind().GroupVersionKind(), list, err) - } -} - -func DebugFormat(obj client.Object) string { - var s string - gvk := obj.GetObjectKind().GroupVersionKind() - if gvk.Empty() { - s = fmt.Sprintf("%T", obj) - } else { - s = gvk.Kind - } - ns := obj.GetNamespace() - if ns != "" { - s += " " + ns + "/" - } else { - s += " " - } - s += obj.GetName() - return s -} - -func (c *TestSuite) create(ctx context.Context, obj client.Object, opts []client.CreateOption, eh ErrorHandler) { - c.Logf("creating object %v", DebugFormat(obj)) - start := time.Now() - defer func() { - c.Logf("took %v to create %s/%s", time.Since(start), obj.GetNamespace(), obj.GetName()) - }() - - if err := c.client.Create(ctx, obj, opts...); err != nil { - eh("failed to create resource %s: %v", DebugFormat(obj), err) - } -} - -func (c *TestSuite) delete(ctx context.Context, obj client.Object, opts []client.DeleteOption, eh ErrorHandler) { - c.Logf("deleting object %v", DebugFormat(obj)) - - if err := c.client.Delete(ctx, obj, opts...); err != nil { - eh("failed to delete resource %s: %v", DebugFormat(obj), err) - } -} - -func (t *TestSuite) update(ctx context.Context, obj client.Object, opts []client.UpdateOption, eh ErrorHandler) { - t.Logf("updating object %v", DebugFormat(obj)) - - if err := t.client.Update(ctx, obj, opts...); err != nil { - eh("failed to update resource %s: %v", DebugFormat(obj), err) - } -} - -func (t *TestSuite) patch(ctx context.Context, obj client.Object, patch client.Patch, opts []client.PatchOption, eh ErrorHandler) { - t.Logf("patching object %v", DebugFormat(obj)) - - if err := t.client.Patch(ctx, obj, patch, opts...); err != nil { - eh("failed to patch resource %s: %v", DebugFormat(obj), err) - } -} - -func (t *TestSuite) updateApproval(ctx context.Context, obj *porchapi.PackageRevision, opts metav1.UpdateOptions, eh ErrorHandler) *porchapi.PackageRevision { - if res, err := t.clientset.PorchV1alpha1().PackageRevisions(obj.Namespace).UpdateApproval(ctx, obj.Name, obj, opts); err != nil { - eh("failed to update approval of %s/%s: %v", obj.Namespace, obj.Name, err) - return nil - } else { - return res - } -} - -// deleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error - -func (t *TestSuite) GetE(ctx context.Context, key client.ObjectKey, obj client.Object) { - t.get(ctx, key, obj, ErrorHandler(t.Errorf)) -} - -func (t *TestSuite) GetF(ctx context.Context, key client.ObjectKey, obj client.Object) { - t.get(ctx, key, obj, ErrorHandler(t.Fatalf)) -} - -func (t *TestSuite) ListE(ctx context.Context, list client.ObjectList, opts ...client.ListOption) { - t.list(ctx, list, opts, t.Errorf) -} - -func (t *TestSuite) ListF(ctx context.Context, list client.ObjectList, opts ...client.ListOption) { - t.list(ctx, list, opts, t.Fatalf) -} - -func (t *TestSuite) CreateF(ctx context.Context, obj client.Object, opts ...client.CreateOption) { - t.create(ctx, obj, opts, t.Fatalf) -} - -func (t *TestSuite) CreateE(ctx context.Context, obj client.Object, opts ...client.CreateOption) { - t.create(ctx, obj, opts, t.Errorf) -} - -func (t *TestSuite) DeleteF(ctx context.Context, obj client.Object, opts ...client.DeleteOption) { - t.delete(ctx, obj, opts, t.Fatalf) -} - -func (t *TestSuite) DeleteE(ctx context.Context, obj client.Object, opts ...client.DeleteOption) { - t.delete(ctx, obj, opts, t.Errorf) -} - -func (t *TestSuite) DeleteL(ctx context.Context, obj client.Object, opts ...client.DeleteOption) { - t.delete(ctx, obj, opts, t.Logf) -} - -func (t *TestSuite) UpdateF(ctx context.Context, obj client.Object, opts ...client.UpdateOption) { - t.update(ctx, obj, opts, t.Fatalf) -} - -func (t *TestSuite) UpdateE(ctx context.Context, obj client.Object, opts ...client.UpdateOption) { - t.update(ctx, obj, opts, t.Errorf) -} - -func (t *TestSuite) PatchF(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) { - t.patch(ctx, obj, patch, opts, t.Fatalf) -} - -func (t *TestSuite) PatchE(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) { - t.patch(ctx, obj, patch, opts, t.Errorf) -} - -func (t *TestSuite) UpdateApprovalF(ctx context.Context, pr *porchapi.PackageRevision, opts metav1.UpdateOptions) *porchapi.PackageRevision { - return t.updateApproval(ctx, pr, opts, t.Fatalf) -} - -// DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error - -func createClientScheme(t *testing.T) *runtime.Scheme { - scheme := runtime.NewScheme() - - for _, api := range (runtime.SchemeBuilder{ - porchapi.AddToScheme, - internalapi.AddToScheme, - configapi.AddToScheme, - coreapi.AddToScheme, - aggregatorv1.AddToScheme, - appsv1.AddToScheme, - }) { - if err := api(scheme); err != nil { - t.Fatalf("Failed to initialize test k8s api client") - } - } - return scheme -} - -func createLocalGitServer(t *testing.T) GitConfig { - tmp, err := os.MkdirTemp("", "porch-test-*") - if err != nil { - t.Fatalf("Failed to create temp directory for Git repository: %v", err) - return GitConfig{} - } - - t.Cleanup(func() { - if err := os.RemoveAll(tmp); err != nil { - t.Errorf("Failed to delete Git temp directory %q: %v", tmp, err) - } - }) - - var gitRepoOptions []git.GitRepoOption - repos := git.NewDynamicRepos(tmp, gitRepoOptions) - - server, err := git.NewGitServer(repos) - if err != nil { - t.Fatalf("Failed to start git server: %v", err) - return GitConfig{} - } - - var wg sync.WaitGroup - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(func() { - cancel() - wg.Wait() - }) - - addressChannel := make(chan net.Addr) - - wg.Add(1) - go func() { - defer wg.Done() - err := server.ListenAndServe(ctx, "127.0.0.1:0", addressChannel) - if err != nil { - if err == http.ErrServerClosed { - t.Log("Git server shut down successfully") - } else { - t.Errorf("Git server exited with error: %v", err) - } - } - }() - - // Wait for server to start up - address, ok := <-addressChannel - if !ok { - t.Errorf("Server failed to start") - return GitConfig{} - } - - return GitConfig{ - Repo: fmt.Sprintf("http://%s", address), - Branch: "main", - Directory: "/", - } -} - -func createInitialCommit(t *testing.T, repo *gogit.Repository) { - store := repo.Storer - // Create first commit using empty tree. - emptyTree := object.Tree{} - encodedTree := store.NewEncodedObject() - if err := emptyTree.Encode(encodedTree); err != nil { - t.Fatalf("Failed to encode initial empty commit tree: %v", err) - } - - treeHash, err := store.SetEncodedObject(encodedTree) - if err != nil { - t.Fatalf("Failed to create initial empty commit tree: %v", err) - } - - sig := object.Signature{ - Name: "Porch Test", - Email: "porch-test@kpt.dev", - When: time.Now(), - } - - commit := object.Commit{ - Author: sig, - Committer: sig, - Message: "Empty Commit", - TreeHash: treeHash, - ParentHashes: []plumbing.Hash{}, // No parents - } - - encodedCommit := store.NewEncodedObject() - if err := commit.Encode(encodedCommit); err != nil { - t.Fatalf("Failed to encode initial empty commit: %v", err) - } - - commitHash, err := store.SetEncodedObject(encodedCommit) - if err != nil { - t.Fatalf("Failed to create initial empty commit: %v", err) - } - - head := plumbing.NewHashReference(plumbing.ReferenceName("refs/heads/main"), commitHash) - if err := repo.Storer.SetReference(head); err != nil { - t.Fatalf("Failed to set refs/heads/main to commit sha %s", commitHash) - } -} - -func (t *TestSuite) createInClusterGitServer(ctx context.Context) GitConfig { - // Determine git-server image name. Use the same container registry and tag as the Porch server, - // replacing base image name with `git-server`. TODO: Make configurable? - - var porch appsv1.Deployment - t.GetF(ctx, client.ObjectKey{ - Namespace: "porch-system", - Name: "porch-server", - }, &porch) - - gitImage := porchtest.InferGitServerImage(porch.Spec.Template.Spec.Containers[0].Image) - - var replicas int32 = 1 - var selector = strings.ReplaceAll(t.Name(), "/", "_") - - t.CreateF(ctx, &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: "git-server", - Namespace: t.namespace, - Annotations: map[string]string{ - "kpt.dev/porch-test": t.Name(), - }, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: &replicas, - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "git-server": selector, - }, - }, - Template: coreapi.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "git-server": selector, - }, - }, - Spec: coreapi.PodSpec{ - Containers: []coreapi.Container{ - { - Name: "git-server", - Image: gitImage, - Args: []string{}, - Ports: []coreapi.ContainerPort{ - { - ContainerPort: 8080, - Protocol: coreapi.ProtocolTCP, - }, - }, - ImagePullPolicy: coreapi.PullIfNotPresent, - }, - }, - }, - }, - }, - }) - - t.Cleanup(func() { - t.DeleteE(ctx, &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: "git-server", - Namespace: t.namespace, - }, - }) - }) - - t.Cleanup(func() { - t.DumpLogsForDeployment(ctx, types.NamespacedName{ - Name: "git-server", - Namespace: t.namespace, - }) - }) - - t.CreateF(ctx, &coreapi.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "git-server-service", - Namespace: t.namespace, - Annotations: map[string]string{ - "kpt.dev/porch-test": t.Name(), - }, - }, - Spec: coreapi.ServiceSpec{ - Ports: []coreapi.ServicePort{ - { - Protocol: coreapi.ProtocolTCP, - Port: 8080, - TargetPort: intstr.IntOrString{ - Type: intstr.Int, - IntVal: 8080, - }, - }, - }, - Selector: map[string]string{ - "git-server": selector, - }, - }, - }) - - t.Cleanup(func() { - t.DeleteE(ctx, &coreapi.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "git-server-service", - Namespace: t.namespace, - }, - }) - }) - - t.Logf("Waiting for git-server to start ...") - - // Wait a minute for git server to start up. - giveUp := time.Now().Add(time.Minute) - - for { - time.Sleep(5 * time.Second) - - var deployment appsv1.Deployment - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: "git-server", - }, &deployment) - - ready := true - if ready && deployment.Generation != deployment.Status.ObservedGeneration { - t.Logf("waiting for ObservedGeneration %v to match Generation %v", deployment.Status.ObservedGeneration, deployment.Generation) - ready = false - } - if ready && deployment.Status.UpdatedReplicas < deployment.Status.Replicas { - t.Logf("waiting for UpdatedReplicas %d to match Replicas %d", deployment.Status.UpdatedReplicas, deployment.Status.Replicas) - ready = false - } - if ready && deployment.Status.AvailableReplicas < deployment.Status.Replicas { - t.Logf("waiting for AvailableReplicas %d to match Replicas %d", deployment.Status.AvailableReplicas, deployment.Status.Replicas) - ready = false - } - - if ready { - ready = false // Until we've seen Available condition - for _, condition := range deployment.Status.Conditions { - if condition.Type == "Available" { - ready = true - if condition.Status != "True" { - t.Logf("waiting for status.condition %v", condition) - ready = false - } - } - } - } - - if ready { - break - } - - if time.Now().After(giveUp) { - t.Fatalf("git server failed to start: %s", &deployment) - return GitConfig{} - } - } - - t.Logf("git server is up") - - t.Logf("Waiting for git-server-service to be ready ...") - - // Check the Endpoint resource for readiness - giveUp = time.Now().Add(time.Minute) - - for { - time.Sleep(5 * time.Second) - - var endpoint coreapi.Endpoints - err := t.client.Get(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: "git-server-service", - }, &endpoint) - - if err == nil && endpointIsReady(&endpoint) { - t.Logf("git-server-service is ready") - break - } - - if time.Now().After(giveUp) { - t.Fatalf("git-server-service not ready on time: %s", &endpoint) - return GitConfig{} - } - } - - return GitConfig{ - Repo: fmt.Sprintf("http://git-server-service.%s.svc.cluster.local:8080", t.namespace), - Branch: "main", - Directory: "/", - } -} - -func endpointIsReady(endpoints *coreapi.Endpoints) bool { - if len(endpoints.Subsets) == 0 { - return false - } - for _, s := range endpoints.Subsets { - if len(s.Addresses) == 0 { - return false - } - for _, a := range s.Addresses { - if a.IP == "" { - return false - } - } - } - return true -} - -func (t *TestSuite) ParseKptfileF(resources *porchapi.PackageRevisionResources) *kptfilev1.KptFile { - contents, ok := resources.Spec.Resources[kptfilev1.KptFileName] - if !ok { - t.Fatalf("Kptfile not found in %s/%s package", resources.Namespace, resources.Name) - } - kptfile, err := internalpkg.DecodeKptfile(strings.NewReader(contents)) - if err != nil { - t.Fatalf("Cannot decode Kptfile (%s): %v", contents, err) - } - return kptfile -} - -func (t *TestSuite) SaveKptfileF(resources *porchapi.PackageRevisionResources, kptfile *kptfilev1.KptFile) { - b, err := yaml.MarshalWithOptions(kptfile, &yaml.EncoderOptions{SeqIndent: yaml.WideSequenceStyle}) - if err != nil { - t.Fatalf("Failed saving Kptfile: %v", err) - } - resources.Spec.Resources[kptfilev1.KptFileName] = string(b) -} - -func (t *TestSuite) FindAndDecodeF(resources *porchapi.PackageRevisionResources, name string, value interface{}) { - contents, ok := resources.Spec.Resources[name] - if !ok { - t.Fatalf("Cannot find %q in %s/%s package", name, resources.Namespace, resources.Name) - } - var temp interface{} - d := yaml.NewDecoder(strings.NewReader(contents)) - if err := d.Decode(&temp); err != nil { - t.Fatalf("Cannot decode yaml %q in %s/%s package: %v", name, resources.Namespace, resources.Name, err) - } - jsonData, err := json.Marshal(temp) - if err != nil { - t.Fatalf("json.Marshal failed: %v", err) - } - if err := json.Unmarshal(jsonData, value); err != nil { - t.Fatalf("json.Unmarshal failed; %v", err) - } -} - -func (t *TestSuite) CompareGoldenFileYAML(goldenPath string, gotContents string) string { - gotContents = normalizeYamlOrdering(t.T, gotContents) - - if os.Getenv(updateGoldenFiles) != "" { - if err := os.WriteFile(goldenPath, []byte(gotContents), 0644); err != nil { - t.Fatalf("Failed to update golden file %q: %v", goldenPath, err) - } - } - golden, err := os.ReadFile(goldenPath) - if err != nil { - t.Fatalf("Failed to read golden file %q: %v", goldenPath, err) - } - return cmp.Diff(string(golden), gotContents) -} - -func normalizeYamlOrdering(t *testing.T, contents string) string { - var data interface{} - if err := yaml.Unmarshal([]byte(contents), &data); err != nil { - // not yaml. - t.Fatalf("Failed to unmarshal yaml: %v\n%s\n", err, contents) - } - - var stable bytes.Buffer - encoder := yaml.NewEncoder(&stable) - encoder.SetIndent(2) - if err := encoder.Encode(data); err != nil { - t.Fatalf("Failed to re-encode yaml output: %v", err) - } - return stable.String() -} - -func MustFindPackageRevision(t *testing.T, packages *porchapi.PackageRevisionList, name repository.PackageRevisionKey) *porchapi.PackageRevision { - for i := range packages.Items { - pr := &packages.Items[i] - if pr.Spec.RepositoryName == name.Repository && - pr.Spec.PackageName == name.Package && - pr.Spec.Revision == name.Revision { - return pr - } - } - t.Fatalf("Failed to find package %q", name) - return nil -} diff --git a/porch/test/e2e/suite_logs.go b/porch/test/e2e/suite_logs.go deleted file mode 100644 index c004ba3d82..0000000000 --- a/porch/test/e2e/suite_logs.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2022 The kpt 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. - -package e2e - -import ( - "bytes" - "context" - "io" - - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -func (t *TestSuite) DumpLogsForDeployment(ctx context.Context, deploymentKey client.ObjectKey) { - t.dumpLogsForDeployment(ctx, deploymentKey, t.Errorf) -} - -func (c *TestSuite) hasOwner(child, parent runtime.Object) bool { - childAccessor, err := meta.Accessor(child) - if err != nil { - c.Fatalf("could not get accessor for %T: %v", child, err) - } - parentAccessor, err := meta.Accessor(parent) - if err != nil { - c.Fatalf("could not get accessor for %T: %v", parent, err) - } - - for _, ownerRef := range childAccessor.GetOwnerReferences() { - // Kind is not always populated, UID should suffice (as it's globally unique) - if ownerRef.UID != parentAccessor.GetUID() { - continue - } - return true - } - - return false -} - -func (c *TestSuite) dumpLogsForDeployment(ctx context.Context, deploymentKey client.ObjectKey, eh ErrorHandler) { - deployment, err := c.kubeClient.AppsV1().Deployments(deploymentKey.Namespace).Get(ctx, deploymentKey.Name, metav1.GetOptions{}) - if err != nil { - eh("failed to get deployemnt %v: %v", deploymentKey, err) - } - - replicaSets, err := c.kubeClient.AppsV1().ReplicaSets(deployment.Namespace).List(ctx, metav1.ListOptions{}) - if err != nil { - eh("failed to list replicasets: %v", err) - } - - for i := range replicaSets.Items { - replicaSet := &replicaSets.Items[i] - if !c.hasOwner(replicaSet, deployment) { - continue - } - c.dumpLogsForReplicaSet(ctx, replicaSet, eh) - } -} - -func (c *TestSuite) dumpLogsForReplicaSet(ctx context.Context, replicaSet *appsv1.ReplicaSet, eh ErrorHandler) { - pods, err := c.kubeClient.CoreV1().Pods(replicaSet.Namespace).List(ctx, metav1.ListOptions{}) - if err != nil { - eh("failed to list pods: %v", err) - } - - for i := range pods.Items { - pod := &pods.Items[i] - if !c.hasOwner(pod, replicaSet) { - continue - } - c.dumpLogsForPod(ctx, pod, eh) - } -} - -func (c *TestSuite) dumpLogsForPod(ctx context.Context, pod *corev1.Pod, eh ErrorHandler) { - for _, container := range pod.Spec.Containers { - podKey := client.ObjectKey{ - Namespace: pod.Namespace, - Name: pod.Name, - } - c.dumpLogsForPodContainer(ctx, podKey, container.Name, eh) - } -} - -func (c *TestSuite) dumpLogsForPodContainer(ctx context.Context, podKey client.ObjectKey, containerName string, eh ErrorHandler) { - req := c.kubeClient.CoreV1().Pods(podKey.Namespace).GetLogs(podKey.Name, &corev1.PodLogOptions{Container: containerName}) - podLogs, err := req.Stream(ctx) - if err != nil { - eh("failed to open pod logs %v %s: %v", podKey, containerName, err) - } - defer podLogs.Close() - - buf := new(bytes.Buffer) - if _, err = io.Copy(buf, podLogs); err != nil { - eh("failed to copy pod logs %v %s: %v", podKey, containerName, err) - } - - c.Logf("Logs from pod %v, container %s: %s", podKey, containerName, buf.String()) -} diff --git a/porch/test/e2e/testdata/update-resources/add-config-map.yaml b/porch/test/e2e/testdata/update-resources/add-config-map.yaml deleted file mode 100644 index bd9d24f6db..0000000000 --- a/porch/test/e2e/testdata/update-resources/add-config-map.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: update-resources-configmap - namespace: example -data: - value: Update Resources and Render diff --git a/porch/test/e2e/testdata/update-resources/want-config-map.yaml b/porch/test/e2e/testdata/update-resources/want-config-map.yaml deleted file mode 100644 index 8439aee0c6..0000000000 --- a/porch/test/e2e/testdata/update-resources/want-config-map.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v1 -data: - value: Update Resources and Render -kind: ConfigMap -metadata: - annotations: - color: red - fruit: apple - name: update-resources-configmap - namespace: example diff --git a/porch/test/e2e/update_test.go b/porch/test/e2e/update_test.go deleted file mode 100644 index 72a3336552..0000000000 --- a/porch/test/e2e/update_test.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2022 The kpt 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. - -package e2e - -import ( - "context" - - porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" - "github.com/GoogleContainerTools/kpt/porch/pkg/repository" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -func (t *PorchSuite) TestPackageUpdateRecloneAndReplay(ctx context.Context) { - const ( - gitRepository = "package-update" - ) - - t.registerGitRepositoryF(ctx, testBlueprintsRepo, "test-blueprints", "") - - var list porchapi.PackageRevisionList - t.ListE(ctx, &list, client.InNamespace(t.namespace)) - - basensV2 := MustFindPackageRevision(t.T, &list, repository.PackageRevisionKey{Repository: "test-blueprints", Package: "basens", Revision: "v2"}) - t.Logf("basensV2 = %v", basensV2) - - // Register the repository as 'downstream' - t.registerMainGitRepositoryF(ctx, gitRepository) - - // Create PackageRevision from upstream repo - pr := &porchapi.PackageRevision{ - TypeMeta: metav1.TypeMeta{ - Kind: "PackageRevision", - APIVersion: porchapi.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: t.namespace, - }, - Spec: porchapi.PackageRevisionSpec{ - PackageName: "testRecloneAndReplay", - WorkspaceName: "testdescr", - RepositoryName: gitRepository, - Tasks: []porchapi.Task{ - { - Type: porchapi.TaskTypeClone, - Clone: &porchapi.PackageCloneTaskSpec{ - Upstream: porchapi.UpstreamPackage{ - Git: &porchapi.GitPackage{ - Repo: testBlueprintsRepo, - Ref: "v1", - Directory: "basens", - }, - }, - }, - }, - }, - }, - } - - t.CreateF(ctx, pr) - - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, pr) - - // Update the clone task - pr.Spec.Tasks[0].Clone = &porchapi.PackageCloneTaskSpec{ - Upstream: porchapi.UpstreamPackage{ - Git: &porchapi.GitPackage{ - Repo: testBlueprintsRepo, - Ref: "v2", - Directory: "basens", - }, - }, - } - - t.UpdateF(ctx, pr) - - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, pr) - - var revisionResources porchapi.PackageRevisionResources - t.GetF(ctx, client.ObjectKey{ - Namespace: t.namespace, - Name: pr.Name, - }, &revisionResources) - - if _, found := revisionResources.Spec.Resources["resourcequota.yaml"]; !found { - t.Errorf("Updated package should contain 'resourcequota.yaml` file") - } -} diff --git a/porch/test/git/main.go b/porch/test/git/main.go deleted file mode 100644 index b70f3debf8..0000000000 --- a/porch/test/git/main.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2022 The kpt 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. - -package main - -import ( - "context" - "flag" - "fmt" - "net" - "net/http" - "os" - "os/signal" - - "github.com/GoogleContainerTools/kpt/porch/pkg/git" - "k8s.io/klog/v2" -) - -var ( - port = flag.Int("port", 9446, "Server port") -) - -func main() { - klog.InitFlags(nil) - - flag.Parse() - - if err := run(flag.Args()); err != nil { - fmt.Fprintf(os.Stderr, "unexpected error: %v", err) - } -} - -func run(dirs []string) error { - var baseDir string - - switch len(dirs) { - case 0: - var err error - baseDir, err = os.MkdirTemp("", "repo-*") - if err != nil { - return fmt.Errorf("failed to create temporary directory for git repository: %w", err) - } - - case 1: - baseDir = dirs[0] - - default: - return fmt.Errorf("can serve only one git repository, not %d", len(dirs)) - } - - var gitRepoOptions []git.GitRepoOption - repos := git.NewDynamicRepos(baseDir, gitRepoOptions) - - server, err := git.NewGitServer(repos) - if err != nil { - return fmt.Errorf("filed to initialize git server: %w", err) - } - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - addressChannel := make(chan net.Addr) - - go func() { - if err := server.ListenAndServe(ctx, fmt.Sprintf(":%d", *port), addressChannel); err != nil && err != http.ErrServerClosed { - klog.Fatalf("Listen failed: %v", err) - } - }() - - address := <-addressChannel - fmt.Fprintf(os.Stderr, "Listening on %s\n", address) - - wait := make(chan os.Signal, 1) - signal.Notify(wait, os.Interrupt) - - <-wait - - return nil -} diff --git a/porch/test/ociserver/main.go b/porch/test/ociserver/main.go deleted file mode 100644 index 41e98a1015..0000000000 --- a/porch/test/ociserver/main.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2022 The kpt 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. - -package main - -import ( - "context" - "flag" - "fmt" - "net" - "net/http" - "os" - "os/signal" - - "github.com/GoogleContainerTools/kpt/porch/test/ociserver/pkg/oci" - "k8s.io/klog/v2" -) - -var ( - port = flag.Int("port", 8080, "Server port") -) - -func main() { - klog.InitFlags(nil) - - flag.Parse() - - if err := run(flag.Args()); err != nil { - fmt.Fprintf(os.Stderr, "unexpected error: %v", err) - } -} - -func run(dirs []string) error { - var baseDir string - - switch len(dirs) { - case 0: - var err error - baseDir, err = os.MkdirTemp("", "repo-*") - if err != nil { - return fmt.Errorf("failed to create temporary directory for OCI repository: %w", err) - } - - case 1: - baseDir = dirs[0] - - default: - return fmt.Errorf("can serve only one OCI repository, not %d", len(dirs)) - } - - var registryOptions []oci.RegistryOption - registries := oci.NewDynamicRegistries(baseDir, registryOptions) - - server, err := oci.NewServer(registries) - if err != nil { - return fmt.Errorf("filed to initialize OCI server: %w", err) - } - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - addressChannel := make(chan net.Addr) - - go func() { - if err := server.ListenAndServe(ctx, fmt.Sprintf(":%d", *port), addressChannel); err != nil && err != http.ErrServerClosed { - klog.Fatalf("Listen failed: %v", err) - } - }() - - address := <-addressChannel - fmt.Fprintf(os.Stderr, "Listening on %s\n", address) - - wait := make(chan os.Signal, 1) - signal.Notify(wait, os.Interrupt) - - <-wait - - return nil -} diff --git a/porch/test/ociserver/pkg/oci/registries.go b/porch/test/ociserver/pkg/oci/registries.go deleted file mode 100644 index 9b9e14ae6e..0000000000 --- a/porch/test/ociserver/pkg/oci/registries.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2022 The kpt 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. - -package oci - -import ( - "context" - "fmt" - "path/filepath" - "sync" -) - -type Registries interface { - FindRegistry(ctx context.Context, key string) (*Registry, error) -} - -// StaticRegistries holds fixed registries -type StaticRegistries struct { - mutex sync.Mutex - repos map[string]*Registry -} - -// NewStaticRegistries constructs an instance of StaticRegistries -func NewStaticRegistries() *StaticRegistries { - return &StaticRegistries{ - repos: make(map[string]*Registry), - } -} - -// FindRegistry returns a registry registered under the specified id, or nil if none is registered. -func (r *StaticRegistries) FindRegistry(ctx context.Context, id string) (*Registry, error) { - r.mutex.Lock() - defer r.mutex.Unlock() - - return r.repos[id], nil -} - -// Add registers a git repository under the specified id -func (r *StaticRegistries) Add(id string, repo *Registry) error { - if !isRegistryIDAllowed(id) { - return fmt.Errorf("invalid name %q", id) - } - - r.mutex.Lock() - defer r.mutex.Unlock() - if _, found := r.repos[id]; found { - return fmt.Errorf("repo %q already exists", id) - } - r.repos[id] = repo - return nil -} - -func NewDynamicRegistries(baseDir string, options []RegistryOption) *DynamicRegistries { - return &DynamicRegistries{ - baseDir: baseDir, - repos: make(map[string]*dynamicRegistry), - options: options, - } -} - -type DynamicRegistries struct { - mutex sync.Mutex - repos map[string]*dynamicRegistry - baseDir string - options []RegistryOption -} - -type dynamicRegistry struct { - mutex sync.Mutex - registry *Registry - name string - dir string - options []RegistryOption -} - -func isRegistryIDAllowed(s string) bool { - if len(s) == 0 { - return false - } - for _, r := range s { - if r >= 'a' && r <= 'z' { - // OK - } else if r >= '0' && r <= '9' { - // OK - } else { - switch r { - case '-': - // OK - case '/': - // Allowed (!) - default: - return false - } - } - } - return true -} - -func (r *DynamicRegistries) FindRegistry(ctx context.Context, id string) (*Registry, error) { - dir := filepath.Join(r.baseDir, id) - if !isRegistryIDAllowed(id) { - return nil, fmt.Errorf("invalid name %q", id) - } - - r.mutex.Lock() - repo := r.repos[id] - if repo == nil { - repo = &dynamicRegistry{ - name: id, - dir: dir, - options: r.options, - } - r.repos[id] = repo - } - r.mutex.Unlock() - - return repo.open() -} - -func (r *dynamicRegistry) open() (*Registry, error) { - r.mutex.Lock() - defer r.mutex.Unlock() - - if r.registry == nil { - baseDir := r.dir - - registry, err := NewRegistry(r.name, baseDir, r.options...) - if err != nil { - return nil, err - } - r.registry = registry - } - - return r.registry, nil -} diff --git a/porch/test/ociserver/pkg/oci/registry.go b/porch/test/ociserver/pkg/oci/registry.go deleted file mode 100644 index 0fa3400718..0000000000 --- a/porch/test/ociserver/pkg/oci/registry.go +++ /dev/null @@ -1,350 +0,0 @@ -// Copyright 2022 The kpt 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. - -package oci - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "fmt" - "io" - "net/http" - "os" - "path/filepath" - "strconv" - "strings" - "syscall" - "time" - - "github.com/google/uuid" - "k8s.io/klog/v2" -) - -// Registry manages a single oci registry. Our registries serve a single named image, with multiple tags. -type Registry struct { - name string - rootDir string - - uploadsDir string - manifestsDir string - blobsDir string - - // Basic auth - username string - password string -} - -// metaDir is how we differentiate the image data from a child image directory -// (e.g. foo/_image_/blobs holds the blobs for foo, foo/bar/_image_/blobs holds the blobs for foo/bar) -const metaDir = "_image_" - -// NewRegistry constructs an instance of Registry -func NewRegistry(name string, rootDir string, options ...RegistryOption) (*Registry, error) { - r := &Registry{ - name: name, - rootDir: rootDir, - } - for _, option := range options { - if err := option.apply(r); err != nil { - return nil, err - } - } - - r.manifestsDir = filepath.Join(rootDir, metaDir, "manifests") - if err := os.MkdirAll(r.manifestsDir, 0755); err != nil { - return nil, err - } - - r.blobsDir = filepath.Join(rootDir, metaDir, "blobs") - if err := os.MkdirAll(r.blobsDir, 0755); err != nil { - return nil, err - } - - r.uploadsDir = filepath.Join(rootDir, metaDir, "uploads") - if err := os.MkdirAll(r.uploadsDir, 0755); err != nil { - return nil, err - } - - return r, nil -} - -func (r *Registry) CreateManifest(ctx context.Context, tag string, b []byte) error { - { - p := filepath.Join(r.manifestsDir, tag) - - if err := os.WriteFile(p, b, 0644); err != nil { - return err - } - } - - // TODO: Likely we want to write the tags in a different way - - hash := sha256.Sum256(b) - ref := "sha256:" + hex.EncodeToString(hash[:]) - - { - p := filepath.Join(r.manifestsDir, ref) - - if err := os.WriteFile(p, b, 0644); err != nil { - return err - } - } - - return nil -} - -func (r *Registry) ReadManifest(ctx context.Context, tag string) ([]byte, error) { - p := filepath.Join(r.manifestsDir, tag) - b, err := os.ReadFile(p) - if err != nil { - return nil, err - } - return b, nil -} - -func (r *Registry) StartUpload(ctx context.Context) (string, error) { - id := uuid.New().String() - - p := filepath.Join(r.uploadsDir, id) - - f, err := os.Create(p) - if err != nil { - return "", err - } - defer f.Close() - - return id, nil -} - -func (r *Registry) UploadPosition(ctx context.Context, uuid string) (int64, error) { - // TODO: Verify uuid - p := filepath.Join(r.uploadsDir, uuid) - - stat, err := os.Stat(p) - if err != nil { - return 0, err - } - - return stat.Size(), nil -} - -func (r *Registry) AppendUpload(ctx context.Context, uuid string, pos int64, in io.Reader) (int64, error) { - // TODO: Verify uuid - p := filepath.Join(r.uploadsDir, uuid) - - f, err := os.OpenFile(p, os.O_RDWR, 0666) - if err != nil { - return 0, err - } - shouldClose := true - defer func() { - if shouldClose { - f.Close() - } - }() - - endPos, err := f.Seek(0, io.SeekEnd) - if err != nil { - return 0, fmt.Errorf("error seeking to end: %w", err) - } - if pos != endPos { - return 0, fmt.Errorf("position is not end of file (%d vs %d)", endPos, pos) - } - - n, err := io.Copy(f, in) - if err != nil { - return 0, fmt.Errorf("error writing content to upload file: %w", err) - } - - if err := f.Close(); err != nil { - return n, fmt.Errorf("error closing uploaded file: %w", err) - } - shouldClose = false - - return n, nil -} - -func (r *Registry) CompleteUpload(ctx context.Context, uuid string, digest string) (string, error) { - log := klog.FromContext(ctx) - - // TODO: Verify uuid - p := filepath.Join(r.uploadsDir, uuid) - - f, err := os.OpenFile(p, os.O_RDONLY, 0666) - if err != nil { - return "", err - } - shouldClose := true - defer func() { - if shouldClose { - f.Close() - } - }() - - hasher := sha256.New() - if _, err := io.Copy(hasher, f); err != nil { - return "", fmt.Errorf("error hashing uploaded file: %w", err) - } - - if err := f.Close(); err != nil { - return "", fmt.Errorf("error closing uploaded file: %w", err) - } - shouldClose = false - - actualHash := "sha256:" + hex.EncodeToString(hasher.Sum(nil)) - if actualHash != digest { - // TODO: return bad request or similar? - return "", fmt.Errorf("digest mismatch; disk hash is %q, request hash is %q", actualHash, digest) - } - - blobPath := filepath.Join(r.blobsDir, actualHash) - if err := os.Rename(p, blobPath); err != nil { - return "", fmt.Errorf("error renaming uploaded file %q -> %q: %w", p, blobPath, err) - } - log.Info("created blob", "path", blobPath) - - return actualHash, nil -} - -// ServeBlob returns the HTTP response for a blob. -// The return type is optimized for serving for HTTP (we might want an internal method in the future) -func (r *Registry) ServeBlob(ctx context.Context, blob string) (Response, error) { - // TODO: Verify blob - - blobPath := filepath.Join(r.blobsDir, blob) - - stat, err := os.Stat(blobPath) - if err != nil { - if os.IsNotExist(err) { - klog.Infof("file %q not file", blobPath) - return ErrorResponse(http.StatusNotFound), nil - } - return nil, err - } - - // TODO: Additional headers - - return &FileResponse{Stat: stat, Path: blobPath, ContentType: "application/octet-stream"}, nil -} - -type Tags struct { - Name string `json:"name"` - Manifests map[string]ManifestInfo `json:"manifest"` - Tags []string `json:"tags"` - Children []string `json:"child"` -} - -type ManifestInfo struct { - ImageSizeBytes string `json:"imageSizeBytes"` - MediaType string `json:"mediaType"` - TimeCreatedMs string `json:"timeCreatedMs"` - TimeUploadedMS string `json:"timeUploadedMs"` - Tags []string `json:"tag"` -} - -func (r *Registry) ListTags(ctx context.Context) (*Tags, error) { - tags := &Tags{Name: r.name} - - // TODO: We may need to optimize how manifests are stored as this is pretty expensive - includeManifestsInResponse := true - - // gcr includes children (other registries) - includeChildrenInResponse := true - - if includeManifestsInResponse { - tags.Manifests = make(map[string]ManifestInfo) - } - - { - files, err := os.ReadDir(r.manifestsDir) - if err != nil { - return nil, fmt.Errorf("error reading tags directory %q: %w", r.manifestsDir, err) - } - for _, f := range files { - tag := f.Name() - if !strings.HasPrefix(tag, "sha256:") { - tags.Tags = append(tags.Tags, tag) - } - - if includeManifestsInResponse { - p := filepath.Join(r.manifestsDir, tag) - b, err := os.ReadFile(p) - if err != nil { - return nil, fmt.Errorf("error reading %q: %w", p, err) - } - stat, err := os.Stat(p) - if err != nil { - return nil, fmt.Errorf("error from os.Stat(%q): %w", p, err) - } - unixStat := stat.Sys().(*syscall.Stat_t) - - hash := sha256.Sum256(b) - ref := "sha256:" + hex.EncodeToString(hash[:]) - existing, found := tags.Manifests[ref] - if !found { - existing = ManifestInfo{} - ctime := time.Unix(int64(unixStat.Ctim.Sec), int64(unixStat.Ctim.Nsec)) - // TODO: What should these values really be? - existing.TimeCreatedMs = strconv.FormatInt(ctime.UnixMilli(), 10) - existing.TimeUploadedMS = strconv.FormatInt(ctime.UnixMilli(), 10) - // TODO: ImageSizeBytes - // TODO: MediaType - } - if !strings.HasPrefix(tag, "sha256:") { - existing.Tags = append(existing.Tags, tag) - } - tags.Manifests[ref] = existing - } - } - } - - if includeChildrenInResponse { - files, err := os.ReadDir(r.rootDir) - if err != nil { - return nil, fmt.Errorf("error reading directory %q: %w", r.rootDir, err) - } - for _, f := range files { - if f.IsDir() { - name := f.Name() - if name != metaDir { - tags.Children = append(tags.Children, name) - } - } - } - } - - return tags, nil -} - -// RegistryOption is implemented by configuration settings for git repository. -type RegistryOption interface { - apply(*Registry) error -} - -type optionBasicAuth struct { - username, password string -} - -func (o *optionBasicAuth) apply(s *Registry) error { - s.username, s.password = o.username, o.password - return nil -} - -func WithBasicAuth(username, password string) RegistryOption { - return &optionBasicAuth{ - username: username, - password: password, - } -} diff --git a/porch/test/ociserver/pkg/oci/responses.go b/porch/test/ociserver/pkg/oci/responses.go deleted file mode 100644 index 9e5140de5e..0000000000 --- a/porch/test/ociserver/pkg/oci/responses.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2022 The kpt 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. - -package oci - -import ( - "encoding/json" - "io" - "net/http" - "os" - "strconv" - - "k8s.io/klog/v2" -) - -type JSONResponse struct { - Object interface{} -} - -func (v *JSONResponse) WriteTo(w http.ResponseWriter, r *http.Request) { - b, err := json.Marshal(v.Object) - if err != nil { - klog.Warningf("error converting response to json: %v", err) - http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) - return - } - klog.Infof("writing json response %v", string(b)) - w.WriteHeader(http.StatusOK) - w.Write(b) -} - -type BinaryResponse struct { - Body []byte - ContentType string -} - -func (v *BinaryResponse) WriteTo(w http.ResponseWriter, r *http.Request) { - if v.ContentType != "" { - w.Header().Set("Content-Type", v.ContentType) - } - w.WriteHeader(http.StatusOK) - w.Write(v.Body) -} - -type TextResponse struct { - Body string -} - -func (v *TextResponse) WriteTo(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - w.Write([]byte(v.Body)) -} - -type FileResponse struct { - Stat os.FileInfo - ContentType string - Path string -} - -func (v *FileResponse) WriteTo(w http.ResponseWriter, r *http.Request) { - f, err := os.Open(v.Path) - if err != nil { - klog.Warningf("error opening file %q: %v", v.Path, err) - http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) - return - } - defer f.Close() - - if v.ContentType != "" { - w.Header().Add("Content-Type", v.ContentType) - } - w.Header().Add("Content-Length", strconv.FormatInt(v.Stat.Size(), 10)) - w.WriteHeader(http.StatusOK) - - io.Copy(w, f) -} - -type StreamingResponse struct { - ContentType string - Body io.ReadCloser -} - -func (v *StreamingResponse) WriteTo(w http.ResponseWriter, r *http.Request) { - defer v.Body.Close() - - if v.ContentType != "" { - w.Header().Add("Content-Type", v.ContentType) - } - // w.Header().Add("Content-Length", strconv.FormatInt(v.Stat.Size(), 10)) - w.WriteHeader(http.StatusOK) - - io.Copy(w, v.Body) -} - -type HTTPResponse struct { - Status int - Location string - ContentType string - Range string -} - -func (v *HTTPResponse) WriteTo(w http.ResponseWriter, r *http.Request) { - if v.Location != "" { - w.Header().Set("Location", v.Location) - } - if v.Range != "" { - w.Header().Set("Range", v.Range) - } - if v.ContentType != "" { - w.Header().Set("Content-Type", v.ContentType) - } - http.Error(w, http.StatusText(v.Status), v.Status) -} - -func ErrorResponse(statusCode int) *HTTPResponse { - return &HTTPResponse{Status: statusCode} -} - -type Response interface { - WriteTo(w http.ResponseWriter, r *http.Request) -} diff --git a/porch/test/ociserver/pkg/oci/server.go b/porch/test/ociserver/pkg/oci/server.go deleted file mode 100644 index d0da7ac62d..0000000000 --- a/porch/test/ociserver/pkg/oci/server.go +++ /dev/null @@ -1,415 +0,0 @@ -// Copyright 2022 The kpt 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. - -package oci - -import ( - "context" - "encoding/json" - "fmt" - "io" - "net" - "net/http" - "os" - "strconv" - "strings" - "time" - - "k8s.io/klog/v2" -) - -// Server is a mock OCI server implementing "just enough" of the oci protocol -type Server struct { - registries Registries - endpoint string -} - -// ServerOption follows the option pattern for customizing the server -type ServerOption interface { - apply(*Server) error -} - -// NewGitServer constructs a GitServer backed by the specified repo. -func NewServer(registries Registries, opts ...ServerOption) (*Server, error) { - s := &Server{ - registries: registries, - } - - for _, opt := range opts { - if err := opt.apply(s); err != nil { - return nil, err - } - } - - return s, nil -} - -// ListenAndServe starts the git server on "listen". -// The address we actually start listening on will be posted to addressChannel -func (s *Server) ListenAndServe(ctx context.Context, listen string, addressChannel chan<- net.Addr) error { - httpServer := &http.Server{ - Addr: listen, - Handler: s, - ReadTimeout: 10 * time.Second, - WriteTimeout: 10 * time.Second, - MaxHeaderBytes: 1 << 20, - } - - ln, err := net.Listen("tcp", httpServer.Addr) - if err != nil { - close(addressChannel) - return err - } - - ctxWithCancel, cancel := context.WithCancel(ctx) - defer cancel() - - go func() { - <-ctxWithCancel.Done() - if err := httpServer.Shutdown(context.Background()); err != nil { - klog.Warningf("error from oci httpServer.Shutdown: %v", err) - } - if err := httpServer.Close(); err != nil { - klog.Warningf("error from oci httpServer.Close: %v", err) - } - }() - - s.endpoint = ln.Addr().String() - - addressChannel <- ln.Addr() - - return httpServer.Serve(ln) -} - -func (s *Server) Endpoint() string { - return s.endpoint -} - -// ServeHTTP is the entrypoint for http requests. -func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - log := klog.FromContext(ctx) - - log.V(2).Info("http request", "method", r.Method, "url", r.URL) - - response, err := s.serveRequest(w, r) - if err != nil { - klog.Warningf("internal error from %s %s: %v", r.Method, r.URL, err) - - http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) - return - } - response.WriteTo(w, r) -} - -// serveRequest is the main dispatcher for http requests. -func (s *Server) serveRequest(w http.ResponseWriter, r *http.Request) (Response, error) { - pathTokens := strings.Split(strings.TrimPrefix(strings.TrimSuffix(r.URL.Path, "/"), "/"), "/") - n := len(pathTokens) - - if n == 1 && pathTokens[0] == "v2" { - return s.serveV2(w, r) - } - - if len(pathTokens) >= 4 && pathTokens[0] == "v2" && pathTokens[n-2] == "tags" && pathTokens[n-1] == "list" { - return s.serveTagsList(w, r, strings.Join(pathTokens[1:n-2], "/")) - } - - if len(pathTokens) >= 4 && pathTokens[0] == "v2" && pathTokens[n-2] == "blobs" && strings.HasPrefix(pathTokens[n-1], "sha256:") { - return s.serveBlob(w, r, strings.Join(pathTokens[1:n-2], "/"), pathTokens[n-1]) - } - - if len(pathTokens) >= 4 && pathTokens[0] == "v2" && pathTokens[n-2] == "blobs" && pathTokens[n-1] == "uploads" { - return s.serveUploads(w, r, strings.Join(pathTokens[1:n-2], "/")) - } - - if len(pathTokens) >= 5 && pathTokens[0] == "v2" && pathTokens[n-3] == "blobs" && pathTokens[n-2] == "uploads" { - return s.serveUpload(w, r, strings.Join(pathTokens[1:n-3], "/"), pathTokens[n-1]) - } - - if len(pathTokens) >= 4 && pathTokens[0] == "v2" && pathTokens[n-2] == "manifests" { - return s.serveManifest(w, r, strings.Join(pathTokens[1:n-2], "/"), pathTokens[n-1]) - } - - klog.Warningf("404 for %s %s", r.Method, r.URL) - return ErrorResponse(http.StatusNotFound), nil -} - -func (s *Server) serveV2(w http.ResponseWriter, r *http.Request) (Response, error) { - if r.Method != "GET" && r.Method != "HEAD" { - return ErrorResponse(http.StatusMethodNotAllowed), nil - } - return &TextResponse{}, nil -} - -func (s *Server) serveTagsList(w http.ResponseWriter, r *http.Request, name string) (Response, error) { - ctx := r.Context() - - if r.Method != "GET" && r.Method != "HEAD" { - return ErrorResponse(http.StatusMethodNotAllowed), nil - } - - repo, err := s.registries.FindRegistry(r.Context(), name) - if err != nil { - klog.Warningf("500 for %s %s: %v", r.Method, r.URL, err) - return nil, err - } - - tags, err := repo.ListTags(ctx) - if err != nil { - return nil, err - } - return &JSONResponse{Object: tags}, nil -} - -func (s *Server) openRegistry(r *http.Request, name string) (*Registry, Response, error) { - repo, err := s.registries.FindRegistry(r.Context(), name) - if err != nil { - klog.Warningf("500 for %s %s: %v", r.Method, r.URL, err) - return nil, ErrorResponse(http.StatusInternalServerError), nil - } - - if repo == nil { - // TODO: Should we send something consistent with auth failure? - klog.Warningf("404 for %s %s (repo not found)", r.Method, r.URL) - return nil, ErrorResponse(http.StatusNotFound), nil - } - - if repo.username != "" || repo.password != "" { - username, password, ok := r.BasicAuth() - if !ok || username != repo.username || password != repo.password { - return nil, ErrorResponse(http.StatusForbidden), nil - } - } - - return repo, nil, nil -} - -func (s *Server) serveUploads(w http.ResponseWriter, r *http.Request, name string) (Response, error) { - ctx := r.Context() - - if r.Method != "POST" { - return ErrorResponse(http.StatusMethodNotAllowed), nil - } - - repo, response, err := s.openRegistry(r, name) - if response != nil || err != nil { - return response, err - } - - digest := r.PostFormValue("digest") - if digest != "" { - // TODO: single-post uploads - return nil, fmt.Errorf("digest not implemented on /uploads/") - } - - uuid, err := repo.StartUpload(ctx) - if err != nil { - return nil, err - } - - return &HTTPResponse{ - Status: http.StatusAccepted, - Location: "/v2/" + name + "/blobs/uploads/" + uuid, - }, nil -} - -func (s *Server) serveUpload(w http.ResponseWriter, r *http.Request, name string, uuid string) (Response, error) { - ctx := r.Context() - - switch r.Method { - case "PUT", "PATCH": - // ok - default: - return ErrorResponse(http.StatusMethodNotAllowed), nil - } - - repo, response, err := s.openRegistry(r, name) - if response != nil || err != nil { - return response, err - } - - contentLengthString := r.Header.Get("Content-Length") - - from := int64(0) - to := int64(-1) - - pos, err := repo.UploadPosition(ctx, uuid) - if err != nil { - return nil, err - } - - rangeNotSatisfiable := func() (*HTTPResponse, error) { - return &HTTPResponse{ - Status: http.StatusRequestedRangeNotSatisfiable, - Location: "/v2/" + name + "/blobs/uploads/" + uuid, - Range: fmt.Sprintf("0-%d", pos), - }, nil - } - if r.Method == "PATCH" || contentLengthString != "0" { - if pos != from { - klog.Warningf("write to wrong position for PATCH %v; pos=%d, from=%d", r.URL, pos, from) - return rangeNotSatisfiable() - } - } - - contentRangeString := r.Header.Get("Content-Range") - if contentRangeString != "" { - tokens := strings.Split(contentRangeString, "-") - if len(tokens) != 2 { - klog.Warningf("invalid content-range %q for PATCH %v", contentRangeString, r.URL) - return rangeNotSatisfiable() - } - - from, err = strconv.ParseInt(tokens[0], 10, 64) - if err != nil || from < 0 { - klog.Warningf("invalid content-range %q for PATCH %v", contentRangeString, r.URL) - return rangeNotSatisfiable() - } - - to, err = strconv.ParseInt(tokens[1], 10, 64) - if err != nil || to < 0 { - klog.Warningf("invalid content-range %q for PATCH %v", contentRangeString, r.URL) - return rangeNotSatisfiable() - } - } - - if r.Method == "PATCH" || contentLengthString != "0" { - n, err := repo.AppendUpload(ctx, uuid, from, r.Body) - if err != nil { - return nil, fmt.Errorf("error writing content to upload file: %w", err) - } - if to >= 0 && from+n != to { - klog.Warningf("received short content for PATCH %v: from=%d, to=%d, n=%d", r.URL, from, to, n) - return ErrorResponse(http.StatusBadRequest), nil - } - to = from + n - } - - if r.Method == "PUT" { - digest := r.FormValue("digest") - if digest == "" { - klog.Warningf("digest is required for %v %v", r.Method, r.URL) - return ErrorResponse(http.StatusBadRequest), nil - } - - blobID, err := repo.CompleteUpload(ctx, uuid, digest) - if err != nil { - return nil, err - } - return &HTTPResponse{ - Status: http.StatusCreated, - Location: "/v2/" + name + "/blobs/" + blobID, - }, nil - } - - return &HTTPResponse{ - Status: http.StatusAccepted, - Location: "/v2/" + name + "/blobs/uploads/" + uuid, - Range: fmt.Sprintf("0-%d", to), - }, nil -} - -func (s *Server) serveBlob(w http.ResponseWriter, r *http.Request, name string, blob string) (Response, error) { - ctx := r.Context() - - switch r.Method { - case "GET", "HEAD": - // ok - default: - return ErrorResponse(http.StatusMethodNotAllowed), nil - } - - repo, response, err := s.openRegistry(r, name) - if response != nil || err != nil { - return response, err - } - - return repo.ServeBlob(ctx, blob) -} - -func (s *Server) serveManifest(w http.ResponseWriter, r *http.Request, name string, tag string) (Response, error) { - ctx := r.Context() - log := klog.FromContext(ctx) - - switch r.Method { - case "PUT", "GET": - // ok - default: - return ErrorResponse(http.StatusMethodNotAllowed), nil - } - - repo, response, err := s.openRegistry(r, name) - if response != nil || err != nil { - return response, err - } - - // TODO: Verify tag is "legal" - - switch r.Method { - case "PUT": - b, err := io.ReadAll(r.Body) - if err != nil { - return nil, err - } - - // TODO: Verify name and tag match provided values - // TODO: Verify layers are known to registry - - if err := repo.CreateManifest(ctx, tag, b); err != nil { - return nil, err - } - - return &HTTPResponse{ - Status: http.StatusCreated, - }, nil - - case "GET": - // We read the file because it's (typically) pretty small, and this is an easy way to get the correct content-type - // Otherwise crane warns about the lack of a content-type - b, err := repo.ReadManifest(ctx, tag) - if err != nil { - if os.IsNotExist(err) { - log.Info("manifest not found", "manifest", tag) - return ErrorResponse(http.StatusNotFound), nil - } - return nil, err - } - type manifestInfo struct { - MediaType string `json:"mediaType"` - } - var manifest manifestInfo - if err := json.Unmarshal(b, &manifest); err != nil { - klog.Warningf("error unmarshaling manifest %q: %v", tag, err) - } - response := &BinaryResponse{ - Body: b, - } - if manifest.MediaType != "" { - switch manifest.MediaType { - case "application/vnd.docker.distribution.manifest.v2+json": - response.ContentType = "application/vnd.docker.distribution.manifest.v2+json" - case "application/vnd.oci.image.manifest.v1+json": - response.ContentType = "application/vnd.oci.image.manifest.v1+json" - } - } - if response.ContentType == "" { - klog.Warningf("cannot determine media type for %q: %v", tag, string(b)) - } - return response, nil - - default: - return nil, fmt.Errorf("unexpected method") - } -} diff --git a/porch/test/testhelpers/harness.go b/porch/test/testhelpers/harness.go deleted file mode 100644 index 3a7273bae7..0000000000 --- a/porch/test/testhelpers/harness.go +++ /dev/null @@ -1,69 +0,0 @@ -package testhelpers - -/* -Copyright 2022 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. -*/ - -import ( - "bytes" - "context" - "os" - "testing" - - "github.com/google/go-cmp/cmp" -) - -type Harness struct { - *testing.T - - Ctx context.Context -} - -func NewHarness(t *testing.T) *Harness { - h := &Harness{ - T: t, - Ctx: context.Background(), - } - - return h -} - -func (h *Harness) AssertMatchesFile(p string, got string) { - if os.Getenv("WRITE_GOLDEN_OUTPUT") != "" { - // Short-circuit when the output is correct - b, err := os.ReadFile(p) - if err == nil && bytes.Equal(b, []byte(got)) { - return - } - - if err := os.WriteFile(p, []byte(got), 0644); err != nil { - h.Fatalf("failed to write golden output %s: %v", p, err) - } - h.Errorf("wrote output to %s", p) - } else { - want := string(h.MustReadFile(p)) - if diff := cmp.Diff(want, got); diff != "" { - h.Errorf("unexpected diff in %s: %s", p, diff) - } - } -} - -func (h *Harness) MustReadFile(p string) []byte { - b, err := os.ReadFile(p) - if err != nil { - h.Fatalf("error from ReadFile(%q): %v", p, err) - } - return b -} diff --git a/porch/test/testhelpers/oci.go b/porch/test/testhelpers/oci.go deleted file mode 100644 index 85694569bf..0000000000 --- a/porch/test/testhelpers/oci.go +++ /dev/null @@ -1,59 +0,0 @@ -package testhelpers - -/* -Copyright 2022 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. -*/ - -import ( - "context" - "net" - "net/http" - "os" - - "github.com/GoogleContainerTools/kpt/porch/test/ociserver/pkg/oci" -) - -func (h *Harness) StartOCIServer() *oci.Server { - baseDir, err := os.MkdirTemp("", "repo-*") - if err != nil { - h.Fatalf("failed to create temporary directory for mock OCI server: %v", err) - } - - var registryOptions []oci.RegistryOption - registries := oci.NewDynamicRegistries(baseDir, registryOptions) - - server, err := oci.NewServer(registries) - if err != nil { - h.Fatalf("filed to initialize OCI server: %v", err) - } - - ctx, cancel := context.WithCancel(h.Ctx) - h.Cleanup(func() { - cancel() - }) - - addressChannel := make(chan net.Addr) - - go func() { - if err := server.ListenAndServe(ctx, "127.0.0.1:0", addressChannel); err != nil && err != http.ErrServerClosed { - h.Errorf("Listen failed: %v", err) - } - }() - - address := <-addressChannel - h.Logf("mock oci server listening on %s", address) - - return server -} diff --git a/porch/test/testhelpers/yaml.go b/porch/test/testhelpers/yaml.go deleted file mode 100644 index d3bee72bdb..0000000000 --- a/porch/test/testhelpers/yaml.go +++ /dev/null @@ -1,83 +0,0 @@ -package testhelpers - -/* -Copyright 2022 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. -*/ - -import ( - "bytes" - "io" - "strings" - - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - yamlserializer "k8s.io/apimachinery/pkg/runtime/serializer/yaml" - yamlutil "k8s.io/apimachinery/pkg/util/yaml" - "sigs.k8s.io/yaml" -) - -func (h *Harness) ParseObjects(y string) []*unstructured.Unstructured { - t := h.T - - var objects []*unstructured.Unstructured - - decoder := yamlutil.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(y)), 100) - for { - var rawObj runtime.RawExtension - if err := decoder.Decode(&rawObj); err != nil { - if err != io.EOF { - t.Fatalf("error decoding yaml: %v", err) - } - break - } - - m, _, err := yamlserializer.NewDecodingSerializer(unstructured.UnstructuredJSONScheme).Decode(rawObj.Raw, nil, nil) - if err != nil { - t.Fatalf("error decoding yaml: %v", err) - } - - unstructuredMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(m) - if err != nil { - t.Fatalf("error parsing object: %v", err) - } - unstructuredObj := &unstructured.Unstructured{Object: unstructuredMap} - - objects = append(objects, unstructuredObj) - } - - return objects -} - -func (h *Harness) ParseOneObject(y string) *unstructured.Unstructured { - objects := h.ParseObjects(y) - if len(objects) != 1 { - h.Fatalf("expected exactly one object, got %d", len(objects)) - } - return objects[0] -} - -func ToYAML[T any](h *Harness, items []T) string { - var s []string - for i := range items { - item := &items[i] - b, err := yaml.Marshal(item) - if err != nil { - h.Fatalf("failed to marshal object to yaml: %v", err) - return "" - } - s = append(s, string(b)) - } - return strings.Join(s, "\n---\n") -}