diff --git a/.env b/.env new file mode 100644 index 0000000..d0534d1 --- /dev/null +++ b/.env @@ -0,0 +1,7 @@ +CONDUKTOR_CONSOLE_IMAGE=conduktor/conduktor-console:1.27.0 +CONDUKTOR_CONSOLE_CORTEX_IMAGE=conduktor/conduktor-console-cortex:1.27.0 +CDK_BASE_URL=http://localhost:8080 +CDK_ADMIN_EMAIL=admin@conduktor.io +CDK_ADMIN_PASSWORD=test +CDK_DEBUG=false +TF_LOG_PROVIDER_CONDUKTOR=INFO diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 0000000..09e7b80 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +echo "Run fmt" +make go-fmt + +echo +echo "Run linters" +make go-lint diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..c457105 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @conduktor/engineering diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..8bf8897 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# See GitHub's documentation for more information on this file: +# https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates +version: 2 +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 0000000..d2bf8ac --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,67 @@ +name-template: "v$RESOLVED_VERSION" +tag-template: "v$RESOLVED_VERSION" + +version-resolver: + major: + labels: + - "major" + minor: + labels: + - "minor" + patch: + labels: + - "patch" + default: minor + +categories: + - title: "Features" + label: "enhancement" + - title: "Bug Fixes" + label: "bug" + - title: "Module updates" + label: "module-upgrade" + - title: "Dependency updates" + label: "dependencies" + +exclude-labels: + - "skip" + +autolabeler: + - label: "module-upgrade" + title: + - '/\[Bump\].*\[version\]/' + branch: + - "/update_.+/" + - label: "bug" + title: + - '/.*\[fix\].*/' + - label: "patch" + title: + - '/.*\[fix\].*/' + - label: "enhancement" + title: + - '/.*\[feat\].*/' + - label: "minor" + title: + - '/.*\[feat\].*/' + - label: "skip" + title: + - '/.*\[skip\].*/' + - label: "major" + title: + - '/.*\[breaking\].*/' + +replacers: + - search: '/\[feat\]/g' + replace: "" + - search: '/\[fix\]/g' + replace: "" + - search: '/\[skip\]/g' + replace: "" + - search: '/\[breaking\]/g' + replace: "" + +template: | + # What's Changed + + $CHANGES diff --git a/.github/workflows/draft.yml b/.github/workflows/draft.yml new file mode 100644 index 0000000..2061649 --- /dev/null +++ b/.github/workflows/draft.yml @@ -0,0 +1,17 @@ +name: Release Drafter + +on: + push: + branches: + - main + + pull_request: + types: [opened, reopened, synchronize] + +jobs: + update_release_draft: + runs-on: ubuntu-latest + steps: + - uses: release-drafter/release-drafter@v6.0.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..996f294 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,43 @@ +# Terraform Provider release workflow. +name: Release + +# This GitHub action creates a release when a tag that matches the pattern +# "v*" (e.g. v0.1.0) is created. +on: + push: + tags: + - "v*" + +# Releases need permissions to read and write the repository contents. +# GitHub considers creating releases and uploading assets as writing contents. +permissions: + contents: write + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + # Allow goreleaser to access older tag information. + fetch-depth: 0 + - uses: actions/setup-go@v5 + with: + go-version-file: "go.mod" + cache: true + - name: Import GPG key + uses: crazy-max/ghaction-import-gpg@v6 + id: import_gpg + with: + gpg_private_key: ${{ secrets.CONDUKTOR_BOT_GPG_PRIVATE_KEY }} + git_user_signingkey: true + git_commit_gpgsign: true + git_tag_gpgsign: true + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v6 + with: + args: release --clean + env: + # GitHub sets the GITHUB_TOKEN secret automatically. + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..f62b237 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,117 @@ +# Terraform Provider testing workflow. +name: Tests + +# This GitHub action runs your tests for each pull request and push. +# Optionally, you can turn it on using a schedule for regular testing. +on: + pull_request: + paths-ignore: + - "README.md" + push: + branches: + - main + paths-ignore: + - "README.md" + +# Testing only needs permissions to read the repository contents. +permissions: + contents: read + +jobs: + # Ensure project builds before running testing matrix + build: + name: Build + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: "go.mod" + cache: true + - run: go mod download + - run: go build -v . + - name: Run linters + uses: golangci/golangci-lint-action@v6 + with: + version: latest + + generate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: "go.mod" + cache: true + - uses: hashicorp/setup-terraform@v3.1.2 + with: + terraform_version: "1.9.5" + terraform_wrapper: false + - run: go generate ./... + - name: git diff + run: | + git diff --compact-summary --exit-code || \ + (echo; echo "Unexpected difference in directories after code generation. Run 'go generate ./...' command and commit."; exit 1) + + # Run acceptance tests in a matrix with Terraform CLI versions + test: + name: Terraform Provider Acceptance Tests + needs: build + runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + # list whatever Terraform versions here you would like to support + terraform: + - version: "1.0.*" + name: "TF-1.0" + - version: "1.9.*" + name: "TF-1.9" + console: + - "1.25.0" + - "1.26.0" + - "1.27.0" + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: "go.mod" + cache: true + - uses: hashicorp/setup-terraform@v3.1.2 + with: + terraform_version: ${{ matrix.terraform.version }} + terraform_wrapper: false + - run: go mod download + - run: make pull_test_assets + timeout-minutes: 10 + - name: Set License if not dependabot + run: | + if [ "${{ github.actor }}" != "dependabot[bot]" ]; then + echo "CDK_LICENSE=${{ secrets.TEST_LICENSE }}" >> "$GITHUB_ENV" + fi + - name: Run acceptance tests + env: + TF_ACC: "1" + TESTARGS: "-cover ./internal/provider/" + CONDUKTOR_CONSOLE_IMAGE: conduktor/conduktor-console:${{ matrix.console }} + CONDUKTOR_CONSOLE_CORTEX_IMAGE: conduktor/conduktor-console-cortex:${{ matrix.console }} + CDK_BASE_URL: http://localhost:8080 + CDK_ADMIN_EMAIL: admin@conduktor.io + CDK_ADMIN_PASSWORD: test + TF_LOG_PROVIDER_CONDUKTOR: DEBUG + timeout-minutes: 15 + run: | + # empty env to avoid any conflict with the current env + echo "" > .env + + make testacc + + - uses: actions/upload-artifact@v4 + if: always() + with: + name: api-logs-CDK-${{ matrix.console }}-${{ matrix.terraform.name }} + path: ./logs/ + if-no-files-found: error + retention-days: 1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fb20e2a --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +*.dll +*.exe +.DS_Store +example.tf +terraform.tfplan +terraform.tfstate +bin/ +dist/ +modules-dev/ +/pkg/ +website/.vagrant +website/.bundle +website/build +website/node_modules +.vagrant/ +*.backup +./*.tfstate +.terraform/ +*.log +*.bak +*~ +.*.swp +.idea +*.iml +*.test +*.iml +.envrc +logs/* + +website/vendor + +# Test exclusions +!command/test-fixtures/**/*.tfstate +!command/test-fixtures/**/.terraform/ + +# Keep windows files with windows line endings +*.winfile eol=crlf + +# ingore binary build +terraform-provider-conduktor diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..6301ca6 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,27 @@ +# Visit https://golangci-lint.run/ for usage documentation +# and information on other useful linters +issues: + max-per-linter: 0 + max-same-issues: 0 + +linters: + disable-all: true + enable: + - durationcheck + - errcheck + - copyloopvar + - forcetypeassert + - godot + - gofmt + - gosimple + - ineffassign + - makezero + - misspell + - nilerr + - predeclared + - staticcheck + - tenv + - unconvert + - unparam + - unused + - govet diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..13524d8 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,53 @@ +# Visit https://goreleaser.com for documentation on how to customize this +# behavior. +version: 2 +before: + hooks: [] +builds: + - env: + # goreleaser does not work with CGO, it could also complicate + # usage by users in CI/CD systems like HCP Terraform where + # they are unable to install libraries. + - CGO_ENABLED=0 + mod_timestamp: "{{ .CommitTimestamp }}" + flags: + - -trimpath + ldflags: + - "-s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}" + goos: + - windows + - linux + - darwin + goarch: + - amd64 + - arm64 + binary: "{{ .ProjectName }}_v{{ .Version }}" +archives: + - format: zip + name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" +checksum: + extra_files: + - glob: "terraform-registry-manifest.json" + name_template: "{{ .ProjectName }}_{{ .Version }}_manifest.json" + name_template: "{{ .ProjectName }}_{{ .Version }}_SHA256SUMS" + algorithm: sha256 +signs: + - artifacts: checksum + args: + # if you are using this in a GitHub action or some other automated pipeline, you + # need to pass the batch flag to indicate its not interactive. + - "--batch" + - "--local-user" + - "{{ .Env.GPG_FINGERPRINT }}" # set this environment variable for your signing key + - "--output" + - "${signature}" + - "--detach-sign" + - "${artifact}" +release: + extra_files: + - glob: "terraform-registry-manifest.json" + name_template: "{{ .ProjectName }}_{{ .Version }}_manifest.json" + # If you want to manually examine the release before its live, uncomment this line: + # draft: true +changelog: + disable: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..e795ca9 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,141 @@ + +# Contributing to terraform-provider-conduktor + +First off, thanks for taking the time to contribute! 鉂わ笍 + +All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 馃帀 + +> And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about: +> - Star the project +> - Tweet about it +> - Refer this project in your project's readme +> - Mention the project at local meetups and tell your friends/colleagues + + +## Table of Contents + +- [I Have a Question](#i-have-a-question) +- [I Want To Contribute](#i-want-to-contribute) +- [Reporting Bugs](#reporting-bugs) +- [Suggesting Enhancements](#suggesting-enhancements) +- [Your First Code Contribution](#your-first-code-contribution) +- [Improving The Documentation](#improving-the-documentation) +- [Styleguides](#styleguides) +- [Commit Messages](#commit-messages) +- [Join The Project Team](#join-the-project-team) + + + +## I Have a Question + +> If you want to ask a question, we assume that you have read the available [Documentation](https://docs.conduktor.io/). + +Before you ask a question, it is best to search for existing [Issues](https://github.com/conduktor/terraform-provider-conduktor/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first. + +If you then still feel the need to ask a question and need clarification, we recommend the following: + +- Open an [Issue](https://github.com/conduktor/terraform-provider-conduktor/issues/new). +- Provide as much context as you can about what you're running into. +- Provide project and platform versions (go, docker, etc), depending on what seems relevant. + +We will then take care of the issue as soon as possible. + +## I Want To Contribute + +### Reporting Bugs + + +#### Before Submitting a Bug Report + +A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible. + +- Make sure that you are using the latest version. +- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](https://docs.conduktor.io/). If you are looking for support, you might want to check [this section](#i-have-a-question)). +- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/conduktor/terraform-provider-conduktor/issues?q=label%3Abug). +- Collect information about the bug: + - Version of the conduktor-ctl you are using + - Version of Conduktor Console you are targeting + - Stack trace (Traceback) + - OS, Platform and Version (Windows, Linux, macOS, x86, ARM) + - Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant. + - Possibly your input and the output + - Can you reliably reproduce the issue? And can you also reproduce it with older versions? + + +#### How Do I Submit a Good Bug Report? + +> You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to [security@conduktor.io](). + +We use GitHub issues to track bugs and errors. If you run into an issue with the project: + +- Open an [Issue](https://github.com/conduktor/terraform-provider-conduktor/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.) +- Explain the behavior you would expect and the actual behavior. +- Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case. +- Provide the information you collected in the previous section. + +You can also contact us at [support@conduktor.io]() if you need help with the issue. + + +### Suggesting Enhancements + +This section guides you through submitting an enhancement suggestion for conduktor-ctl, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions. + + +#### Before Submitting an Enhancement + +- Make sure that you are using the latest version. +- Read the [documentation](https://docs.conduktor.io/) carefully and find out if the functionality is already covered, maybe by an individual configuration. +- Perform a [search](https://github.com/conduktor/terraform-provider-conduktor/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one. +- Search for similar suggestions in the [Conduktor Roadmap](https://product.conduktor.help/) and Submit an idea if it is not already there. +- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. + + +#### How Do I Submit a Good Enhancement Suggestion? + +Enhancement suggestions are tracked as [GitHub issues](https://github.com/conduktor/terraform-provider-conduktor/issues) or in [Conduktor Roadmap](https://product.conduktor.help/). + +- Use a **clear and descriptive title** for the issue to identify the suggestion. +- Provide a **step-by-step description of the suggested enhancement** in as many details as possible. +- **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you. +- **Explain why this enhancement would be useful** to most conduktor-ctl users. You may also want to point out the other projects that solved it better and which could serve as inspiration. + +### Your First Code Contribution + +To run the project locally, you will need Go 1.22+ installed and configured on your machine. +Here some useful commands to get you started: + +Install pre-commit git hooks: +```shell +make install-githooks +``` + +Run code formatting and linting: +```shell +make go-fmt +make go-lint +``` + +Build the provider locally: +```shell +make build +``` + +Deploy the provider locally on `~/.terraform.d/plugins/` directory: +```shell +make deploy-locally +``` + +Run acceptance tests: +This will start a local Conduktor Console instance and run the acceptance tests against it. +```shell +make testacc +``` + +Don't forget to run the tests to make sure everything is working as expected before submitting a pull request. + +## Styleguides +### Commit Messages +Use explicit commit message that follows the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification. This convention makes it easier to understand the changes in a project and to automate the versioning process. + + + diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..8541af1 --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,71 @@ +export SHELL:=/bin/bash +export SHELLOPTS:=$(if $(SHELLOPTS),$(SHELLOPTS):)pipefail:errexit + +include .env + +.ONESHELL: + +default: testacc + +.PHONY: help +help: ## Prints help for targets with comments + @cat $(MAKEFILE_LIST) | grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: install-githooks +install-githooks: ## Install git hooks + git config --local core.hooksPath .githooks + +.PHONY: build +build: ## Build the provider + go build + +.PHONY: deploy-locally +deploy-locally: ## Install the provider locally in ~/.terraform.d/plugins. Optional set VERSION arg to use specific verion, otherwise 0.0.1 will be used + "$(CURDIR)/scripts/deploy_locally.sh" $(VERSION) + +.PHONY: generate +generate: ## Run go generate + go generate ./... + +.PHONY: go-fmt +go-fmt: ## Run go fmt + go fmt ./... + +tools: + go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.60.2 + +.PHONY: go-lint +go-lint: tools ## Run Golang linters + @echo "==> Run Golang CLI linter..." + @golangci-lint run + +setup_test_env: + "$(CURDIR)/scripts/setup_test_env.sh" + +.PHONY: pull_test_assets +pull_test_assets: ## Pull test docker images + @docker compose -f "$(CURDIR)/docker-compose.yaml" pull + +.PHONY: start_test_env +start_test_env: ## Start test environment + "$(CURDIR)/scripts/start_test_env.sh" + "$(CURDIR)/scripts/wait_for_test_env_ready.sh" + $(MAKE) setup_test_env + +.PHONY: test +test: ## Run acceptance tests only (no setup or cleanup) + TF_ACC=1 go test ./... -v $(TESTARGS) -timeout 120m + +# Run acceptance tests +.PHONY: testacc +testacc: start_test_env ## Start test environment, run acceptance tests and clean up + @function tearDown { + $(MAKE) clean + } + @trap tearDown EXIT + + $(MAKE) test + +.PHONY: clean +clean: ## Clean up test environment + "$(CURDIR)/scripts/stop_test_env.sh" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1cd7a6d --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2024 Conduktor + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f8eebf8 --- /dev/null +++ b/README.md @@ -0,0 +1,269 @@ + + +

+ +

+

+ Conduktor Terraform Provider +

+ +

+ Explore the docs 禄 +
+
+ Report Bug + 路 + Request Feature + 路 + Contact support +
+
+ GitHub Release + 路 + License + 路 + Terraform registry +
+
+ Scale Data Streaming With Security and Control + 路 + X (formerly Twitter) Follow + 路 + Slack +

+ +This repository contains the Conduktor Terraform provider, which defines Conduktor resources so that they can be deployed using Infrastructure as Code (IaC). + +> [!WARNING] +> - The Conduktor Terraform provider is currently in **Alpha**. +> - It does not support all Console and Gateway resources yet. See our [resources roadmap](#resources-roadmap). +> - Let us know if you have [feedback](https://product.conduktor.help/c/74-terraform-provider) or wish to be a design partner. + +## Supported resources + +- [Console user](./docs/resources/user_v2.md) +- [Console group](./docs/resources/group_v2.md) +- [Generic](./docs/resources/generic.md) :warning: This resource is experimental and should be used with care. + +## Install + +Provider should be installed automatically with `terraform init`, but it's recommended to pin a specific version or range of version using following [`required_providers` configuration](https://developer.hashicorp.com/terraform/language/providers/requirements) : + +```hcl +terraform { + required_providers { + conduktor = { + source = "conduktor/conduktor" + version = "~> X.Y" # where X.Y is the current major version and minor version + } + } +} +``` + +## Usage/Examples + + +```hcl +# configure provider +provider "conduktor" { + console_url = "http://localhost:8080" + api_token = "your-api-key" # can also use admin email/password to authenticate. +} + +# register an external user bob with PLATFORM.userView permission +resource "conduktor_user_v2" "bob" { + name = "bob@mycompany.io" + spec { + firstname = "Bob" + lastname = "Smith" + permissions = [ + { + permissions = [ "userView" ] + resource_type = "PLATFORM" + }, + ] + } +} + +# create a group with Bob as a member +resource "conduktor_group_v2" "qa" { + name = "qa" + spec { + display_name = "QA team" + description = "Quality Assurance team" + members = [ conduktor_user_v2.bob.name ] + permissions = [ + { + resource_type = "PLATFORM" + permissions = ["userView", "clusterConnectionsManage"] + } + ] + } +} +``` + +You can find more examples in this repository inside [`example`](./examples/) directory. + +Examples can also be found in provider reference documentation available either in [`docs`](./docs/) directory or at [registry.terraform.io/conduktor/conduktor](https://registry.terraform.io/conduktor/conduktor/latest/docs) + +You can also check out our [documentation](https://docs.conduktor.io/) for resources reference and provider usage. + +### Provider authentication + +To use Conduktor Console API, the Terraform provider needs to authenticate against it. + +For that we offer two possibilities: + +#### API key + +Use an already manually forged API key. See [documentation](https://docs.conduktor.io/platform/reference/api-reference/#generate-an-api-key) to create one. + +Using HCL `api_token` attribute +```hcl +provider "conduktor" { + api_token = "your-api-key" +} +``` +Using environment variables `CDK_API_TOKEN` or `CDK_API_KEY`. + +#### Admin credentials +Use local user (usually admin) credentials pair. This will login against the API and use an ephemeral access token to make API calls. + + +Using HCL `admin_email`/`admin_password` attributes +```hcl +provider "conduktor" { + admin_email = "admin@my-org.com" + admin_password = "admin-password" +} +``` +Using environment variables `CDK_ADMIN_EMAIL` or `CDK_ADMIN_PASSWORD`. + +Either way be aware that API Key and admin credentials are sensitive data and should be stored and provided to Terraform [properly](https://developer.hashicorp.com/terraform/tutorials/configuration-language/sensitive-variables). + +## Development +### Requirements + +- [Terraform](https://developer.hashicorp.com/terraform/downloads) >= 1.0 +- [Go](https://golang.org/doc/install) >= 1.23 +- [Docker](https://docs.docker.com/get-docker/) with compose to run acceptance tests locally +- [Git hooks](#install-git-hooks) to format/lint code before committing + + +### Install git hooks +Please install the git hooks to ensure that the code is formatted correctly and pass linter check before committing. + +Run `make install-githooks` to install the git hooks. + +### Building The Provider + +1. Clone the repository +1. Enter the repository directory +1. Build the provider using the Go `install` command: + +```shell +go install +``` + +#### Build and install provider in local Terraform registry + +Will build and install terraform provider locally in `~/.terraform.d/plugins` directory. +Local provider version is set on `VERSION` variable of [GNUmakefile](./GNUmakefile) + +```shell +VERSION=0.0.1 make deploy-locally +``` +It can then be used on terraform recipe like +```hcl +terraform { + required_providers { + conduktor = { + source = "terraform.local/conduktor/conduktor" # local provider + version = ">= 0.0.1" # latest version found locally in the plugin cache. + } + } +} +``` + +### Adding Dependencies + +This provider uses [Go modules](https://github.com/golang/go/wiki/Modules). +Please see the Go documentation for the most up to date information about using Go modules. + +To add a new dependency `github.com/author/dependency` to your Terraform provider: + +```shell +go get github.com/author/dependency +go mod tidy +``` + +Then commit the changes to `go.mod` and `go.sum`. + +### Codegen + +The project uses different codegen tool to generate source files. + +**Documentation** in [`docs`](./docs/) folder is generated using [tfplugindocs](github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs) + +**Terraform schema definition** in [`schema`](./internal/schema/) module are generated using [tfplugingen-framework](github.com/hashicorp/terraform-plugin-codegen-framework/cmd/tfplugingen-framework) from currently manually maintained code spec [json file](./provider_code_spec.json). + +### Run acceptance tests + +```shell +# Optional +export CDK_LICENSE="your_license_here" +make testacc +``` +This action will start a testing environment using [Docker Compose](./docker-compose.yaml) and run all acceptance tests against it. Test environment is destroy at the end. + +You can also start/stop environment and run tests in separate actions using `make start_test_env` / `make test` / `make clean`. + +### Misc + +```shell +make generate # run go generate +make build # run build +make go-fmt # run go fmt on the project +make go-lint # run golangci-lint linter +``` + +## Resources Roadmap + +Future versions of the Conduktor Terraform provider will evolve to support more resources. + +Need a resource to unblock a use case? [Feedback](https://product.conduktor.help/c/74-terraform-provider) to the Product team directly. + +Our current order of priority is: + +1. Console resources: + - [Kafka Clusters with Schema Regsitry](https://docs.conduktor.io/platform/reference/resource-reference/console/#kafkacluster) + - [Kafka Connect Cluster](https://docs.conduktor.io/platform/reference/resource-reference/console/#kafkaconnectcluster) +2. Kafka resources: + - [Topic](https://docs.conduktor.io/platform/reference/resource-reference/kafka/#topic) + - [Subject](https://docs.conduktor.io/platform/reference/resource-reference/kafka/#subject) + - [Connector](https://docs.conduktor.io/platform/reference/resource-reference/kafka/#connector) +3. Self-service resources: + - [Application](https://docs.conduktor.io/platform/reference/resource-reference/self-service/#application) + - [ApplicationInstance](https://docs.conduktor.io/platform/reference/resource-reference/self-service/#application-instance) + - [TopicPolicy](https://docs.conduktor.io/platform/reference/resource-reference/self-service/#topic-policy) + - [ApplicationInstancePermission](https://docs.conduktor.io/platform/reference/resource-reference/self-service/#application-instance-permissions) + - [ApplicationGroup](https://docs.conduktor.io/platform/reference/resource-reference/self-service/#application-group) +4. Gateway resources: + - [Interceptor](https://docs.conduktor.io/gateway/reference/resources-reference/#interceptor) + - [GatewayServiceAccount](https://docs.conduktor.io/gateway/reference/resources-reference/#gatewayserviceaccount) + - [GatewayGroup](https://docs.conduktor.io/gateway/reference/resources-reference/#gatewaygroup) + - [ConcentrationRule](https://docs.conduktor.io/gateway/reference/resources-reference/#concentrationrule) + - [VirtualCluster](https://docs.conduktor.io/gateway/reference/resources-reference/#virtualcluster) + - [AliasTopic](https://docs.conduktor.io/gateway/reference/resources-reference/#aliastopic) + +> [!NOTE] +> +> This list is not exaustive and can change depending on requests and needs. + +## Contributing + +Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests to us. + +## License + +This project is licensed under the Apache 2.0 License - see the [LICENSE](LICENSE) file for details. diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..7e3dc1f --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,63 @@ +services: + postgresql: + image: postgres:14 + hostname: postgresql + volumes: + - pg_data:/var/lib/postgresql/data + environment: + POSTGRES_DB: "conduktor-console" + POSTGRES_USER: "conduktor" + POSTGRES_PASSWORD: "change_me" + POSTGRES_HOST_AUTH_METHOD: "scram-sha-256" + healthcheck: + test: + [ + "CMD", + "pg_isready", + "-U", + "conduktor", + "-d", + "conduktor-console", + "-h", + "localhost", + "-p", + "5432", + ] + interval: 10s + timeout: 5s + retries: 5 + + conduktor-console: + image: ${CONDUKTOR_CONSOLE_IMAGE} + depends_on: + postgresql: + condition: service_healthy + conduktor-monitoring: + condition: service_healthy + ports: + - "8080:8080" + volumes: + - conduktor_data:/var/conduktor + environment: + - CDK_LICENSE # forward from the environment if set + - CDK_DEBUG # forward from the environment if set + - CDK_ADMIN_EMAIL=${CDK_ADMIN_EMAIL:-admin@conduktor.io} + - CDK_ADMIN_PASSWORD=${CDK_ADMIN_PASSWORD:-test} + - CDK_DATABASE_URL=postgresql://conduktor:change_me@postgresql:5432/conduktor-console + - CDK_MONITORING_CORTEX-URL=http://conduktor-monitoring:9009/ + - CDK_MONITORING_ALERT-MANAGER-URL=http://conduktor-monitoring:9010/ + - CDK_MONITORING_CALLBACK-URL=http://conduktor-platform:8080/monitoring/api/ + - CDK_MONITORING_NOTIFICATIONS-CALLBACK-URL=http://localhost:8080 + healthcheck: + test: ["CMD", "/opt/conduktor/scripts/healthcheck.sh"] + + conduktor-monitoring: + image: ${CONDUKTOR_CONSOLE_CORTEX_IMAGE} + environment: + CDK_CONSOLE-URL: "http://conduktor-console:8080" + healthcheck: + test: ["CMD", "/opt/conduktor/scripts/healthcheck.sh"] + +volumes: + pg_data: {} + conduktor_data: {} diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..cb2427f --- /dev/null +++ b/docs/index.md @@ -0,0 +1,53 @@ +--- +page_title: "Provider: Conduktor" +subcategory: "" +description: |- + The Conduktor provider is used to interact with the resources supported by Conduktor. The provider needs to be configured with the proper credentials before it can be used. +--- + +# Conduktor Provider + +The Conduktor provider is used to interact with the resources supported by Conduktor. The provider needs to be configured with the proper credentials before it can be used. + +> [!WARNING] +> - The Conduktor Terraform provider is currently in **Alpha**. +> - It does not support all Console and Gateway resources yet. See our [resources roadmap](https://github.com/conduktor/terraform-provider-conduktor/blob/main/README.md#resources-roadmap). +> - Let us know if you have [feedback](https://product.conduktor.help/c/74-terraform-provider) or wish to be a design partner. + +## Example Usage + +```terraform +provider "conduktor" { + # mandatory console URL + console_url = "http://localhost:8080" # or env vars CDK_CONSOLE_URL or CDK_BASE_URL + + # authentication either with api token or admin credentials + api_token = "your-api-token" # or env var CDK_API_TOKEN or CDK_API_KEY + #admin_email = "admin@my-org.com" # or env var CDK_ADMIN_EMAIL + #admin_password = "admin-password" # or env var CDK_ADMIN_PASSWORD + + # optional http client TLS configuration + cert = file("path/to/cert.pem") # or env var CDK_CERT + insecure = true # or env var CDK_INSECURE + + # optional authentication via certificate + key = file("path/to/key.pem") # or env var CDK_KEY + cacert = file("path/to/ca.pem") # or env var CDK_CA_CERT +} +``` + + +## Schema + +### Optional + +- `admin_email` (String) The email of the admin user. May be set using environment variable `CDK_ADMIN_EMAIL`. Required if admin_password is set. If not provided, the API token will be used to authenticate. +- `admin_password` (String, Sensitive) The password of the admin user. May be set using environment variable `CDK_ADMIN_PASSWORD`. Required if admin_email is set. If not provided, the API token will be used to authenticater. +- `api_token` (String, Sensitive) The API token to authenticate with the Conduktor API. May be set using environment variable `CDK_API_TOKEN` or `CDK_API_KEY`. If not provided, admin_email and admin_password will be used to authenticate. See [documentation](https://docs.conduktor.io/platform/reference/api-reference/#generate-an-api-key) for more information. +- `cacert` (String) Root CA certificate in PEM format to verify the Conduktor Console certificate. May be set using environment variable `CDK_CACERT`. If not provided, the system's root CA certificates will be used. +- `cert` (String) Cert in PEM format to authenticate using client certificates. May be set using environment variable `CDK_CERT`. Must be used with key. If key is provided, cert is required. Useful when Console behind a reverse proxy with client certificate authentication. +- `console_url` (String) The URL of the Conduktor Console. May be set using environment variable `CDK_BASE_URL` or `CDK_CONSOLE_URL`. Required either here or in the environment. +- `insecure` (Boolean) Skip TLS verification flag. May be set using environment variable `CDK_INSECURE`. +- `key` (String) Key in PEM format to authenticate using client certificates. May be set using environment variable `CDK_KEY`. Must be used with cert. If cert is provided, key is required. Useful when Console behind a reverse proxy with client certificate authentication. + + diff --git a/docs/resources/generic.md b/docs/resources/generic.md new file mode 100644 index 0000000..fc623b6 --- /dev/null +++ b/docs/resources/generic.md @@ -0,0 +1,104 @@ +--- +page_title: "Condutkor : conduktor_generic " +description: |- + Generic Resource that use manifests in YAML format. + This resource allows you to create, read, update and delete any resource supported by Conduktor Console. +--- + +# conduktor_generic + +Generic Resource that use manifests in YAML format. +This resource allows you to create, read, update and delete any resource supported by Conduktor Console. + +> **Caution** +> +> This resource is experimental and have many [limitations](#limitations) and might have breaking changes in next releases. +> Be aware that using it to manage production environement is not recommended as it will cause [migrations](./migrations-notes) issues in future. + +## Example Usage + +### Using embedded YAML string +```terraform +resource "conduktor_generic" "example" { + kind = "User" + version = "v2" + name = "bob@company.io" + manifest = < +## Schema + +### Required + +- `kind` (String) resource kind +- `manifest` (String) resource manifest in yaml format. See [reference documentation](https://docs.conduktor.io/platform/reference/resource-reference/console/#manifests) for more details +- `name` (String) resource name +- `version` (String) resource version + +### Optional + +- `cluster` (String) resource parent cluster (if any) + + + + +## Limitations + +Current limitation of this resource are : + +- `import` is not supported. +- `plan` after `apply` show changes because of YAML automatic formatting and ordering. +- only support Console resources for now + +## Migrations notes + +In future releases, this terraform provider will support more and more typed resources and you might end up migrating a resource from this generic resource to the typed one. + +This migration can only be done by destroying previous resource on Conduktor and recreate it after using the new typed resouce. + +Because of that you will need to be extra careful of the current state of the resource before doing migrations. diff --git a/docs/resources/group_v2.md b/docs/resources/group_v2.md new file mode 100644 index 0000000..a82e178 --- /dev/null +++ b/docs/resources/group_v2.md @@ -0,0 +1,111 @@ +--- +page_title: "Condutkor : conduktor_group_v2 " +subcategory: "iam/v2" +description: |- + Resource for managing Conduktor groups. + This resource allows you to create, read, update and delete groups in Conduktor. +--- + +# conduktor_group_v2 + +Resource for managing Conduktor groups. +This resource allows you to create, read, update and delete groups in Conduktor. + +## Example Usage + +### Simple group without members or permissions +```terraform +resource "conduktor_group_v2" "example" { + name = "simple-group" + spec { + display_name = "Simple Group" + description = "Simple group description" + members = [] + permissions = [] + } +} +``` + +### Complex group with members, external reference and permissions +```terraform +resource "conduktor_user_v2" "user1" { + name = "user1@company.com" + spec { + firstname = "User" + lastname = "1" + permissions = [] + } +} + +resource "conduktor_group_v2" "example" { + name = "complex-group" + spec { + display_name = "Complex group" + description = "Complex group description" + external_groups = ["sso-group1"] + members = [conduktor_user_v2.user1.name] + permissions = [ + { + resource_type = "PLATFORM" + permissions = ["userView", "datamaskingView", "auditLogView"] + }, + { + resource_type = "TOPIC" + name = "test-topic" + cluster = "*" + pattern_type = "LITERAL" + permissions = ["topicViewConfig", "topicConsume", "topicProduce"] + } + ] + } +} +``` + + + +## Schema + +### Required + +- `name` (String) Group name, must be unique, act as ID for import + +### Optional + +- `spec` (Block, Optional) (see [below for nested schema](#nestedblock--spec)) + + +### Nested Schema for `spec` + +Required: + +- `display_name` (String) Group display name +- `permissions` (Attributes List) Set of all group permissions (see [below for nested schema](#nestedatt--spec--permissions)) + +Optional: + +- `description` (String) Group description +- `external_groups` (List of String) List of external groups from SSO mapped to this group +- `members` (List of String) List of members of the group + +Read-Only: + +- `members_from_external_groups` (List of String) List of members of the group + + +### Nested Schema for `spec.permissions` + +Required: + +- `permissions` (List of String) Set of all permissions to apply on the resource. See https://docs.conduktor.io/platform/reference/resource-reference/console/#permissions for more details +- `resource_type` (String) Type of the resource to apply permission on valid values are: CLUSTER, CONSUMER_GROUP, KAFKA_CONNECT, KSQLDB, PLATFORM, SUBJECT, TOPIC + +Optional: + +- `cluster` (String) Name of the cluster to apply permission, only required if resource_type is TOPIC, SUBJECT, CONSUMER_GROUP, KAFKA_CONNECT, KSQLDB +- `kafka_connect` (String) Name of the Kafka Connect to apply permission, only required if resource_type is KAFKA_CONNECT +- `name` (String) Name of the resource to apply permission could be a topic, a cluster, a consumer group, etc. depending on resource_type +- `pattern_type` (String) Type of the pattern to apply permission on valid values are: LITERAL, PREFIXED + + + + diff --git a/docs/resources/user_v2.md b/docs/resources/user_v2.md new file mode 100644 index 0000000..55bedb0 --- /dev/null +++ b/docs/resources/user_v2.md @@ -0,0 +1,90 @@ +--- +page_title: "Condutkor : conduktor_user_v2 " +subcategory: "iam/v2" +description: |- + Resource for managing Conduktor users. + This resource allows you to create, read, update and delete users in Conduktor. +--- + +# conduktor_user_v2 + +Resource for managing Conduktor users. +This resource allows you to create, read, update and delete users in Conduktor. + +## Example Usage + +### Simple user without permissions +```terraform +resource "conduktor_user_v2" "example" { + name = "bob@company.io" + spec { + firstname = "Bob" + lastname = "Smith" + permissions = [] + } +} +``` + +### Complex user with permissions +```terraform +resource "conduktor_user_v2" "example" { + name = "bob@company.io" + spec { + firstname = "Bob" + lastname = "Smith" + permissions = [ + { + resource_type = "PLATFORM" + permissions = ["userView", "datamaskingView", "auditLogView"] + }, + { + resource_type = "TOPIC" + name = "test-topic" + cluster = "*" + pattern_type = "LITERAL" + permissions = ["topicViewConfig", "topicConsume", "topicProduce"] + } + ] + } +} +``` + + + +## Schema + +### Required + +- `name` (String) User email, must be unique, act as ID for import + +### Optional + +- `spec` (Block, Optional) (see [below for nested schema](#nestedblock--spec)) + + +### Nested Schema for `spec` + +Required: + +- `firstname` (String) User firstname +- `lastname` (String) User lastname +- `permissions` (Attributes List) Set of all user permissions (see [below for nested schema](#nestedatt--spec--permissions)) + + +### Nested Schema for `spec.permissions` + +Required: + +- `permissions` (List of String) Set of all permissions to apply on the resource. See https://docs.conduktor.io/platform/reference/resource-reference/console/#permissions for more details +- `resource_type` (String) Type of the resource to apply permission on valid values are: CLUSTER, CONSUMER_GROUP, KAFKA_CONNECT, KSQLDB, PLATFORM, SUBJECT, TOPIC + +Optional: + +- `cluster` (String) Name of the cluster to apply permission, only required if resource_type is TOPIC, SUBJECT, CONSUMER_GROUP, KAFKA_CONNECT, KSQLDB +- `kafka_connect` (String) Name of the Kafka Connect to apply permission, only required if resource_type is KAFKA_CONNECT +- `name` (String) Name of the resource to apply permission could be a topic, a cluster, a consumer group, etc. depending on resource_type +- `pattern_type` (String) Type of the pattern to apply permission on valid values are: LITERAL, PREFIXED + + + + diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..026c42c --- /dev/null +++ b/examples/README.md @@ -0,0 +1,9 @@ +# Examples + +This directory contains examples that are mostly used for documentation, but can also be run/tested manually via the Terraform CLI. + +The document generation tool looks for files in the following locations by default. All other *.tf files besides the ones mentioned below are ignored by the documentation tool. This is useful for creating examples that can run and/or ar testable even if some parts are not relevant for the documentation. + +* **provider/provider.tf** example file for the provider index page +* **data-sources/`full data source name`/data-source.tf** example file for the named data source page +* **resources/`full resource name`/resource.tf** example file for the named data source page diff --git a/examples/provider/provider.tf b/examples/provider/provider.tf new file mode 100644 index 0000000..481ce8f --- /dev/null +++ b/examples/provider/provider.tf @@ -0,0 +1,17 @@ +provider "conduktor" { + # mandatory console URL + console_url = "http://localhost:8080" # or env vars CDK_CONSOLE_URL or CDK_BASE_URL + + # authentication either with api token or admin credentials + api_token = "your-api-token" # or env var CDK_API_TOKEN or CDK_API_KEY + #admin_email = "admin@my-org.com" # or env var CDK_ADMIN_EMAIL + #admin_password = "admin-password" # or env var CDK_ADMIN_PASSWORD + + # optional http client TLS configuration + cert = file("path/to/cert.pem") # or env var CDK_CERT + insecure = true # or env var CDK_INSECURE + + # optional authentication via certificate + key = file("path/to/key.pem") # or env var CDK_KEY + cacert = file("path/to/ca.pem") # or env var CDK_CA_CERT +} diff --git a/examples/resources/conduktor_generic/cluster_a.yaml b/examples/resources/conduktor_generic/cluster_a.yaml new file mode 100644 index 0000000..b299d55 --- /dev/null +++ b/examples/resources/conduktor_generic/cluster_a.yaml @@ -0,0 +1,9 @@ +#cluster_a.yaml +apiVersion: v2 +kind: KafkaCluster +metadata: + name: cluster_a +spec: + displayName: "Cluster A" + bootstrapServers: "localhost:9092" + ignoreUntrustedCertificate: false diff --git a/examples/resources/conduktor_generic/embedded.tf b/examples/resources/conduktor_generic/embedded.tf new file mode 100644 index 0000000..7483be3 --- /dev/null +++ b/examples/resources/conduktor_generic/embedded.tf @@ -0,0 +1,28 @@ +resource "conduktor_generic" "example" { + kind = "User" + version = "v2" + name = "bob@company.io" + manifest = < envs. +func GetStringConfig(configValue basetypes.StringValue, envs []string) string { + if !configValue.IsNull() { + return configValue.ValueString() + } + for _, env := range envs { + if value := os.Getenv(env); value != "" { + return value + } + } + return "" +} + +// Provider bool configuration extracted from the schema and environment variables. +// Priority order: configValue > envs > fallback. +func GetBooleanConfig(configValue basetypes.BoolValue, envs []string, fallback bool) bool { + if !configValue.IsNull() { + return configValue.ValueBool() + } + for _, env := range envs { + if value := os.Getenv(env); value != "" { + if b, err := strconv.ParseBool(value); err == nil { + return b + } + } + } + + return fallback +} + +// Convert a string to a basetypes.StringValue. +func NewStringValue(s string) basetypes.StringValue { + if s == "" { + return basetypes.NewStringNull() + } + return basetypes.NewStringValue(s) +} + +// Convert a ListValue to a string array. +func ListValueToStringArray(ctx context.Context, list basetypes.ListValue) ([]string, diag.Diagnostics) { + if list.IsNull() { + return nil, diag.Diagnostics{} + } + + var result []string + diag := list.ElementsAs(ctx, &result, false) + return result, diag +} + +// Convert a string array to a ListValue. +func StringArrayToListValue(array []string) (basetypes.ListValue, diag.Diagnostics) { + + var values []attr.Value + for _, f := range array { + values = append(values, types.StringValue(f)) + } + + return types.ListValue(types.StringType, values) +} diff --git a/internal/schema/validation/schema_validation.go b/internal/schema/validation/schema_validation.go new file mode 100644 index 0000000..a792e93 --- /dev/null +++ b/internal/schema/validation/schema_validation.go @@ -0,0 +1,47 @@ +package validation + +var ValidPermissions = []string{ + "clusterViewBroker", + "clusterEditSRCompatibility", + "clusterEditBroker", + "clusterViewACL", + "clusterManageACL", + "kafkaConnectorViewConfig", + "kafkaConnectorStatus", + "kafkaConnectorEditConfig", + "kafkaConnectorDelete", + "kafkaConnectorCreate", + "kafkaConnectPauseResume", + "kafkaConnectRestart", + "ksqldbAccess", + "consumerGroupView", + "consumerGroupReset", + "consumerGroupDelete", + "consumerGroupCreate", + "auditLogView", + "taasView", + "certificateManage", + "userManage", + "clusterConnectionsManage", + "notificationChannelManage", + "datamaskingView", + "userView", + "testingView", + "datamaskingManage", + "taasManage", + "notificationChannelView", + "subjectCreateUpdate", + "subjectEditCompatibility", + "subjectDelete", + "subjectView", + "topicViewConfig", + "topicEmpty", + "topicConsume", + "topicProduce", + "topicEditConfig", + "topicCreate", + "topicAddPartition", + "topicDelete", +} +var ValidPermissionTypes = []string{"CLUSTER", "CONSUMER_GROUP", "KAFKA_CONNECT", "KSQLDB", "PLATFORM", "SUBJECT", "TOPIC"} +var ValidPermissionPatternTypes = []string{"LITERAL", "PREFIXED"} diff --git a/internal/test/test_helpers.go b/internal/test/test_helpers.go new file mode 100644 index 0000000..4e131ae --- /dev/null +++ b/internal/test/test_helpers.go @@ -0,0 +1,75 @@ +package test + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "strings" + "testing" +) + +// Helper to read testdata files into string. +func TestAccTestdata(t *testing.T, path string) string { + t.Helper() + + _, currentFile, _, ok := runtime.Caller(0) + if !ok { + t.Fatal("could not get current file") + } + example, err := os.ReadFile(filepath.Join(filepath.Dir(currentFile), "..", "testdata", path)) + if err != nil { + t.Fatal(err) + } + return string(example) +} + +// Helper to read examples files into string. +// path is defined relative to examples directory. +func TestAccExample(t *testing.T, path ...string) string { + t.Helper() + + _, currentFile, _, ok := runtime.Caller(0) + if !ok { + t.Fatal("could not get current file") + } + pathFragments := append([]string{filepath.Dir(currentFile), "..", "..", "examples"}, path...) + example, err := os.ReadFile(filepath.Join(pathFragments...)) + if err != nil { + t.Fatal(err) + } + return string(example) +} + +// Check if a string contains all expected values. +func TestCheckResourceAttrContainsStringsFunc(expected ...string) func(value string) error { + return func(value string) error { + for _, e := range expected { + if !strings.Contains(value, e) { + return fmt.Errorf("expected manifest to contain %q", e) + } + } + return nil + } +} + +// Check if license is setup in env to enable some tests behind license. +func CheckEnterpriseEnabled(t *testing.T) { + if !(os.Getenv("CDK_LICENSE") != "") { + t.Skip("Skipping TestAccGroupV2Resource tests in free mode as it requires a license set on CDK_LICENSE env var") + } +} + +// Provider configuration pre-checks. +func TestAccPreCheck(t *testing.T) { + // check that the environment variables are set + if os.Getenv("CDK_BASE_URL") == "" { + t.Fatal("CDK_BASE_URL must be set for acceptance tests") + } + if os.Getenv("CDK_ADMIN_EMAIL") == "" { + t.Fatal("CDK_ADMIN_EMAIL must be set for acceptance tests") + } + if os.Getenv("CDK_ADMIN_PASSWORD") == "" { + t.Fatal("CDK_ADMIN_PASSWORD must be set for acceptance tests") + } +} diff --git a/internal/testdata/generic_resource_create_embedded.tf b/internal/testdata/generic_resource_create_embedded.tf new file mode 100644 index 0000000..35433d5 --- /dev/null +++ b/internal/testdata/generic_resource_create_embedded.tf @@ -0,0 +1,21 @@ + +resource "conduktor_generic" "embedded" { + kind = "User" + version = "v2" + name = "jim.halpert@dunder.mifflin.com" + manifest = < ./logs/docker-compose.log + +echo "Stopping the containers and removing volumes" +docker compose -f ${SCRIPT_DIR}/../docker-compose.yaml down -v diff --git a/scripts/wait_for_test_env_ready.sh b/scripts/wait_for_test_env_ready.sh new file mode 100755 index 0000000..7581103 --- /dev/null +++ b/scripts/wait_for_test_env_ready.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -eu + +# get the container name +CONSOLE_CONTAINER_ID=$(docker container ls -a --filter "name=conduktor-console" --filter "status=running" --format "{{.ID}}") + +echo "Waiting for the Conduktor Console container $CONSOLE_CONTAINER_ID to be ready..." +until [ "$(docker inspect -f {{.State.Health.Status}} "$CONSOLE_CONTAINER_ID")" == "healthy" ]; do + sleep 1; + printf "." +done; +echo "Conduktor Console container is ready!" diff --git a/templates/index.md.tmpl b/templates/index.md.tmpl new file mode 100644 index 0000000..d519e72 --- /dev/null +++ b/templates/index.md.tmpl @@ -0,0 +1,21 @@ +--- +page_title: "Provider: Conduktor" +subcategory: "" +description: |- + The Conduktor provider is used to interact with the resources supported by Conduktor. The provider needs to be configured with the proper credentials before it can be used. +--- + +# Conduktor Provider + +The Conduktor provider is used to interact with the resources supported by Conduktor. The provider needs to be configured with the proper credentials before it can be used. + +> [!WARNING] +> - The Conduktor Terraform provider is currently in **Alpha**. +> - It does not support all Console and Gateway resources yet. See our [resources roadmap](https://github.com/conduktor/terraform-provider-conduktor/blob/main/README.md#resources-roadmap). +> - Let us know if you have [feedback](https://product.conduktor.help/c/74-terraform-provider) or wish to be a design partner. + +## Example Usage + +{{tffile "examples/provider/provider.tf"}} + +{{ .SchemaMarkdown }} diff --git a/templates/resources/generic.md.tmpl b/templates/resources/generic.md.tmpl new file mode 100644 index 0000000..1e126bf --- /dev/null +++ b/templates/resources/generic.md.tmpl @@ -0,0 +1,44 @@ +--- +page_title: "Condutkor : conduktor_generic " +description: |- + Generic Resource that use manifests in YAML format. + This resource allows you to create, read, update and delete any resource supported by Conduktor Console. +--- + +# {{ .Name }} + +Generic Resource that use manifests in YAML format. +This resource allows you to create, read, update and delete any resource supported by Conduktor Console. + +> **Caution** +> +> This resource is experimental and have many [limitations](#limitations) and might have breaking changes in next releases. +> Be aware that using it to manage production environement is not recommended as it will cause [migrations](./migrations-notes) issues in future. + +## Example Usage + +### Using embedded YAML string +{{tffile "examples/resources/conduktor_generic/embedded.tf"}} + +### Using incuded YAML string +{{tffile "examples/resources/conduktor_generic/include.tf"}} +{{codefile "yaml" "examples/resources/conduktor_generic/cluster_a.yaml"}} + +{{ .SchemaMarkdown }} + + +## Limitations + +Current limitation of this resource are : + +- `import` is not supported. +- `plan` after `apply` show changes because of YAML automatic formatting and ordering. +- only support Console resources for now + +## Migrations notes + +In future releases, this terraform provider will support more and more typed resources and you might end up migrating a resource from this generic resource to the typed one. + +This migration can only be done by destroying previous resource on Conduktor and recreate it after using the new typed resouce. + +Because of that you will need to be extra careful of the current state of the resource before doing migrations. diff --git a/templates/resources/group_v2.md.tmpl b/templates/resources/group_v2.md.tmpl new file mode 100644 index 0000000..2f1e8f2 --- /dev/null +++ b/templates/resources/group_v2.md.tmpl @@ -0,0 +1,23 @@ +--- +page_title: "Condutkor : conduktor_group_v2 " +subcategory: "iam/v2" +description: |- + Resource for managing Conduktor groups. + This resource allows you to create, read, update and delete groups in Conduktor. +--- + +# {{ .Name }} + +Resource for managing Conduktor groups. +This resource allows you to create, read, update and delete groups in Conduktor. + +## Example Usage + +### Simple group without members or permissions +{{tffile "examples/resources/conduktor_group_v2/simple.tf"}} + +### Complex group with members, external reference and permissions +{{tffile "examples/resources/conduktor_group_v2/complex.tf"}} + + +{{ .SchemaMarkdown }} diff --git a/templates/resources/user_v2.md.tmpl b/templates/resources/user_v2.md.tmpl new file mode 100644 index 0000000..6a9e860 --- /dev/null +++ b/templates/resources/user_v2.md.tmpl @@ -0,0 +1,23 @@ +--- +page_title: "Condutkor : conduktor_user_v2 " +subcategory: "iam/v2" +description: |- + Resource for managing Conduktor users. + This resource allows you to create, read, update and delete users in Conduktor. +--- + +# {{ .Name }} + +Resource for managing Conduktor users. +This resource allows you to create, read, update and delete users in Conduktor. + +## Example Usage + +### Simple user without permissions +{{tffile "examples/resources/conduktor_user_v2/simple.tf"}} + +### Complex user with permissions +{{tffile "examples/resources/conduktor_user_v2/complex.tf"}} + + +{{ .SchemaMarkdown }} diff --git a/terraform-registry-manifest.json b/terraform-registry-manifest.json new file mode 100644 index 0000000..fec2a56 --- /dev/null +++ b/terraform-registry-manifest.json @@ -0,0 +1,6 @@ +{ + "version": 1, + "metadata": { + "protocol_versions": ["6.0"] + } +} diff --git a/testdata/init/init.yaml b/testdata/init/init.yaml new file mode 100644 index 0000000..c94f919 --- /dev/null +++ b/testdata/init/init.yaml @@ -0,0 +1 @@ +# Init manifests are used to initialize Console with the necessary resources using CLI. diff --git a/tools/tools.go b/tools/tools.go new file mode 100644 index 0000000..c379e19 --- /dev/null +++ b/tools/tools.go @@ -0,0 +1,12 @@ +//go:build tools + +package tools + +import ( + + // Documentation generation + _ "github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs" + + // Terraform plugin code generation + _ "github.com/hashicorp/terraform-plugin-codegen-framework/cmd/tfplugingen-framework" +)