From f6b47c43dc10d0dce91c2fe74daf0779d97678da Mon Sep 17 00:00:00 2001 From: David Flanagan Date: Tue, 16 Sep 2025 21:57:00 +0100 Subject: [PATCH] feat: improve e2e testing tooling and documentation Major improvements to the end-to-end testing infrastructure: Testing Infrastructure: - Add automatic payment method ID fetching from RedisCloud API - Create templated test examples with dynamic payment method injection - Add cluster/test/setup.sh script for comprehensive test environment setup - Add datasource.yaml for dynamic value injection in tests - Support environment variable configuration via .envrc Documentation Updates: - Restructure TESTING.md with clear quick-start instructions - Add comprehensive payment method configuration section - Document environment variable setup with .envrc.example - Update CI-TESTING.md to reflect current CI/CD workflows - Clean up references to removed scripts in all docs Cleanup: - Remove obsolete scripts (quick-start.sh, setup-podman.sh, test-provider.sh) - Consolidate functionality into Makefile targets - Add proper .gitignore entries for test artifacts - Remove untracked files (provider-aws/, kubeconfig, etc.) Developer Experience: - Add devenv.nix configuration for development environment - Add rediscloud-payment-methods and rediscloud-first-payment-method-id make targets - Improve error handling and user feedback in setup scripts - Simplify credential management with environment variables This refactoring makes the e2e testing process more robust and user-friendly, particularly for testing Pro subscription features that require payment methods. --- .claude/settings.local.json | 18 - .envrc | 8 +- .envrc.example | 7 + .github/workflows/ci.yml | 57 +++ .gitignore | 7 + CONTRIBUTING.md | 42 +- Makefile | 47 ++- README.md | 31 +- TESTING.md | 258 +++++++++---- .../v1alpha1/zz_activesubscription_types.go | 90 ++++- .../zz_activesubscriptiondatabase_types.go | 13 + apis/active/v1alpha1/zz_generated.deepcopy.go | 146 +++++++ .../v1alpha1/zz_generated.deepcopy.go | 116 ++++++ .../v1alpha1/zz_subscription_types.go | 77 +++- .../v1alpha1/zz_database_types.go | 32 +- .../v1alpha1/zz_generated.deepcopy.go | 35 ++ .../v1alpha1/zz_generated.resolvers.go | 57 +++ cluster/test/setup.sh | 69 +++- config/provider-metadata.yaml | 159 ++++++-- config/provider.go | 7 + config/schema.json | 2 +- devenv.nix | 6 + docs/CI-TESTING.md | 41 +- .../active/v1alpha1/activesubscription.yaml | 2 - .../v1alpha1/activesubscriptiondatabase.yaml | 2 - .../v1alpha1/activesubscriptionregions.yaml | 1 - .../rediscloud/v1alpha1/subscription.yaml | 4 - .../subscription/v1alpha1/database.yaml | 9 +- examples/rediscloud/database.yaml | 6 +- examples/rediscloud/subscription.yaml | 5 +- ....redis.io_activesubscriptiondatabases.yaml | 15 + .../active.redis.io_activesubscriptions.yaml | 101 ++++- .../rediscloud.redis.io_subscriptions.yaml | 86 ++++- .../crds/subscription.redis.io_databases.yaml | 171 ++++++++- package/crossplane.yaml | 9 + scripts/quick-start.sh | 42 -- scripts/setup-podman.sh | 33 -- scripts/test-provider.sh | 362 ------------------ 38 files changed, 1523 insertions(+), 650 deletions(-) delete mode 100644 .claude/settings.local.json create mode 100644 .envrc.example create mode 100644 apis/subscription/v1alpha1/zz_generated.resolvers.go delete mode 100755 scripts/quick-start.sh delete mode 100755 scripts/setup-podman.sh delete mode 100755 scripts/test-provider.sh diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index ceabebd..0000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(grep:*)", - "Bash(chmod:*)", - "Bash(go test:*)", - "Bash(pip3 install:*)", - "Bash(gh run view:*)", - "Bash(gh api:*)", - "Bash(go:*)", - "Bash(golangci-lint:*)", - "Bash(devenv shell:*)", - "WebSearch" - ], - "deny": [], - "ask": [] - } -} \ No newline at end of file diff --git a/.envrc b/.envrc index 2d0487e..5b2b469 100644 --- a/.envrc +++ b/.envrc @@ -1,3 +1,5 @@ +source_env_if_exists .envrc.local + export DIRENV_WARN_TIMEOUT=20s if has devenv; then @@ -7,8 +9,8 @@ fi # RedisCloud API Credentials # Get these from: RedisCloud Console → Account Settings → API Keys -export REDISCLOUD_API_KEY="your-api-key-here" -export REDISCLOUD_SECRET_KEY="your-secret-key-here" +#export REDISCLOUD_API_KEY="YOUR_API_KEY_HERE" +#export REDISCLOUD_SECRET_KEY="YOUR_SECRET_KEY_HERE" export REDISCLOUD_URL="https://api.redislabs.com/v1" # Kubernetes/Crossplane Configuration @@ -16,7 +18,5 @@ export CROSSPLANE_NAMESPACE="crossplane-system" export PROVIDER_NAMESPACE="crossplane-system" # Development Settings -export DOCKER_HOST="unix:///run/user/$(id -u)/podman/podman.sock" export KIND_CLUSTER_NAME="rediscloud-test" -export KIND_EXPERIMENTAL_PROVIDER=podman │ │ export KUBECONFIG_PATH="${PWD}/.kube/config" diff --git a/.envrc.example b/.envrc.example new file mode 100644 index 0000000..4551391 --- /dev/null +++ b/.envrc.example @@ -0,0 +1,7 @@ +# RedisCloud API Credentials +# Get these from: RedisCloud Console → Account Settings → API Keys +export REDISCLOUD_API_KEY="YOUR_API_KEY_HERE" +export REDISCLOUD_SECRET_KEY="YOUR_SECRET_KEY_HERE" + +# Optional +export REDISCLOUD_URL="https://api.redislabs.com/v1" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2993c85..7252613 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -290,6 +290,62 @@ jobs: run: | ./scripts/check-examples.py package/crds examples + e2e-tests: + runs-on: ubuntu-24.04 + needs: detect-noop + if: ${{ needs.detect-noop.outputs.noop != 'true' }} + + steps: + - name: Setup QEMU + uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3 + with: + platforms: all + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + version: ${{ env.DOCKER_BUILDX_VERSION }} + install: true + + - name: Checkout + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + with: + submodules: true + + - name: Setup Go + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Find the Go Build Cache + id: go + run: echo "cache=$(make go.cachedir)" >> $GITHUB_OUTPUT + + - name: Cache the Go Build Cache + uses: actions/cache@v4 + with: + path: ${{ steps.go.outputs.cache }} + key: ${{ runner.os }}-build-e2e-tests-${{ hashFiles('**/go.sum') }} + restore-keys: ${{ runner.os }}-build-e2e-tests- + + - name: Cache Go Dependencies + uses: actions/cache@v4 + with: + path: .work/pkg + key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} + restore-keys: ${{ runner.os }}-pkg- + + - name: Vendor Dependencies + run: make vendor vendor.check + + - name: Build Helm Chart + run: make -j2 build.all + env: + BUILD_ARGS: "--load" + + - name: Run E2E Tests + run: make e2e USE_HELM3=true + publish-artifacts: runs-on: ubuntu-24.04 needs: @@ -300,6 +356,7 @@ jobs: - unit-tests - local-deploy - check-examples + - e2e-tests if: needs.detect-noop.outputs.noop != 'true' steps: diff --git a/.gitignore b/.gitignore index bc5533d..a5c3458 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,10 @@ cover.out # ignore IDE folders .vscode/ .idea/ +.claude/ + +# Secrets +.envrc.local # Devenv .devenv* @@ -22,3 +26,6 @@ devenv.local.nix # Testing .kube/ +kubeconfig +cluster/test/processed-examples/ +cluster/test/datasource.yaml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2e24761..fb9c259 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,8 +27,46 @@ See the [README.md](README.md#developing) for development setup instructions. Before submitting a pull request: 1. Run the full test suite: `make test` -2. Test your changes locally: `./scripts/test-provider.sh` -3. Ensure all CRDs generate properly: `make generate` +2. Test your changes locally: `make local-deploy` +3. Run end-to-end tests: `make e2e` +4. Ensure all CRDs generate properly: `make generate` +5. Run all pre-submit checks: `make reviewable` + +### Testing with RedisCloud Pro Subscriptions + +For testing Pro subscription features that require payment methods: + +```bash +# Set RedisCloud API credentials +export REDISCLOUD_API_KEY="your-api-key" +export REDISCLOUD_SECRET_KEY="your-secret-key" +export REDISCLOUD_URL="https://api.redislabs.com/v1" + +# List available payment methods +make rediscloud-payment-methods + +# Get first payment method ID +make rediscloud-first-payment-method-id + +# Run e2e tests with automatic payment method fetching +make e2e + +# Or with 1Password integration +op run -- make e2e +``` + +### Useful Make Targets + +```bash +make help # Show all available targets +make test # Run unit tests +make e2e # Run end-to-end tests +make local-deploy # Deploy provider to local Kind cluster +make run # Run provider locally (out of cluster) +make reviewable # Run all checks before submitting PR +make rediscloud-payment-methods # List available payment methods from RedisCloud +make rediscloud-first-payment-method-id # Get first payment method ID +``` ## Submitting Changes diff --git a/Makefile b/Makefile index bf000ff..2b137f0 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ TERRAFORM_VERSION_VALID := $(shell [ "$(TERRAFORM_VERSION)" = "`printf "$(TERRAF export TERRAFORM_PROVIDER_SOURCE ?= RedisLabs/rediscloud export TERRAFORM_PROVIDER_REPO ?= https://github.com/RedisLabs/terraform-provider-rediscloud -export TERRAFORM_PROVIDER_VERSION ?= 2.1.5 +export TERRAFORM_PROVIDER_VERSION ?= 2.4.1 export TERRAFORM_PROVIDER_DOWNLOAD_NAME ?= terraform-provider-rediscloud export TERRAFORM_PROVIDER_DOWNLOAD_URL_PREFIX ?= https://github.com/RedisLabs/${TERRAFORM_PROVIDER_DOWNLOAD_NAME}/releases/download/v${TERRAFORM_PROVIDER_VERSION} export TERRAFORM_NATIVE_PROVIDER_BINARY ?= ${TERRAFORM_PROVIDER_DOWNLOAD_NAME}_v${TERRAFORM_PROVIDER_VERSION}_x5 @@ -175,12 +175,13 @@ run: go.build # ==================================================================================== # End to End Testing CROSSPLANE_VERSION = 1.16.0 -CROSSPLANE_NAMESPACE = upbound-system +CROSSPLANE_NAMESPACE ?= crossplane-system -include build/makelib/local.xpkg.mk -include build/makelib/controlplane.mk # This target requires the following environment variables to be set: # - UPTEST_EXAMPLE_LIST, a comma-separated list of examples to test +# Default: examples/rediscloud/subscription.yaml # To ensure the proper functioning of the end-to-end test resource pre-deletion hook, it is crucial to arrange your resources appropriately. # You can check the basic implementation here: https://github.com/crossplane/uptest/blob/main/internal/templates/03-delete.yaml.tmpl. # - UPTEST_CLOUD_CREDENTIALS (optional), multiple sets of AWS IAM User credentials specified as key=value pairs. @@ -193,15 +194,31 @@ CROSSPLANE_NAMESPACE = upbound-system # aws_secret_access_key = REDACTED' # The associated `ProviderConfig`s will be named as `default` and `peer`. # - UPTEST_DATASOURCE_PATH (optional), please see https://github.com/crossplane/uptest#injecting-dynamic-values-and-datasource +# - REDISCLOUD_PAYMENT_METHOD_ID (optional), the payment method ID to use for subscription examples +# - REDISCLOUD_API_KEY, REDISCLOUD_SECRET_KEY, REDISCLOUD_URL - RedisCloud API credentials to fetch payment method ID +UPTEST_EXAMPLE_LIST ?= examples/rediscloud/subscription.yaml,examples/rediscloud/database.yaml,examples/rediscloud/subscription-peering.yaml,examples/rediscloud/acl-user.yaml,examples/rediscloud/acl-rule.yaml,examples/rediscloud/cloud-account.yaml uptest: $(UPTEST) $(KUBECTL) $(KUTTL) @$(INFO) running automated tests - @KUBECTL=$(KUBECTL) KUTTL=$(KUTTL) $(UPTEST) e2e "${UPTEST_EXAMPLE_LIST}" --data-source="${UPTEST_DATASOURCE_PATH}" --setup-script=cluster/test/setup.sh --default-conditions="Test" || $(FAIL) + @# Create datasource.yaml file before running uptest (will be updated by setup script) + @mkdir -p cluster/test + @echo "# Placeholder datasource file - will be populated by setup script" > cluster/test/datasource.yaml + @echo "payment_method_id: \"\"" >> cluster/test/datasource.yaml + @echo "api_key: \"\"" >> cluster/test/datasource.yaml + @echo "secret_key: \"\"" >> cluster/test/datasource.yaml + @echo "url: \"\"" >> cluster/test/datasource.yaml + @KUBECTL=$(KUBECTL) KUTTL=$(KUTTL) \ + REDISCLOUD_API_KEY=$${REDISCLOUD_API_KEY:-} \ + REDISCLOUD_SECRET_KEY=$${REDISCLOUD_SECRET_KEY:-} \ + REDISCLOUD_URL=$${REDISCLOUD_URL:-} \ + REDISCLOUD_PAYMENT_METHOD_ID=$${REDISCLOUD_PAYMENT_METHOD_ID:-} \ + UPTEST_DATASOURCE_PATH="cluster/test/datasource.yaml" \ + $(UPTEST) e2e "$(UPTEST_EXAMPLE_LIST)" --data-source="cluster/test/datasource.yaml" --setup-script=cluster/test/setup.sh --default-conditions="Test" || $(FAIL) @$(OK) running automated tests local-deploy: build controlplane.up local.xpkg.deploy.provider.$(PROJECT_NAME) @$(INFO) running locally built provider - @$(KUBECTL) wait provider.pkg $(PROJECT_NAME) --for condition=Healthy --timeout 5m - @$(KUBECTL) -n upbound-system wait --for=condition=Available deployment --all --timeout=5m + @$(KUBECTL) wait provider.pkg $(PROJECT_NAME) --for condition=Installed --timeout 5m + @$(KUBECTL) -n $(CROSSPLANE_NAMESPACE) wait --for=condition=Available deployment --all --timeout=5m @$(OK) running locally built provider e2e: local-deploy uptest @@ -261,6 +278,26 @@ help-special: crossplane.help .PHONY: crossplane.help help-special +# ==================================================================================== +# RedisCloud API Testing + +# Fetch payment methods from RedisCloud API +.PHONY: rediscloud-payment-methods +rediscloud-payment-methods: + @$(INFO) Fetching RedisCloud payment methods + @curl -s -X GET "$${REDISCLOUD_URL}/payment-methods" \ + -H "x-api-key: $${REDISCLOUD_API_KEY}" \ + -H "x-api-secret-key: $${REDISCLOUD_SECRET_KEY}" | jq '.' || $(FAIL) + @$(OK) Fetched RedisCloud payment methods + +# Get the first payment method ID from RedisCloud API +.PHONY: rediscloud-first-payment-method-id +rediscloud-first-payment-method-id: + @curl -s -X GET "$${REDISCLOUD_URL}/payment-methods" \ + -H "x-api-key: $${REDISCLOUD_API_KEY}" \ + -H "x-api-secret-key: $${REDISCLOUD_SECRET_KEY}" | jq -r '.paymentMethods[0].id // empty' + + # TODO(negz): Update CI to use these targets. vendor: modules.download vendor.check: modules.check diff --git a/README.md b/README.md index 703eea1..fd772ed 100644 --- a/README.md +++ b/README.md @@ -120,10 +120,37 @@ make build ### Testing -Run the test harness (uses podman by default): +Run unit tests: ```bash -./scripts/test-provider.sh +make test +``` + +Run end-to-end tests: + +```bash +# Run with default examples (subscription + database) +make e2e + +# Run with custom examples +UPTEST_EXAMPLE_LIST="examples/rediscloud/acl-user.yaml" make e2e +``` + +#### E2E Testing with RedisCloud Pro Subscriptions + +Pro subscriptions require a valid payment method ID. The test infrastructure automatically handles this: + +```bash +# Set RedisCloud API credentials +export REDISCLOUD_API_KEY="your-api-key" +export REDISCLOUD_SECRET_KEY="your-secret-key" +export REDISCLOUD_URL="https://api.redislabs.com/v1" + +# Run e2e tests (automatically fetches payment method ID) +make e2e + +# Or with 1Password integration +op run -- make e2e ``` For detailed testing instructions, see [TESTING.md](TESTING.md). diff --git a/TESTING.md b/TESTING.md index b134567..68d8719 100644 --- a/TESTING.md +++ b/TESTING.md @@ -1,12 +1,14 @@ # Testing the RedisCloud Crossplane Provider -This guide explains how to test the RedisCloud Crossplane provider locally using kind (Kubernetes in Docker). +This guide explains how to test the RedisCloud Crossplane provider using standard Crossplane workflows. ## Prerequisites -- Docker running +- Docker or Podman installed and running +- Go 1.21+ installed - Access to RedisCloud API credentials -- `devenv` shell environment (includes all necessary tools) +- Make installed +- Kind (Kubernetes in Docker) installed ## Quick Start @@ -17,108 +19,174 @@ This guide explains how to test the RedisCloud Crossplane provider locally using # Create a new API key or use existing one ``` -2. **Configure Credentials** +2. **Set Credentials as Environment Variables** + + Copy `.envrc.example` to `.envrc` and update with your credentials: ```bash - # Edit .envrc and replace placeholder values - export REDISCLOUD_API_KEY="your-actual-api-key" - export REDISCLOUD_SECRET_KEY="your-actual-secret-key" - - # Reload environment - direnv allow + cp .envrc.example .envrc + # Edit .envrc with your actual API credentials + source .envrc ``` -3. **Run Quick Start** + Or set directly: ```bash - ./scripts/quick-start.sh + # For Pro subscriptions, set RedisCloud API credentials + # These are used to automatically fetch payment method IDs + export REDISCLOUD_API_KEY="your-api-key" + export REDISCLOUD_SECRET_KEY="your-secret-key" + export REDISCLOUD_URL="https://api.redislabs.com/v1" + + # Optionally specify a payment method ID directly + # export REDISCLOUD_PAYMENT_METHOD_ID=47739 ``` -4. **Test the Provider** + For 1Password users: ```bash - ./scripts/test-provider.sh + # Store your op:// references in .envrc.local + echo 'export REDISCLOUD_API_KEY="op://Private/Redis Cloud/api-tokens/api-account-key"' >> .envrc.local + echo 'export REDISCLOUD_SECRET_KEY="op://Private/Redis Cloud/api-tokens/api-user-key"' >> .envrc.local ``` -## Step-by-Step Testing +3. **Run Tests** + ```bash + # Run unit tests + make test -### 1. Create Kind Cluster -```bash -./scripts/test-provider.sh cluster -``` + # Run end-to-end tests with local deployment + make e2e -This creates a kind cluster named `rediscloud-test` with proper port mappings. + # Or with 1Password (if credentials are stored there) + op run -- make e2e + ``` -### 2. Install Crossplane -```bash -./scripts/test-provider.sh crossplane -``` +## Testing Workflows -Installs Crossplane using Helm in the `crossplane-system` namespace. +### Unit Tests -### 3. Install Provider +Run unit tests for all packages: ```bash -./scripts/test-provider.sh provider +make test ``` -Builds the provider image, loads it into kind, and installs it as a Crossplane provider. - -### 4. Configure Credentials +View test coverage: ```bash -./scripts/test-provider.sh config +make test +go tool cover -html=_output/tests/linux_amd64/coverage.txt ``` -Creates a Kubernetes secret with your RedisCloud credentials and a ProviderConfig that references it. +### Local Development Testing + +1. **Start local Crossplane control plane** + ```bash + make local-deploy + ``` + + This will: + - Start a Kind cluster + - Install Crossplane + - Build and install the provider locally + - Wait for all components to be ready + +2. **Apply test resources** + ```bash + kubectl apply -f examples/essentials/subscription.yaml + kubectl get subscription -w + ``` + +3. **Check provider logs** + ```bash + kubectl logs -n crossplane-system -l pkg.crossplane.io/provider=provider-rediscloud -f + ``` + +### End-to-End Testing with Uptest + +The provider uses Crossplane's `uptest` tool for automated e2e testing: -### 5. Test with Sample Resource ```bash -./scripts/test-provider.sh test +# Run e2e tests with default examples (subscription + database) +make e2e + +# Run e2e tests with specific examples +export UPTEST_EXAMPLE_LIST="examples/essentials/subscription.yaml" +make e2e + +# Or specify inline +UPTEST_EXAMPLE_LIST="examples/rediscloud/acl-user.yaml" make e2e ``` -Creates a test Essentials subscription (free tier) to verify the provider works. +**Default test examples**: `examples/rediscloud/subscription.yaml,examples/rediscloud/database.yaml` + +#### Payment Method Configuration for Pro Subscriptions + +Pro subscriptions require a valid payment method ID. The test setup script automatically handles this by: + +1. **Automatic Fetching**: If RedisCloud API credentials are provided, the setup script fetches the first available payment method ID from your account +2. **Manual Override**: You can specify a payment method ID directly using `REDISCLOUD_PAYMENT_METHOD_ID` +3. **Fallback**: If no credentials are provided, a default ID (1) is used, which may cause tests to fail -### 6. Check Status ```bash -./scripts/test-provider.sh status -``` +# List available payment methods +make rediscloud-payment-methods -Shows the status of all components in the cluster. +# Get the first payment method ID +make rediscloud-first-payment-method-id -## Available Resources +# Run e2e tests with automatic payment method fetching +make e2e -The provider includes the following resource groups: +# Or with 1Password +op run -- make e2e +``` -### ACL Resources (`acl.redis.io`) -- `Role` - ACL roles for database access -- `Rule` - ACL rules defining permissions -- `User` - ACL users with assigned roles +### Manual Testing -### Active-Active Resources (`active.redis.io`) -- `ActiveSubscription` - Active-Active subscriptions -- `ActiveSubscriptionDatabase` - Databases in AA subscriptions -- `ActiveSubscriptionPeering` - VPC peering for AA subscriptions -- `ActiveSubscriptionRegions` - Region management for AA -- `ActiveTransitGatewayAttachment` - Transit gateway attachments -- `ActivePrivateServiceConnect*` - Private service connect resources +1. **Build the provider** + ```bash + make build + ``` -### Cloud Resources (`cloud.redis.io`) -- `Account` - Cloud provider account configurations +2. **Start Crossplane locally** + ```bash + # In one terminal, start the control plane + make controlplane.up + ``` -### Essentials Resources (`essentials.redis.io`) -- `Database` - Essentials tier databases -- `Subscription` - Essentials tier subscriptions +3. **Install the provider** + ```bash + # In another terminal + make local.xpkg.deploy.provider.provider-rediscloud + ``` -### Private Service Connect (`private.redis.io`) -- `ServiceConnect` - Private service connect -- `ServiceConnectEndpoint` - Service connect endpoints -- `ServiceConnectEndpointAccepter` - Endpoint accepters +4. **Create provider config with credentials** + ```bash + kubectl create secret generic rediscloud-creds \ + --namespace=crossplane-system \ + --from-literal=credentials='{ + "api_key": "your-api-key", + "secret_key": "your-secret-key", + "url": "https://api.redislabs.com/v1" + }' + + kubectl apply -f examples/providerconfig/providerconfig.yaml + ``` -### Pro Subscription Resources (`rediscloud.redis.io`, `subscription.redis.io`) -- `Subscription` - Pro tier subscriptions -- `Database` - Pro tier databases -- `Peering` - VPC peering for subscriptions +5. **Create resources** + ```bash + kubectl apply -f examples/essentials/subscription.yaml + ``` -### Transit Gateway (`transit.redis.io`) -- `GatewayAttachment` - Transit gateway attachments +## Available Make Targets -## Example Usage +```bash +make help # Show all available targets +make test # Run unit tests +make e2e # Run end-to-end tests +make build # Build the provider binary +make local-deploy # Deploy provider to local Kind cluster +make run # Run provider locally (out of cluster) +``` + +## Example Resources ### Create an Essentials Subscription ```yaml @@ -145,6 +213,7 @@ spec: name: "My Pro Subscription" memoryStorage: "ram" paymentMethod: "credit-card" + paymentMethodId: 1 # Required for credit-card payment method cloudProvider: - provider: "AWS" region: @@ -195,29 +264,50 @@ kubectl get events --sort-by=.metadata.creationTimestamp ### Clean Up ```bash # Remove test resources -./scripts/test-provider.sh cleanup +kubectl delete -f examples/ + +# Tear down local development environment +make controlplane.down -# Delete entire cluster -kind delete cluster --name rediscloud-test +# Delete entire Kind cluster +kind delete cluster --name kind ``` -## Environment Variables +## CI/CD Integration + +The project uses GitHub Actions for continuous integration: -The test scripts use these environment variables (configured in `.envrc`): +- **Unit tests** run on every pull request +- **E2E tests** run on every pull request +- **Code coverage** is reported to Codecov +- **Linting** enforces code quality standards -- `REDISCLOUD_API_KEY` - Your RedisCloud API key -- `REDISCLOUD_SECRET_KEY` - Your RedisCloud secret key -- `REDISCLOUD_URL` - RedisCloud API URL (default: https://api.redislabs.com/v1) -- `KIND_CLUSTER_NAME` - Kind cluster name (default: rediscloud-test) -- `CROSSPLANE_NAMESPACE` - Crossplane namespace (default: crossplane-system) -- `PROVIDER_NAMESPACE` - Provider namespace (default: crossplane-system) -- `KUBECONFIG_PATH` - Kubeconfig file path (default: ./.kube/config) +To run the same checks locally before pushing: +```bash +make reviewable +``` ## Development Workflow 1. Make changes to the provider code -2. Rebuild: `make build` -3. Reload provider: `./scripts/test-provider.sh provider` -4. Test changes: `./scripts/test-provider.sh test` +2. Run unit tests: `make test` +3. Build provider: `make build` +4. Deploy locally: `make local-deploy` +5. Test your changes with example resources +6. Run full e2e suite: `make e2e` +7. Submit PR - CI will run all tests automatically + +## Environment Variables + +The following environment variables can be used to configure testing: + +- `UPTEST_CLOUD_CREDENTIALS` - JSON string with RedisCloud credentials +- `UPTEST_EXAMPLE_LIST` - Comma-separated list of example files to test +- `UPTEST_DATASOURCE_PATH` - Path to datasource file for dynamic values +- `CROSSPLANE_NAMESPACE` - Namespace for Crossplane (default: crossplane-system) + +## Additional Resources -The provider image uses `packagePullPolicy: Never` so it will use the locally built image without pulling from a registry. \ No newline at end of file +- [Crossplane Testing Guide](https://crossplane.io/docs/latest/contributing/testing.html) +- [Uptest Documentation](https://github.com/crossplane/uptest) +- [RedisCloud API Documentation](https://api.redislabs.com/v1/swagger-ui.html) \ No newline at end of file diff --git a/apis/active/v1alpha1/zz_activesubscription_types.go b/apis/active/v1alpha1/zz_activesubscription_types.go index 244da69..ce99e0b 100755 --- a/apis/active/v1alpha1/zz_activesubscription_types.go +++ b/apis/active/v1alpha1/zz_activesubscription_types.go @@ -23,6 +23,18 @@ type ActiveSubscriptionInitParameters struct { // Information about the planned databases used to optimise the database infrastructure. This information is only used when creating a new subscription and any changes will be ignored after this. CreationPlan []CreationPlanInitParameters `json:"creationPlan,omitempty" tf:"creation_plan,omitempty"` + // The customer managed keys (CMK) to use for this subscription. In an active-active subscription, you must set a key for each region. + // CMK resources used to encrypt the databases in this subscription. Ignored if `customer_managed_key_enabled` set to false. See documentation for CMK flow. + CustomerManagedKey []CustomerManagedKeyInitParameters `json:"customerManagedKey,omitempty" tf:"customer_managed_key,omitempty"` + + // The grace period for deleting the subscription. If not set, will default to immediate deletion grace period. + // The grace period for deleting the subscription. If not set, will default to immediate deletion grace period. + CustomerManagedKeyDeletionGracePeriod *string `json:"customerManagedKeyDeletionGracePeriod,omitempty" tf:"customer_managed_key_deletion_grace_period,omitempty"` + + // Whether to enable the CMK flow. + // Whether to enable CMK (customer managed key) for the subscription. If this is true, then the subscription will be put in a pending state until you supply the CMEK. See documentation for further details on this process. Defaults to false. + CustomerManagedKeyEnabled *bool `json:"customerManagedKeyEnabled,omitempty" tf:"customer_managed_key_enabled,omitempty"` + // The subscription's maintenance window specification, documented below. // Specify the subscription's maintenance windows MaintenanceWindows []MaintenanceWindowsInitParameters `json:"maintenanceWindows,omitempty" tf:"maintenance_windows,omitempty"` @@ -31,7 +43,7 @@ type ActiveSubscriptionInitParameters struct { // A meaningful name to identify the subscription Name *string `json:"name,omitempty" tf:"name,omitempty"` - // card or marketplace). If credit-card is specified, payment_method_id must be defined. Default: 'credit-card'. (Changes to) this attribute are ignored after creation. + // The payment method for the requested subscription, (either credit-card or marketplace). Must not be set for direct contracts. If credit-card is specified, payment_method_id must be defined. Default: 'credit-card'. (Changes to) this attribute are ignored after creation. // Payment method for the requested subscription. If credit card is specified, the payment method id must be defined. This information is only used when creating a new subscription and any changes will be ignored after this. PaymentMethod *string `json:"paymentMethod,omitempty" tf:"payment_method,omitempty"` @@ -39,7 +51,7 @@ type ActiveSubscriptionInitParameters struct { // A valid payment method pre-defined in the current account PaymentMethodID *string `json:"paymentMethodId,omitempty" tf:"payment_method_id,omitempty"` - // The Redis version of the databases in the subscription. If omitted, the Redis version will be the default. Modifying this attribute will force creation of a new resource. + // The Redis version of the databases in the subscription. If omitted, the Redis version will be the default. Deprecated: This attribute is deprecated on the subscription level. Please specify // Version of Redis to create RedisVersion *string `json:"redisVersion,omitempty" tf:"redis_version,omitempty"` } @@ -54,6 +66,22 @@ type ActiveSubscriptionObservation struct { // Information about the planned databases used to optimise the database infrastructure. This information is only used when creating a new subscription and any changes will be ignored after this. CreationPlan []CreationPlanObservation `json:"creationPlan,omitempty" tf:"creation_plan,omitempty"` + // The customer managed keys (CMK) to use for this subscription. In an active-active subscription, you must set a key for each region. + // CMK resources used to encrypt the databases in this subscription. Ignored if `customer_managed_key_enabled` set to false. See documentation for CMK flow. + CustomerManagedKey []CustomerManagedKeyObservation `json:"customerManagedKey,omitempty" tf:"customer_managed_key,omitempty"` + + // The grace period for deleting the subscription. If not set, will default to immediate deletion grace period. + // The grace period for deleting the subscription. If not set, will default to immediate deletion grace period. + CustomerManagedKeyDeletionGracePeriod *string `json:"customerManagedKeyDeletionGracePeriod,omitempty" tf:"customer_managed_key_deletion_grace_period,omitempty"` + + // Whether to enable the CMK flow. + // Whether to enable CMK (customer managed key) for the subscription. If this is true, then the subscription will be put in a pending state until you supply the CMEK. See documentation for further details on this process. Defaults to false. + CustomerManagedKeyEnabled *bool `json:"customerManagedKeyEnabled,omitempty" tf:"customer_managed_key_enabled,omitempty"` + + // Outputs the id of the service account associated with the subscription. Useful as part of the CMK flow. + // The principal of the Redis service account that the subscription is created in. This is used by the user to give access to their customer managed key + CustomerManagedKeyRedisServiceAccount *string `json:"customerManagedKeyRedisServiceAccount,omitempty" tf:"customer_managed_key_redis_service_account,omitempty"` + ID *string `json:"id,omitempty" tf:"id,omitempty"` // The subscription's maintenance window specification, documented below. @@ -64,7 +92,7 @@ type ActiveSubscriptionObservation struct { // A meaningful name to identify the subscription Name *string `json:"name,omitempty" tf:"name,omitempty"` - // card or marketplace). If credit-card is specified, payment_method_id must be defined. Default: 'credit-card'. (Changes to) this attribute are ignored after creation. + // The payment method for the requested subscription, (either credit-card or marketplace). Must not be set for direct contracts. If credit-card is specified, payment_method_id must be defined. Default: 'credit-card'. (Changes to) this attribute are ignored after creation. // Payment method for the requested subscription. If credit card is specified, the payment method id must be defined. This information is only used when creating a new subscription and any changes will be ignored after this. PaymentMethod *string `json:"paymentMethod,omitempty" tf:"payment_method,omitempty"` @@ -76,7 +104,7 @@ type ActiveSubscriptionObservation struct { // Pricing details totalled over this Subscription Pricing []PricingObservation `json:"pricing,omitempty" tf:"pricing,omitempty"` - // The Redis version of the databases in the subscription. If omitted, the Redis version will be the default. Modifying this attribute will force creation of a new resource. + // The Redis version of the databases in the subscription. If omitted, the Redis version will be the default. Deprecated: This attribute is deprecated on the subscription level. Please specify // Version of Redis to create RedisVersion *string `json:"redisVersion,omitempty" tf:"redis_version,omitempty"` } @@ -93,6 +121,21 @@ type ActiveSubscriptionParameters struct { // +kubebuilder:validation:Optional CreationPlan []CreationPlanParameters `json:"creationPlan,omitempty" tf:"creation_plan,omitempty"` + // The customer managed keys (CMK) to use for this subscription. In an active-active subscription, you must set a key for each region. + // CMK resources used to encrypt the databases in this subscription. Ignored if `customer_managed_key_enabled` set to false. See documentation for CMK flow. + // +kubebuilder:validation:Optional + CustomerManagedKey []CustomerManagedKeyParameters `json:"customerManagedKey,omitempty" tf:"customer_managed_key,omitempty"` + + // The grace period for deleting the subscription. If not set, will default to immediate deletion grace period. + // The grace period for deleting the subscription. If not set, will default to immediate deletion grace period. + // +kubebuilder:validation:Optional + CustomerManagedKeyDeletionGracePeriod *string `json:"customerManagedKeyDeletionGracePeriod,omitempty" tf:"customer_managed_key_deletion_grace_period,omitempty"` + + // Whether to enable the CMK flow. + // Whether to enable CMK (customer managed key) for the subscription. If this is true, then the subscription will be put in a pending state until you supply the CMEK. See documentation for further details on this process. Defaults to false. + // +kubebuilder:validation:Optional + CustomerManagedKeyEnabled *bool `json:"customerManagedKeyEnabled,omitempty" tf:"customer_managed_key_enabled,omitempty"` + // The subscription's maintenance window specification, documented below. // Specify the subscription's maintenance windows // +kubebuilder:validation:Optional @@ -103,7 +146,7 @@ type ActiveSubscriptionParameters struct { // +kubebuilder:validation:Optional Name *string `json:"name,omitempty" tf:"name,omitempty"` - // card or marketplace). If credit-card is specified, payment_method_id must be defined. Default: 'credit-card'. (Changes to) this attribute are ignored after creation. + // The payment method for the requested subscription, (either credit-card or marketplace). Must not be set for direct contracts. If credit-card is specified, payment_method_id must be defined. Default: 'credit-card'. (Changes to) this attribute are ignored after creation. // Payment method for the requested subscription. If credit card is specified, the payment method id must be defined. This information is only used when creating a new subscription and any changes will be ignored after this. // +kubebuilder:validation:Optional PaymentMethod *string `json:"paymentMethod,omitempty" tf:"payment_method,omitempty"` @@ -113,7 +156,7 @@ type ActiveSubscriptionParameters struct { // +kubebuilder:validation:Optional PaymentMethodID *string `json:"paymentMethodId,omitempty" tf:"payment_method_id,omitempty"` - // The Redis version of the databases in the subscription. If omitted, the Redis version will be the default. Modifying this attribute will force creation of a new resource. + // The Redis version of the databases in the subscription. If omitted, the Redis version will be the default. Deprecated: This attribute is deprecated on the subscription level. Please specify // Version of Redis to create // +kubebuilder:validation:Optional RedisVersion *string `json:"redisVersion,omitempty" tf:"redis_version,omitempty"` @@ -193,6 +236,41 @@ type CreationPlanParameters struct { Region []RegionParameters `json:"region" tf:"region,omitempty"` } +type CustomerManagedKeyInitParameters struct { + + // Name of the region for the customer managed key as defined by the cloud provider. + // Name of region for the customer managed key as defined by the cloud provider. + Region *string `json:"region,omitempty" tf:"region,omitempty"` + + // Resource name of the customer managed key as defined by the cloud provider, e.g. projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY_NAME + // Resource name of the customer managed key as defined by the cloud provider, e.g. projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY_NAME + ResourceName *string `json:"resourceName,omitempty" tf:"resource_name,omitempty"` +} + +type CustomerManagedKeyObservation struct { + + // Name of the region for the customer managed key as defined by the cloud provider. + // Name of region for the customer managed key as defined by the cloud provider. + Region *string `json:"region,omitempty" tf:"region,omitempty"` + + // Resource name of the customer managed key as defined by the cloud provider, e.g. projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY_NAME + // Resource name of the customer managed key as defined by the cloud provider, e.g. projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY_NAME + ResourceName *string `json:"resourceName,omitempty" tf:"resource_name,omitempty"` +} + +type CustomerManagedKeyParameters struct { + + // Name of the region for the customer managed key as defined by the cloud provider. + // Name of region for the customer managed key as defined by the cloud provider. + // +kubebuilder:validation:Optional + Region *string `json:"region" tf:"region,omitempty"` + + // Resource name of the customer managed key as defined by the cloud provider, e.g. projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY_NAME + // Resource name of the customer managed key as defined by the cloud provider, e.g. projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY_NAME + // +kubebuilder:validation:Optional + ResourceName *string `json:"resourceName" tf:"resource_name,omitempty"` +} + type MaintenanceWindowsInitParameters struct { // Either automatic (Redis specified) or manual (User specified) diff --git a/apis/active/v1alpha1/zz_activesubscriptiondatabase_types.go b/apis/active/v1alpha1/zz_activesubscriptiondatabase_types.go index 642f82d..064a3f1 100755 --- a/apis/active/v1alpha1/zz_activesubscriptiondatabase_types.go +++ b/apis/active/v1alpha1/zz_activesubscriptiondatabase_types.go @@ -81,6 +81,10 @@ type ActiveSubscriptionDatabaseInitParameters struct { // TCP port on which the database is available Port *float64 `json:"port,omitempty" tf:"port,omitempty"` + // The Redis version of the database. If omitted, the Redis version will be the default. Modifying this attribute will force creation of a new resource. + // Defines the Redis database version. If omitted, the Redis version will be set to the default version + RedisVersion *string `json:"redisVersion,omitempty" tf:"redis_version,omitempty"` + // Active subscription to create the database in. Modifying this attribute will force creation of a new resource. // Identifier of the subscription SubscriptionID *float64 `json:"subscriptionId,omitempty" tf:"subscription_id,omitempty"` @@ -175,6 +179,10 @@ type ActiveSubscriptionDatabaseObservation struct { // +mapType=granular PublicEndpoint map[string]*string `json:"publicEndpoint,omitempty" tf:"public_endpoint,omitempty"` + // The Redis version of the database. If omitted, the Redis version will be the default. Modifying this attribute will force creation of a new resource. + // Defines the Redis database version. If omitted, the Redis version will be set to the default version + RedisVersion *string `json:"redisVersion,omitempty" tf:"redis_version,omitempty"` + // Active subscription to create the database in. Modifying this attribute will force creation of a new resource. // Identifier of the subscription SubscriptionID *float64 `json:"subscriptionId,omitempty" tf:"subscription_id,omitempty"` @@ -273,6 +281,11 @@ type ActiveSubscriptionDatabaseParameters struct { // +kubebuilder:validation:Optional Port *float64 `json:"port,omitempty" tf:"port,omitempty"` + // The Redis version of the database. If omitted, the Redis version will be the default. Modifying this attribute will force creation of a new resource. + // Defines the Redis database version. If omitted, the Redis version will be set to the default version + // +kubebuilder:validation:Optional + RedisVersion *string `json:"redisVersion,omitempty" tf:"redis_version,omitempty"` + // Active subscription to create the database in. Modifying this attribute will force creation of a new resource. // Identifier of the subscription // +kubebuilder:validation:Optional diff --git a/apis/active/v1alpha1/zz_generated.deepcopy.go b/apis/active/v1alpha1/zz_generated.deepcopy.go index 76cab03..6534d8e 100644 --- a/apis/active/v1alpha1/zz_generated.deepcopy.go +++ b/apis/active/v1alpha1/zz_generated.deepcopy.go @@ -831,6 +831,11 @@ func (in *ActiveSubscriptionDatabaseInitParameters) DeepCopyInto(out *ActiveSubs *out = new(float64) **out = **in } + if in.RedisVersion != nil { + in, out := &in.RedisVersion, &out.RedisVersion + *out = new(string) + **out = **in + } if in.SubscriptionID != nil { in, out := &in.SubscriptionID, &out.SubscriptionID *out = new(float64) @@ -1043,6 +1048,11 @@ func (in *ActiveSubscriptionDatabaseObservation) DeepCopyInto(out *ActiveSubscri (*out)[key] = outVal } } + if in.RedisVersion != nil { + in, out := &in.RedisVersion, &out.RedisVersion + *out = new(string) + **out = **in + } if in.SubscriptionID != nil { in, out := &in.SubscriptionID, &out.SubscriptionID *out = new(float64) @@ -1186,6 +1196,11 @@ func (in *ActiveSubscriptionDatabaseParameters) DeepCopyInto(out *ActiveSubscrip *out = new(float64) **out = **in } + if in.RedisVersion != nil { + in, out := &in.RedisVersion, &out.RedisVersion + *out = new(string) + **out = **in + } if in.SubscriptionID != nil { in, out := &in.SubscriptionID, &out.SubscriptionID *out = new(float64) @@ -1274,6 +1289,23 @@ func (in *ActiveSubscriptionInitParameters) DeepCopyInto(out *ActiveSubscription (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.CustomerManagedKey != nil { + in, out := &in.CustomerManagedKey, &out.CustomerManagedKey + *out = make([]CustomerManagedKeyInitParameters, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.CustomerManagedKeyDeletionGracePeriod != nil { + in, out := &in.CustomerManagedKeyDeletionGracePeriod, &out.CustomerManagedKeyDeletionGracePeriod + *out = new(string) + **out = **in + } + if in.CustomerManagedKeyEnabled != nil { + in, out := &in.CustomerManagedKeyEnabled, &out.CustomerManagedKeyEnabled + *out = new(bool) + **out = **in + } if in.MaintenanceWindows != nil { in, out := &in.MaintenanceWindows, &out.MaintenanceWindows *out = make([]MaintenanceWindowsInitParameters, len(*in)) @@ -1360,6 +1392,28 @@ func (in *ActiveSubscriptionObservation) DeepCopyInto(out *ActiveSubscriptionObs (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.CustomerManagedKey != nil { + in, out := &in.CustomerManagedKey, &out.CustomerManagedKey + *out = make([]CustomerManagedKeyObservation, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.CustomerManagedKeyDeletionGracePeriod != nil { + in, out := &in.CustomerManagedKeyDeletionGracePeriod, &out.CustomerManagedKeyDeletionGracePeriod + *out = new(string) + **out = **in + } + if in.CustomerManagedKeyEnabled != nil { + in, out := &in.CustomerManagedKeyEnabled, &out.CustomerManagedKeyEnabled + *out = new(bool) + **out = **in + } + if in.CustomerManagedKeyRedisServiceAccount != nil { + in, out := &in.CustomerManagedKeyRedisServiceAccount, &out.CustomerManagedKeyRedisServiceAccount + *out = new(string) + **out = **in + } if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) @@ -1426,6 +1480,23 @@ func (in *ActiveSubscriptionParameters) DeepCopyInto(out *ActiveSubscriptionPara (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.CustomerManagedKey != nil { + in, out := &in.CustomerManagedKey, &out.CustomerManagedKey + *out = make([]CustomerManagedKeyParameters, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.CustomerManagedKeyDeletionGracePeriod != nil { + in, out := &in.CustomerManagedKeyDeletionGracePeriod, &out.CustomerManagedKeyDeletionGracePeriod + *out = new(string) + **out = **in + } + if in.CustomerManagedKeyEnabled != nil { + in, out := &in.CustomerManagedKeyEnabled, &out.CustomerManagedKeyEnabled + *out = new(bool) + **out = **in + } if in.MaintenanceWindows != nil { in, out := &in.MaintenanceWindows, &out.MaintenanceWindows *out = make([]MaintenanceWindowsParameters, len(*in)) @@ -2559,6 +2630,81 @@ func (in *CreationPlanParameters) DeepCopy() *CreationPlanParameters { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomerManagedKeyInitParameters) DeepCopyInto(out *CustomerManagedKeyInitParameters) { + *out = *in + if in.Region != nil { + in, out := &in.Region, &out.Region + *out = new(string) + **out = **in + } + if in.ResourceName != nil { + in, out := &in.ResourceName, &out.ResourceName + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomerManagedKeyInitParameters. +func (in *CustomerManagedKeyInitParameters) DeepCopy() *CustomerManagedKeyInitParameters { + if in == nil { + return nil + } + out := new(CustomerManagedKeyInitParameters) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomerManagedKeyObservation) DeepCopyInto(out *CustomerManagedKeyObservation) { + *out = *in + if in.Region != nil { + in, out := &in.Region, &out.Region + *out = new(string) + **out = **in + } + if in.ResourceName != nil { + in, out := &in.ResourceName, &out.ResourceName + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomerManagedKeyObservation. +func (in *CustomerManagedKeyObservation) DeepCopy() *CustomerManagedKeyObservation { + if in == nil { + return nil + } + out := new(CustomerManagedKeyObservation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomerManagedKeyParameters) DeepCopyInto(out *CustomerManagedKeyParameters) { + *out = *in + if in.Region != nil { + in, out := &in.Region, &out.Region + *out = new(string) + **out = **in + } + if in.ResourceName != nil { + in, out := &in.ResourceName, &out.ResourceName + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomerManagedKeyParameters. +func (in *CustomerManagedKeyParameters) DeepCopy() *CustomerManagedKeyParameters { + if in == nil { + return nil + } + out := new(CustomerManagedKeyParameters) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DatabaseInitParameters) DeepCopyInto(out *DatabaseInitParameters) { *out = *in diff --git a/apis/rediscloud/v1alpha1/zz_generated.deepcopy.go b/apis/rediscloud/v1alpha1/zz_generated.deepcopy.go index e249cf8..978dd92 100644 --- a/apis/rediscloud/v1alpha1/zz_generated.deepcopy.go +++ b/apis/rediscloud/v1alpha1/zz_generated.deepcopy.go @@ -432,6 +432,66 @@ func (in *CreationPlanParameters) DeepCopy() *CreationPlanParameters { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomerManagedKeyInitParameters) DeepCopyInto(out *CustomerManagedKeyInitParameters) { + *out = *in + if in.ResourceName != nil { + in, out := &in.ResourceName, &out.ResourceName + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomerManagedKeyInitParameters. +func (in *CustomerManagedKeyInitParameters) DeepCopy() *CustomerManagedKeyInitParameters { + if in == nil { + return nil + } + out := new(CustomerManagedKeyInitParameters) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomerManagedKeyObservation) DeepCopyInto(out *CustomerManagedKeyObservation) { + *out = *in + if in.ResourceName != nil { + in, out := &in.ResourceName, &out.ResourceName + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomerManagedKeyObservation. +func (in *CustomerManagedKeyObservation) DeepCopy() *CustomerManagedKeyObservation { + if in == nil { + return nil + } + out := new(CustomerManagedKeyObservation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomerManagedKeyParameters) DeepCopyInto(out *CustomerManagedKeyParameters) { + *out = *in + if in.ResourceName != nil { + in, out := &in.ResourceName, &out.ResourceName + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomerManagedKeyParameters. +func (in *CustomerManagedKeyParameters) DeepCopy() *CustomerManagedKeyParameters { + if in == nil { + return nil + } + out := new(CustomerManagedKeyParameters) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MaintenanceWindowsInitParameters) DeepCopyInto(out *MaintenanceWindowsInitParameters) { *out = *in @@ -859,6 +919,23 @@ func (in *SubscriptionInitParameters) DeepCopyInto(out *SubscriptionInitParamete (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.CustomerManagedKey != nil { + in, out := &in.CustomerManagedKey, &out.CustomerManagedKey + *out = make([]CustomerManagedKeyInitParameters, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.CustomerManagedKeyDeletionGracePeriod != nil { + in, out := &in.CustomerManagedKeyDeletionGracePeriod, &out.CustomerManagedKeyDeletionGracePeriod + *out = new(string) + **out = **in + } + if in.CustomerManagedKeyEnabled != nil { + in, out := &in.CustomerManagedKeyEnabled, &out.CustomerManagedKeyEnabled + *out = new(bool) + **out = **in + } if in.MaintenanceWindows != nil { in, out := &in.MaintenanceWindows, &out.MaintenanceWindows *out = make([]MaintenanceWindowsInitParameters, len(*in)) @@ -959,6 +1036,28 @@ func (in *SubscriptionObservation) DeepCopyInto(out *SubscriptionObservation) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.CustomerManagedKey != nil { + in, out := &in.CustomerManagedKey, &out.CustomerManagedKey + *out = make([]CustomerManagedKeyObservation, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.CustomerManagedKeyDeletionGracePeriod != nil { + in, out := &in.CustomerManagedKeyDeletionGracePeriod, &out.CustomerManagedKeyDeletionGracePeriod + *out = new(string) + **out = **in + } + if in.CustomerManagedKeyEnabled != nil { + in, out := &in.CustomerManagedKeyEnabled, &out.CustomerManagedKeyEnabled + *out = new(bool) + **out = **in + } + if in.CustomerManagedKeyRedisServiceAccount != nil { + in, out := &in.CustomerManagedKeyRedisServiceAccount, &out.CustomerManagedKeyRedisServiceAccount + *out = new(string) + **out = **in + } if in.ID != nil { in, out := &in.ID, &out.ID *out = new(string) @@ -1039,6 +1138,23 @@ func (in *SubscriptionParameters) DeepCopyInto(out *SubscriptionParameters) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.CustomerManagedKey != nil { + in, out := &in.CustomerManagedKey, &out.CustomerManagedKey + *out = make([]CustomerManagedKeyParameters, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.CustomerManagedKeyDeletionGracePeriod != nil { + in, out := &in.CustomerManagedKeyDeletionGracePeriod, &out.CustomerManagedKeyDeletionGracePeriod + *out = new(string) + **out = **in + } + if in.CustomerManagedKeyEnabled != nil { + in, out := &in.CustomerManagedKeyEnabled, &out.CustomerManagedKeyEnabled + *out = new(bool) + **out = **in + } if in.MaintenanceWindows != nil { in, out := &in.MaintenanceWindows, &out.MaintenanceWindows *out = make([]MaintenanceWindowsParameters, len(*in)) diff --git a/apis/rediscloud/v1alpha1/zz_subscription_types.go b/apis/rediscloud/v1alpha1/zz_subscription_types.go index 16eb0cf..5588307 100755 --- a/apis/rediscloud/v1alpha1/zz_subscription_types.go +++ b/apis/rediscloud/v1alpha1/zz_subscription_types.go @@ -253,6 +253,28 @@ type CreationPlanParameters struct { ThroughputMeasurementValue *float64 `json:"throughputMeasurementValue" tf:"throughput_measurement_value,omitempty"` } +type CustomerManagedKeyInitParameters struct { + + // The resource name of the customer managed key as defined by the cloud provider, e.g. projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY_NAME + // Resource name of the customer managed key as defined by the cloud provider. + ResourceName *string `json:"resourceName,omitempty" tf:"resource_name,omitempty"` +} + +type CustomerManagedKeyObservation struct { + + // The resource name of the customer managed key as defined by the cloud provider, e.g. projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY_NAME + // Resource name of the customer managed key as defined by the cloud provider. + ResourceName *string `json:"resourceName,omitempty" tf:"resource_name,omitempty"` +} + +type CustomerManagedKeyParameters struct { + + // The resource name of the customer managed key as defined by the cloud provider, e.g. projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY_NAME + // Resource name of the customer managed key as defined by the cloud provider. + // +kubebuilder:validation:Optional + ResourceName *string `json:"resourceName" tf:"resource_name,omitempty"` +} + type MaintenanceWindowsInitParameters struct { // Either automatic (Redis specified) or manual (User specified) @@ -429,6 +451,18 @@ type SubscriptionInitParameters struct { // Information about the planned databases used to optimise the database infrastructure. This information is only used when creating a new subscription and any changes will be ignored after this. CreationPlan []CreationPlanInitParameters `json:"creationPlan,omitempty" tf:"creation_plan,omitempty"` + // The customer managed keys (CMK) to use for this subscription. + // CMK resources used to encrypt the databases in this subscription. Ignored if `customer_managed_key_enabled` set to false. Supply after the database has been put into database pending state. See documentation for CMK flow. + CustomerManagedKey []CustomerManagedKeyInitParameters `json:"customerManagedKey,omitempty" tf:"customer_managed_key,omitempty"` + + // The grace period for deleting the subscription. If not set, will default to immediate deletion grace period. + // The grace period for deleting the subscription. If not set, will default to immediate deletion grace period. + CustomerManagedKeyDeletionGracePeriod *string `json:"customerManagedKeyDeletionGracePeriod,omitempty" tf:"customer_managed_key_deletion_grace_period,omitempty"` + + // Whether to enable the customer managed encryption key flow. + // Whether to enable CMK (customer managed key) for the subscription. If this is true, then the subscription will be put in a pending state until you supply the CMEK. See documentation for further details on this process. Defaults to false. + CustomerManagedKeyEnabled *bool `json:"customerManagedKeyEnabled,omitempty" tf:"customer_managed_key_enabled,omitempty"` + // The subscription's maintenance window specification, documented below. // Specify the subscription's maintenance windows MaintenanceWindows []MaintenanceWindowsInitParameters `json:"maintenanceWindows,omitempty" tf:"maintenance_windows,omitempty"` @@ -441,7 +475,7 @@ type SubscriptionInitParameters struct { // A meaningful name to identify the subscription Name *string `json:"name,omitempty" tf:"name,omitempty"` - // card or marketplace). If credit-card is specified, payment_method_id must be defined. Default: 'credit-card'. (Changes to) this attribute are ignored after creation. + // card or marketplace). Must not be set for direct contracts. If credit-card is specified, payment_method_id must be defined. Default: 'credit-card'. (Changes to) this attribute are ignored after creation. // Payment method for the requested subscription. If credit card is specified, the payment method id must be defined. This information is only used when creating a new subscription and any changes will be ignored after this. PaymentMethod *string `json:"paymentMethod,omitempty" tf:"payment_method,omitempty"` @@ -449,7 +483,7 @@ type SubscriptionInitParameters struct { // A valid payment method pre-defined in the current account PaymentMethodID *string `json:"paymentMethodId,omitempty" tf:"payment_method_id,omitempty"` - // The Redis version of the databases in the subscription. If omitted, the Redis version will be the default. Modifying this attribute will force creation of a new resource. + // The Redis version of the databases in the subscription. If omitted, the Redis version will be the default. Deprecated: This attribute is deprecated on the subscriptions level. Please specify // Version of Redis to create RedisVersion *string `json:"redisVersion,omitempty" tf:"redis_version,omitempty"` } @@ -468,6 +502,22 @@ type SubscriptionObservation struct { // Information about the planned databases used to optimise the database infrastructure. This information is only used when creating a new subscription and any changes will be ignored after this. CreationPlan []CreationPlanObservation `json:"creationPlan,omitempty" tf:"creation_plan,omitempty"` + // The customer managed keys (CMK) to use for this subscription. + // CMK resources used to encrypt the databases in this subscription. Ignored if `customer_managed_key_enabled` set to false. Supply after the database has been put into database pending state. See documentation for CMK flow. + CustomerManagedKey []CustomerManagedKeyObservation `json:"customerManagedKey,omitempty" tf:"customer_managed_key,omitempty"` + + // The grace period for deleting the subscription. If not set, will default to immediate deletion grace period. + // The grace period for deleting the subscription. If not set, will default to immediate deletion grace period. + CustomerManagedKeyDeletionGracePeriod *string `json:"customerManagedKeyDeletionGracePeriod,omitempty" tf:"customer_managed_key_deletion_grace_period,omitempty"` + + // Whether to enable the customer managed encryption key flow. + // Whether to enable CMK (customer managed key) for the subscription. If this is true, then the subscription will be put in a pending state until you supply the CMEK. See documentation for further details on this process. Defaults to false. + CustomerManagedKeyEnabled *bool `json:"customerManagedKeyEnabled,omitempty" tf:"customer_managed_key_enabled,omitempty"` + + // Outputs the id of the service account associated with the subscription. Useful as part of the CMK flow. + // The principal of the Redis service account that the subscription is created in. This is used by the user to give access to their customer managed key + CustomerManagedKeyRedisServiceAccount *string `json:"customerManagedKeyRedisServiceAccount,omitempty" tf:"customer_managed_key_redis_service_account,omitempty"` + ID *string `json:"id,omitempty" tf:"id,omitempty"` // The subscription's maintenance window specification, documented below. @@ -482,7 +532,7 @@ type SubscriptionObservation struct { // A meaningful name to identify the subscription Name *string `json:"name,omitempty" tf:"name,omitempty"` - // card or marketplace). If credit-card is specified, payment_method_id must be defined. Default: 'credit-card'. (Changes to) this attribute are ignored after creation. + // card or marketplace). Must not be set for direct contracts. If credit-card is specified, payment_method_id must be defined. Default: 'credit-card'. (Changes to) this attribute are ignored after creation. // Payment method for the requested subscription. If credit card is specified, the payment method id must be defined. This information is only used when creating a new subscription and any changes will be ignored after this. PaymentMethod *string `json:"paymentMethod,omitempty" tf:"payment_method,omitempty"` @@ -493,7 +543,7 @@ type SubscriptionObservation struct { // Pricing details totalled over this Subscription Pricing []PricingObservation `json:"pricing,omitempty" tf:"pricing,omitempty"` - // The Redis version of the databases in the subscription. If omitted, the Redis version will be the default. Modifying this attribute will force creation of a new resource. + // The Redis version of the databases in the subscription. If omitted, the Redis version will be the default. Deprecated: This attribute is deprecated on the subscriptions level. Please specify // Version of Redis to create RedisVersion *string `json:"redisVersion,omitempty" tf:"redis_version,omitempty"` } @@ -515,6 +565,21 @@ type SubscriptionParameters struct { // +kubebuilder:validation:Optional CreationPlan []CreationPlanParameters `json:"creationPlan,omitempty" tf:"creation_plan,omitempty"` + // The customer managed keys (CMK) to use for this subscription. + // CMK resources used to encrypt the databases in this subscription. Ignored if `customer_managed_key_enabled` set to false. Supply after the database has been put into database pending state. See documentation for CMK flow. + // +kubebuilder:validation:Optional + CustomerManagedKey []CustomerManagedKeyParameters `json:"customerManagedKey,omitempty" tf:"customer_managed_key,omitempty"` + + // The grace period for deleting the subscription. If not set, will default to immediate deletion grace period. + // The grace period for deleting the subscription. If not set, will default to immediate deletion grace period. + // +kubebuilder:validation:Optional + CustomerManagedKeyDeletionGracePeriod *string `json:"customerManagedKeyDeletionGracePeriod,omitempty" tf:"customer_managed_key_deletion_grace_period,omitempty"` + + // Whether to enable the customer managed encryption key flow. + // Whether to enable CMK (customer managed key) for the subscription. If this is true, then the subscription will be put in a pending state until you supply the CMEK. See documentation for further details on this process. Defaults to false. + // +kubebuilder:validation:Optional + CustomerManagedKeyEnabled *bool `json:"customerManagedKeyEnabled,omitempty" tf:"customer_managed_key_enabled,omitempty"` + // The subscription's maintenance window specification, documented below. // Specify the subscription's maintenance windows // +kubebuilder:validation:Optional @@ -530,7 +595,7 @@ type SubscriptionParameters struct { // +kubebuilder:validation:Optional Name *string `json:"name,omitempty" tf:"name,omitempty"` - // card or marketplace). If credit-card is specified, payment_method_id must be defined. Default: 'credit-card'. (Changes to) this attribute are ignored after creation. + // card or marketplace). Must not be set for direct contracts. If credit-card is specified, payment_method_id must be defined. Default: 'credit-card'. (Changes to) this attribute are ignored after creation. // Payment method for the requested subscription. If credit card is specified, the payment method id must be defined. This information is only used when creating a new subscription and any changes will be ignored after this. // +kubebuilder:validation:Optional PaymentMethod *string `json:"paymentMethod,omitempty" tf:"payment_method,omitempty"` @@ -540,7 +605,7 @@ type SubscriptionParameters struct { // +kubebuilder:validation:Optional PaymentMethodID *string `json:"paymentMethodId,omitempty" tf:"payment_method_id,omitempty"` - // The Redis version of the databases in the subscription. If omitted, the Redis version will be the default. Modifying this attribute will force creation of a new resource. + // The Redis version of the databases in the subscription. If omitted, the Redis version will be the default. Deprecated: This attribute is deprecated on the subscriptions level. Please specify // Version of Redis to create // +kubebuilder:validation:Optional RedisVersion *string `json:"redisVersion,omitempty" tf:"redis_version,omitempty"` diff --git a/apis/subscription/v1alpha1/zz_database_types.go b/apis/subscription/v1alpha1/zz_database_types.go index 3461dc3..9c1b158 100755 --- a/apis/subscription/v1alpha1/zz_database_types.go +++ b/apis/subscription/v1alpha1/zz_database_types.go @@ -129,6 +129,10 @@ type DatabaseInitParameters struct { // Query performance factor for this specific database QueryPerformanceFactor *string `json:"queryPerformanceFactor,omitempty" tf:"query_performance_factor,omitempty"` + // The Redis version of the database. If omitted, the Redis version will be the default. + // Defines the Redis database version. If omitted, the Redis version will be set to the default version + RedisVersion *string `json:"redisVersion,omitempty" tf:"redis_version,omitempty"` + // block instead // An object that specifies the backup options for the database RemoteBackup []RemoteBackupInitParameters `json:"remoteBackup,omitempty" tf:"remote_backup,omitempty"` @@ -155,8 +159,17 @@ type DatabaseInitParameters struct { // The ID of the subscription to create the database in. Modifying this attribute will force creation of a new resource. // Identifier of the pro subscription + // +crossplane:generate:reference:type=github.com/RedisLabs/provider-rediscloud/apis/rediscloud/v1alpha1.Subscription SubscriptionID *float64 `json:"subscriptionId,omitempty" tf:"subscription_id,omitempty"` + // Reference to a Subscription in rediscloud to populate subscriptionId. + // +kubebuilder:validation:Optional + SubscriptionIDRef *v1.Reference `json:"subscriptionIdRef,omitempty" tf:"-"` + + // Selector for a Subscription in rediscloud to populate subscriptionId. + // +kubebuilder:validation:Optional + SubscriptionIDSelector *v1.Selector `json:"subscriptionIdSelector,omitempty" tf:"-"` + // Support Redis open-source (OSS) Cluster API. Default: ‘false’ // Support Redis open-source (OSS) Cluster API SupportOssClusterAPI *bool `json:"supportOssClusterApi,omitempty" tf:"support_oss_cluster_api,omitempty"` @@ -266,6 +279,10 @@ type DatabaseObservation struct { // Query performance factor for this specific database QueryPerformanceFactor *string `json:"queryPerformanceFactor,omitempty" tf:"query_performance_factor,omitempty"` + // The Redis version of the database. If omitted, the Redis version will be the default. + // Defines the Redis database version. If omitted, the Redis version will be set to the default version + RedisVersion *string `json:"redisVersion,omitempty" tf:"redis_version,omitempty"` + // block instead // An object that specifies the backup options for the database RemoteBackup []RemoteBackupObservation `json:"remoteBackup,omitempty" tf:"remote_backup,omitempty"` @@ -412,6 +429,11 @@ type DatabaseParameters struct { // +kubebuilder:validation:Optional QueryPerformanceFactor *string `json:"queryPerformanceFactor,omitempty" tf:"query_performance_factor,omitempty"` + // The Redis version of the database. If omitted, the Redis version will be the default. + // Defines the Redis database version. If omitted, the Redis version will be set to the default version + // +kubebuilder:validation:Optional + RedisVersion *string `json:"redisVersion,omitempty" tf:"redis_version,omitempty"` + // block instead // An object that specifies the backup options for the database // +kubebuilder:validation:Optional @@ -443,9 +465,18 @@ type DatabaseParameters struct { // The ID of the subscription to create the database in. Modifying this attribute will force creation of a new resource. // Identifier of the pro subscription + // +crossplane:generate:reference:type=github.com/RedisLabs/provider-rediscloud/apis/rediscloud/v1alpha1.Subscription // +kubebuilder:validation:Optional SubscriptionID *float64 `json:"subscriptionId,omitempty" tf:"subscription_id,omitempty"` + // Reference to a Subscription in rediscloud to populate subscriptionId. + // +kubebuilder:validation:Optional + SubscriptionIDRef *v1.Reference `json:"subscriptionIdRef,omitempty" tf:"-"` + + // Selector for a Subscription in rediscloud to populate subscriptionId. + // +kubebuilder:validation:Optional + SubscriptionIDSelector *v1.Selector `json:"subscriptionIdSelector,omitempty" tf:"-"` + // Support Redis open-source (OSS) Cluster API. Default: ‘false’ // Support Redis open-source (OSS) Cluster API // +kubebuilder:validation:Optional @@ -585,7 +616,6 @@ type Database struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` // +kubebuilder:validation:XValidation:rule="!('*' in self.managementPolicies || 'Create' in self.managementPolicies || 'Update' in self.managementPolicies) || has(self.forProvider.name) || (has(self.initProvider) && has(self.initProvider.name))",message="spec.forProvider.name is a required parameter" - // +kubebuilder:validation:XValidation:rule="!('*' in self.managementPolicies || 'Create' in self.managementPolicies || 'Update' in self.managementPolicies) || has(self.forProvider.subscriptionId) || (has(self.initProvider) && has(self.initProvider.subscriptionId))",message="spec.forProvider.subscriptionId is a required parameter" // +kubebuilder:validation:XValidation:rule="!('*' in self.managementPolicies || 'Create' in self.managementPolicies || 'Update' in self.managementPolicies) || has(self.forProvider.throughputMeasurementBy) || (has(self.initProvider) && has(self.initProvider.throughputMeasurementBy))",message="spec.forProvider.throughputMeasurementBy is a required parameter" // +kubebuilder:validation:XValidation:rule="!('*' in self.managementPolicies || 'Create' in self.managementPolicies || 'Update' in self.managementPolicies) || has(self.forProvider.throughputMeasurementValue) || (has(self.initProvider) && has(self.initProvider.throughputMeasurementValue))",message="spec.forProvider.throughputMeasurementValue is a required parameter" Spec DatabaseSpec `json:"spec"` diff --git a/apis/subscription/v1alpha1/zz_generated.deepcopy.go b/apis/subscription/v1alpha1/zz_generated.deepcopy.go index 6e76f8a..8b9a973 100644 --- a/apis/subscription/v1alpha1/zz_generated.deepcopy.go +++ b/apis/subscription/v1alpha1/zz_generated.deepcopy.go @@ -229,6 +229,11 @@ func (in *DatabaseInitParameters) DeepCopyInto(out *DatabaseInitParameters) { *out = new(string) **out = **in } + if in.RedisVersion != nil { + in, out := &in.RedisVersion, &out.RedisVersion + *out = new(string) + **out = **in + } if in.RemoteBackup != nil { in, out := &in.RemoteBackup, &out.RemoteBackup *out = make([]RemoteBackupInitParameters, len(*in)) @@ -273,6 +278,16 @@ func (in *DatabaseInitParameters) DeepCopyInto(out *DatabaseInitParameters) { *out = new(float64) **out = **in } + if in.SubscriptionIDRef != nil { + in, out := &in.SubscriptionIDRef, &out.SubscriptionIDRef + *out = new(v1.Reference) + (*in).DeepCopyInto(*out) + } + if in.SubscriptionIDSelector != nil { + in, out := &in.SubscriptionIDSelector, &out.SubscriptionIDSelector + *out = new(v1.Selector) + (*in).DeepCopyInto(*out) + } if in.SupportOssClusterAPI != nil { in, out := &in.SupportOssClusterAPI, &out.SupportOssClusterAPI *out = new(bool) @@ -477,6 +492,11 @@ func (in *DatabaseObservation) DeepCopyInto(out *DatabaseObservation) { *out = new(string) **out = **in } + if in.RedisVersion != nil { + in, out := &in.RedisVersion, &out.RedisVersion + *out = new(string) + **out = **in + } if in.RemoteBackup != nil { in, out := &in.RemoteBackup, &out.RemoteBackup *out = make([]RemoteBackupObservation, len(*in)) @@ -678,6 +698,11 @@ func (in *DatabaseParameters) DeepCopyInto(out *DatabaseParameters) { *out = new(string) **out = **in } + if in.RedisVersion != nil { + in, out := &in.RedisVersion, &out.RedisVersion + *out = new(string) + **out = **in + } if in.RemoteBackup != nil { in, out := &in.RemoteBackup, &out.RemoteBackup *out = make([]RemoteBackupParameters, len(*in)) @@ -722,6 +747,16 @@ func (in *DatabaseParameters) DeepCopyInto(out *DatabaseParameters) { *out = new(float64) **out = **in } + if in.SubscriptionIDRef != nil { + in, out := &in.SubscriptionIDRef, &out.SubscriptionIDRef + *out = new(v1.Reference) + (*in).DeepCopyInto(*out) + } + if in.SubscriptionIDSelector != nil { + in, out := &in.SubscriptionIDSelector, &out.SubscriptionIDSelector + *out = new(v1.Selector) + (*in).DeepCopyInto(*out) + } if in.SupportOssClusterAPI != nil { in, out := &in.SupportOssClusterAPI, &out.SupportOssClusterAPI *out = new(bool) diff --git a/apis/subscription/v1alpha1/zz_generated.resolvers.go b/apis/subscription/v1alpha1/zz_generated.resolvers.go new file mode 100644 index 0000000..0556600 --- /dev/null +++ b/apis/subscription/v1alpha1/zz_generated.resolvers.go @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2024 The Crossplane Authors +// +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by angryjet. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + v1alpha1 "github.com/RedisLabs/provider-rediscloud/apis/rediscloud/v1alpha1" + reference "github.com/crossplane/crossplane-runtime/pkg/reference" + errors "github.com/pkg/errors" + client "sigs.k8s.io/controller-runtime/pkg/client" +) + +// ResolveReferences of this Database. +func (mg *Database) ResolveReferences(ctx context.Context, c client.Reader) error { + r := reference.NewAPIResolver(c, mg) + + var rsp reference.ResolutionResponse + var err error + + rsp, err = r.Resolve(ctx, reference.ResolutionRequest{ + CurrentValue: reference.FromFloatPtrValue(mg.Spec.ForProvider.SubscriptionID), + Extract: reference.ExternalName(), + Reference: mg.Spec.ForProvider.SubscriptionIDRef, + Selector: mg.Spec.ForProvider.SubscriptionIDSelector, + To: reference.To{ + List: &v1alpha1.SubscriptionList{}, + Managed: &v1alpha1.Subscription{}, + }, + }) + if err != nil { + return errors.Wrap(err, "mg.Spec.ForProvider.SubscriptionID") + } + mg.Spec.ForProvider.SubscriptionID = reference.ToFloatPtrValue(rsp.ResolvedValue) + mg.Spec.ForProvider.SubscriptionIDRef = rsp.ResolvedReference + + rsp, err = r.Resolve(ctx, reference.ResolutionRequest{ + CurrentValue: reference.FromFloatPtrValue(mg.Spec.InitProvider.SubscriptionID), + Extract: reference.ExternalName(), + Reference: mg.Spec.InitProvider.SubscriptionIDRef, + Selector: mg.Spec.InitProvider.SubscriptionIDSelector, + To: reference.To{ + List: &v1alpha1.SubscriptionList{}, + Managed: &v1alpha1.Subscription{}, + }, + }) + if err != nil { + return errors.Wrap(err, "mg.Spec.InitProvider.SubscriptionID") + } + mg.Spec.InitProvider.SubscriptionID = reference.ToFloatPtrValue(rsp.ResolvedValue) + mg.Spec.InitProvider.SubscriptionIDRef = rsp.ResolvedReference + + return nil +} diff --git a/cluster/test/setup.sh b/cluster/test/setup.sh index 827aab3..16b7981 100755 --- a/cluster/test/setup.sh +++ b/cluster/test/setup.sh @@ -2,14 +2,20 @@ set -aeuo pipefail echo "Running setup.sh" -echo "Creating cloud credential secret..." -${KUBECTL} -n upbound-system create secret generic provider-secret --from-literal=credentials="${UPTEST_CLOUD_CREDENTIALS}" --dry-run=client -o yaml | ${KUBECTL} apply -f - +echo "Current directory: $(pwd)" -echo "Waiting until provider is healthy..." -${KUBECTL} wait provider.pkg --all --for condition=Healthy --timeout 5m +# Set up paths +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +TEST_DIR="${SCRIPT_DIR}" -echo "Waiting for all pods to come online..." -${KUBECTL} -n upbound-system wait --for=condition=Available deployment --all --timeout=5m +# Set default credentials if not provided +if [ -z "${UPTEST_CLOUD_CREDENTIALS:-}" ]; then + echo "UPTEST_CLOUD_CREDENTIALS not set, using default RedisCloud credentials from environment" + UPTEST_CLOUD_CREDENTIALS="{\"api_key\":\"${REDISCLOUD_API_KEY:-}\",\"secret_key\":\"${REDISCLOUD_SECRET_KEY:-}\",\"url\":\"${REDISCLOUD_URL:-https://api.redislabs.com/v1}\"}" +fi + +echo "Creating cloud credential secret..." +${KUBECTL} -n crossplane-system create secret generic provider-secret --from-literal=credentials="${UPTEST_CLOUD_CREDENTIALS}" --dry-run=client -o yaml | ${KUBECTL} apply -f - echo "Creating a default provider config..." cat < "${TEST_DIR}/datasource.yaml" < + meta.crossplane.io/source: github.com/redislabs/crossplane-provider-rediscloud + meta.crossplane.io/license: Apache-2.0 + meta.crossplane.io/description: The Redis Cloud Crossplane provider adds support for managing Redis Cloud resources in Kubernetes. + meta.crossplane.io/readme: | + The Redis Cloud provider for Crossplane enables infrastructure operators to manage Redis Cloud resources using Kubernetes custom resources. + + Available resources include subscriptions, databases, ACLs, and more. diff --git a/scripts/quick-start.sh b/scripts/quick-start.sh deleted file mode 100755 index bf7aef8..0000000 --- a/scripts/quick-start.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Quick start script for testing the RedisCloud provider -echo "🚀 RedisCloud Crossplane Provider Quick Start" -echo "============================================" -echo - -# Check if credentials are set -if [[ "${REDISCLOUD_API_KEY:-}" == "your-api-key-here" || -z "${REDISCLOUD_API_KEY:-}" ]]; then - echo "❌ RedisCloud credentials not configured!" - echo - echo "Please update your .envrc file with real credentials:" - echo " export REDISCLOUD_API_KEY=\"your-actual-api-key\"" - echo " export REDISCLOUD_SECRET_KEY=\"your-actual-secret-key\"" - echo - echo "Get credentials from: https://app.redislabs.com/#/login" - echo "Then run: direnv allow" - echo - exit 1 -fi - -echo "✅ Credentials configured" -echo "📦 Building provider..." - -# Build the provider -make build - -echo "🎯 Provider built successfully!" -echo -echo "🔧 Next steps:" -echo "1. Run the test script: ./scripts/test-provider.sh" -echo "2. Or run individual steps:" -echo " ./scripts/test-provider.sh cluster # Create kind cluster" -echo " ./scripts/test-provider.sh crossplane # Install Crossplane" -echo " ./scripts/test-provider.sh provider # Install provider" -echo " ./scripts/test-provider.sh config # Configure credentials" -echo " ./scripts/test-provider.sh test # Test with sample resource" -echo -echo "📊 Check status anytime with:" -echo " ./scripts/test-provider.sh status" -echo diff --git a/scripts/setup-podman.sh b/scripts/setup-podman.sh deleted file mode 100755 index 143b895..0000000 --- a/scripts/setup-podman.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -# Setup script to configure podman as a drop-in replacement for docker - -# Colors for output -GREEN='\033[0;32m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -echo -e "${BLUE}[INFO]${NC} Setting up podman environment..." - -# Start podman socket if not running -if ! systemctl --user is-active --quiet podman.socket; then - echo -e "${BLUE}[INFO]${NC} Starting podman socket..." - systemctl --user start podman.socket -fi - -# Export environment variables -export DOCKER_HOST="unix:///run/user/$(id -u)/podman/podman.sock" -export KIND_EXPERIMENTAL_PROVIDER=podman - -# Create docker alias if it doesn't exist -if ! command -v docker &> /dev/null; then - echo -e "${BLUE}[INFO]${NC} Creating docker alias to podman..." - alias docker=podman -fi - -echo -e "${GREEN}[SUCCESS]${NC} Podman environment configured!" -echo -echo "Environment variables set:" -echo " DOCKER_HOST=$DOCKER_HOST" -echo " KIND_EXPERIMENTAL_PROVIDER=$KIND_EXPERIMENTAL_PROVIDER" -echo -echo "To make these settings permanent, add them to your .envrc file" \ No newline at end of file diff --git a/scripts/test-provider.sh b/scripts/test-provider.sh deleted file mode 100755 index c765824..0000000 --- a/scripts/test-provider.sh +++ /dev/null @@ -1,362 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -# Logging functions -log_info() { - echo -e "${BLUE}[INFO]${NC} $1" -} - -log_success() { - echo -e "${GREEN}[SUCCESS]${NC} $1" -} - -log_warning() { - echo -e "${YELLOW}[WARNING]${NC} $1" -} - -log_error() { - echo -e "${RED}[ERROR]${NC} $1" -} - -# Configuration -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROJECT_DIR="$(dirname "$SCRIPT_DIR")" -KIND_CLUSTER_NAME="${KIND_CLUSTER_NAME:-rediscloud-test}" -CROSSPLANE_NAMESPACE="${CROSSPLANE_NAMESPACE:-crossplane-system}" -PROVIDER_NAMESPACE="${PROVIDER_NAMESPACE:-crossplane-system}" -KUBECONFIG_PATH="${KUBECONFIG_PATH:-${PROJECT_DIR}/.kube/config}" - -# Create .kube directory if it doesn't exist -mkdir -p "$(dirname "$KUBECONFIG_PATH")" -export KUBECONFIG="$KUBECONFIG_PATH" - -# Configure for podman -export KIND_EXPERIMENTAL_PROVIDER=podman -export DOCKER_HOST=${DOCKER_HOST:-unix:///run/user/$(id -u)/podman/podman.sock} - -# Cleanup function -cleanup() { - if [[ "${1:-}" != "keep" ]]; then - log_info "Cleaning up..." - kind delete cluster --name "$KIND_CLUSTER_NAME" 2>/dev/null || true - log_success "Cleanup completed" - fi -} - -# Trap cleanup on exit -trap cleanup EXIT - -# Function to wait for pods to be ready -wait_for_pods() { - local namespace="$1" - local app_label="$2" - local timeout="${3:-300}" - - log_info "Waiting for pods with label app=$app_label in namespace $namespace to be ready..." - kubectl wait --for=condition=ready pod -l "app=$app_label" -n "$namespace" --timeout="${timeout}s" || { - log_error "Pods failed to become ready within ${timeout}s" - kubectl get pods -n "$namespace" -l "app=$app_label" - kubectl describe pods -n "$namespace" -l "app=$app_label" - return 1 - } - log_success "Pods are ready" -} - -# Function to check if credentials are set -check_credentials() { - if [[ "${REDISCLOUD_API_KEY:-}" == "your-api-key-here" || -z "${REDISCLOUD_API_KEY:-}" ]]; then - log_warning "RedisCloud API key not set. Update REDISCLOUD_API_KEY in .envrc" - log_warning "Get credentials from: RedisCloud Console → Account Settings → API Keys" - return 1 - fi - - if [[ "${REDISCLOUD_SECRET_KEY:-}" == "your-secret-key-here" || -z "${REDISCLOUD_SECRET_KEY:-}" ]]; then - log_warning "RedisCloud secret key not set. Update REDISCLOUD_SECRET_KEY in .envrc" - return 1 - fi - - log_success "RedisCloud credentials are configured" - return 0 -} - -# Function to create kind cluster -create_kind_cluster() { - log_info "Creating kind cluster: $KIND_CLUSTER_NAME" - - # Set KIND_EXPERIMENTAL_PROVIDER to use podman - export KIND_EXPERIMENTAL_PROVIDER=podman - - if kind get clusters | grep -q "^$KIND_CLUSTER_NAME$"; then - log_info "Kind cluster $KIND_CLUSTER_NAME already exists" - kind export kubeconfig --name "$KIND_CLUSTER_NAME" --kubeconfig "$KUBECONFIG_PATH" - else - # Create kind cluster with registry support - cat </dev/null | head -1) - if [[ -z "$xpkg_file" ]]; then - log_error "No xpkg file found" - return 1 - fi - - # Import xpkg as OCI image - local image_tag="build-fbf0549c/provider-rediscloud-amd64:latest" - log_info "Importing xpkg as OCI image..." - - # Use podman to import the xpkg - podman load -i "$xpkg_file" || { - # If that doesn't work, try copying the xpkg as-is - log_info "Trying alternative load method..." - # The xpkg is already an OCI image, so we can import it - podman import "$xpkg_file" "$image_tag" - } - - # Load image into kind - kind load docker-image "$image_tag" --name "$KIND_CLUSTER_NAME" - - log_success "Provider image loaded into kind cluster" -} - -# Function to install provider -install_provider() { - log_info "Installing RedisCloud provider..." - - # Create provider installation - cat </dev/null || echo "No Essentials subscriptions found" - kubectl get subscription.rediscloud.redis.io 2>/dev/null || echo "No Pro subscriptions found" -} - -# Function to cleanup test resources -cleanup_test_resources() { - log_info "Cleaning up test resources..." - kubectl delete subscription test-subscription --ignore-not-found=true - log_success "Test resources cleaned up" -} - -# Main function -main() { - local action="${1:-all}" - - case "$action" in - "cluster") - create_kind_cluster - ;; - "crossplane") - install_crossplane - ;; - "provider") - load_provider_image - install_provider - ;; - "config") - create_credentials - create_provider_config - ;; - "test") - test_provider - ;; - "status") - show_status - ;; - "cleanup") - cleanup_test_resources - ;; - "all") - create_kind_cluster - install_crossplane - load_provider_image - install_provider - create_credentials - create_provider_config - show_status - log_success "Setup complete! Run '$0 test' to test the provider" - cleanup keep # Don't cleanup on successful completion - ;; - *) - echo "Usage: $0 [cluster|crossplane|provider|config|test|status|cleanup|all]" - echo - echo "Commands:" - echo " cluster - Create kind cluster" - echo " crossplane - Install Crossplane" - echo " provider - Load and install RedisCloud provider" - echo " config - Create credentials and ProviderConfig" - echo " test - Test provider with sample resource" - echo " status - Show cluster and provider status" - echo " cleanup - Clean up test resources" - echo " all - Run complete setup (default)" - echo - echo "Environment variables:" - echo " REDISCLOUD_API_KEY - Your RedisCloud API key" - echo " REDISCLOUD_SECRET_KEY - Your RedisCloud secret key" - echo " KIND_CLUSTER_NAME - Kind cluster name (default: rediscloud-test)" - exit 1 - ;; - esac -} - -# Run main function -main "$@" \ No newline at end of file