From 96e0ba0705ae8c4bc0a9936b6f23fb976411fdce Mon Sep 17 00:00:00 2001 From: Vui Lam Date: Thu, 14 Dec 2023 08:55:24 -0800 Subject: [PATCH] Add e2e test changes for cliplugins crd package Adds an e2e test that performs plugin sync using crd package built from the package/cliplugin.cli.tanzu.vmware.com directory. The specific test requires an envvar CRD_PACKAGE_IMAGE to be set and pointing to a registry location that the test has push permissions on. Also adds build-crd-package.sh that will conditionally build and publish the CRD package if CRD_PACKAGE_IMAGE is set. Signed-off-by: Vui Lam --- hack/scripts/build-crd-package.sh | 28 + .../cli.tanzu.vmware.com_cliplugins.yaml | 0 .../package-build.yml | 2 +- .../package-resources.yml | 0 .../test/kapp-controller.yaml | 2676 +++++++++++++++++ .../test/package-pi.yaml | 174 ++ test/e2e/Makefile | 1 - test/e2e/framework/cluster_interface.go | 2 + test/e2e/framework/cluster_kind.go | 9 + test/e2e/framework/framework_constants.go | 1 + .../k8s/plugin_sync_k8s_lifecycle_test.go | 143 +- 11 files changed, 3024 insertions(+), 12 deletions(-) create mode 100755 hack/scripts/build-crd-package.sh rename package/{ => cliplugin.cli.tanzu.vmware.com}/cli.tanzu.vmware.com_cliplugins.yaml (100%) rename package/{ => cliplugin.cli.tanzu.vmware.com}/package-build.yml (89%) rename package/{ => cliplugin.cli.tanzu.vmware.com}/package-resources.yml (100%) create mode 100644 package/cliplugin.cli.tanzu.vmware.com/test/kapp-controller.yaml create mode 100644 package/cliplugin.cli.tanzu.vmware.com/test/package-pi.yaml diff --git a/hack/scripts/build-crd-package.sh b/hack/scripts/build-crd-package.sh new file mode 100755 index 000000000..b0f12bafd --- /dev/null +++ b/hack/scripts/build-crd-package.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +# Copyright 2024 VMware, Inc. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +set -e +set -x + +if [ -z "$CRD_PACKAGE_IMAGE" ]; then + echo "skip building of CRD package because CRD_PACKAGE_IMAGE is not set" + exit 0 +fi + +BASE_DIR=$(cd $(dirname "${BASH_SOURCE[0]}"); pwd) +PACKAGE_DIR=${BASE_DIR}/../../package/cliplugin.cli.tanzu.vmware.com +BINDIR=${BASE_DIR}/../tools/bin + +KCTRL=${KCTRL:-$BINDIR/kctrl} +YQ=${YQ:-$BINDIR/yq} + +pushd ${PACKAGE_DIR} + +$YQ e -i ".spec.template.spec.export[0].imgpkgBundle.image=\"${CRD_PACKAGE_IMAGE}\"" ./package-build.yml + +PATH=${BINDIR}:$PATH ${KCTRL} package release --yes + +popd + diff --git a/package/cli.tanzu.vmware.com_cliplugins.yaml b/package/cliplugin.cli.tanzu.vmware.com/cli.tanzu.vmware.com_cliplugins.yaml similarity index 100% rename from package/cli.tanzu.vmware.com_cliplugins.yaml rename to package/cliplugin.cli.tanzu.vmware.com/cli.tanzu.vmware.com_cliplugins.yaml diff --git a/package/package-build.yml b/package/cliplugin.cli.tanzu.vmware.com/package-build.yml similarity index 89% rename from package/package-build.yml rename to package/cliplugin.cli.tanzu.vmware.com/package-build.yml index dfe6ed137..974931de7 100755 --- a/package/package-build.yml +++ b/package/cliplugin.cli.tanzu.vmware.com/package-build.yml @@ -19,7 +19,7 @@ spec: - kbld: {} export: - imgpkgBundle: - image: localhost:6001/tanzu_cli/lever-v2/cliplugin + image: localhost:6001/tanzu_cli/cliplugin includePaths: - cli.tanzu.vmware.com_cliplugins.yaml - .imgpkg/images.yml diff --git a/package/package-resources.yml b/package/cliplugin.cli.tanzu.vmware.com/package-resources.yml similarity index 100% rename from package/package-resources.yml rename to package/cliplugin.cli.tanzu.vmware.com/package-resources.yml diff --git a/package/cliplugin.cli.tanzu.vmware.com/test/kapp-controller.yaml b/package/cliplugin.cli.tanzu.vmware.com/test/kapp-controller.yaml new file mode 100644 index 000000000..61f4f1ecf --- /dev/null +++ b/package/cliplugin.cli.tanzu.vmware.com/test/kapp-controller.yaml @@ -0,0 +1,2676 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: kapp-controller +--- +apiVersion: v1 +kind: Namespace +metadata: + name: kapp-controller-packaging-global +--- +apiVersion: apiregistration.k8s.io/v1 +kind: APIService +metadata: + name: v1alpha1.data.packaging.carvel.dev +spec: + group: data.packaging.carvel.dev + groupPriorityMinimum: 100 + service: + name: packaging-api + namespace: kapp-controller + version: v1alpha1 + versionPriority: 100 +--- +apiVersion: v1 +kind: Service +metadata: + name: packaging-api + namespace: kapp-controller +spec: + ports: + - port: 443 + protocol: TCP + targetPort: api + selector: + app: kapp-controller +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: internalpackagemetadatas.internal.packaging.carvel.dev +spec: + group: internal.packaging.carvel.dev + names: + kind: InternalPackageMetadata + listKind: InternalPackageMetadataList + plural: internalpackagemetadatas + singular: internalpackagemetadata + 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: + categories: + description: Classifiers of the package (optional; Array of strings) + items: + type: string + type: array + displayName: + description: Human friendly name of the package (optional; string) + type: string + iconSVGBase64: + description: Base64 encoded icon (optional; string) + type: string + longDescription: + description: Long description of the package (optional; string) + type: string + maintainers: + description: List of maintainer info for the package. Currently only + supports the name key. (optional; array of maintner info) + items: + properties: + name: + type: string + type: object + type: array + providerName: + description: Name of the entity distributing the package (optional; + string) + type: string + shortDescription: + description: Short desription of the package (optional; string) + type: string + supportDescription: + description: Description of the support available for the package + (optional; string) + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: internalpackages.internal.packaging.carvel.dev +spec: + group: internal.packaging.carvel.dev + names: + kind: InternalPackage + listKind: InternalPackageList + plural: internalpackages + singular: internalpackage + 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: + capacityRequirementsDescription: + description: 'System requirements needed to install the package. Note: + these requirements will not be verified by kapp-controller on installation. + (optional; string)' + type: string + includedSoftware: + description: IncludedSoftware can be used to show the software contents + of a Package. This is especially useful if the underlying versions + do not match the Package version + items: + description: IncludedSoftware contains the underlying Software Contents + of a Package + properties: + description: + type: string + displayName: + type: string + version: + type: string + type: object + type: array + kappControllerVersionSelection: + description: KappControllerVersionSelection specifies the versions + of kapp-controller which can install this package + properties: + constraints: + type: string + type: object + kubernetesVersionSelection: + description: KubernetesVersionSelection specifies the versions of + k8s which this package can be installed on + properties: + constraints: + type: string + type: object + licenses: + description: Description of the licenses that apply to the package + software (optional; Array of strings) + items: + type: string + type: array + refName: + description: The name of the PackageMetadata associated with this + version Must be a valid PackageMetadata name (see PackageMetadata + CR for details) Cannot be empty + type: string + releaseNotes: + description: Version release notes (optional; string) + type: string + releasedAt: + description: Timestamp of release (iso8601 formatted string; optional) + format: date-time + nullable: true + type: string + template: + properties: + spec: + properties: + canceled: + description: Cancels current and future reconciliations (optional; + default=false) + type: boolean + cluster: + description: Specifies that app should be deployed to destination + cluster; by default, cluster is same as where this resource + resides (optional; v0.5.0+) + properties: + kubeconfigSecretRef: + description: Specifies secret containing kubeconfig (required) + properties: + key: + description: Specifies key that contains kubeconfig + (optional) + type: string + name: + description: Specifies secret name within app's namespace + (required) + type: string + type: object + namespace: + description: Specifies namespace in destination cluster + (optional) + type: string + type: object + defaultNamespace: + description: Specifies the default namespace to install the + App resources, by default this is same as the App's namespace + (optional; v0.48.0+) + type: string + deploy: + items: + properties: + kapp: + description: Use kapp to deploy resources + properties: + delete: + description: Configuration for delete command (optional) + properties: + rawOptions: + description: Pass through options to kapp delete + (optional) + items: + type: string + type: array + type: object + inspect: + description: 'Configuration for inspect command + (optional) as of kapp-controller v0.31.0, inspect + is disabled by default add rawOptions or use an + empty inspect config like `inspect: {}` to enable' + properties: + rawOptions: + description: Pass through options to kapp inspect + (optional) + items: + type: string + type: array + type: object + intoNs: + description: Override namespace for all resources + (optional) + type: string + mapNs: + description: Provide custom namespace override mapping + (optional) + items: + type: string + type: array + rawOptions: + description: Pass through options to kapp deploy + (optional) + items: + type: string + type: array + type: object + type: object + type: array + fetch: + items: + properties: + git: + description: Uses git to clone repository + properties: + lfsSkipSmudge: + description: Skip lfs download (optional) + type: boolean + ref: + description: Branch, tag, commit; origin is the + name of the remote (optional) + type: string + refSelection: + description: Specifies a strategy to resolve to + an explicit ref (optional; v0.24.0+) + properties: + semver: + properties: + constraints: + type: string + prereleases: + properties: + identifiers: + items: + type: string + type: array + type: object + type: object + type: object + secretRef: + description: 'Secret with auth details. allowed + keys: ssh-privatekey, ssh-knownhosts, username, + password (optional) (if ssh-knownhosts is not + specified, git will not perform strict host checking)' + properties: + name: + description: Object is expected to be within + same namespace + type: string + type: object + subPath: + description: Grab only portion of repository (optional) + type: string + url: + description: http or ssh urls are supported (required) + type: string + type: object + helmChart: + description: Uses helm fetch to fetch specified chart + properties: + name: + description: 'Example: stable/redis' + type: string + repository: + properties: + secretRef: + properties: + name: + description: Object is expected to be within + same namespace + type: string + type: object + url: + description: Repository url; scheme of oci:// + will fetch experimental helm oci chart (v0.19.0+) + (required) + type: string + type: object + version: + type: string + type: object + http: + description: Uses http library to fetch file + properties: + secretRef: + description: 'Secret to provide auth details (optional) + Secret may include one or more keys: username, + password' + properties: + name: + description: Object is expected to be within + same namespace + type: string + type: object + sha256: + description: Checksum to verify after download (optional) + type: string + subPath: + description: Grab only portion of download (optional) + type: string + url: + description: 'URL can point to one of following + formats: text, tgz, zip http and https url are + supported; plain file, tgz and tar types are supported + (required)' + type: string + type: object + image: + description: Pulls content from Docker/OCI registry + properties: + secretRef: + description: 'Secret may include one or more keys: + username, password, token. By default anonymous + access is used for authentication.' + properties: + name: + description: Object is expected to be within + same namespace + type: string + type: object + subPath: + description: Grab only portion of image (optional) + type: string + tagSelection: + description: Specifies a strategy to choose a tag + (optional; v0.24.0+) if specified, do not include + a tag in url key + properties: + semver: + properties: + constraints: + type: string + prereleases: + properties: + identifiers: + items: + type: string + type: array + type: object + type: object + type: object + url: + description: 'Docker image url; unqualified, tagged, + or digest references supported (required) Example: + username/app1-config:v0.1.0' + type: string + type: object + imgpkgBundle: + description: Pulls imgpkg bundle from Docker/OCI registry + (v0.17.0+) + properties: + image: + description: Docker image url; unqualified, tagged, + or digest references supported (required) + type: string + secretRef: + description: 'Secret may include one or more keys: + username, password, token. By default anonymous + access is used for authentication.' + properties: + name: + description: Object is expected to be within + same namespace + type: string + type: object + tagSelection: + description: Specifies a strategy to choose a tag + (optional; v0.24.0+) if specified, do not include + a tag in url key + properties: + semver: + properties: + constraints: + type: string + prereleases: + properties: + identifiers: + items: + type: string + type: array + type: object + type: object + type: object + type: object + inline: + description: Pulls content from within this resource; + or other resources in the cluster + properties: + paths: + additionalProperties: + type: string + description: Specifies mapping of paths to their + content; not recommended for sensitive values + as CR is not encrypted (optional) + type: object + pathsFrom: + description: Specifies content via secrets and config + maps; data values are recommended to be placed + in secrets (optional) + items: + properties: + configMapRef: + properties: + directoryPath: + description: Specifies where to place + files found in secret (optional) + type: string + name: + type: string + type: object + secretRef: + properties: + directoryPath: + description: Specifies where to place + files found in secret (optional) + type: string + name: + type: string + type: object + type: object + type: array + type: object + path: + description: Relative path to place the fetched artifacts + type: string + type: object + type: array + noopDelete: + description: Deletion requests for the App will result in + the App CR being deleted, but its associated resources will + not be deleted (optional; default=false; v0.18.0+) + type: boolean + paused: + description: Pauses _future_ reconciliation; does _not_ affect + currently running reconciliation (optional; default=false) + type: boolean + serviceAccountName: + description: Specifies that app should be deployed authenticated + via given service account, found in this namespace (optional; + v0.6.0+) + type: string + syncPeriod: + description: Specifies the length of time to wait, in time + + unit format, before reconciling. Always >= 30s. If value + below 30s is specified, 30s will be used. (optional; v0.9.0+; + default=30s) + type: string + template: + items: + properties: + cue: + properties: + inputExpression: + description: Cue expression for single path component, + can be used to unify ValuesFrom into a given field + (optional) + type: string + outputExpression: + description: Cue expression to output, default will + export all visible fields (optional) + type: string + paths: + description: Explicit list of files/directories + (optional) + items: + type: string + type: array + valuesFrom: + description: Provide values (optional) + items: + properties: + configMapRef: + properties: + name: + type: string + type: object + downwardAPI: + properties: + items: + items: + properties: + fieldPath: + description: 'Required: Selects + a field of the app: only annotations, + labels, uid, name and namespace + are supported.' + type: string + kappControllerVersion: + description: 'Optional: Get running + KappController version, defaults + (empty) to retrieving the current + running version.. Can be manually + supplied instead.' + properties: + version: + type: string + type: object + kubernetesAPIs: + description: 'Optional: Get running + KubernetesAPIs from cluster, defaults + (empty) to retrieving the APIs + from the cluster. Can be manually + supplied instead, e.g ["group/version", + "group2/version2"]' + properties: + groupVersions: + items: + type: string + type: array + type: object + kubernetesVersion: + description: 'Optional: Get running + Kubernetes version from cluster, + defaults (empty) to retrieving + the version from the cluster. + Can be manually supplied instead.' + properties: + version: + type: string + type: object + name: + type: string + type: object + type: array + type: object + path: + type: string + secretRef: + properties: + name: + type: string + type: object + type: object + type: array + type: object + helmTemplate: + description: Use helm template command to render helm + chart + properties: + kubernetesAPIs: + description: 'Optional: Use kubernetes group/versions + resources available in the live cluster' + properties: + groupVersions: + items: + type: string + type: array + type: object + kubernetesVersion: + description: 'Optional: Get Kubernetes version, + defaults (empty) to retrieving the version from + the cluster. Can be manually overridden to a value + instead.' + properties: + version: + type: string + type: object + name: + description: Set name explicitly, default is App + CR's name (optional; v0.13.0+) + type: string + namespace: + description: Set namespace explicitly, default is + App CR's namespace (optional; v0.13.0+) + type: string + path: + description: Path to chart (optional; v0.13.0+) + type: string + valuesFrom: + description: One or more secrets, config maps, paths + that provide values (optional) + items: + properties: + configMapRef: + properties: + name: + type: string + type: object + downwardAPI: + properties: + items: + items: + properties: + fieldPath: + description: 'Required: Selects + a field of the app: only annotations, + labels, uid, name and namespace + are supported.' + type: string + kappControllerVersion: + description: 'Optional: Get running + KappController version, defaults + (empty) to retrieving the current + running version.. Can be manually + supplied instead.' + properties: + version: + type: string + type: object + kubernetesAPIs: + description: 'Optional: Get running + KubernetesAPIs from cluster, defaults + (empty) to retrieving the APIs + from the cluster. Can be manually + supplied instead, e.g ["group/version", + "group2/version2"]' + properties: + groupVersions: + items: + type: string + type: array + type: object + kubernetesVersion: + description: 'Optional: Get running + Kubernetes version from cluster, + defaults (empty) to retrieving + the version from the cluster. + Can be manually supplied instead.' + properties: + version: + type: string + type: object + name: + type: string + type: object + type: array + type: object + path: + type: string + secretRef: + properties: + name: + type: string + type: object + type: object + type: array + type: object + jsonnet: + description: TODO implement jsonnet + type: object + kbld: + description: Use kbld to resolve image references to + use digests + properties: + paths: + items: + type: string + type: array + type: object + kustomize: + description: TODO implement kustomize + type: object + sops: + description: Use sops to decrypt *.sops.yml files (optional; + v0.11.0+) + properties: + age: + properties: + privateKeysSecretRef: + description: Secret with private armored PGP + private keys (required) + properties: + name: + type: string + type: object + type: object + paths: + description: Lists paths to decrypt explicitly (optional; + v0.13.0+) + items: + type: string + type: array + pgp: + description: Use PGP to decrypt files (required) + properties: + privateKeysSecretRef: + description: Secret with private armored PGP + private keys (required) + properties: + name: + type: string + type: object + type: object + type: object + ytt: + description: Use ytt to template configuration + properties: + fileMarks: + description: Control metadata about input files + passed to ytt (optional; v0.18.0+) see https://carvel.dev/ytt/docs/latest/file-marks/ + for more details + items: + type: string + type: array + ignoreUnknownComments: + description: Ignores comments that ytt doesn't recognize + (optional; default=false) + type: boolean + inline: + description: Specify additional files, including + data values (optional) + properties: + paths: + additionalProperties: + type: string + description: Specifies mapping of paths to their + content; not recommended for sensitive values + as CR is not encrypted (optional) + type: object + pathsFrom: + description: Specifies content via secrets and + config maps; data values are recommended to + be placed in secrets (optional) + items: + properties: + configMapRef: + properties: + directoryPath: + description: Specifies where to place + files found in secret (optional) + type: string + name: + type: string + type: object + secretRef: + properties: + directoryPath: + description: Specifies where to place + files found in secret (optional) + type: string + name: + type: string + type: object + type: object + type: array + type: object + paths: + description: Lists paths to provide to ytt explicitly + (optional) + items: + type: string + type: array + strict: + description: Forces strict mode https://github.com/k14s/ytt/blob/develop/docs/strict.md + (optional; default=false) + type: boolean + valuesFrom: + description: Provide values via ytt's --data-values-file + (optional; v0.19.0-alpha.9) + items: + properties: + configMapRef: + properties: + name: + type: string + type: object + downwardAPI: + properties: + items: + items: + properties: + fieldPath: + description: 'Required: Selects + a field of the app: only annotations, + labels, uid, name and namespace + are supported.' + type: string + kappControllerVersion: + description: 'Optional: Get running + KappController version, defaults + (empty) to retrieving the current + running version.. Can be manually + supplied instead.' + properties: + version: + type: string + type: object + kubernetesAPIs: + description: 'Optional: Get running + KubernetesAPIs from cluster, defaults + (empty) to retrieving the APIs + from the cluster. Can be manually + supplied instead, e.g ["group/version", + "group2/version2"]' + properties: + groupVersions: + items: + type: string + type: array + type: object + kubernetesVersion: + description: 'Optional: Get running + Kubernetes version from cluster, + defaults (empty) to retrieving + the version from the cluster. + Can be manually supplied instead.' + properties: + version: + type: string + type: object + name: + type: string + type: object + type: array + type: object + path: + type: string + secretRef: + properties: + name: + type: string + type: object + type: object + type: array + type: object + type: object + type: array + type: object + required: + - spec + type: object + valuesSchema: + description: valuesSchema can be used to show template values that + can be configured by users when a Package is installed in an OpenAPI + schema format. + properties: + openAPIv3: + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + version: + description: Package version; Referenced by PackageInstall; Must be + valid semver (required) Cannot be empty + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: apps.kappctrl.k14s.io +spec: + group: kappctrl.k14s.io + names: + categories: + - carvel + kind: App + listKind: AppList + plural: apps + singular: app + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Friendly description + jsonPath: .status.friendlyDescription + name: Description + type: string + - description: Last time app started being deployed. Does not mean anything was + changed. + jsonPath: .status.deploy.startedAt + name: Since-Deploy + type: date + - description: Time since creation + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: 'An App is a set of Kubernetes resources. These resources could + span any number of namespaces or could be cluster-wide (e.g. CRDs). An App + is represented in kapp-controller using a App CR. The App CR comprises of + three main sections: spec.fetch – declare source for fetching configuration + and OCI images spec.template – declare templating tool and values spec.deploy + – declare deployment tool and any deploy specific configuration' + 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: + canceled: + description: Cancels current and future reconciliations (optional; + default=false) + type: boolean + cluster: + description: Specifies that app should be deployed to destination + cluster; by default, cluster is same as where this resource resides + (optional; v0.5.0+) + properties: + kubeconfigSecretRef: + description: Specifies secret containing kubeconfig (required) + properties: + key: + description: Specifies key that contains kubeconfig (optional) + type: string + name: + description: Specifies secret name within app's namespace + (required) + type: string + type: object + namespace: + description: Specifies namespace in destination cluster (optional) + type: string + type: object + defaultNamespace: + description: Specifies the default namespace to install the App resources, + by default this is same as the App's namespace (optional; v0.48.0+) + type: string + deploy: + items: + properties: + kapp: + description: Use kapp to deploy resources + properties: + delete: + description: Configuration for delete command (optional) + properties: + rawOptions: + description: Pass through options to kapp delete (optional) + items: + type: string + type: array + type: object + inspect: + description: 'Configuration for inspect command (optional) + as of kapp-controller v0.31.0, inspect is disabled by + default add rawOptions or use an empty inspect config + like `inspect: {}` to enable' + properties: + rawOptions: + description: Pass through options to kapp inspect (optional) + items: + type: string + type: array + type: object + intoNs: + description: Override namespace for all resources (optional) + type: string + mapNs: + description: Provide custom namespace override mapping (optional) + items: + type: string + type: array + rawOptions: + description: Pass through options to kapp deploy (optional) + items: + type: string + type: array + type: object + type: object + type: array + fetch: + items: + properties: + git: + description: Uses git to clone repository + properties: + lfsSkipSmudge: + description: Skip lfs download (optional) + type: boolean + ref: + description: Branch, tag, commit; origin is the name of + the remote (optional) + type: string + refSelection: + description: Specifies a strategy to resolve to an explicit + ref (optional; v0.24.0+) + properties: + semver: + properties: + constraints: + type: string + prereleases: + properties: + identifiers: + items: + type: string + type: array + type: object + type: object + type: object + secretRef: + description: 'Secret with auth details. allowed keys: ssh-privatekey, + ssh-knownhosts, username, password (optional) (if ssh-knownhosts + is not specified, git will not perform strict host checking)' + properties: + name: + description: Object is expected to be within same namespace + type: string + type: object + subPath: + description: Grab only portion of repository (optional) + type: string + url: + description: http or ssh urls are supported (required) + type: string + type: object + helmChart: + description: Uses helm fetch to fetch specified chart + properties: + name: + description: 'Example: stable/redis' + type: string + repository: + properties: + secretRef: + properties: + name: + description: Object is expected to be within same + namespace + type: string + type: object + url: + description: Repository url; scheme of oci:// will fetch + experimental helm oci chart (v0.19.0+) (required) + type: string + type: object + version: + type: string + type: object + http: + description: Uses http library to fetch file + properties: + secretRef: + description: 'Secret to provide auth details (optional) + Secret may include one or more keys: username, password' + properties: + name: + description: Object is expected to be within same namespace + type: string + type: object + sha256: + description: Checksum to verify after download (optional) + type: string + subPath: + description: Grab only portion of download (optional) + type: string + url: + description: 'URL can point to one of following formats: + text, tgz, zip http and https url are supported; plain + file, tgz and tar types are supported (required)' + type: string + type: object + image: + description: Pulls content from Docker/OCI registry + properties: + secretRef: + description: 'Secret may include one or more keys: username, + password, token. By default anonymous access is used for + authentication.' + properties: + name: + description: Object is expected to be within same namespace + type: string + type: object + subPath: + description: Grab only portion of image (optional) + type: string + tagSelection: + description: Specifies a strategy to choose a tag (optional; + v0.24.0+) if specified, do not include a tag in url key + properties: + semver: + properties: + constraints: + type: string + prereleases: + properties: + identifiers: + items: + type: string + type: array + type: object + type: object + type: object + url: + description: 'Docker image url; unqualified, tagged, or + digest references supported (required) Example: username/app1-config:v0.1.0' + type: string + type: object + imgpkgBundle: + description: Pulls imgpkg bundle from Docker/OCI registry (v0.17.0+) + properties: + image: + description: Docker image url; unqualified, tagged, or digest + references supported (required) + type: string + secretRef: + description: 'Secret may include one or more keys: username, + password, token. By default anonymous access is used for + authentication.' + properties: + name: + description: Object is expected to be within same namespace + type: string + type: object + tagSelection: + description: Specifies a strategy to choose a tag (optional; + v0.24.0+) if specified, do not include a tag in url key + properties: + semver: + properties: + constraints: + type: string + prereleases: + properties: + identifiers: + items: + type: string + type: array + type: object + type: object + type: object + type: object + inline: + description: Pulls content from within this resource; or other + resources in the cluster + properties: + paths: + additionalProperties: + type: string + description: Specifies mapping of paths to their content; + not recommended for sensitive values as CR is not encrypted + (optional) + type: object + pathsFrom: + description: Specifies content via secrets and config maps; + data values are recommended to be placed in secrets (optional) + items: + properties: + configMapRef: + properties: + directoryPath: + description: Specifies where to place files found + in secret (optional) + type: string + name: + type: string + type: object + secretRef: + properties: + directoryPath: + description: Specifies where to place files found + in secret (optional) + type: string + name: + type: string + type: object + type: object + type: array + type: object + path: + description: Relative path to place the fetched artifacts + type: string + type: object + type: array + noopDelete: + description: Deletion requests for the App will result in the App + CR being deleted, but its associated resources will not be deleted + (optional; default=false; v0.18.0+) + type: boolean + paused: + description: Pauses _future_ reconciliation; does _not_ affect currently + running reconciliation (optional; default=false) + type: boolean + serviceAccountName: + description: Specifies that app should be deployed authenticated via + given service account, found in this namespace (optional; v0.6.0+) + type: string + syncPeriod: + description: Specifies the length of time to wait, in time + unit + format, before reconciling. Always >= 30s. If value below 30s is + specified, 30s will be used. (optional; v0.9.0+; default=30s) + type: string + template: + items: + properties: + cue: + properties: + inputExpression: + description: Cue expression for single path component, can + be used to unify ValuesFrom into a given field (optional) + type: string + outputExpression: + description: Cue expression to output, default will export + all visible fields (optional) + type: string + paths: + description: Explicit list of files/directories (optional) + items: + type: string + type: array + valuesFrom: + description: Provide values (optional) + items: + properties: + configMapRef: + properties: + name: + type: string + type: object + downwardAPI: + properties: + items: + items: + properties: + fieldPath: + description: 'Required: Selects a field + of the app: only annotations, labels, + uid, name and namespace are supported.' + type: string + kappControllerVersion: + description: 'Optional: Get running KappController + version, defaults (empty) to retrieving + the current running version.. Can be manually + supplied instead.' + properties: + version: + type: string + type: object + kubernetesAPIs: + description: 'Optional: Get running KubernetesAPIs + from cluster, defaults (empty) to retrieving + the APIs from the cluster. Can be manually + supplied instead, e.g ["group/version", + "group2/version2"]' + properties: + groupVersions: + items: + type: string + type: array + type: object + kubernetesVersion: + description: 'Optional: Get running Kubernetes + version from cluster, defaults (empty) + to retrieving the version from the cluster. + Can be manually supplied instead.' + properties: + version: + type: string + type: object + name: + type: string + type: object + type: array + type: object + path: + type: string + secretRef: + properties: + name: + type: string + type: object + type: object + type: array + type: object + helmTemplate: + description: Use helm template command to render helm chart + properties: + kubernetesAPIs: + description: 'Optional: Use kubernetes group/versions resources + available in the live cluster' + properties: + groupVersions: + items: + type: string + type: array + type: object + kubernetesVersion: + description: 'Optional: Get Kubernetes version, defaults + (empty) to retrieving the version from the cluster. Can + be manually overridden to a value instead.' + properties: + version: + type: string + type: object + name: + description: Set name explicitly, default is App CR's name + (optional; v0.13.0+) + type: string + namespace: + description: Set namespace explicitly, default is App CR's + namespace (optional; v0.13.0+) + type: string + path: + description: Path to chart (optional; v0.13.0+) + type: string + valuesFrom: + description: One or more secrets, config maps, paths that + provide values (optional) + items: + properties: + configMapRef: + properties: + name: + type: string + type: object + downwardAPI: + properties: + items: + items: + properties: + fieldPath: + description: 'Required: Selects a field + of the app: only annotations, labels, + uid, name and namespace are supported.' + type: string + kappControllerVersion: + description: 'Optional: Get running KappController + version, defaults (empty) to retrieving + the current running version.. Can be manually + supplied instead.' + properties: + version: + type: string + type: object + kubernetesAPIs: + description: 'Optional: Get running KubernetesAPIs + from cluster, defaults (empty) to retrieving + the APIs from the cluster. Can be manually + supplied instead, e.g ["group/version", + "group2/version2"]' + properties: + groupVersions: + items: + type: string + type: array + type: object + kubernetesVersion: + description: 'Optional: Get running Kubernetes + version from cluster, defaults (empty) + to retrieving the version from the cluster. + Can be manually supplied instead.' + properties: + version: + type: string + type: object + name: + type: string + type: object + type: array + type: object + path: + type: string + secretRef: + properties: + name: + type: string + type: object + type: object + type: array + type: object + jsonnet: + description: TODO implement jsonnet + type: object + kbld: + description: Use kbld to resolve image references to use digests + properties: + paths: + items: + type: string + type: array + type: object + kustomize: + description: TODO implement kustomize + type: object + sops: + description: Use sops to decrypt *.sops.yml files (optional; + v0.11.0+) + properties: + age: + properties: + privateKeysSecretRef: + description: Secret with private armored PGP private + keys (required) + properties: + name: + type: string + type: object + type: object + paths: + description: Lists paths to decrypt explicitly (optional; + v0.13.0+) + items: + type: string + type: array + pgp: + description: Use PGP to decrypt files (required) + properties: + privateKeysSecretRef: + description: Secret with private armored PGP private + keys (required) + properties: + name: + type: string + type: object + type: object + type: object + ytt: + description: Use ytt to template configuration + properties: + fileMarks: + description: Control metadata about input files passed to + ytt (optional; v0.18.0+) see https://carvel.dev/ytt/docs/latest/file-marks/ + for more details + items: + type: string + type: array + ignoreUnknownComments: + description: Ignores comments that ytt doesn't recognize + (optional; default=false) + type: boolean + inline: + description: Specify additional files, including data values + (optional) + properties: + paths: + additionalProperties: + type: string + description: Specifies mapping of paths to their content; + not recommended for sensitive values as CR is not + encrypted (optional) + type: object + pathsFrom: + description: Specifies content via secrets and config + maps; data values are recommended to be placed in + secrets (optional) + items: + properties: + configMapRef: + properties: + directoryPath: + description: Specifies where to place files + found in secret (optional) + type: string + name: + type: string + type: object + secretRef: + properties: + directoryPath: + description: Specifies where to place files + found in secret (optional) + type: string + name: + type: string + type: object + type: object + type: array + type: object + paths: + description: Lists paths to provide to ytt explicitly (optional) + items: + type: string + type: array + strict: + description: Forces strict mode https://github.com/k14s/ytt/blob/develop/docs/strict.md + (optional; default=false) + type: boolean + valuesFrom: + description: Provide values via ytt's --data-values-file + (optional; v0.19.0-alpha.9) + items: + properties: + configMapRef: + properties: + name: + type: string + type: object + downwardAPI: + properties: + items: + items: + properties: + fieldPath: + description: 'Required: Selects a field + of the app: only annotations, labels, + uid, name and namespace are supported.' + type: string + kappControllerVersion: + description: 'Optional: Get running KappController + version, defaults (empty) to retrieving + the current running version.. Can be manually + supplied instead.' + properties: + version: + type: string + type: object + kubernetesAPIs: + description: 'Optional: Get running KubernetesAPIs + from cluster, defaults (empty) to retrieving + the APIs from the cluster. Can be manually + supplied instead, e.g ["group/version", + "group2/version2"]' + properties: + groupVersions: + items: + type: string + type: array + type: object + kubernetesVersion: + description: 'Optional: Get running Kubernetes + version from cluster, defaults (empty) + to retrieving the version from the cluster. + Can be manually supplied instead.' + properties: + version: + type: string + type: object + name: + type: string + type: object + type: array + type: object + path: + type: string + secretRef: + properties: + name: + type: string + type: object + type: object + type: array + type: object + type: object + type: array + type: object + status: + properties: + conditions: + items: + properties: + message: + description: Human-readable message indicating details about + last transition. + type: string + reason: + description: Unique, this should be a short, machine understandable + string that gives the reason for condition's last transition. + If it reports "ResizeStarted" that means the underlying persistent + volume is being resized. + type: string + status: + type: string + type: + description: ConditionType represents reconciler state + type: string + required: + - status + - type + type: object + type: array + consecutiveReconcileFailures: + type: integer + consecutiveReconcileSuccesses: + type: integer + deploy: + properties: + error: + type: string + exitCode: + type: integer + finished: + type: boolean + kapp: + description: KappDeployStatus contains the associated AppCR deployed + resources + properties: + associatedResources: + description: AssociatedResources contains the associated App + label, namespaces and GKs + properties: + groupKinds: + items: + 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 + properties: + group: + type: string + kind: + type: string + required: + - group + - kind + type: object + type: array + label: + type: string + namespaces: + items: + type: string + type: array + type: object + type: object + startedAt: + format: date-time + type: string + stderr: + type: string + stdout: + type: string + updatedAt: + format: date-time + type: string + type: object + fetch: + properties: + error: + type: string + exitCode: + type: integer + startedAt: + format: date-time + type: string + stderr: + type: string + stdout: + type: string + updatedAt: + format: date-time + type: string + type: object + friendlyDescription: + type: string + inspect: + properties: + error: + type: string + exitCode: + type: integer + stderr: + type: string + stdout: + type: string + updatedAt: + format: date-time + type: string + type: object + managedAppName: + type: string + observedGeneration: + description: Populated based on metadata.generation when controller + observes a change to the resource; if this value is out of data, + other status fields do not reflect latest state + format: int64 + type: integer + template: + properties: + error: + type: string + exitCode: + type: integer + stderr: + type: string + updatedAt: + format: date-time + type: string + type: object + usefulErrorMessage: + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: packageinstalls.packaging.carvel.dev +spec: + group: packaging.carvel.dev + names: + categories: + - carvel + kind: PackageInstall + listKind: PackageInstallList + plural: packageinstalls + shortNames: + - pkgi + singular: packageinstall + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: PackageMetadata name + jsonPath: .spec.packageRef.refName + name: Package name + type: string + - description: PackageMetadata version + jsonPath: .status.version + name: Package version + type: string + - description: Friendly description + jsonPath: .status.friendlyDescription + name: Description + type: string + - description: Time since creation + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: A Package Install is an actual installation of a package and + its underlying resources on a Kubernetes cluster. It is represented in kapp-controller + by a PackageInstall CR. A PackageInstall CR must reference a Package CR. + 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: + canceled: + description: Canceled when set to true will stop all active changes + type: boolean + cluster: + description: Specifies that Package should be deployed to destination + cluster; by default, cluster is same as where this resource resides + (optional) + properties: + kubeconfigSecretRef: + description: Specifies secret containing kubeconfig (required) + properties: + key: + description: Specifies key that contains kubeconfig (optional) + type: string + name: + description: Specifies secret name within app's namespace + (required) + type: string + type: object + namespace: + description: Specifies namespace in destination cluster (optional) + type: string + type: object + defaultNamespace: + description: Specifies the default namespace to install the Package + resources, by default this is same as the PackageInstall namespace + (optional; v0.48.0+) + type: string + noopDelete: + description: When NoopDelete set to true, PackageInstall deletion + should delete PackageInstall/App CR but preserve App's associated + resources. + type: boolean + packageRef: + description: Specifies the name of the package to install (required) + properties: + refName: + type: string + versionSelection: + properties: + constraints: + type: string + prereleases: + properties: + identifiers: + items: + type: string + type: array + type: object + type: object + type: object + paused: + description: Paused when set to true will ignore all pending changes, + once it set back to false, pending changes will be applied + type: boolean + serviceAccountName: + description: Specifies service account that will be used to install + underlying package contents + type: string + syncPeriod: + description: Controls frequency of App reconciliation in time + unit + format. Always >= 30s. If value below 30s is specified, 30s will + be used. + type: string + values: + description: Values to be included in package's templating step (currently + only included in the first templating step) (optional) + items: + properties: + secretRef: + properties: + key: + type: string + name: + type: string + type: object + type: object + type: array + type: object + status: + properties: + conditions: + items: + properties: + message: + description: Human-readable message indicating details about + last transition. + type: string + reason: + description: Unique, this should be a short, machine understandable + string that gives the reason for condition's last transition. + If it reports "ResizeStarted" that means the underlying persistent + volume is being resized. + type: string + status: + type: string + type: + description: ConditionType represents reconciler state + type: string + required: + - status + - type + type: object + type: array + friendlyDescription: + type: string + lastAttemptedVersion: + description: LastAttemptedVersion specifies what version was last + attempted to be installed. It does _not_ indicate it was successfully + installed. + type: string + observedGeneration: + description: Populated based on metadata.generation when controller + observes a change to the resource; if this value is out of data, + other status fields do not reflect latest state + format: int64 + type: integer + usefulErrorMessage: + type: string + version: + description: TODO this is desired resolved version (not actually deployed) + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + packaging.carvel.dev/global-namespace: kapp-controller-packaging-global + name: packagerepositories.packaging.carvel.dev +spec: + group: packaging.carvel.dev + names: + categories: + - carvel + kind: PackageRepository + listKind: PackageRepositoryList + plural: packagerepositories + shortNames: + - pkgr + singular: packagerepository + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Time since creation + jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Friendly description + jsonPath: .status.friendlyDescription + name: Description + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: A package repository is a collection of packages and their metadata. + Similar to a maven repository or a rpm repository, adding a package repository + to a cluster gives users of that cluster the ability to install any of the + packages from that 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: + properties: + fetch: + properties: + git: + description: Uses git to clone repository containing package list + properties: + lfsSkipSmudge: + description: Skip lfs download (optional) + type: boolean + ref: + description: Branch, tag, commit; origin is the name of the + remote (optional) + type: string + refSelection: + description: Specifies a strategy to resolve to an explicit + ref (optional; v0.24.0+) + properties: + semver: + properties: + constraints: + type: string + prereleases: + properties: + identifiers: + items: + type: string + type: array + type: object + type: object + type: object + secretRef: + description: 'Secret with auth details. allowed keys: ssh-privatekey, + ssh-knownhosts, username, password (optional) (if ssh-knownhosts + is not specified, git will not perform strict host checking)' + properties: + name: + description: Object is expected to be within same namespace + type: string + type: object + subPath: + description: Grab only portion of repository (optional) + type: string + url: + description: http or ssh urls are supported (required) + type: string + type: object + http: + description: Uses http library to fetch file containing packages + properties: + secretRef: + description: 'Secret to provide auth details (optional) Secret + may include one or more keys: username, password' + properties: + name: + description: Object is expected to be within same namespace + type: string + type: object + sha256: + description: Checksum to verify after download (optional) + type: string + subPath: + description: Grab only portion of download (optional) + type: string + url: + description: 'URL can point to one of following formats: text, + tgz, zip http and https url are supported; plain file, tgz + and tar types are supported (required)' + type: string + type: object + image: + description: Image url; unqualified, tagged, or digest references + supported (required) + properties: + secretRef: + description: 'Secret may include one or more keys: username, + password, token. By default anonymous access is used for + authentication.' + properties: + name: + description: Object is expected to be within same namespace + type: string + type: object + subPath: + description: Grab only portion of image (optional) + type: string + tagSelection: + description: Specifies a strategy to choose a tag (optional; + v0.24.0+) if specified, do not include a tag in url key + properties: + semver: + properties: + constraints: + type: string + prereleases: + properties: + identifiers: + items: + type: string + type: array + type: object + type: object + type: object + url: + description: 'Docker image url; unqualified, tagged, or digest + references supported (required) Example: username/app1-config:v0.1.0' + type: string + type: object + imgpkgBundle: + description: Pulls imgpkg bundle from Docker/OCI registry + properties: + image: + description: Docker image url; unqualified, tagged, or digest + references supported (required) + type: string + secretRef: + description: 'Secret may include one or more keys: username, + password, token. By default anonymous access is used for + authentication.' + properties: + name: + description: Object is expected to be within same namespace + type: string + type: object + tagSelection: + description: Specifies a strategy to choose a tag (optional; + v0.24.0+) if specified, do not include a tag in url key + properties: + semver: + properties: + constraints: + type: string + prereleases: + properties: + identifiers: + items: + type: string + type: array + type: object + type: object + type: object + type: object + inline: + description: Pull content from within this resource; or other + resources in the cluster + properties: + paths: + additionalProperties: + type: string + description: Specifies mapping of paths to their content; + not recommended for sensitive values as CR is not encrypted + (optional) + type: object + pathsFrom: + description: Specifies content via secrets and config maps; + data values are recommended to be placed in secrets (optional) + items: + properties: + configMapRef: + properties: + directoryPath: + description: Specifies where to place files found + in secret (optional) + type: string + name: + type: string + type: object + secretRef: + properties: + directoryPath: + description: Specifies where to place files found + in secret (optional) + type: string + name: + type: string + type: object + type: object + type: array + type: object + type: object + paused: + description: Paused when set to true will ignore all pending changes, + once it set back to false, pending changes will be applied + type: boolean + syncPeriod: + description: Controls frequency of PackageRepository reconciliation + type: string + required: + - fetch + type: object + status: + properties: + conditions: + items: + properties: + message: + description: Human-readable message indicating details about + last transition. + type: string + reason: + description: Unique, this should be a short, machine understandable + string that gives the reason for condition's last transition. + If it reports "ResizeStarted" that means the underlying persistent + volume is being resized. + type: string + status: + type: string + type: + description: ConditionType represents reconciler state + type: string + required: + - status + - type + type: object + type: array + consecutiveReconcileFailures: + type: integer + consecutiveReconcileSuccesses: + type: integer + deploy: + properties: + error: + type: string + exitCode: + type: integer + finished: + type: boolean + kapp: + description: KappDeployStatus contains the associated AppCR deployed + resources + properties: + associatedResources: + description: AssociatedResources contains the associated App + label, namespaces and GKs + properties: + groupKinds: + items: + 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 + properties: + group: + type: string + kind: + type: string + required: + - group + - kind + type: object + type: array + label: + type: string + namespaces: + items: + type: string + type: array + type: object + type: object + startedAt: + format: date-time + type: string + stderr: + type: string + stdout: + type: string + updatedAt: + format: date-time + type: string + type: object + fetch: + properties: + error: + type: string + exitCode: + type: integer + startedAt: + format: date-time + type: string + stderr: + type: string + stdout: + type: string + updatedAt: + format: date-time + type: string + type: object + friendlyDescription: + type: string + observedGeneration: + description: Populated based on metadata.generation when controller + observes a change to the resource; if this value is out of data, + other status fields do not reflect latest state + format: int64 + type: integer + template: + properties: + error: + type: string + exitCode: + type: integer + stderr: + type: string + updatedAt: + format: date-time + type: string + type: object + usefulErrorMessage: + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + kapp-controller.carvel.dev/version: v0.48.2 + kbld.k14s.io/images: | + - origins: + - local: + path: /home/runner/work/kapp-controller/kapp-controller + - git: + dirty: true + remoteURL: https://github.com/carvel-dev/kapp-controller + sha: 22eade485af00e3a5e72726e3fb5a678748eaf79 + tags: + - v0.48.2 + url: ghcr.io/carvel-dev/kapp-controller@sha256:fb045495cbde0318b5a66a457c375d32a9eda23ec376dcd580df41e37837ff83 + name: kapp-controller + namespace: kapp-controller +spec: + replicas: 1 + revisionHistoryLimit: 0 + selector: + matchLabels: + app: kapp-controller + template: + metadata: + labels: + app: kapp-controller + spec: + containers: + - args: + - -packaging-global-namespace=kapp-controller-packaging-global + - -enable-api-priority-and-fairness=True + - -tls-cipher-suites= + env: + - name: KAPPCTRL_MEM_TMP_DIR + value: /etc/kappctrl-mem-tmp + - name: KAPPCTRL_SIDECAREXEC_SOCK + value: /etc/kappctrl-mem-tmp/sidecarexec.sock + - name: KAPPCTRL_SYSTEM_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: KAPPCTRL_API_PORT + value: "10350" + image: ghcr.io/carvel-dev/kapp-controller@sha256:fb045495cbde0318b5a66a457c375d32a9eda23ec376dcd580df41e37837ff83 + name: kapp-controller + ports: + - containerPort: 10350 + name: api + protocol: TCP + resources: + requests: + cpu: 120m + memory: 100Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + volumeMounts: + - mountPath: /etc/kappctrl-mem-tmp + name: template-fs + - mountPath: /home/kapp-controller + name: home + - args: + - --sidecarexec + env: + - name: KAPPCTRL_SIDECAREXEC_SOCK + value: /etc/kappctrl-mem-tmp/sidecarexec.sock + - name: IMGPKG_ACTIVE_KEYCHAINS + value: gke,aks,ecr + image: ghcr.io/carvel-dev/kapp-controller@sha256:fb045495cbde0318b5a66a457c375d32a9eda23ec376dcd580df41e37837ff83 + name: kapp-controller-sidecarexec + resources: + requests: + cpu: 120m + memory: 100Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + runAsNonRoot: true + volumeMounts: + - mountPath: /etc/kappctrl-mem-tmp + name: template-fs + - mountPath: /home/kapp-controller + name: home + - mountPath: /var/run/secrets/kubernetes.io/serviceaccount + name: empty-sa + serviceAccount: kapp-controller-sa + volumes: + - emptyDir: + medium: Memory + name: template-fs + - emptyDir: + medium: Memory + name: home + - emptyDir: {} + name: empty-sa +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kapp-controller-sa + namespace: kapp-controller +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kapp-controller-cluster-role +rules: +- apiGroups: + - "" + resources: + - secrets + verbs: + - create + - get + - list + - watch +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - get +- apiGroups: + - "" + resources: + - serviceaccounts/token + verbs: + - create +- apiGroups: + - kappctrl.k14s.io + resources: + - apps + - apps/status + verbs: + - '*' +- apiGroups: + - packaging.carvel.dev + resources: + - packageinstalls + - packageinstalls/status + - packageinstalls/finalizers + verbs: + - '*' +- apiGroups: + - packaging.carvel.dev + resources: + - packagerepositories + - packagerepositories/status + verbs: + - '*' +- apiGroups: + - internal.packaging.carvel.dev + resources: + - internalpackagemetadatas + verbs: + - '*' +- apiGroups: + - data.packaging.carvel.dev + resources: + - packagemetadatas + - packagemetadatas/status + verbs: + - '*' +- apiGroups: + - internal.packaging.carvel.dev + resources: + - internalpackages + verbs: + - '*' +- apiGroups: + - data.packaging.carvel.dev + resources: + - packages + - packages/status + verbs: + - '*' +- apiGroups: + - "" + resources: + - configmaps + verbs: + - '*' +- apiGroups: + - apiregistration.k8s.io + resources: + - apiservices + verbs: + - update + - get +- apiGroups: + - "" + resources: + - namespaces + verbs: + - list + - watch + - get + - update +- apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + verbs: + - list + - watch +- apiGroups: + - admissionregistration.k8s.io + resources: + - validatingwebhookconfigurations + verbs: + - list + - watch +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create +- apiGroups: + - flowcontrol.apiserver.k8s.io + resources: + - prioritylevelconfigurations + - flowschemas + verbs: + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kapp-controller-user-role +rules: +- apiGroups: + - "" + resources: + - secrets + verbs: + - create + - get + - list + - watch +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - get +- apiGroups: + - "" + resources: + - serviceaccounts/token + verbs: + - create +- apiGroups: + - kappctrl.k14s.io + resources: + - apps + - apps/status + verbs: + - '*' +- apiGroups: + - packaging.carvel.dev + resources: + - packageinstalls + - packageinstalls/status + - packageinstalls/finalizers + verbs: + - '*' +- apiGroups: + - "" + resources: + - configmaps + verbs: + - '*' +- apiGroups: + - packaging.carvel.dev + resources: + - packagerepositories + - packagerepositories/status + verbs: + - get + - list + - watch +- apiGroups: + - internal.packaging.carvel.dev + resources: + - internalpackagemetadatas + verbs: + - get + - list + - watch +- apiGroups: + - data.packaging.carvel.dev + resources: + - packagemetadatas + - packagemetadatas/status + verbs: + - get + - list + - watch +- apiGroups: + - internal.packaging.carvel.dev + resources: + - internalpackages + verbs: + - get + - list + - watch +- apiGroups: + - data.packaging.carvel.dev + resources: + - packages + - packages/status + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: kapp-controller-cluster-role-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kapp-controller-cluster-role +subjects: +- kind: ServiceAccount + name: kapp-controller-sa + namespace: kapp-controller +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: pkg-apiserver:system:auth-delegator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: +- kind: ServiceAccount + name: kapp-controller-sa + namespace: kapp-controller +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: pkgserver-auth-reader + namespace: kube-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: extension-apiserver-authentication-reader +subjects: +- kind: ServiceAccount + name: kapp-controller-sa + namespace: kapp-controller diff --git a/package/cliplugin.cli.tanzu.vmware.com/test/package-pi.yaml b/package/cliplugin.cli.tanzu.vmware.com/test/package-pi.yaml new file mode 100644 index 000000000..5025eb836 --- /dev/null +++ b/package/cliplugin.cli.tanzu.vmware.com/test/package-pi.yaml @@ -0,0 +1,174 @@ +apiVersion: packaging.carvel.dev/v1alpha1 +kind: PackageInstall +metadata: + annotations: + kctrl.carvel.dev/local-fetch-0: . + creationTimestamp: null + name: cliplugin +spec: + packageRef: + refName: cliplugin.cli.tanzu.vmware.com + versionSelection: + # XXX sufficient for now to pick up any version of package deployed during test + constraints: "<1.0.0" + serviceAccountName: tanzu-cliplugins-package-sa +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: tanzu-cliplugins-package-sa + namespace: default + annotations: + kapp.k14s.io/change-group: "cliplugins-packageinstall/serviceaccount-0" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: tanzu-cliplugins-package-cluster-role + annotations: + kapp.k14s.io/change-group: "cliplugins-packageinstall/serviceaccount-0" +rules: + - apiGroups: + - "" + resources: + - configmaps + - secrets + - serviceaccounts + - services + - namespaces + verbs: + - create + - update + - get + - list + - delete + - watch + - patch + - apiGroups: + - apps + resources: + - deployments + verbs: + - create + - update + - get + - list + - delete + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - create + - update + - get + - list + - delete + - watch + - apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterroles + - clusterrolebindings + verbs: + - create + - update + - get + - list + - delete + - apiGroups: + - cli.tanzu.vmware.com + resources: + - cliplugins + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - delete + - apiGroups: + - cli.tanzu.vmware.com + resources: + - cliplugins/finalizers + verbs: + - update + - apiGroups: + - cli.tanzu.vmware.com + resources: + - cliplugins/status + verbs: + - get + - patch + - update + - apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list + - watch + - apiGroups: + - data.packaging.carvel.dev + resources: + - packages + verbs: + - get + - list + - watch + - apiGroups: + - data.packaging.carvel.dev + resources: + - packages/status + verbs: + - get + - list + - apiGroups: + - packaging.carvel.dev + resources: + - packageinstalls + verbs: + - get + - list + - watch + - update + - patch + - apiGroups: + - packaging.carvel.dev + resources: + - packageinstalls/status + verbs: + - get + - apiGroups: + - "admissionregistration.k8s.io" + resources: + - mutatingwebhookconfigurations + - validatingwebhookconfigurations + verbs: + - create + - get + - list + - patch + - update + - watch + - delete +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: tanzu-cliplugins-package-cluster-rolebinding + annotations: + kapp.k14s.io/change-group: "cliplugins-packageinstall/serviceaccount" + kapp.k14s.io/change-rule.0: "upsert after upserting cliplugins-packageinstall/serviceaccount-0" + kapp.k14s.io/change-rule.1: "delete before deleting cliplugins-packageinstall/serviceaccount-0" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: tanzu-cliplugins-package-cluster-role +subjects: + - kind: ServiceAccount + name: tanzu-cliplugins-package-sa + namespace: default diff --git a/test/e2e/Makefile b/test/e2e/Makefile index 28af856cd..7ee1c1bdc 100644 --- a/test/e2e/Makefile +++ b/test/e2e/Makefile @@ -67,7 +67,6 @@ E2E_TEST_USE_PLGINS_FROM_PLUGIN_GROUP_FOR_K8S ?= vmware-tkg/default:v9.9.9 .PHONY: e2e-cli-core-all ## Execute all CLI Core E2E Tests e2e-cli-core-all: e2e-cli-lifecycle e2e-cli-config e2e-plugin-compatibility-tests e2e-plugin-lifecycle-tests e2e-plugin-sync-tmc e2e-plugin-sync-k8s e2e-context-tmc-tests e2e-context-k8s-tests e2e-airgapped-tests e2e-catalog-tests e2e-extra-column-tests - .PHONY: e2e-cli-lifecycle ## Execute CLI life cycle specific e2e tests e2e-cli-lifecycle: export TANZU_CLI_CEIP_OPT_IN_PROMPT_ANSWER="No" ; \ diff --git a/test/e2e/framework/cluster_interface.go b/test/e2e/framework/cluster_interface.go index 0cb592c7b..6343d6609 100644 --- a/test/e2e/framework/cluster_interface.go +++ b/test/e2e/framework/cluster_interface.go @@ -19,6 +19,8 @@ type ClusterOps interface { GetKubeconfigPath() string // ApplyConfig applies the given configFilePath on to the given contextName cluster context ApplyConfig(contextName, configFilePath string) (stdOut, stdErr string, err error) + // WaitForCondition waits for certain condition on cluster to be true + WaitForCondition(contextName string, waitArgs []string) (err error) } // ClusterInfo holds the general cluster details diff --git a/test/e2e/framework/cluster_kind.go b/test/e2e/framework/cluster_kind.go index 610560223..c1a11949e 100644 --- a/test/e2e/framework/cluster_kind.go +++ b/test/e2e/framework/cluster_kind.go @@ -7,6 +7,7 @@ import ( "fmt" "os" "path/filepath" + "strings" "github.com/pkg/errors" @@ -72,6 +73,14 @@ func (kc *kindCluster) ApplyConfig(contextName, configFilePath string) (stdOut, return stdOutBuff.String(), stdErrBuff.String(), err } +// WaitForCondition waits for certain condition on cluster to be true or returns error otherwise +func (kc *kindCluster) WaitForCondition(contextName string, waitArgs []string) error { + waitString := strings.Join(waitArgs, " ") + waitCmd := fmt.Sprintf(KubectlWait, contextName, waitString) + _, _, err := kc.CmdOps.Exec(waitCmd) + return err +} + // GetClusterEndpoint returns given kind cluster control plane endpoint func (kc *kindCluster) GetClusterEndpoint(kindClusterName string) (endpoint, stdOut, stdErr string, err error) { stdOut, stdErr, err = kc.ContainerRuntimeStatus() diff --git a/test/e2e/framework/framework_constants.go b/test/e2e/framework/framework_constants.go index e86cfa72c..112b35fe6 100644 --- a/test/e2e/framework/framework_constants.go +++ b/test/e2e/framework/framework_constants.go @@ -114,6 +114,7 @@ const ( KindClusterGet = "kind get clusters " KindClusterInfo = "kubectl cluster-info --context %s" KubectlApply = "kubectl --context %s apply -f %s" + KubectlWait = "kubectl --context %s wait %s" // specific plugin custom resource file name cr___.yaml to apply on kind cluster PluginCRFileName = "cr_%s_%s_%s.yaml" diff --git a/test/e2e/plugin_sync/k8s/plugin_sync_k8s_lifecycle_test.go b/test/e2e/plugin_sync/k8s/plugin_sync_k8s_lifecycle_test.go index fbe57a497..b96847c24 100644 --- a/test/e2e/plugin_sync/k8s/plugin_sync_k8s_lifecycle_test.go +++ b/test/e2e/plugin_sync/k8s/plugin_sync_k8s_lifecycle_test.go @@ -6,16 +6,28 @@ package pluginsynce2ek8s import ( "fmt" + "os" + "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/util/retry" + f "github.com/vmware-tanzu/tanzu-cli/test/e2e/framework" "github.com/vmware-tanzu/tanzu-plugin-runtime/config/types" ) var stdOut string +var backOff = wait.Backoff{ + Steps: 10, + Duration: 5 * time.Second, + Factor: 1.0, + Jitter: 0.1, +} + // Below Use cases executed in this test suite // cleanup and initialize the config files // Use case 1: create a KIND cluster, don't apply CRD and CRs, create context, make sure no plugins are installed @@ -88,7 +100,7 @@ var _ = f.CLICoreDescribe("[Tests:E2E][Feature:Plugin-sync-lifecycle]", func() { // Use case 2: Create kind cluster, apply CRD and CRs, create context, should install all plugins, uninstall the specific plugin, and perform plugin sync: // Steps: // a. create KIND cluster, apply CRD - // b. apply CRD (cluster resource definition) and CR's (cluster resource) for few plugins + // b. apply CRD and CRs for few plugins // c. create context and make sure context has created // d. list plugins and validate plugins info, make sure all plugins installed for which CR's has applied to KIND cluster // e. simulate context-scoped plugin upgrade by applying updated CRs again (with updated plugin versions) to KIND cluster to validate sync (BugFix: https://github.com/vmware-tanzu/tanzu-cli/issues/358) @@ -108,7 +120,7 @@ var _ = f.CLICoreDescribe("[Tests:E2E][Feature:Plugin-sync-lifecycle]", func() { clusterInfo, err = f.CreateKindCluster(tf, f.ContextPrefixK8s+f.RandomNumber(4)) Expect(err).To(BeNil(), "should not get any error for KIND cluster creation") }) - // Test case: b. apply CRD (cluster resource definition) and CR's (cluster resource) for few plugins + // Test case: b. apply CRD and CRs for few plugins It("apply CRD and CRs to KIND cluster", func() { err = f.ApplyConfigOnKindCluster(tf, clusterInfo, append(make([]string, 0), f.K8SCRDFilePath)) Expect(err).To(BeNil(), "should not get any error for config apply") @@ -218,10 +230,11 @@ var _ = f.CLICoreDescribe("[Tests:E2E][Feature:Plugin-sync-lifecycle]", func() { Expect(err).To(BeNil(), "kind cluster should be deleted without any error") }) }) + // Use case 3: Test plugin sync when central repo does not have all plugin CRs being applied in KIND cluster // Steps: // a. create KIND cluster - // b. apply CRD (cluster resource definition) and CRs (cluster resource) for a few plugins which are available in the central repo and CRs for plugins which are not available in the central repo + // b. apply CRD and CRs for a few plugins which are available in the central repo and CRs for plugins which are not available in the central repo // c. create context and make sure context has been created // d. list plugins and validate plugins info, make sure all plugins installed for which CRs have applied to the KIND cluster and are available in the central repo // e. run plugin sync and validate the plugin list @@ -238,7 +251,7 @@ var _ = f.CLICoreDescribe("[Tests:E2E][Feature:Plugin-sync-lifecycle]", func() { clusterInfo, err = f.CreateKindCluster(tf, f.ContextPrefixK8s+f.RandomNumber(4)) Expect(err).To(BeNil(), "should not get any error for KIND cluster creation") }) - // Test case: b. apply CRD (cluster resource definition) and CR's (cluster resource) for few plugins which are available in centra repo + // Test case: b. apply CRD and CRs for few plugins which are available in centra repo // and CR's for plugins which are not available in central repo It("apply CRD and CRs to KIND cluster", func() { err = f.ApplyConfigOnKindCluster(tf, clusterInfo, append(make([]string, 0), f.K8SCRDFilePath)) @@ -331,7 +344,7 @@ var _ = f.CLICoreDescribe("[Tests:E2E][Feature:Plugin-sync-lifecycle]", func() { // Use case 4: test delete context use case, it should uninstall plugins installed for the context // Steps: // a. create KIND cluster - // b. apply CRD (cluster resource definition) and CRs (cluster resource) for few plugins + // b. apply CRD and CRs for few plugins // c. create context and make sure context gets created, list plugins, make sure all // plugins installed for which CRs are applied in KIND cluster // d. delete the context, make sure all context specific plugins are uninstalled @@ -348,7 +361,7 @@ var _ = f.CLICoreDescribe("[Tests:E2E][Feature:Plugin-sync-lifecycle]", func() { clusterInfo, err = f.CreateKindCluster(tf, f.ContextPrefixK8s+f.RandomNumber(4)) Expect(err).To(BeNil(), "should not get any error for KIND cluster creation") }) - // Test case: b. apply CRD (cluster resource definition) and CR's (cluster resource) for few plugins which are available in centra repo + // Test case: b. apply CRD and CRs for few plugins which are available in centra repo // and CR's for plugins which are not available in central repo It("apply CRD and CRs to KIND cluster", func() { err = f.ApplyConfigOnKindCluster(tf, clusterInfo, append(make([]string, 0), f.K8SCRDFilePath)) @@ -394,7 +407,7 @@ var _ = f.CLICoreDescribe("[Tests:E2E][Feature:Plugin-sync-lifecycle]", func() { // Use case 5: test switch context use case, make installed plugins should be updated as per the context // Steps: // a. create KIND clusters - // b. for both clusters, apply CRD (cluster resource definition) and CR's (cluster resource) for few plugins + // b. for both clusters, apply CRD and CRs for few plugins // c. for cluster one, create random context and validate the plugin list should show all plugins for which CRs are applied // d. for cluster two, create random context and validate the plugin list should show all plugins for which CRs are applied // e. switch context's, make sure installed plugins also updated @@ -416,7 +429,7 @@ var _ = f.CLICoreDescribe("[Tests:E2E][Feature:Plugin-sync-lifecycle]", func() { Expect(err).To(BeNil(), "should not get any error for KIND cluster creation") }) - // Test case: b. for both clusters, apply CRD (cluster resource definition) and CR's (cluster resource) for few plugins + // Test case: b. for both clusters, apply CRD and CRs for few plugins It("apply CRD and CRs to KIND cluster", func() { err = f.ApplyConfigOnKindCluster(tf, clusterOne, append(make([]string, 0), f.K8SCRDFilePath)) pluginsToGenerateCRs, ok := pluginGroupToPluginListMap[usePluginsFromPluginGroup] @@ -493,7 +506,7 @@ var _ = f.CLICoreDescribe("[Tests:E2E][Feature:Plugin-sync-lifecycle]", func() { // Use case 6: Test plugin sync when discovered plugin versions are of format vMAJOR or vMAJOR.MINOR // Steps: // a. create KIND cluster - // b. apply CRD (cluster resource definition) + // b. apply CRD // c. create context and make sure context has created // d. apply CRs with different plugin versions and validate plugins being installed after context being created // e. delete the KIND cluster @@ -509,7 +522,7 @@ var _ = f.CLICoreDescribe("[Tests:E2E][Feature:Plugin-sync-lifecycle]", func() { clusterInfo, err = f.CreateKindCluster(tf, f.ContextPrefixK8s+f.RandomNumber(4)) Expect(err).To(BeNil(), "should not get any error for KIND cluster creation") }) - // Test case: b. apply CRD (cluster resource definition) + // Test case: b. apply CRD It("apply CRD to KIND cluster", func() { err = f.ApplyConfigOnKindCluster(tf, clusterInfo, append(make([]string, 0), f.K8SCRDFilePath)) Expect(err).To(BeNil(), "should not get any error for config apply") @@ -562,4 +575,114 @@ var _ = f.CLICoreDescribe("[Tests:E2E][Feature:Plugin-sync-lifecycle]", func() { Expect(err).To(BeNil(), "kind cluster should be deleted without any error") }) }) + + // Perform plugin sync tests by deploying the cliplugins CRD through a package via kapp-controller + // Requirements: + // - CRD_PACKAGE_IMAGE is set (otherwise the test is skipped) + // - the test has permissions to publish the crd package to set CRD_PACKAGE_IMAGE location + Context("Deploy CRD via package", func() { + var clusterInfo *f.ClusterInfo + var pluginCRFilePaths []string + var pluginsList []*f.PluginInfo + var contextName string + var err error + + BeforeEach(func() { + if os.Getenv("CRD_PACKAGE_IMAGE") == "" { + Skip("Skipping test because CRD_PACKAGE_IMAGE is not set") + } + }) + + It("create KIND cluster, deploying kapp-controller and crd package", func() { + const ( + kappYAML = "../../../../package/cliplugin.cli.tanzu.vmware.com/test/kapp-controller.yaml" + packageYAML = "../../../../package/cliplugin.cli.tanzu.vmware.com/carvel-artifacts/packages/cliplugin.cli.tanzu.vmware.com/package.yml" + packageinstallYAML = "../../../../package/cliplugin.cli.tanzu.vmware.com/test/package-pi.yaml" + ) + + // Create KIND cluster, which is used in test cases to create context's + clusterInfo, err = f.CreateKindCluster(tf, f.ContextPrefixK8s+f.RandomNumber(4)) + Expect(err).To(BeNil(), "should not get any error for KIND cluster creation") + + yamlPaths := []string{kappYAML} + yamlPaths2 := []string{packageYAML, packageinstallYAML} + + err = f.ApplyConfigOnKindCluster(tf, clusterInfo, yamlPaths) + Expect(err).To(BeNil(), "should not get any error for apply kapp-controller config") + + var waitArgs []string + waitArgs = []string{"--for=condition=Ready", "pod", "-l", "app=kapp-controller", "-A"} + err = retry.OnError( + backOff, + func(e error) bool { return e != nil }, + func() error { + return tf.KindCluster.WaitForCondition(clusterInfo.ClusterKubeContext, waitArgs) + }, + ) + Expect(err).To(BeNil(), "kapp controller should be available") + + err = retry.OnError( + backOff, + func(e error) bool { return e != nil }, + func() error { + return f.ApplyConfigOnKindCluster(tf, clusterInfo, yamlPaths2) + }, + ) + Expect(err).To(BeNil(), "should not get any error for config apply") + + waitArgs = []string{"--for=condition=established", "crd", "cliplugins.cli.tanzu.vmware.com"} + err = retry.OnError( + backOff, + func(e error) bool { return e != nil }, + func() error { + return tf.KindCluster.WaitForCondition(clusterInfo.ClusterKubeContext, waitArgs) + }, + ) + Expect(err).To(BeNil(), "should not get any error waiting for cli plugins crd") + }) + + It("create context with kubeconfig and context", func() { + contextName = f.ContextPrefixK8s + f.RandomString(4) + _, _, err = tf.ContextCmd.CreateContextWithKubeconfig(contextName, clusterInfo.KubeConfigPath, clusterInfo.ClusterKubeContext) + Expect(err).To(BeNil(), "context should create without any error") + active, err := tf.ContextCmd.GetActiveContext(string(types.TargetK8s)) + Expect(err).To(BeNil(), "there should be a active context") + Expect(active).To(Equal(contextName), "the active context should be recently added context") + }) + + // apply CRs with different plugin versions and validate plugins being installed after context being created + It("apply CRs with different plugin versions and validate plugins being installed after context being created", func() { + pluginsList, err = tf.PluginCmd.ListPluginsForGivenContext(contextName, true) + Expect(err).To(BeNil(), "should not get any error for plugin list") + Expect(len(pluginsList)).Should(Equal(0), "no plugins should be available at this time") + + for _, testcase := range PluginsMultiVersionInstallTests { + pluginInfo := testcase.pluginInfo + _, pluginCRFilePaths, err = f.CreateTemporaryCRsFromPluginInfos([]*f.PluginInfo{&pluginInfo}) + Expect(err).To(BeNil(), "should not get any error while generating CR files") + err = f.ApplyConfigOnKindCluster(tf, clusterInfo, pluginCRFilePaths) + Expect(err).To(BeNil(), "should not get any error for config apply") + + _, _, err = tf.PluginCmd.Sync() + if testcase.err != "" { + Expect(err.Error()).To(ContainSubstring(testcase.err)) + } else { + Expect(err).To(BeNil(), "should not get any error for syncing plugins") + var pd []*f.PluginDescribe + pd, err = tf.PluginCmd.DescribePlugin(testcase.pluginInfo.Name, testcase.pluginInfo.Target, f.GetJsonOutputFormatAdditionalFlagFunction()) + Expect(err).To(BeNil(), f.PluginDescribeShouldNotThrowErr) + Expect(len(pd)).To(Equal(1), f.PluginDescShouldExist) + Expect(pd[0].Name).To(Equal(testcase.pluginInfo.Name), f.PluginNameShouldMatch) + Expect(pd[0].Version).To(Equal(testcase.expectedInstalledVersion), f.PluginNameShouldMatch) + } + } + }) + + It("delete the KIND cluster", func() { + _, _, err = tf.ContextCmd.DeleteContext(contextName) + Expect(err).To(BeNil(), "context should be deleted without error") + _, _, err := tf.KindCluster.DeleteCluster(clusterInfo.Name) + Expect(err).To(BeNil(), "kind cluster should be deleted without any error") + }) + }) })