├── .air.toml ├── .githooks └── pre-commit ├── .github ├── CODEOWNERS ├── actions │ ├── cleanup-aws │ │ └── action.yaml │ ├── cleanup-clickhouse │ │ └── action.yaml │ ├── e2e │ │ └── action.yaml │ ├── find-tf-releases │ │ └── action.yaml │ ├── import │ │ └── action.yaml │ └── list-examples │ │ └── action.yaml ├── dependabot.yaml ├── scripts │ └── set_api_env.sh └── workflows │ ├── autolabel.yaml │ ├── docs.yaml │ ├── e2e.yaml │ ├── fmt.yaml │ ├── import.yaml │ ├── release.yaml │ ├── stale.yml │ ├── test.yaml │ └── tidy.yaml ├── .gitignore ├── .golangci.yml ├── .goreleaser-alpha.yml ├── .goreleaser-stable.yml ├── LICENSE ├── Makefile ├── README.md ├── development └── README.md ├── docs ├── data-sources │ ├── api_key_id.md │ └── private_endpoint_config.md ├── index.md └── resources │ ├── private_endpoint_registration.md │ ├── service.md │ ├── service_private_endpoints_attachment.md │ └── service_transparent_data_encryption_key_association.md ├── examples ├── clickpipe │ ├── README.md │ ├── externally_managed_table │ │ ├── README.md │ │ ├── main.tf │ │ ├── provider.tf │ │ ├── provider.tf.template.alpha │ │ └── variables.sample.tfvars │ ├── kafka_azure_eventhub │ │ ├── README.md │ │ ├── main.tf │ │ ├── provider.tf │ │ ├── provider.tf.template.alpha │ │ └── variables.sample.tfvars │ ├── kafka_confluent │ │ ├── README.md │ │ ├── main.tf │ │ ├── provider.tf │ │ ├── provider.tf.template.alpha │ │ └── variables.sample.tfvars │ ├── kafka_msk_iam_role │ │ ├── README.md │ │ ├── main.tf │ │ ├── provider.tf │ │ ├── provider.tf.template.alpha │ │ └── variables.sample.tfvars │ ├── kafka_msk_iam_user │ │ ├── README.md │ │ ├── main.tf │ │ ├── provider.tf │ │ ├── provider.tf.template.alpha │ │ └── variables.sample.tfvars │ ├── kafka_offset_strategy │ │ ├── README.md │ │ ├── main.tf │ │ ├── provider.tf │ │ ├── provider.tf.template.alpha │ │ └── variables.sample.tfvars │ ├── kafka_redpanda_scram │ │ ├── README.md │ │ ├── main.tf │ │ ├── provider.tf │ │ ├── provider.tf.template.alpha │ │ └── variables.sample.tfvars │ ├── kafka_schema_registry │ │ ├── README.md │ │ ├── main.tf │ │ ├── provider.tf │ │ ├── provider.tf.template.alpha │ │ └── variables.sample.tfvars │ ├── multiple_pipes_example │ │ ├── README.md │ │ ├── main.tf │ │ ├── provider.tf │ │ ├── provider.tf.template.alpha │ │ └── variables.sample.tfvars │ ├── object_storage_iam_role │ │ ├── README.md │ │ ├── main.tf │ │ ├── provider.tf │ │ ├── provider.tf.template.alpha │ │ └── variables.sample.tfvars │ ├── object_storage_iam_user │ │ ├── README.md │ │ ├── main.tf │ │ ├── provider.tf │ │ ├── provider.tf.template.alpha │ │ └── variables.sample.tfvars │ ├── reverse_private_endpoint_msk │ │ ├── main.tf │ │ ├── provider.tf │ │ ├── provider.tf.template.alpha │ │ └── variables.sample.tfvars │ ├── reverse_private_endpoint_msk_pipe │ │ ├── clickpipe.tf │ │ ├── provider.tf │ │ ├── provider.tf.template.alpha │ │ ├── reverse_private_endpoint.tf │ │ ├── variables.sample.tfvars │ │ └── vars.tf │ ├── reverse_private_endpoint_vpc_resource │ │ ├── main.tf │ │ ├── provider.tf │ │ ├── provider.tf.template.alpha │ │ └── variables.sample.tfvars │ ├── reverse_private_endpoint_vpce_service │ │ ├── main.tf │ │ ├── provider.tf │ │ ├── provider.tf.template.alpha │ │ └── variables.sample.tfvars │ └── service_and_clickpipe │ │ ├── README.md │ │ ├── main.tf │ │ ├── provider.tf │ │ ├── provider.tf.template.alpha │ │ └── variables.sample.tfvars ├── data-sources │ └── clickhouse_api_key_id │ │ └── data-source.tf ├── database │ ├── README.md │ ├── main.tf │ ├── provider.tf │ ├── provider.tf.template.alpha │ └── variables.tfvars.sample ├── full │ ├── README.md │ ├── basic │ │ ├── aws │ │ │ ├── README.md │ │ │ ├── main.tf │ │ │ ├── provider.tf │ │ │ ├── provider.tf.template │ │ │ └── variables.tfvars.sample │ │ ├── azure │ │ │ ├── README.md │ │ │ ├── main.tf │ │ │ ├── provider.tf │ │ │ ├── provider.tf.template │ │ │ └── variables.tfvars.sample │ │ └── gcp │ │ │ ├── README.md │ │ │ ├── main.tf │ │ │ ├── provider.tf │ │ │ ├── provider.tf.template │ │ │ └── variables.tfvars.sample │ ├── private_endpoint │ │ └── aws │ │ │ ├── README.md │ │ │ ├── aws.tf │ │ │ ├── main.tf │ │ │ ├── provider.tf │ │ │ ├── provider.tf.template │ │ │ └── variables.tfvars.sample │ ├── tde │ │ ├── aws │ │ │ ├── README.md │ │ │ ├── aws.tf │ │ │ ├── main.tf │ │ │ ├── provider.tf │ │ │ ├── provider.tf.template │ │ │ └── variables.tfvars.sample │ │ └── gcp │ │ │ ├── README.md │ │ │ ├── main.tf │ │ │ ├── provider.tf │ │ │ ├── provider.tf.template │ │ │ └── variables.tfvars.sample │ └── warehouse │ │ └── aws │ │ ├── README.md │ │ ├── main.tf │ │ ├── provider.tf │ │ ├── provider.tf.template │ │ └── variables.tfvars.sample ├── provider │ ├── provider.tf │ └── provider.tf.template ├── rbac │ ├── README.md │ ├── main.tf │ ├── provider.tf │ ├── provider.tf.template.alpha │ └── variables.tfvars.sample └── resources │ ├── clickhouse_clickpipe │ ├── import.sh │ └── resource.tf │ ├── clickhouse_clickpipes_reverse_private_endpoint │ ├── import.sh │ └── resource.tf │ ├── clickhouse_service │ ├── import.sh │ └── resource.tf │ ├── clickhouse_service_private_endpoints_attachment │ ├── import.sh │ └── resource.tf │ └── clickhouse_service_transparent_data_encryption_key_association │ ├── import.sh │ └── resource.tf ├── go.mod ├── go.sum ├── main.go ├── pkg ├── datasource │ ├── api_key_id.go │ ├── descriptions │ │ └── api_key_id.md │ └── private_endpoint_config.go ├── internal │ ├── api │ │ ├── api_keys.go │ │ ├── backup_configuration.go │ │ ├── clickpipe.go │ │ ├── clickpipe_models.go │ │ ├── clickpipe_reverse_private_endpoint.go │ │ ├── clickpipe_reverse_private_endpoint_models.go │ │ ├── client.go │ │ ├── client_mock.go │ │ ├── client_test.go │ │ ├── common.go │ │ ├── constants.go │ │ ├── database.go │ │ ├── db_grant_privilege.go │ │ ├── db_grant_privilege_test.go │ │ ├── db_grant_role.go │ │ ├── db_role.go │ │ ├── db_user.go │ │ ├── errors.go │ │ ├── interface.go │ │ ├── models.go │ │ ├── password.go │ │ ├── private_endpoints.go │ │ ├── query_endpoints.go │ │ ├── scaling.go │ │ └── service.go │ ├── planmodifier │ │ └── usestateforunknownexcept.go │ ├── sql │ │ └── sql.go │ ├── test │ │ └── updater.go │ ├── tfutils │ │ └── utils.go │ └── tools │ │ └── tools.go ├── project │ └── project.go ├── provider │ ├── README.md │ └── provider.go └── resource │ ├── clickpipe.go │ ├── clickpipe_reverse_private_endpoint.go │ ├── data │ └── grants.tsv │ ├── database.go │ ├── descriptions │ ├── database.md │ ├── grant_privilege.md │ ├── grant_role.md │ ├── role.md │ ├── service.md │ ├── service_transparent_data_encryption_key_association.md │ └── user.md │ ├── grant_privilege.go │ ├── grant_role.go │ ├── models │ ├── clickpipe_resource.go │ ├── clickpipe_reverse_private_endpoint_resource.go │ ├── database_resource.go │ ├── grant_privilege.go │ ├── grant_role.go │ ├── private_endpoint_registration.go │ ├── role.go │ ├── service_private_endpoints_attachment.go │ ├── service_resource.go │ ├── service_resource_test.go │ ├── service_transparent_data_encryption_key_association.go │ └── user.go │ ├── private_endpoint_registration.go │ ├── register_debug.go │ ├── register_stable.go │ ├── role.go │ ├── service.go │ ├── service_private_endpoints_attachment.go │ ├── service_test.go │ ├── service_transparent_data_encryption_key_association.go │ └── user.go ├── terraform-registry-manifest.json ├── tests └── import │ └── service │ ├── main.tf │ ├── provider.tf │ └── provider.tf.template └── tmp └── .gitignore /.air.toml: -------------------------------------------------------------------------------- 1 | root = "." 2 | testdata_dir = "testdata" 3 | tmp_dir = "tmp" 4 | 5 | [build] 6 | args_bin = [] 7 | bin = "./tmp/terraform-provider-clickhouse" 8 | cmd = "go build -tags alpha -o ./tmp/terraform-provider-clickhouse ." 9 | delay = 1000 10 | exclude_dir = ["tmp"] 11 | exclude_file = [] 12 | exclude_regex = ["_test.go"] 13 | exclude_unchanged = false 14 | follow_symlink = false 15 | full_bin = "" 16 | include_dir = [ "pkg" ] 17 | include_ext = ["go", "tpl", "tmpl", "html"] 18 | include_file = [] 19 | kill_delay = "0s" 20 | log = "build-errors.log" 21 | poll = false 22 | poll_interval = 0 23 | post_cmd = [] 24 | pre_cmd = [] 25 | rerun = false 26 | rerun_delay = 500 27 | send_interrupt = false 28 | stop_on_error = false 29 | 30 | [color] 31 | app = "" 32 | build = "yellow" 33 | main = "magenta" 34 | runner = "green" 35 | watcher = "cyan" 36 | 37 | [log] 38 | main_only = false 39 | time = false 40 | 41 | [misc] 42 | clean_on_exit = false 43 | 44 | [proxy] 45 | app_port = 0 46 | enabled = false 47 | proxy_port = 0 48 | 49 | [screen] 50 | clear_on_rebuild = false 51 | keep_scroll = true 52 | -------------------------------------------------------------------------------- /.githooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ( 4 | start=$(date +%s) 5 | echo "========== Started pre-commit git hook at $(date -R) ==========" 6 | (make fmt) 7 | (make docs) 8 | (make build) 9 | exit_code=$? 10 | end=$(date +%s) 11 | echo "========== Finished pre-commit git hook with error code $exit_code at $(date -R). The duration is $((end - start)) second(-s) ==========" 12 | exit $exit_code 13 | ) 14 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | 2 | * @ClickHouse/sre 3 | -------------------------------------------------------------------------------- /.github/actions/cleanup-aws/action.yaml: -------------------------------------------------------------------------------- 1 | name: "Cleanup AWS leftovers" 2 | description: "Cleanup any AWS leftovers of e2e test" 3 | inputs: 4 | service_name: 5 | required: true 6 | description: "The full name of the service for filtering purposes" 7 | aws_role_arn: 8 | required: true 9 | description: "The ARN of the AWS role to assume for AWS tests" 10 | aws_region: 11 | required: true 12 | description: "The AWS region to use for AWS tests" 13 | 14 | runs: 15 | using: "composite" 16 | steps: 17 | - name: Configure AWS credentials 18 | id: aws-auth 19 | uses: aws-actions/configure-aws-credentials@v4 20 | with: 21 | role-to-assume: ${{ inputs.aws_role_arn }} 22 | aws-region: ${{ inputs.aws_region }} 23 | 24 | - name: Cleanup AWS 25 | shell: bash 26 | run: | 27 | echo "::group::Deleting VPC Endpoints" 28 | attempts=10 29 | while [ $attempts -gt 0 ]; do 30 | attempts=$((attempts - 1)) 31 | endpointids="$(aws ec2 --region ${{ inputs.aws_region }} describe-vpc-endpoints|jq --arg name "${{ inputs.service_name }}" -r '.VpcEndpoints[] | select(.Tags[0].Value == $name) | .VpcEndpointId')" 32 | if [ "$endpointids" == "" ] 33 | then 34 | break 35 | fi 36 | 37 | echo "Deleting endpoints $endpointids" 38 | for endpointid in $endpointids 39 | do 40 | echo "Deleting vpc endpoint $endpointid" 41 | aws ec2 --region "${{ inputs.aws_region }}" delete-vpc-endpoints --vpc-endpoint-ids "$endpointid" 42 | done 43 | 44 | sleep 60 45 | done 46 | echo "::endgroup::" 47 | 48 | echo "::group::Deleting Security Groups" 49 | sgids="$(aws ec2 --region "${{ inputs.aws_region }}" describe-security-groups|jq --arg name "${{ inputs.service_name }}" -r '.SecurityGroups[] | select(.Tags[0].Value == $name) | .GroupId')" 50 | for sgid in $sgids 51 | do 52 | echo "Deleting SG $sgid" 53 | aws ec2 --region "${{ inputs.aws_region }}" delete-security-group --group-id "$sgid" 54 | done 55 | echo "::endgroup::" 56 | 57 | echo "::group::Deleting Subnets" 58 | subnetids="$(aws ec2 --region "${{ inputs.aws_region }}" describe-subnets|jq --arg name "${{ inputs.service_name }}" -r '.Subnets[] | select(.Tags[0].Value == $name) | .SubnetId')" 59 | for subnetid in $subnetids 60 | do 61 | echo "Deleting subnet $subnetid" 62 | aws ec2 --region "${{ inputs.aws_region }}" delete-subnet --subnet-id "$subnetid" 63 | done 64 | echo "::endgroup::" 65 | 66 | echo "::group::Deleting VPCs" 67 | vpcids="$(aws ec2 --region "${{ inputs.aws_region }}" describe-vpcs|jq --arg name "${{ inputs.service_name }}" -r '.Vpcs[] | select(.Tags[0].Value == $name) | .VpcId')" 68 | for vpcid in $vpcids 69 | do 70 | echo "Deleting vpc $vpcid" 71 | aws ec2 --region "${{ inputs.aws_region }}" delete-vpc --vpc-id "$vpcid" 72 | done 73 | echo "::endgroup::" 74 | -------------------------------------------------------------------------------- /.github/actions/cleanup-clickhouse/action.yaml: -------------------------------------------------------------------------------- 1 | name: "Cleanup leftovers" 2 | description: "Cleanup any leftovers of e2e test" 3 | inputs: 4 | api_url: 5 | required: false 6 | description: "Full URL of the API service to use. Defaults to the production API endpoint https://api.clickhouse.cloud/v1" 7 | default: "" 8 | organization_id: 9 | required: true 10 | description: "The clickhouse organization ID" 11 | token_key: 12 | required: true 13 | description: "The clickhouse token key" 14 | token_secret: 15 | required: true 16 | description: "The clickhouse token secret" 17 | token: 18 | required: true 19 | description: "The unique token assigned to this e2e run" 20 | 21 | runs: 22 | using: "composite" 23 | steps: 24 | - name: cleanup clikchouse 25 | shell: bash 26 | run: | 27 | api_url="${{ inputs.api_url }}" 28 | if [ "$api_url" == "" ] 29 | then 30 | api_url="https://api.clickhouse.cloud/v1" 31 | fi 32 | organization_id="${{ inputs.organization_id }}" 33 | token_key="${{ inputs.token_key }}" 34 | token_secret="${{ inputs.token_secret }}" 35 | suffix="${{ inputs.token }}" 36 | 37 | echo "Deleting any service with suffix ${suffix}" 38 | 39 | while :; do 40 | output="$(curl -su ${token_key}:${token_secret} ${api_url}/organizations/${organization_id}/services)" 41 | ids=$(echo "$output"|jq --arg suffix "${suffix}" -r '.result[]| select(.name | endswith($suffix)) |(.id + "," + .state)') 42 | 43 | if [ "$ids" == "" ] 44 | then 45 | break 46 | fi 47 | 48 | count="$(echo "$ids"|wc -l)" 49 | echo "There are ${count} services to be cleaned up" 50 | 51 | for idandstatus in $ids 52 | do 53 | id="$(echo "${idandstatus}" | cut -d"," -f1)" 54 | status="$(echo "${idandstatus}" | cut -d"," -f2)" 55 | 56 | case "$status" in 57 | stopped) 58 | echo "Deleting service ${id}" 59 | curl -su ${token_key}:${token_secret} -XDELETE "${api_url}/organizations/${organization_id}/services/${id}" -o /dev/null 60 | ;; 61 | stopping) 62 | echo "Service ${id} is stopping, waiting" 63 | ;; 64 | *) 65 | echo "Stopping service ${id}" 66 | curl -su ${token_key}:${token_secret} -XPATCH "${api_url}/organizations/${organization_id}/services/${id}/state" --data '{"command": "stop"}' -H 'Content-Type: application/json' -o /dev/null 67 | ;; 68 | esac 69 | done 70 | 71 | sleep 5 72 | done 73 | 74 | echo "Cleanup complete" 75 | -------------------------------------------------------------------------------- /.github/actions/find-tf-releases/action.yaml: -------------------------------------------------------------------------------- 1 | name: "Find terraform releases" 2 | description: "Return names of latest terraform cli releases" 3 | inputs: 4 | count: 5 | required: false 6 | default: "3" 7 | description: "The number of releases to return" 8 | 9 | outputs: 10 | releases: 11 | description: "The json encoded array of release names" 12 | value: ${{steps.find-tf-releases.outputs.releases}} 13 | 14 | runs: 15 | using: "composite" 16 | steps: 17 | - shell: bash 18 | id: find-tf-releases 19 | run: | 20 | all="$(curl -s -L -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/hashicorp/terraform/releases?per_page=100| jq -r '.[]|.name'|sort -V -r)" 21 | 22 | want=${{inputs.count}} 23 | 24 | versions=() 25 | current_nopatch="" 26 | for candidate in $all 27 | do 28 | # only keep final releases such as x.y.z 29 | if [[ $candidate =~ ^v?(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then 30 | candidate=${candidate#v} 31 | 32 | # Keep major.minor for each release to check if it changes since last iteration 33 | nopatch="$(echo "$candidate" | cut -d "." -f1).$(echo "$candidate" | cut -d "." -f2)" 34 | 35 | if [ "$nopatch" != "${current_nopatch}" ]; then 36 | # First time we see this major.minor, this is a good candidate 37 | versions+=(${candidate}) 38 | current_nopatch=${nopatch} 39 | fi 40 | fi 41 | [ ${#versions[@]} -ge $want ] && break 42 | done 43 | 44 | json="$(printf '%s\n' "${versions[@]}" | jq -R . | jq -cs .)" 45 | echo "releases=${json}" >> "$GITHUB_OUTPUT" 46 | -------------------------------------------------------------------------------- /.github/actions/list-examples/action.yaml: -------------------------------------------------------------------------------- 1 | name: "List examples to be used by e2e tests" 2 | description: "Return JSON array with a list of examples defined" 3 | inputs: 4 | ignore: 5 | required: false 6 | description: "Regex to match against example names. Matched examples won't be returned. Empty regex does nothing." 7 | default: "" 8 | 9 | outputs: 10 | examples: 11 | description: "The json encoded array of examples defined, split by provider" 12 | value: ${{steps.list.outputs.examples}} 13 | 14 | runs: 15 | using: "composite" 16 | steps: 17 | - shell: bash 18 | id: list 19 | env: 20 | ignoreRegex: "${{ inputs.ignore }}" 21 | run: | 22 | examples="$(echo '[]' | jq .)" 23 | pushd examples/full 24 | for candidate in $(ls -1 .) 25 | do 26 | if [[ ! -z "$ignoreRegex" ]] && [[ "$candidate" =~ "$ignoreRegex" ]]; then 27 | echo "skipping $candidate..." 28 | continue 29 | fi 30 | if [ -d $candidate ] 31 | then 32 | cloud_providers=() 33 | pushd $candidate 34 | for cloud in $(ls -1 .) 35 | do 36 | if [ -d $cloud ] 37 | then 38 | examples="$(echo "$examples" | jq -c --arg name "$candidate" --arg cloud "$cloud" '.[. | length] = { "name": $name, "cloud": $cloud }')" 39 | fi 40 | done 41 | popd 42 | fi 43 | done 44 | popd 45 | echo "examples=${examples}" >> "$GITHUB_OUTPUT" 46 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gomod 4 | directory: / 5 | schedule: 6 | interval: daily -------------------------------------------------------------------------------- /.github/scripts/set_api_env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | api_url=${api_url:-""} 6 | organization_id=${organization_id:-""} 7 | api_key_id=${api_key_id:-""} 8 | api_key_secret=${api_key_secret:-""} 9 | aws_region=${aws_region:-""} 10 | azure_region=${azure_region:-""} 11 | gcp_region=${gcp_region:-""} 12 | 13 | cloud="$1" 14 | region="" 15 | 16 | # When this script is called by the cron schedule inputs are empty so we default to Production. 17 | ENV=${api_env:-"Production"} 18 | 19 | case "${ENV}" in 20 | Production) 21 | api_url="$(echo "${api_env_production}" | jq -r .api_url)" 22 | organization_id="$(echo "${api_env_production}" | jq -r .organization_id)" 23 | api_key_id="$(echo "${api_env_production}" | jq -r .api_key_id)" 24 | api_key_secret="$(echo "${api_env_production}" | jq -r .api_key_secret)" 25 | if [ "$cloud" != "" ]; then 26 | region="$(echo "${api_env_production}" | jq -rc --arg cloud $cloud '.regions[$cloud]' | jq -c '.[]' | shuf -n 1 |jq -r .)" 27 | fi 28 | ;; 29 | 30 | Staging) 31 | api_url="$(echo "${api_env_staging}" | jq -r .api_url)" 32 | organization_id="$(echo "${api_env_staging}" | jq -r .organization_id)" 33 | api_key_id="$(echo "${api_env_staging}" | jq -r .api_key_id)" 34 | api_key_secret="$(echo "${api_env_staging}" | jq -r .api_key_secret)" 35 | if [ "$cloud" != "" ]; then 36 | region="$(echo "${api_env_staging}" | jq -rc --arg cloud $cloud '.regions[$cloud]' | jq -c '.[]' | shuf -n 1 |jq -r .)" 37 | fi 38 | ;; 39 | 40 | Development) 41 | api_url="$(echo "${api_env_development}" | jq -r .api_url)" 42 | organization_id="$(echo "${api_env_development}" | jq -r .organization_id)" 43 | api_key_id="$(echo "${api_env_development}" | jq -r .api_key_id)" 44 | api_key_secret="$(echo "${api_env_development}" | jq -r .api_key_secret)" 45 | if [ "$cloud" != "" ]; then 46 | region="$(echo "${api_env_development}" | jq -rc --arg cloud $cloud '.regions[$cloud]' | jq -c '.[]' | shuf -n 1 |jq -r .)" 47 | fi 48 | ;; 49 | 50 | Custom) 51 | if [ "${api_url}" == "" ]; then 52 | echo "api_url input must be set when api_env is set to 'Custom'" 53 | exit 1 54 | fi 55 | 56 | if [ "${organization_id}" == "" ]; then 57 | echo "organization_id input must be set when api_env is set to 'Custom'" 58 | exit 1 59 | fi 60 | 61 | if [ "${api_key_id}" == "" ]; then 62 | echo "api_key_id input must be set when api_env is set to 'Custom'" 63 | exit 1 64 | fi 65 | 66 | if [ "${api_key_secret}" == "" ]; then 67 | echo "api_key_secret input must be set when api_env is set to 'Custom'" 68 | exit 1 69 | fi 70 | 71 | if [ "${region}" == "" ]; then 72 | echo "Setting default region for ${cloud}" 73 | case "${cloud}" in 74 | aws) 75 | region="${aws_region}" 76 | ;; 77 | azure) 78 | region="${azure_region}" 79 | ;; 80 | gcp) 81 | region="${gcp_region}" 82 | ;; 83 | esac 84 | 85 | if [ "${region}" == "" ]; then 86 | echo "${cloud}_region input must be set when api_env is set to 'Custom'" 87 | exit 1 88 | fi 89 | fi 90 | ;; 91 | esac 92 | 93 | echo "api_url=${api_url}" >> $GITHUB_OUTPUT 94 | echo "organization_id=${organization_id}" >> $GITHUB_OUTPUT 95 | echo "api_key_id=${api_key_id}" >> $GITHUB_OUTPUT 96 | echo "api_key_secret=${api_key_secret}" >> $GITHUB_OUTPUT 97 | echo "region='${region}'" 98 | if [ "$region" != "" ]; then 99 | echo "region=${region}" >> $GITHUB_OUTPUT 100 | fi 101 | -------------------------------------------------------------------------------- /.github/workflows/autolabel.yaml: -------------------------------------------------------------------------------- 1 | name: Automatically label issues with 'terraform-provider' 2 | on: 3 | issues: 4 | types: 5 | - reopened 6 | - opened 7 | jobs: 8 | label_issues: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | issues: write 12 | steps: 13 | - run: gh issue edit "$NUMBER" --add-label "$LABELS" 14 | env: 15 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 16 | GH_REPO: ${{ github.repository }} 17 | NUMBER: ${{ github.event.issue.number }} 18 | LABELS: terraform-provider 19 | -------------------------------------------------------------------------------- /.github/workflows/docs.yaml: -------------------------------------------------------------------------------- 1 | name: Ensure docs are up to date 2 | 3 | on: 4 | pull_request: {} 5 | 6 | defaults: 7 | run: 8 | shell: bash 9 | 10 | jobs: 11 | check_docs: 12 | runs-on: [dataplane, self-hosted, linux, x64, small] 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v4 16 | 17 | - name: Setup go 18 | uses: actions/setup-go@v5 19 | with: 20 | go-version-file: 'go.mod' 21 | cache: true 22 | 23 | - name: Generate docs 24 | run: make docs 25 | 26 | - name: Check for changes 27 | run: git diff --exit-code 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /.github/workflows/fmt.yaml: -------------------------------------------------------------------------------- 1 | name: Ensure source code is properly formatted 2 | 3 | on: 4 | pull_request: {} 5 | 6 | defaults: 7 | run: 8 | shell: bash 9 | 10 | jobs: 11 | fmt: 12 | runs-on: [dataplane, self-hosted, linux, x64, small] 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v4 16 | 17 | - name: Setup go 18 | uses: actions/setup-go@v5 19 | with: 20 | go-version-file: 'go.mod' 21 | cache: true 22 | 23 | - name: Run fmt 24 | run: make fmt 25 | 26 | - name: Check for changes 27 | run: git diff --exit-code 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | # This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time. 2 | # 3 | # You can adjust the behavior by modifying this file. 4 | # For more information, see: 5 | # https://github.com/actions/stale 6 | name: Mark stale issues and pull requests 7 | 8 | on: 9 | schedule: 10 | - cron: '45 23 * * *' 11 | 12 | jobs: 13 | stale: 14 | runs-on: ubuntu-latest 15 | permissions: 16 | issues: write 17 | pull-requests: write 18 | 19 | steps: 20 | - uses: actions/stale@v5 21 | with: 22 | repo-token: ${{ secrets.GITHUB_TOKEN }} 23 | stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove no-issue-activity label or comment or this will be closed in 5 days.' 24 | stale-pr-message: 'This PR is stale because it has been open 45 days with no activity. Remove no-pr-activity label or comment or this will be closed in 10 days.' 25 | close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity.' 26 | close-pr-message: 'This PR was closed because it has been stalled for 10 days with no activity.' 27 | days-before-issue-stale: 30 28 | days-before-pr-stale: 45 29 | days-before-issue-close: 5 30 | days-before-pr-close: 10 31 | stale-issue-label: 'no-issue-activity' 32 | exempt-issue-labels: 'awaiting-approval,work-in-progress' 33 | stale-pr-label: 'no-pr-activity' 34 | exempt-pr-labels: 'awaiting-approval,work-in-progress' 35 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: Run go tests 2 | 3 | on: 4 | pull_request: {} 5 | 6 | defaults: 7 | run: 8 | shell: bash 9 | 10 | jobs: 11 | test: 12 | runs-on: [dataplane, self-hosted, linux, x64, small] 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v4 16 | 17 | - name: Setup go 18 | uses: actions/setup-go@v5 19 | with: 20 | go-version-file: 'go.mod' 21 | cache: true 22 | 23 | - name: Run fmt 24 | run: make test 25 | -------------------------------------------------------------------------------- /.github/workflows/tidy.yaml: -------------------------------------------------------------------------------- 1 | name: Ensure go modules are tidy 2 | 3 | on: 4 | pull_request: {} 5 | 6 | defaults: 7 | run: 8 | shell: bash 9 | 10 | jobs: 11 | tidy: 12 | runs-on: [dataplane, self-hosted, linux, x64, small] 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v4 16 | 17 | - name: Setup go 18 | uses: actions/setup-go@v5 19 | with: 20 | go-version-file: 'go.mod' 21 | cache: true 22 | 23 | - name: Run go mod tidy 24 | run: go mod tidy 25 | 26 | - name: Check for changes 27 | run: git diff --exit-code 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .terraform* 2 | terraform.tfstate* 3 | 4 | terraform-provider-clickhouse 5 | 6 | node_modules/ 7 | secrets.tfvars 8 | dev/ 9 | .idea/ 10 | *.backup 11 | 12 | **/variables.tfvars 13 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | enable: 3 | - errcheck 4 | - gosimple 5 | - govet 6 | - ineffassign 7 | - staticcheck 8 | - typecheck 9 | - gosec 10 | - unconvert 11 | - dupl 12 | - goconst 13 | - goimports 14 | - copyloopvar 15 | - gofumpt 16 | 17 | linters-settings: 18 | goimports: 19 | # Put imports beginning with prefix after 3rd-party packages. 20 | # It's a comma-separated list of prefixes. 21 | autofix: true 22 | local-prefixes: github.com/ClickHouse/terraform-provider-clickhouse 23 | 24 | run: 25 | timeout: 10m 26 | skip-dirs: 27 | skip-dirs-default: true 28 | -------------------------------------------------------------------------------- /.goreleaser-alpha.yml: -------------------------------------------------------------------------------- 1 | # Visit https://goreleaser.com for documentation on how to customize this 2 | # behavior. 3 | version: 2 4 | before: 5 | hooks: 6 | # this is just an example and not a requirement for provider building/publishing 7 | - go mod tidy 8 | builds: 9 | - env: 10 | # goreleaser does not work with CGO, it could also complicate 11 | # usage by users in CI/CD systems like Terraform Cloud where 12 | # they are unable to install libraries. 13 | - CGO_ENABLED=0 14 | mod_timestamp: '{{ .CommitTimestamp }}' 15 | flags: 16 | - -trimpath 17 | ldflags: 18 | - '-s -w -X github.com/ClickHouse/terraform-provider-clickhouse/pkg/project.version={{.Version}} -X github.com/ClickHouse/terraform-provider-clickhouse/pkg/project.commit={{.Commit}}' 19 | goos: 20 | - freebsd 21 | - windows 22 | - linux 23 | - darwin 24 | goarch: 25 | - amd64 26 | - '386' 27 | - arm 28 | - arm64 29 | ignore: 30 | - goos: darwin 31 | goarch: '386' 32 | tags: 33 | - alpha 34 | binary: '{{ .ProjectName }}_v{{ .Version }}' 35 | archives: 36 | - format: zip 37 | name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}' 38 | checksum: 39 | extra_files: 40 | - glob: 'terraform-registry-manifest.json' 41 | name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json' 42 | name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS' 43 | algorithm: sha256 44 | signs: 45 | - artifacts: checksum 46 | args: 47 | # if you are using this in a GitHub action or some other automated pipeline, you 48 | # need to pass the batch flag to indicate its not interactive. 49 | - "--batch" 50 | - "--local-user" 51 | - "{{ .Env.GPG_FINGERPRINT }}" # set this environment variable for your signing key 52 | - "--output" 53 | - "${signature}" 54 | - "--detach-sign" 55 | - "${artifact}" 56 | release: 57 | extra_files: 58 | - glob: 'terraform-registry-manifest.json' 59 | name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json' 60 | prerelease: false 61 | make_latest: false 62 | changelog: 63 | # skip: true 64 | -------------------------------------------------------------------------------- /.goreleaser-stable.yml: -------------------------------------------------------------------------------- 1 | # Visit https://goreleaser.com for documentation on how to customize this 2 | # behavior. 3 | version: 2 4 | before: 5 | hooks: 6 | # this is just an example and not a requirement for provider building/publishing 7 | - go mod tidy 8 | builds: 9 | - env: 10 | # goreleaser does not work with CGO, it could also complicate 11 | # usage by users in CI/CD systems like Terraform Cloud where 12 | # they are unable to install libraries. 13 | - CGO_ENABLED=0 14 | mod_timestamp: '{{ .CommitTimestamp }}' 15 | flags: 16 | - -trimpath 17 | ldflags: 18 | - '-s -w -X github.com/ClickHouse/terraform-provider-clickhouse/pkg/project.version={{.Version}} -X github.com/ClickHouse/terraform-provider-clickhouse/pkg/project.commit={{.Commit}}' 19 | goos: 20 | - freebsd 21 | - windows 22 | - linux 23 | - darwin 24 | goarch: 25 | - amd64 26 | - '386' 27 | - arm 28 | - arm64 29 | ignore: 30 | - goos: darwin 31 | goarch: '386' 32 | binary: '{{ .ProjectName }}_v{{ .Version }}' 33 | archives: 34 | - format: zip 35 | name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}' 36 | checksum: 37 | extra_files: 38 | - glob: 'terraform-registry-manifest.json' 39 | name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json' 40 | name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS' 41 | algorithm: sha256 42 | signs: 43 | - artifacts: checksum 44 | args: 45 | # if you are using this in a GitHub action or some other automated pipeline, you 46 | # need to pass the batch flag to indicate its not interactive. 47 | - "--batch" 48 | - "--local-user" 49 | - "{{ .Env.GPG_FINGERPRINT }}" # set this environment variable for your signing key 50 | - "--output" 51 | - "${signature}" 52 | - "--detach-sign" 53 | - "${artifact}" 54 | release: 55 | extra_files: 56 | - glob: 'terraform-registry-manifest.json' 57 | name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json' 58 | # If you want to manually examine the release before its live, uncomment this line: 59 | # draft: true 60 | changelog: 61 | # skip: true 62 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TEST?=$$(go list ./... | grep -v 'vendor') 2 | HOSTNAME=clickhouse.cloud 3 | NAMESPACE=terraform 4 | NAME=clickhouse 5 | BINARY=terraform-provider-${NAME} 6 | VERSION=0.1 7 | OS_ARCH=darwin_arm64 8 | 9 | default: install 10 | 11 | build: 12 | go build -o ${BINARY} 13 | 14 | release: 15 | GOOS=darwin GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_darwin_amd64 16 | GOOS=freebsd GOARCH=386 go build -o ./bin/${BINARY}_${VERSION}_freebsd_386 17 | GOOS=freebsd GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_freebsd_amd64 18 | GOOS=freebsd GOARCH=arm go build -o ./bin/${BINARY}_${VERSION}_freebsd_arm 19 | GOOS=linux GOARCH=386 go build -o ./bin/${BINARY}_${VERSION}_linux_386 20 | GOOS=linux GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_linux_amd64 21 | GOOS=linux GOARCH=arm go build -o ./bin/${BINARY}_${VERSION}_linux_arm 22 | GOOS=openbsd GOARCH=386 go build -o ./bin/${BINARY}_${VERSION}_openbsd_386 23 | GOOS=openbsd GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_openbsd_amd64 24 | GOOS=solaris GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_solaris_amd64 25 | GOOS=windows GOARCH=386 go build -o ./bin/${BINARY}_${VERSION}_windows_386 26 | GOOS=windows GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_windows_amd64 27 | 28 | install: build 29 | mkdir -p ~/.terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH} 30 | mv ${BINARY} ~/.terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH} 31 | 32 | test: 33 | go test -i $(TEST) || exit 1 34 | echo $(TEST) | xargs -t -n4 go test $(TESTARGS) -timeout=30s -parallel=4 35 | 36 | enable_git_hooks: ## Add githooks for code validation before commit, as symlink so they get updated automatically 37 | mkdir -p .git/hooks 38 | cd .git/hooks && ln -fs ../../.githooks/* . 39 | echo "Git hooks were updated from .githooks/ into .git/hooks/" 40 | 41 | docs: ensure-tfplugindocs 42 | $(TFPLUGINDOCS) generate --provider-name=clickhouse 43 | 44 | docs-alpha: ensure-tfplugindocs 45 | $(TFPLUGINDOCS) generate --provider-name=clickhouse --additional-go-build-args="-tags alpha" 46 | 47 | fmt: ensure-golangci-lint 48 | go fmt ./... 49 | $(GOLANGCILINT) run --fix --allow-serial-runners 50 | 51 | mock: 52 | cd ./pkg/internal/api && minimock -i github.com/ClickHouse/terraform-provider-clickhouse/pkg/internal/api.Client -o client_mock.go -n ClientMock -p api && cd ../../.. 53 | 54 | TFPLUGINDOCS = /tmp/tfplugindocs-patched 55 | ensure-tfplugindocs: ## Download tfplugindocs locally if necessary. 56 | $(call get-tfplugindocs,$(TFPLUGINDOCS),github.com/whites11/terraform-plugin-docs) 57 | 58 | GOLANGCILINT = $(shell go env GOPATH)/bin/golangci-lint 59 | # Test if golangci-lint is available in the GOPATH, if not, set to local and download if needed 60 | ifneq ($(shell test -f $(GOLANGCILINT) && echo -n yes),yes) 61 | GOLANGCILINT = /tmp/golangci-lint 62 | endif 63 | ensure-golangci-lint: ## Download golangci-lint locally if necessary. 64 | $(call go-get-tool,$(GOLANGCILINT),github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.8) 65 | 66 | # go-get-tool will 'go get' any package $2 and install it to $1. 67 | define go-get-tool 68 | @[ -f $(1) ] || { \ 69 | set -e ;\ 70 | TMP_DIR=$$(mktemp -d) ;\ 71 | cd $$TMP_DIR ;\ 72 | go mod init tmp ;\ 73 | gobin="$$(dirname $(1))" ;\ 74 | echo "Downloading $(2) into $$gobin" ;\ 75 | GOBIN=$$gobin go install $(2) ;\ 76 | rm -rf $$TMP_DIR ;\ 77 | } 78 | endef 79 | 80 | define get-tfplugindocs 81 | @[ -f $(1) ] || { \ 82 | set -e ;\ 83 | TMP_DIR=$$(mktemp -d) ;\ 84 | cd $$TMP_DIR ;\ 85 | echo "Cloning https://$(2).git into $$TMP_DIR" ;\ 86 | git clone https://$(2).git tfplugindocs ;\ 87 | cd tfplugindocs ;\ 88 | echo "Building tfplugindocs into $(1)" ;\ 89 | go build -o $(1) cmd/tfplugindocs/main.go ;\ 90 | rm -rf $$TMP_DIR ;\ 91 | } 92 | endef 93 | -------------------------------------------------------------------------------- /development/README.md: -------------------------------------------------------------------------------- 1 | # Development 2 | 3 | Quick start guide for contributors. 4 | 5 | ## Preparation 6 | 7 | Create a new file called .terraformrc in your home directory (~), then add the dev_overrides block below. Change the `` to the full path of the `tmp` directory in this repo. For example: 8 | 9 | ```t 10 | provider_installation { 11 | 12 | dev_overrides { 13 | "ClickHouse/clickhouse" = "" 14 | } 15 | 16 | # For all other providers, install them directly from their origin provider 17 | # registries as normal. If you omit this, Terraform will _only_ use 18 | # the dev_overrides block, and so no other providers will be available. 19 | direct {} 20 | } 21 | ``` 22 | 23 | Ensure you have [`air`](https://github.com/air-verse/air) or install it with: 24 | 25 | ```bash 26 | go install github.com/air-verse/air@latest 27 | ``` 28 | 29 | Run `air` to automatically build the plugin binary every time you make changes to the code: 30 | 31 | ```bash 32 | $ air 33 | ``` 34 | 35 | You can now run `terraform` and you'll be using the locally built binary. Please note that the `dev_overrides` make it so that you have to skip `terraform init`). 36 | For example, go to the `examples/full/basic/aws` directory and : 37 | 38 | ```bash 39 | terraform apply -var-file="variables.tfvars" 40 | ╷ 41 | │ Warning: Provider development overrides are in effect 42 | │ 43 | │ The following provider development overrides are set in the CLI configuration: 44 | │ - ClickHouse/clickhouse in /home/user/workdir/terraform-provider-clickhouse/tmp 45 | │ 46 | │ The behavior may therefore not match any released version of the provider and applying changes may 47 | │ cause the state to become incompatible with published releases. 48 | ╵ 49 | 50 | Terraform used the selected providers to generate the following execution plan. Resource actions are 51 | indicated with the following symbols: 52 | + create 53 | 54 | Terraform will perform the following actions: 55 | 56 | # clickhouse_service.service will be created 57 | + resource "clickhouse_service" "service" { 58 | ... 59 | } 60 | 61 | Plan: 1 to add, 0 to change, 0 to destroy. 62 | 63 | Do you want to perform these actions? 64 | Terraform will perform the actions described above. 65 | Only 'yes' will be accepted to approve. 66 | 67 | Enter a value: 68 | ``` 69 | 70 | 71 | Make sure to change the organization id, token key, and token secret to valid values. 72 | 73 | ## Git hooks 74 | 75 | We suggest to add git hooks to your local repo, by running: 76 | 77 | ```bash 78 | make enable_git_hooks 79 | ``` 80 | 81 | Code will be formatted and docs generated before each commit. 82 | 83 | ## Docs 84 | 85 | If you made any changes to the provider's interface, please run `make docs` to update documentation as well. 86 | 87 | NOTE: this is done automatically by git hooks. 88 | 89 | ## Release 90 | 91 | NOTE: Release process is only possible for ClickHouse employees. 92 | 93 | To make a new public release: 94 | 95 | - ensure the `main` branch contains all the changes you want to release 96 | - Run the [`Release`](https://github.com/ClickHouse/terraform-provider-clickhouse/actions/workflows/release.yaml) workflow against the main branch (enter the desired release version in semver format without leading `v`, example: "1.2.3") 97 | - Release will be automatically created if end to end tests will be successful. 98 | -------------------------------------------------------------------------------- /docs/data-sources/api_key_id.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "clickhouse_api_key_id Data Source - clickhouse" 4 | subcategory: "" 5 | description: |- 6 | The clickhouse_api_key_id data source can be used to retrieve the UUID of a ClickHouse cloud API key. 7 | It is meant to be used in the clickhouse_service resource to set the query_api_endpoints attribute. 8 | It can be used in two ways: 9 | To retrieve information about an API Key, by providing its nameTo retrieve information about the API Key currently configured for running the terraform provider 10 | In both cases the data source will contain the id and name attributes. 11 | --- 12 | 13 | # clickhouse_api_key_id (Data Source) 14 | 15 | The *clickhouse_api_key_id* data source can be used to retrieve the UUID of a ClickHouse cloud API key. 16 | It is meant to be used in the *clickhouse_service* resource to set the `query_api_endpoints` attribute. 17 | 18 | It can be used in two ways: 19 | 20 | 1) To retrieve information about an API Key, by providing its name 21 | 2) To retrieve information about the API Key currently configured for running the terraform provider 22 | 23 | In both cases the data source will contain the `id` and `name` attributes. 24 | 25 | ## Example Usage 26 | 27 | ```terraform 28 | data "clickhouse_api_key_id" "my_api_key" { 29 | # The name attribute can be omitted 30 | # In this case the API Key used to run the terraform provider will be retrieved. 31 | name = "my-api-key" 32 | } 33 | ``` 34 | 35 | 36 | ## Schema 37 | 38 | ### Optional 39 | 40 | - `name` (String) The name of the API key to retrieve information about. If left empty, the API key used by the Terraform provider is used instead. 41 | 42 | ### Read-Only 43 | 44 | - `id` (String) The ID of the API key used by the provider to connect to the service. This is a read-only attribute. 45 | -------------------------------------------------------------------------------- /docs/data-sources/private_endpoint_config.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "clickhouse_private_endpoint_config Data Source - clickhouse" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # clickhouse_private_endpoint_config (Data Source) 10 | 11 | 12 | 13 | 14 | 15 | 16 | ## Schema 17 | 18 | ### Required 19 | 20 | - `cloud_provider` (String) The cloud provider for the private endpoint. Valid values are 'aws', 'gcp', or 'azure'. 21 | - `region` (String) The region for the private endpoint. Valid values are specific to the cloud provider i.e. us-east-2 22 | 23 | ### Read-Only 24 | 25 | - `endpoint_service_id` (String) The ID of the private endpoint that is used to securely connect to ClickHouse. This is a read-only attribute. 26 | -------------------------------------------------------------------------------- /docs/resources/private_endpoint_registration.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "clickhouse_private_endpoint_registration Resource - clickhouse" 4 | subcategory: "" 5 | description: |- 6 | This resource is deprecated since version 3.2.0. Please refer to the docs https://github.com/ClickHouse/terraform-provider-clickhouse?tab=readme-ov-file#breaking-changes-and-deprecations for migration steps. 7 | --- 8 | 9 | # clickhouse_private_endpoint_registration (Resource) 10 | 11 | This resource is deprecated since version 3.2.0. Please refer to [the docs](https://github.com/ClickHouse/terraform-provider-clickhouse?tab=readme-ov-file#breaking-changes-and-deprecations) for migration steps. 12 | 13 | 14 | 15 | 16 | ## Schema 17 | 18 | ### Required 19 | 20 | - `cloud_provider` (String) Cloud provider of the private endpoint ID 21 | - `private_endpoint_id` (String) ID of the private endpoint (replaces deprecated attribute `id`) 22 | - `region` (String) Region of the private endpoint 23 | 24 | ### Optional 25 | 26 | - `description` (String) Description of the private endpoint 27 | -------------------------------------------------------------------------------- /docs/resources/service_private_endpoints_attachment.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "clickhouse_service_private_endpoints_attachment Resource - clickhouse" 4 | subcategory: "" 5 | description: |- 6 | Use the clickhouse_service_private_endpoints_attachment resource to attach a ClickHouse service to a Private Endpoint. 7 | Important: Please note that if you want to attach the same ClickHouse service to multiple Private Endpoints you have to specify all the Private Endpoint IDs in a single clickhouse_service_private_endpoints_attachment resource. 8 | Having multiple clickhouse_service_private_endpoints_attachment resources for the same service is unsupported and the outcome is unpredictable. 9 | See private_endpoint_registration https://registry.terraform.io/providers/ClickHouse/clickhouse/latest/docs/resources/private_endpoint_registration for how to create a private endpoint. 10 | See full example https://github.com/ClickHouse/terraform-provider-clickhouse/tree/main/examples/full/private_endpoint on GitHub. 11 | --- 12 | 13 | # clickhouse_service_private_endpoints_attachment (Resource) 14 | 15 | Use the *clickhouse_service_private_endpoints_attachment* resource to attach a ClickHouse *service* to a *Private Endpoint*. 16 | Important: Please note that if you want to attach the same ClickHouse *service* to multiple *Private Endpoints* you have to specify all the *Private Endpoint IDs* in a single *clickhouse_service_private_endpoints_attachment* resource. 17 | Having multiple *clickhouse_service_private_endpoints_attachment* resources for the same service is unsupported and the outcome is unpredictable. 18 | 19 | See [private_endpoint_registration](https://registry.terraform.io/providers/ClickHouse/clickhouse/latest/docs/resources/private_endpoint_registration) for how to create a *private endpoint*. 20 | 21 | See [full example](https://github.com/ClickHouse/terraform-provider-clickhouse/tree/main/examples/full/private_endpoint) on GitHub. 22 | 23 | ## Example Usage 24 | 25 | ```terraform 26 | resource "clickhouse_service" "svc" { 27 | ... 28 | } 29 | 30 | resource "clickhouse_private_endpoint_registration" "endpoint" { 31 | ... 32 | } 33 | 34 | resource "clickhouse_service_private_endpoints_attachment" "attachment" { 35 | private_endpoint_ids = [ 36 | clickhouse_private_endpoint_registration.endpoint.id 37 | ] 38 | service_id = clickhouse_service.svc.id 39 | } 40 | ``` 41 | 42 | 43 | ## Schema 44 | 45 | ### Optional 46 | 47 | - `private_endpoint_ids` (List of String) List of private endpoint IDs 48 | - `service_id` (String) ClickHouse Service ID 49 | 50 | ## Import 51 | 52 | Import is supported using the following syntax: 53 | 54 | ```shell 55 | # Endpoint Attachments can be imported by specifying the clickhouse service UUID 56 | terraform import clickhouse_service_private_endpoints_attachment.example xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 57 | ``` 58 | -------------------------------------------------------------------------------- /docs/resources/service_transparent_data_encryption_key_association.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "clickhouse_service_transparent_data_encryption_key_association Resource - clickhouse" 4 | subcategory: "" 5 | description: |- 6 | You can use the clickhouse_service_transparent_data_encryption_key_association resource to associate your own Encryption Key with a Clickhouse Service with the Transparent Data Encryption (TDE) feature enabled. 7 | Please note that this feature requires an organization with the Enterprise plan. 8 | --- 9 | 10 | # clickhouse_service_transparent_data_encryption_key_association (Resource) 11 | 12 | You can use the *clickhouse_service_transparent_data_encryption_key_association* resource to associate your own Encryption Key with a Clickhouse Service with the Transparent Data Encryption (TDE) feature enabled. 13 | Please note that this feature requires an organization with the `Enterprise` plan. 14 | 15 | ## Example Usage 16 | 17 | ```terraform 18 | resource "clickhouse_service" "service" { 19 | ... 20 | } 21 | 22 | resource "aws_kms_key" "enc" { 23 | ... 24 | } 25 | 26 | resource "clickhouse_service_transparent_data_encryption_key_association" "service_key_association" { 27 | service_id = clickhouse_service.service.id 28 | key_id = aws_kms_key.enc.arn 29 | } 30 | ``` 31 | 32 | 33 | ## Schema 34 | 35 | ### Required 36 | 37 | - `key_id` (String) ID of the Encryption key to use for data encryption. Must be an ARN for AWS services or a Key Resource Path for GCP services. 38 | - `service_id` (String) ClickHouse Service ID 39 | 40 | ## Import 41 | 42 | Import is supported using the following syntax: 43 | 44 | ```shell 45 | # Endpoint Attachments can be imported by specifying the clickhouse service UUID 46 | terraform import clickhouse_service_transparent_data_encryption_key_association.example xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 47 | ``` 48 | -------------------------------------------------------------------------------- /examples/clickpipe/README.md: -------------------------------------------------------------------------------- 1 | # Experimental `clickhouse_clickpipe` resource usage examples 2 | 3 | This directory contains a set of example configurations for deploying a ClickHouse ClickPipe with different input sources. 4 | 5 | Note: These examples are not provisioning ClickHouse service for you. You need to have a ClickHouse service running before deploying a ClickPipe. 6 | Except a `service_and_clickpipe` example, which provisions a ClickHouse service and a ClickPipe in one go. -------------------------------------------------------------------------------- /examples/clickpipe/externally_managed_table/README.md: -------------------------------------------------------------------------------- 1 | ## Creating a Kafka ClickPipe with an externally managed table 2 | 3 | This example demonstrates how to deploy a Kafka ClickPipe with an externally managed table. 4 | 5 | ## How to run 6 | 7 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 8 | - Run `terraform init` 9 | - Run `terraform -var-file=variables.tfvars` 10 | -------------------------------------------------------------------------------- /examples/clickpipe/externally_managed_table/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" {} 2 | variable "token_key" {} 3 | variable "token_secret" {} 4 | 5 | variable "service_id" { 6 | description = "ClickHouse service ID" 7 | } 8 | 9 | variable "kafka_brokers" { 10 | description = "Kafka brokers" 11 | } 12 | 13 | variable "kafka_topics" { 14 | description = "Kafka topics" 15 | } 16 | 17 | variable "kafka_username" { 18 | description = "Username" 19 | sensitive = true 20 | } 21 | 22 | variable "kafka_password" { 23 | description = "Password" 24 | sensitive = true 25 | } 26 | 27 | variable "table_name" { 28 | description = "Table name" 29 | type = string 30 | } 31 | 32 | variable "table_columns" { 33 | description = "Table columns" 34 | type = list(object({ 35 | name = string 36 | type = string 37 | })) 38 | } 39 | 40 | variable "field_mappings" { 41 | description = "Field mappings" 42 | type = list(object({ 43 | source_field = string 44 | destination_field = string 45 | })) 46 | } 47 | 48 | resource "clickhouse_clickpipe" "kafka_confluent" { 49 | name = "Confluent 🚀 ClickPipe" 50 | description = "Data pipeline from Confluent to ClickHouse" 51 | 52 | service_id = var.service_id 53 | 54 | scaling = { 55 | replicas = 1 56 | } 57 | 58 | state = "Running" 59 | 60 | source = { 61 | kafka = { 62 | type = "confluent" 63 | format = "JSONEachRow" 64 | brokers = var.kafka_brokers 65 | topics = var.kafka_topics 66 | 67 | credentials = { 68 | username = var.kafka_username 69 | password = var.kafka_password 70 | } 71 | } 72 | } 73 | 74 | destination = { 75 | table = var.table_name 76 | managed_table = false 77 | 78 | columns = var.table_columns 79 | } 80 | 81 | field_mappings = var.field_mappings 82 | } 83 | 84 | output "clickpipe_id" { 85 | value = clickhouse_clickpipe.kafka_confluent.id 86 | } -------------------------------------------------------------------------------- /examples/clickpipe/externally_managed_table/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.2.0-alpha1" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/clickpipe/externally_managed_table/provider.tf.template.alpha: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/clickpipe/externally_managed_table/variables.sample.tfvars: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | service_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 6 | 7 | kafka_brokers = "broker.us-east-2.aws.confluent.cloud:9092" 8 | kafka_topics = "cell_towers" 9 | 10 | kafka_username = "" 11 | kafka_password = "" 12 | 13 | table_name = "externally_managed_table" 14 | 15 | table_columns = [ 16 | { 17 | name: "id", 18 | type: "UInt64" 19 | }, 20 | { 21 | name: "name", 22 | type: "String" 23 | } 24 | ] 25 | 26 | field_mappings = [ 27 | { 28 | source_field = "bar", 29 | destination_field = "id" 30 | }, 31 | { 32 | source_field = "foo", 33 | destination_field = "name" 34 | } 35 | ] 36 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_azure_eventhub/README.md: -------------------------------------------------------------------------------- 1 | ## ClickPipe Kafka with Azure Event Hub example 2 | 3 | This example demonstrates how to deploy a Kafka ClickPipe with an Azure Event Hub as the input source. 4 | 5 | ## How to run 6 | 7 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 8 | - Run `terraform init` 9 | - Run `terraform -var-file=variables.tfvars` 10 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_azure_eventhub/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" {} 2 | variable "token_key" {} 3 | variable "token_secret" {} 4 | 5 | variable "service_id" { 6 | description = "ClickHouse service ID" 7 | } 8 | 9 | variable "kafka_brokers" { 10 | description = "Kafka brokers" 11 | } 12 | 13 | variable "kafka_topics" { 14 | description = "Kafka topics" 15 | } 16 | 17 | variable "azure_eventhub_connection_string" { 18 | description = "Connection string for Azure EventHub" 19 | sensitive = true 20 | } 21 | 22 | resource "clickhouse_clickpipe" "kafka_azure_eventhub" { 23 | name = "Azure EventHub 🚀 ClickPipe" 24 | description = "Data pipeline from Azure EventHub to ClickHouse" 25 | 26 | service_id = var.service_id 27 | 28 | scaling = { 29 | replicas = 1 30 | } 31 | 32 | state = "Running" 33 | 34 | source = { 35 | kafka = { 36 | type = "azureeventhub" 37 | format = "JSONEachRow" 38 | brokers = var.kafka_brokers 39 | topics = var.kafka_topics 40 | 41 | credentials = { 42 | connection_string = var.azure_eventhub_connection_string 43 | } 44 | } 45 | } 46 | 47 | destination = { 48 | table = "my_table" 49 | managed_table = true 50 | 51 | table_definition = { 52 | engine = { 53 | type = "MergeTree" 54 | } 55 | } 56 | 57 | columns = [ 58 | { 59 | name = "my_field1" 60 | type = "String" 61 | }, { 62 | name = "my_field2" 63 | type = "UInt64" 64 | } 65 | ] 66 | } 67 | 68 | field_mappings = [ 69 | { 70 | source_field = "my_field" 71 | destination_field = "my_field1" 72 | } 73 | ] 74 | } 75 | 76 | output "clickpipe_id" { 77 | value = clickhouse_clickpipe.kafka_azure_eventhub.id 78 | } -------------------------------------------------------------------------------- /examples/clickpipe/kafka_azure_eventhub/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.2.0-alpha1" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_azure_eventhub/provider.tf.template.alpha: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_azure_eventhub/variables.sample.tfvars: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | service_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 6 | 7 | kafka_brokers = "xxxx.servicebus.windows.net:9093" 8 | kafka_topics = "my_topic" 9 | 10 | azure_eventhub_connection_string = "" -------------------------------------------------------------------------------- /examples/clickpipe/kafka_confluent/README.md: -------------------------------------------------------------------------------- 1 | ## ClickPipe Kafka with Confluent example 2 | 3 | This example demonstrates how to deploy a Kafka ClickPipe with a Confluent Kafka cluster as the input source. 4 | 5 | ## How to run 6 | 7 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 8 | - Run `terraform init` 9 | - Run `terraform -var-file=variables.tfvars` 10 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_confluent/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" {} 2 | variable "token_key" {} 3 | variable "token_secret" {} 4 | 5 | variable "service_id" { 6 | description = "ClickHouse service ID" 7 | } 8 | 9 | variable "kafka_brokers" { 10 | description = "Kafka brokers" 11 | } 12 | 13 | variable "kafka_topics" { 14 | description = "Kafka topics" 15 | } 16 | 17 | variable "kafka_username" { 18 | description = "Username" 19 | sensitive = true 20 | } 21 | 22 | variable "kafka_password" { 23 | description = "Password" 24 | sensitive = true 25 | } 26 | 27 | resource "clickhouse_clickpipe" "kafka_confluent" { 28 | name = "Confluent 🚀 ClickPipe" 29 | description = "Data pipeline from Confluent to ClickHouse" 30 | 31 | service_id = var.service_id 32 | 33 | scaling = { 34 | replicas = 1 35 | } 36 | 37 | state = "Running" 38 | 39 | source = { 40 | kafka = { 41 | type = "confluent" 42 | format = "JSONEachRow" 43 | brokers = var.kafka_brokers 44 | topics = var.kafka_topics 45 | 46 | credentials = { 47 | username = var.kafka_username 48 | password = var.kafka_password 49 | } 50 | } 51 | } 52 | 53 | destination = { 54 | table = "my_table" 55 | managed_table = true 56 | 57 | table_definition = { 58 | engine = { 59 | type = "MergeTree" 60 | } 61 | } 62 | 63 | columns = [ 64 | { 65 | name = "my_field1" 66 | type = "String" 67 | }, { 68 | name = "my_field2" 69 | type = "UInt64" 70 | } 71 | ] 72 | } 73 | 74 | field_mappings = [ 75 | { 76 | source_field = "my_field" 77 | destination_field = "my_field1" 78 | } 79 | ] 80 | } 81 | 82 | output "clickpipe_id" { 83 | value = clickhouse_clickpipe.kafka_confluent.id 84 | } -------------------------------------------------------------------------------- /examples/clickpipe/kafka_confluent/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.2.0-alpha1" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_confluent/provider.tf.template.alpha: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_confluent/variables.sample.tfvars: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | service_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 6 | 7 | kafka_brokers = "broker.us-east-2.aws.confluent.cloud:9092" 8 | kafka_topics = "cell_towers" 9 | 10 | kafka_username = "" 11 | kafka_password = "" -------------------------------------------------------------------------------- /examples/clickpipe/kafka_msk_iam_role/README.md: -------------------------------------------------------------------------------- 1 | ## ClickPipe Kafka with MSK/IAM role 2 | 3 | This example demonstrates how to deploy a Kafka ClickPipe with a MSK cluster as the input source, 4 | authenticated with an IAM role. 5 | 6 | ## How to run 7 | 8 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 9 | - Run `terraform init` 10 | - Run `terraform -var-file=variables.tfvars` 11 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_msk_iam_role/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" {} 2 | variable "token_key" {} 3 | variable "token_secret" {} 4 | 5 | variable "service_id" { 6 | description = "ClickHouse service ID" 7 | } 8 | 9 | variable "kafka_brokers" { 10 | description = "Kafka brokers" 11 | } 12 | 13 | variable "kafka_topics" { 14 | description = "Kafka topics" 15 | } 16 | 17 | variable "iam_role" { 18 | description = "IAM role ARN" 19 | } 20 | 21 | resource "clickhouse_clickpipe" "kafka_msk" { 22 | name = "MSK 🚀 ClickPipe" 23 | description = "Data pipeline from MSK to ClickHouse" 24 | 25 | service_id = var.service_id 26 | 27 | scaling = { 28 | replicas = 1 29 | } 30 | 31 | state = "Running" 32 | 33 | source = { 34 | kafka = { 35 | type = "msk" 36 | format = "JSONEachRow" 37 | brokers = var.kafka_brokers 38 | topics = var.kafka_topics 39 | 40 | authentication = "IAM_ROLE" 41 | iam_role = var.iam_role 42 | } 43 | } 44 | 45 | destination = { 46 | table = "my_table" 47 | managed_table = true 48 | 49 | table_definition = { 50 | engine = { 51 | type = "MergeTree" 52 | } 53 | } 54 | 55 | columns = [ 56 | { 57 | name = "my_field1" 58 | type = "String" 59 | }, { 60 | name = "my_field2" 61 | type = "UInt64" 62 | } 63 | ] 64 | } 65 | 66 | field_mappings = [ 67 | { 68 | source_field = "my_field" 69 | destination_field = "my_field1" 70 | } 71 | ] 72 | } 73 | 74 | output "clickpipe_id" { 75 | value = clickhouse_clickpipe.kafka_msk.id 76 | } -------------------------------------------------------------------------------- /examples/clickpipe/kafka_msk_iam_role/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.2.0-alpha1" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_msk_iam_role/provider.tf.template.alpha: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_msk_iam_role/variables.sample.tfvars: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | service_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 6 | 7 | kafka_brokers = "broker.us-east-2.aws.confluent.cloud:9092" 8 | kafka_topics = "cell_towers" 9 | 10 | iam_role = "arn:aws:iam::123456789012:role/ClickHouseMSKRole" -------------------------------------------------------------------------------- /examples/clickpipe/kafka_msk_iam_user/README.md: -------------------------------------------------------------------------------- 1 | ## ClickPipe Kafka with MSK/IAM user 2 | 3 | This example demonstrates how to deploy a Kafka ClickPipe with a MSK cluster as the input source, 4 | authenticated with an IAM user. 5 | 6 | ## How to run 7 | 8 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 9 | - Run `terraform init` 10 | - Run `terraform -var-file=variables.tfvars` 11 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_msk_iam_user/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" {} 2 | variable "token_key" {} 3 | variable "token_secret" {} 4 | 5 | variable "service_id" { 6 | description = "ClickHouse service ID" 7 | } 8 | 9 | variable "kafka_brokers" { 10 | description = "Kafka brokers" 11 | } 12 | 13 | variable "kafka_topics" { 14 | description = "Kafka topics" 15 | } 16 | 17 | variable "iam_access_key_id" { 18 | description = "IAM access key ID" 19 | sensitive = true 20 | } 21 | 22 | variable "iam_secret_key" { 23 | description = "IAM secret key" 24 | sensitive = true 25 | } 26 | 27 | resource "clickhouse_clickpipe" "kafka_msk" { 28 | name = "MSK 🚀 ClickPipe" 29 | description = "Data pipeline from MSK to ClickHouse" 30 | 31 | service_id = var.service_id 32 | 33 | scaling = { 34 | replicas = 1 35 | } 36 | 37 | state = "Running" 38 | 39 | source = { 40 | kafka = { 41 | type = "msk" 42 | format = "JSONEachRow" 43 | brokers = var.kafka_brokers 44 | topics = var.kafka_topics 45 | 46 | authentication = "IAM_USER" 47 | credentials = { 48 | access_key_id = var.iam_access_key_id 49 | secret_key = var.iam_secret_key 50 | } 51 | } 52 | } 53 | 54 | destination = { 55 | table = "my_table" 56 | managed_table = true 57 | 58 | table_definition = { 59 | engine = { 60 | type = "MergeTree" 61 | } 62 | } 63 | 64 | columns = [ 65 | { 66 | name = "my_field1" 67 | type = "String" 68 | }, { 69 | name = "my_field2" 70 | type = "UInt64" 71 | } 72 | ] 73 | } 74 | 75 | field_mappings = [ 76 | { 77 | source_field = "my_field" 78 | destination_field = "my_field1" 79 | } 80 | ] 81 | } 82 | 83 | output "clickpipe_id" { 84 | value = clickhouse_clickpipe.kafka_msk.id 85 | } -------------------------------------------------------------------------------- /examples/clickpipe/kafka_msk_iam_user/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.2.0-alpha1" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_msk_iam_user/provider.tf.template.alpha: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_msk_iam_user/variables.sample.tfvars: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | service_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 6 | 7 | kafka_brokers = "broker.us-east-2.aws.confluent.cloud:9092" 8 | kafka_topics = "cell_towers" 9 | 10 | iam_access_key_id = "xxxx" 11 | iam_secret_key = "xxx" -------------------------------------------------------------------------------- /examples/clickpipe/kafka_offset_strategy/README.md: -------------------------------------------------------------------------------- 1 | ## ClickPipe Kafka with offset strategy example 2 | 3 | This example demonstrates how to deploy a Kafka ClickPipe with a Kafka cluster as the input source, 4 | with additional configuration for the Kafka offset strategy. 5 | 6 | ## How to run 7 | 8 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 9 | - Run `terraform init` 10 | - Run `terraform -var-file=variables.tfvars` 11 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_offset_strategy/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" {} 2 | variable "token_key" {} 3 | variable "token_secret" {} 4 | 5 | variable "service_id" { 6 | description = "ClickHouse service ID" 7 | } 8 | 9 | variable "kafka_brokers" { 10 | description = "Kafka brokers" 11 | } 12 | 13 | variable "kafka_topics" { 14 | description = "Kafka topics" 15 | } 16 | 17 | variable "kafka_username" { 18 | description = "Username" 19 | sensitive = true 20 | } 21 | 22 | variable "kafka_password" { 23 | description = "Password" 24 | sensitive = true 25 | } 26 | 27 | resource "clickhouse_clickpipe" "kafka_offset_strategy" { 28 | name = "Offset strategy 🚀 ClickPipe" 29 | description = "Data pipeline with a custom offset strategy" 30 | 31 | service_id = var.service_id 32 | 33 | scaling = { 34 | replicas = 1 35 | } 36 | 37 | state = "Running" 38 | 39 | source = { 40 | kafka = { 41 | type = "confluent" 42 | format = "JSONEachRow" 43 | brokers = var.kafka_brokers 44 | topics = var.kafka_topics 45 | 46 | credentials = { 47 | username = var.kafka_username 48 | password = var.kafka_password 49 | } 50 | 51 | offset = { 52 | strategy = "from_timestamp" 53 | timestamp = "2021-01-01T00:00" 54 | } 55 | 56 | } 57 | } 58 | 59 | destination = { 60 | table = "my_table" 61 | managed_table = true 62 | 63 | table_definition = { 64 | engine = { 65 | type = "MergeTree" 66 | } 67 | } 68 | 69 | columns = [ 70 | { 71 | name = "my_field1" 72 | type = "String" 73 | }, { 74 | name = "my_field2" 75 | type = "UInt64" 76 | } 77 | ] 78 | } 79 | 80 | field_mappings = [ 81 | { 82 | source_field = "my_field" 83 | destination_field = "my_field1" 84 | } 85 | ] 86 | } 87 | 88 | output "clickpipe_id" { 89 | value = clickhouse_clickpipe.kafka_offset_strategy.id 90 | } -------------------------------------------------------------------------------- /examples/clickpipe/kafka_offset_strategy/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.2.0-alpha1" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_offset_strategy/provider.tf.template.alpha: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_offset_strategy/variables.sample.tfvars: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | service_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 6 | 7 | kafka_brokers = "broker.us-east-2.aws.confluent.cloud:9092" 8 | kafka_topics = "cell_towers" 9 | 10 | kafka_username = "" 11 | kafka_password = "" -------------------------------------------------------------------------------- /examples/clickpipe/kafka_redpanda_scram/README.md: -------------------------------------------------------------------------------- 1 | ## ClickPipe Kafka example 2 | 3 | The Terraform code deploys following resources: 4 | - 1 ClickPipe Kafka on ClickHouse Cloud 5 | 6 | The ClickHouse service is available from anywhere. 7 | 8 | ## How to run 9 | 10 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 11 | - Run `terraform init` 12 | - Run `terraform -var-file=variables.tfvars` 13 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_redpanda_scram/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" {} 2 | variable "token_key" {} 3 | variable "token_secret" {} 4 | 5 | variable "service_id" { 6 | description = "ClickHouse service ID" 7 | } 8 | 9 | variable "kafka_brokers" { 10 | description = "Kafka brokers" 11 | } 12 | 13 | variable "kafka_topics" { 14 | description = "Kafka topics" 15 | } 16 | 17 | variable "kafka_username" { 18 | description = "Username" 19 | sensitive = true 20 | } 21 | 22 | variable "kafka_password" { 23 | description = "Password" 24 | sensitive = true 25 | } 26 | 27 | resource "clickhouse_clickpipe" "kafka_redpanda" { 28 | name = "Redpanda 🚀 ClickPipe" 29 | description = "Data pipeline from Redpanda to ClickHouse" 30 | 31 | service_id = var.service_id 32 | 33 | scaling = { 34 | replicas = 1 35 | } 36 | 37 | state = "Running" 38 | 39 | source = { 40 | kafka = { 41 | type = "redpanda" 42 | format = "JSONEachRow" 43 | brokers = var.kafka_brokers 44 | topics = var.kafka_topics 45 | 46 | authentication = "SCRAM-SHA-512" 47 | credentials = { 48 | username = var.kafka_username 49 | password = var.kafka_password 50 | } 51 | } 52 | } 53 | 54 | destination = { 55 | table = "my_table" 56 | managed_table = true 57 | 58 | table_definition = { 59 | engine = { 60 | type = "MergeTree" 61 | } 62 | } 63 | 64 | columns = [ 65 | { 66 | name = "my_field1" 67 | type = "String" 68 | }, { 69 | name = "my_field2" 70 | type = "UInt64" 71 | } 72 | ] 73 | } 74 | 75 | field_mappings = [ 76 | { 77 | source_field = "my_field" 78 | destination_field = "my_field1" 79 | } 80 | ] 81 | } 82 | 83 | output "clickpipe_id" { 84 | value = clickhouse_clickpipe.kafka_redpanda.id 85 | } -------------------------------------------------------------------------------- /examples/clickpipe/kafka_redpanda_scram/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.2.0-alpha1" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_redpanda_scram/provider.tf.template.alpha: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_redpanda_scram/variables.sample.tfvars: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | service_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 6 | 7 | kafka_brokers = "broker.us-east-2.aws.confluent.cloud:9092" 8 | kafka_topics = "cell_towers" 9 | 10 | kafka_username = "" 11 | kafka_password = "" -------------------------------------------------------------------------------- /examples/clickpipe/kafka_schema_registry/README.md: -------------------------------------------------------------------------------- 1 | ## ClickPipe Kafka with schema registry example 2 | 3 | This example demonstrates how to deploy a Kafka ClickPipe with a Kafka cluster as the input source, 4 | with additional configuration for the Kafka schema registry. 5 | 6 | ## How to run 7 | 8 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 9 | - Run `terraform init` 10 | - Run `terraform -var-file=variables.tfvars` 11 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_schema_registry/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" {} 2 | variable "token_key" {} 3 | variable "token_secret" {} 4 | 5 | variable "service_id" { 6 | description = "ClickHouse service ID" 7 | } 8 | 9 | variable "kafka_brokers" { 10 | description = "Kafka brokers" 11 | } 12 | 13 | variable "kafka_topics" { 14 | description = "Kafka topics" 15 | } 16 | 17 | variable "kafka_username" { 18 | description = "Username" 19 | sensitive = true 20 | } 21 | 22 | variable "kafka_password" { 23 | description = "Password" 24 | sensitive = true 25 | } 26 | 27 | variable "schema_registry_url" { 28 | description = "Schema Registry URL" 29 | } 30 | 31 | variable "schema_registry_username" { 32 | description = "Schema Registry Username" 33 | sensitive = true 34 | } 35 | 36 | variable "schema_registry_password" { 37 | description = "Schema Registry Password" 38 | sensitive = true 39 | } 40 | 41 | resource "clickhouse_clickpipe" "kafka_schema_registry" { 42 | name = "Schema Registry 🚀 ClickPipe" 43 | description = "Data pipeline with use of Schema Registry" 44 | 45 | service_id = var.service_id 46 | 47 | scaling = { 48 | replicas = 1 49 | } 50 | 51 | state = "Running" 52 | 53 | source = { 54 | kafka = { 55 | type = "confluent" 56 | format = "AvroConfluent" 57 | brokers = var.kafka_brokers 58 | topics = var.kafka_topics 59 | 60 | credentials = { 61 | username = var.kafka_username 62 | password = var.kafka_password 63 | } 64 | 65 | schema_registry = { 66 | url = var.schema_registry_url 67 | authentication = "PLAIN" 68 | credentials = { 69 | username = var.schema_registry_username 70 | password = var.schema_registry_password 71 | } 72 | } 73 | } 74 | } 75 | 76 | destination = { 77 | table = "my_table" 78 | managed_table = true 79 | 80 | table_definition = { 81 | engine = { 82 | type = "MergeTree" 83 | } 84 | } 85 | 86 | columns = [ 87 | { 88 | name = "my_field1" 89 | type = "String" 90 | }, { 91 | name = "my_field2" 92 | type = "UInt64" 93 | } 94 | ] 95 | } 96 | 97 | field_mappings = [ 98 | { 99 | source_field = "my_field" 100 | destination_field = "my_field1" 101 | } 102 | ] 103 | } 104 | 105 | output "clickpipe_id" { 106 | value = clickhouse_clickpipe.kafka_schema_registry.id 107 | } 108 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_schema_registry/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.2.0-alpha1" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_schema_registry/provider.tf.template.alpha: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/clickpipe/kafka_schema_registry/variables.sample.tfvars: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | service_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 6 | 7 | kafka_brokers = "broker.us-east-2.aws.confluent.cloud:9092" 8 | kafka_topics = "cell_towers" 9 | 10 | kafka_username = "" 11 | kafka_password = "" 12 | 13 | schema_registry_url = "https://xxxxx.us-east-2.aws.confluent.cloud/schemas/ids/100001" 14 | schema_registry_username = "" 15 | schema_registry_password = "" -------------------------------------------------------------------------------- /examples/clickpipe/multiple_pipes_example/README.md: -------------------------------------------------------------------------------- 1 | ## Multiple ClickPipe Kafka example 2 | 3 | This example demonstrates how to deploy multiple Kafka pipes in a single Terraform. 4 | 5 | ## How to run 6 | 7 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 8 | - Run `terraform init` 9 | - Run `terraform -var-file=variables.tfvars` 10 | -------------------------------------------------------------------------------- /examples/clickpipe/multiple_pipes_example/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.2.0-alpha1" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/clickpipe/multiple_pipes_example/provider.tf.template.alpha: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/clickpipe/multiple_pipes_example/variables.sample.tfvars: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | service_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 6 | 7 | kafka_brokers = "broker.us-east-2.aws.confluent.cloud:9092" 8 | kafka_topics = "cell_towers" 9 | 10 | kafka_username = "" 11 | kafka_password = "" -------------------------------------------------------------------------------- /examples/clickpipe/object_storage_iam_role/README.md: -------------------------------------------------------------------------------- 1 | ## ClickPipe Object Storage with S3/IAM role example 2 | 3 | This example demonstrates how to deploy a ClickPipe with an S3 bucket as the input source, 4 | authenticated with an IAM role. 5 | 6 | ## How to run 7 | 8 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 9 | - Run `terraform init` 10 | - Run `terraform -var-file=variables.tfvars` 11 | -------------------------------------------------------------------------------- /examples/clickpipe/object_storage_iam_role/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" {} 2 | variable "token_key" {} 3 | variable "token_secret" {} 4 | 5 | variable "service_id" { 6 | description = "ClickHouse service ID" 7 | } 8 | 9 | variable "bucket_url" { 10 | description = "S3-compatible bucket URL" 11 | } 12 | 13 | variable "iam_role" { 14 | description = "IAM role" 15 | sensitive = true 16 | } 17 | 18 | resource "clickhouse_clickpipe" "kafka_s3" { 19 | name = "S3 🚀 ClickPipe with IAM role" 20 | description = "Data pipeline from S3 to ClickHouse" 21 | 22 | service_id = var.service_id 23 | 24 | state = "Running" 25 | 26 | source = { 27 | object_storage = { 28 | type = "s3" 29 | format = "JSONEachRow" 30 | 31 | url = var.bucket_url 32 | 33 | authentication = "IAM_ROLE" 34 | iam_role = var.iam_role 35 | } 36 | } 37 | 38 | destination = { 39 | table = "my_table" 40 | managed_table = true 41 | 42 | table_definition = { 43 | engine = { 44 | type = "MergeTree" 45 | } 46 | } 47 | 48 | columns = [ 49 | { 50 | name = "my_field1" 51 | type = "String" 52 | }, { 53 | name = "my_field2" 54 | type = "UInt64" 55 | } 56 | ] 57 | } 58 | 59 | field_mappings = [ 60 | { 61 | source_field = "my_field" 62 | destination_field = "my_field1" 63 | } 64 | ] 65 | } 66 | 67 | output "clickpipe_id" { 68 | value = clickhouse_clickpipe.kafka_s3.id 69 | } -------------------------------------------------------------------------------- /examples/clickpipe/object_storage_iam_role/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.2.0-alpha1" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/clickpipe/object_storage_iam_role/provider.tf.template.alpha: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/clickpipe/object_storage_iam_role/variables.sample.tfvars: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | service_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 6 | 7 | bucket_url = "https://s3.amazonaws.com/mybucket/**" 8 | 9 | iam_access_key_id = "xxxx" 10 | iam_secret_key = "xxx" -------------------------------------------------------------------------------- /examples/clickpipe/object_storage_iam_user/README.md: -------------------------------------------------------------------------------- 1 | ## ClickPipe Object Storage with S3/IAM user example 2 | 3 | This example demonstrates how to deploy a ClickPipe with an S3 bucket as the input source, 4 | authenticated with an IAM user. 5 | 6 | ## How to run 7 | 8 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 9 | - Run `terraform init` 10 | - Run `terraform -var-file=variables.tfvars` 11 | -------------------------------------------------------------------------------- /examples/clickpipe/object_storage_iam_user/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" {} 2 | variable "token_key" {} 3 | variable "token_secret" {} 4 | 5 | variable "service_id" { 6 | description = "ClickHouse service ID" 7 | } 8 | 9 | variable "bucket_url" { 10 | description = "S3-compatible bucket URL" 11 | } 12 | 13 | variable "iam_access_key_id" { 14 | description = "IAM access key ID" 15 | sensitive = true 16 | } 17 | 18 | variable "iam_secret_key" { 19 | description = "IAM secret key" 20 | sensitive = true 21 | } 22 | 23 | resource "clickhouse_clickpipe" "kafka_s3" { 24 | name = "S3 🚀 ClickPipe with IAM user" 25 | description = "Data pipeline from S3 to ClickHouse" 26 | 27 | service_id = var.service_id 28 | 29 | state = "Running" 30 | 31 | source = { 32 | object_storage = { 33 | type = "s3" 34 | format = "JSONEachRow" 35 | 36 | url = var.bucket_url 37 | 38 | authentication = "IAM_USER" 39 | access_key = { 40 | access_key_id = var.iam_access_key_id 41 | secret_key = var.iam_secret_key 42 | } 43 | } 44 | } 45 | 46 | destination = { 47 | table = "my_data_table" 48 | managed_table = true 49 | 50 | table_definition = { 51 | engine = { 52 | type = "MergeTree" 53 | } 54 | } 55 | 56 | columns = [ 57 | { 58 | name = "my_field1" 59 | type = "String" 60 | }, { 61 | name = "my_field2" 62 | type = "UInt64" 63 | } 64 | ] 65 | } 66 | 67 | field_mappings = [ 68 | { 69 | source_field = "my_field" 70 | destination_field = "my_field1" 71 | } 72 | ] 73 | } 74 | 75 | output "clickpipe_id" { 76 | value = clickhouse_clickpipe.kafka_s3.id 77 | } -------------------------------------------------------------------------------- /examples/clickpipe/object_storage_iam_user/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.2.0-alpha1" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/clickpipe/object_storage_iam_user/provider.tf.template.alpha: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/clickpipe/object_storage_iam_user/variables.sample.tfvars: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | service_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 6 | 7 | bucket_url = "https://s3.amazonaws.com/mybucket/**" 8 | 9 | iam_access_key_id = "xxxx" 10 | iam_secret_key = "xxx" -------------------------------------------------------------------------------- /examples/clickpipe/reverse_private_endpoint_msk/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" {} 2 | variable "token_key" {} 3 | variable "token_secret" {} 4 | 5 | variable "service_id" { 6 | description = "ClickHouse service ID" 7 | } 8 | 9 | variable "msk_cluster_arn" { 10 | description = "MSK cluter ARN" 11 | } 12 | 13 | variable "msk_authentication" { 14 | description = "MSK authentication" 15 | default = "SASL_SCRAM" 16 | } 17 | 18 | resource "clickhouse_clickpipes_reverse_private_endpoint" "endpoint" { 19 | service_id = var.service_id 20 | description = "Reverse private endpoint for ClickPipes" 21 | type = "MSK_MULTI_VPC" 22 | msk_cluster_arn = var.msk_cluster_arn 23 | msk_authentication = var.msk_authentication 24 | } 25 | 26 | output "id" { 27 | value = clickhouse_clickpipes_reverse_private_endpoint.endpoint.id 28 | } 29 | 30 | output "msk_vpc_connection_id" { 31 | value = clickhouse_clickpipes_reverse_private_endpoint.endpoint.endpoint_id 32 | } 33 | 34 | output "dns_names" { 35 | value = concat( 36 | clickhouse_clickpipes_reverse_private_endpoint.endpoint.dns_names != null ? clickhouse_clickpipes_reverse_private_endpoint.endpoint.dns_names : [], 37 | clickhouse_clickpipes_reverse_private_endpoint.endpoint.private_dns_names != null ? clickhouse_clickpipes_reverse_private_endpoint.endpoint.private_dns_names : [] 38 | ) 39 | } 40 | 41 | output "status" { 42 | value = clickhouse_clickpipes_reverse_private_endpoint.endpoint.status 43 | } 44 | -------------------------------------------------------------------------------- /examples/clickpipe/reverse_private_endpoint_msk/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.2.0-alpha1" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/clickpipe/reverse_private_endpoint_msk/provider.tf.template.alpha: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/clickpipe/reverse_private_endpoint_msk/variables.sample.tfvars: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | service_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 6 | 7 | msk_cluster_arn = "arn:aws:kafka:us-east-2:123456789012:cluster/ExampleCluster/12345678-1234-1234-1234-123456789012-1" 8 | msk_authentication = "SASL_SCRAM" # or SASL_IAM -------------------------------------------------------------------------------- /examples/clickpipe/reverse_private_endpoint_msk_pipe/clickpipe.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | // MSK brokers for multi-VPC connectivity ports starting from 14001 incremented by a broker number 3 | msk_brokers = [for i, dns in clickhouse_clickpipes_reverse_private_endpoint.endpoint.private_dns_names : "${dns}:${i + 14001}"] 4 | } 5 | 6 | resource "clickhouse_clickpipe" "msk" { 7 | name = "MSK pipe using Reverse Private Endpoint" 8 | description = "This pipe is using a secure private endpoint to connect to MSK" 9 | 10 | service_id = var.service_id 11 | 12 | scaling = { 13 | replicas = 1 14 | } 15 | 16 | state = "Running" 17 | 18 | source = { 19 | kafka = { 20 | type = "msk" 21 | format = "JSONEachRow" 22 | brokers = join(",", local.msk_brokers) 23 | topics = var.kafka_topic 24 | 25 | authentication = var.msk_authentication 26 | credentials = { 27 | username = var.msk_scram_user 28 | password = var.msk_scram_password 29 | } 30 | 31 | reverse_private_endpoint_ids = [ 32 | clickhouse_clickpipes_reverse_private_endpoint.endpoint.id 33 | ] 34 | } 35 | } 36 | 37 | destination = { 38 | table = "my_table" 39 | managed_table = true 40 | 41 | table_definition = { 42 | engine = { 43 | type = "MergeTree" 44 | } 45 | } 46 | 47 | columns = [ 48 | { 49 | name = "my_field1" 50 | type = "String" 51 | }, { 52 | name = "my_field2" 53 | type = "UInt64" 54 | } 55 | ] 56 | } 57 | 58 | field_mappings = [ 59 | { 60 | source_field = "my_field" 61 | destination_field = "my_field1" 62 | } 63 | ] 64 | } 65 | 66 | output "clickpipe_id" { 67 | value = clickhouse_clickpipe.msk.id 68 | } -------------------------------------------------------------------------------- /examples/clickpipe/reverse_private_endpoint_msk_pipe/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.2.0-alpha1" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/clickpipe/reverse_private_endpoint_msk_pipe/provider.tf.template.alpha: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/clickpipe/reverse_private_endpoint_msk_pipe/reverse_private_endpoint.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | rpe_msk_authentication_mapping = { 3 | "SCRAM-SHA-512" = "SASL_SCRAM" 4 | "IAM_ROLE" = "SASL_IAM" 5 | "IAM_USER" = "SASL_IAM" 6 | } 7 | 8 | // In this example we map from a ClickPipe authentication method 9 | // into a MSK multi-VPC authentication method. 10 | rpe_msk_authentication = local.rpe_msk_authentication_mapping[var.msk_authentication] 11 | } 12 | 13 | resource "clickhouse_clickpipes_reverse_private_endpoint" "endpoint" { 14 | service_id = var.service_id 15 | description = "Reverse private endpoint for my ClickPipe" 16 | type = "MSK_MULTI_VPC" 17 | msk_cluster_arn = var.msk_cluster_arn 18 | msk_authentication = local.rpe_msk_authentication 19 | } 20 | 21 | output "reverse_private_endpoint_id" { 22 | value = clickhouse_clickpipes_reverse_private_endpoint.endpoint.id 23 | } 24 | 25 | output "msk_vpc_connection_id" { 26 | value = clickhouse_clickpipes_reverse_private_endpoint.endpoint.endpoint_id 27 | } 28 | -------------------------------------------------------------------------------- /examples/clickpipe/reverse_private_endpoint_msk_pipe/variables.sample.tfvars: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | service_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 6 | 7 | msk_cluster_arn = "arn:aws:kafka:us-east-2:123456789012:cluster/ExampleCluster/12345678-1234-1234-1234-123456789012-1" 8 | msk_authentication = "SASL_SCRAM" # or SASL_IAM 9 | msk_scram_user = "example_user" 10 | msk_scram_password = "example_password" 11 | kafka_topic = "example_topic" -------------------------------------------------------------------------------- /examples/clickpipe/reverse_private_endpoint_msk_pipe/vars.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" {} 2 | variable "token_key" {} 3 | variable "token_secret" {} 4 | 5 | variable "service_id" { 6 | description = "ClickHouse service ID" 7 | } 8 | 9 | variable "msk_cluster_arn" { 10 | description = "MSK cluter ARN" 11 | } 12 | 13 | variable "msk_authentication" { 14 | description = "MSK authentication" 15 | default = "SCRAM-SHA-512" # or IAM_USER or IAM_ROLE 16 | } 17 | 18 | variable "msk_scram_user" { 19 | description = "MSK scram user" 20 | default = "scram_user" 21 | } 22 | 23 | variable "msk_scram_password" { 24 | description = "MSK scram password" 25 | default = "scram_password" 26 | } 27 | 28 | variable "kafka_topic" { 29 | description = "Kafka topic" 30 | default = "my_topic" 31 | } 32 | -------------------------------------------------------------------------------- /examples/clickpipe/reverse_private_endpoint_vpc_resource/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" {} 2 | variable "token_key" {} 3 | variable "token_secret" {} 4 | 5 | variable "service_id" { 6 | description = "ClickHouse service ID" 7 | } 8 | 9 | variable "vpc_resource_configuration_id" { 10 | description = "VPC resource configuration id" 11 | } 12 | 13 | variable "vpc_resource_share_arn" { 14 | description = "VPC resource share ARN" 15 | } 16 | 17 | resource "clickhouse_clickpipes_reverse_private_endpoint" "endpoint" { 18 | service_id = var.service_id 19 | description = "Reverse private endpoint for ClickPipes" 20 | type = "VPC_RESOURCE" 21 | vpc_resource_configuration_id = var.vpc_resource_configuration_id 22 | vpc_resource_share_arn = var.vpc_resource_share_arn 23 | } 24 | 25 | output "id" { 26 | value = clickhouse_clickpipes_reverse_private_endpoint.endpoint.id 27 | } 28 | 29 | output "endpoint_id" { 30 | value = clickhouse_clickpipes_reverse_private_endpoint.endpoint.endpoint_id 31 | } 32 | 33 | output "dns_names" { 34 | value = concat( 35 | clickhouse_clickpipes_reverse_private_endpoint.endpoint.dns_names, 36 | clickhouse_clickpipes_reverse_private_endpoint.endpoint.private_dns_names != null ? clickhouse_clickpipes_reverse_private_endpoint.endpoint.private_dns_names : [] 37 | ) 38 | } 39 | 40 | output "status" { 41 | value = clickhouse_clickpipes_reverse_private_endpoint.endpoint.status 42 | } 43 | -------------------------------------------------------------------------------- /examples/clickpipe/reverse_private_endpoint_vpc_resource/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.2.0-alpha1" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/clickpipe/reverse_private_endpoint_vpc_resource/provider.tf.template.alpha: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/clickpipe/reverse_private_endpoint_vpc_resource/variables.sample.tfvars: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | service_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 6 | 7 | vpc_resource_configuration_id = "rcfg-1234567890abcdef" 8 | vpc_resource_share_arn = "arn:aws:ram:us-east-2:123456789012:resource-share/12345678-1234-1234-1234-123456789012" -------------------------------------------------------------------------------- /examples/clickpipe/reverse_private_endpoint_vpce_service/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" {} 2 | variable "token_key" {} 3 | variable "token_secret" {} 4 | 5 | variable "service_id" { 6 | description = "ClickHouse service ID" 7 | } 8 | 9 | variable "vpc_endpoint_service_name" { 10 | description = "VPC endpoint service name" 11 | } 12 | 13 | resource "clickhouse_clickpipes_reverse_private_endpoint" "endpoint" { 14 | service_id = var.service_id 15 | description = "Reverse private endpoint for ClickPipes" 16 | type = "VPC_ENDPOINT_SERVICE" 17 | vpc_endpoint_service_name = var.vpc_endpoint_service_name 18 | } 19 | 20 | output "id" { 21 | value = clickhouse_clickpipes_reverse_private_endpoint.endpoint.id 22 | } 23 | 24 | output "endpoint_id" { 25 | value = clickhouse_clickpipes_reverse_private_endpoint.endpoint.endpoint_id 26 | } 27 | 28 | output "dns_names" { 29 | value = concat( 30 | clickhouse_clickpipes_reverse_private_endpoint.endpoint.dns_names, 31 | clickhouse_clickpipes_reverse_private_endpoint.endpoint.private_dns_names != null ? clickhouse_clickpipes_reverse_private_endpoint.endpoint.private_dns_names : [] 32 | ) 33 | } 34 | 35 | output "status" { 36 | value = clickhouse_clickpipes_reverse_private_endpoint.endpoint.status 37 | } 38 | -------------------------------------------------------------------------------- /examples/clickpipe/reverse_private_endpoint_vpce_service/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.2.0-alpha1" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/clickpipe/reverse_private_endpoint_vpce_service/provider.tf.template.alpha: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/clickpipe/reverse_private_endpoint_vpce_service/variables.sample.tfvars: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | service_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 6 | 7 | vpc_endpoint_service_name = "com.amazonaws.us-east-2.vpce-svc-0a1b2c3d4e5f6g7h8" -------------------------------------------------------------------------------- /examples/clickpipe/service_and_clickpipe/README.md: -------------------------------------------------------------------------------- 1 | ## ClickPipe Kafka with Confluent example 2 | 3 | This example demonstrates how to deploy a Kafka ClickPipe with a Confluent Kafka cluster as the input source. 4 | 5 | ## How to run 6 | 7 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 8 | - Run `terraform init` 9 | - Run `terraform -var-file=variables.tfvars` 10 | -------------------------------------------------------------------------------- /examples/clickpipe/service_and_clickpipe/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" {} 2 | variable "token_key" {} 3 | variable "token_secret" {} 4 | 5 | variable "service_name" { 6 | type = string 7 | default = "My Terraform Service" 8 | } 9 | 10 | variable "region" { 11 | type = string 12 | default = "us-east-2" 13 | } 14 | 15 | variable "kafka_brokers" { 16 | description = "Kafka brokers" 17 | } 18 | 19 | variable "kafka_topics" { 20 | description = "Kafka topics" 21 | } 22 | 23 | variable "kafka_username" { 24 | description = "Username" 25 | sensitive = true 26 | } 27 | 28 | variable "kafka_password" { 29 | description = "Password" 30 | sensitive = true 31 | } 32 | 33 | resource "clickhouse_service" "service" { 34 | name = var.service_name 35 | cloud_provider = "aws" 36 | region = var.region 37 | tier = "development" 38 | idle_scaling = true 39 | idle_timeout_minutes = 5 40 | password_hash = "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=" # base64 encoded sha256 hash of "test" 41 | 42 | ip_access = [ 43 | { 44 | source = "0.0.0.0" 45 | description = "Anywhere" 46 | } 47 | ] 48 | } 49 | 50 | resource "clickhouse_clickpipe" "kafka_confluent" { 51 | name = "🚀 ClickPipe created with Terraform" 52 | description = "Data pipeline from Confluent to ClickHouse" 53 | 54 | service_id = clickhouse_service.service.id 55 | 56 | scaling = { 57 | replicas = 1 58 | } 59 | 60 | state = "Running" 61 | 62 | source = { 63 | kafka = { 64 | type = "confluent" 65 | format = "JSONEachRow" 66 | brokers = var.kafka_brokers 67 | topics = var.kafka_topics 68 | 69 | credentials = { 70 | username = var.kafka_username 71 | password = var.kafka_password 72 | } 73 | } 74 | } 75 | 76 | destination = { 77 | table = "my_table" 78 | managed_table = true 79 | 80 | table_definition = { 81 | engine = { 82 | type = "MergeTree" 83 | } 84 | } 85 | 86 | columns = [ 87 | { 88 | name = "my_field1" 89 | type = "String" 90 | }, { 91 | name = "my_field2" 92 | type = "UInt64" 93 | } 94 | ] 95 | } 96 | 97 | field_mappings = [ 98 | { 99 | source_field = "my_field" 100 | destination_field = "my_field1" 101 | } 102 | ] 103 | } 104 | 105 | output "clickpipe_id" { 106 | value = clickhouse_clickpipe.kafka_confluent.id 107 | } -------------------------------------------------------------------------------- /examples/clickpipe/service_and_clickpipe/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.2.0-alpha1" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/clickpipe/service_and_clickpipe/provider.tf.template.alpha: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/clickpipe/service_and_clickpipe/variables.sample.tfvars: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | 6 | kafka_brokers = "broker.us-east-2.aws.confluent.cloud:9092" 7 | kafka_topics = "cell_towers" 8 | 9 | kafka_username = "" 10 | kafka_password = "" -------------------------------------------------------------------------------- /examples/data-sources/clickhouse_api_key_id/data-source.tf: -------------------------------------------------------------------------------- 1 | data "clickhouse_api_key_id" "my_api_key" { 2 | # The name attribute can be omitted 3 | # In this case the API Key used to run the terraform provider will be retrieved. 4 | name = "my-api-key" 5 | } 6 | -------------------------------------------------------------------------------- /examples/database/README.md: -------------------------------------------------------------------------------- 1 | ## Basic example to manage Role Based Access Control 2 | 3 | The Terraform code deploys following resources: 4 | - 1 ClickHouse service on AWS 5 | - 1 database on the ClickHouse service 6 | 7 | ## How to run 8 | 9 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 10 | - Run `terraform init` 11 | - Run `terraform -var-file=variables.tfvars` 12 | -------------------------------------------------------------------------------- /examples/database/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" { 2 | type = string 3 | } 4 | 5 | variable "token_key" { 6 | type = string 7 | } 8 | 9 | variable "token_secret" { 10 | type = string 11 | } 12 | 13 | variable "service_name" { 14 | type = string 15 | default = "My Terraform Service" 16 | } 17 | 18 | variable "region" { 19 | type = string 20 | default = "us-east-2" 21 | } 22 | 23 | variable "release_channel" { 24 | type = string 25 | default = "default" 26 | validation { 27 | condition = var.release_channel == "default" || var.release_channel == "fast" 28 | error_message = "Release channel can be either 'default' or 'fast'." 29 | } 30 | } 31 | 32 | data "clickhouse_api_key_id" "self" { 33 | } 34 | 35 | resource "clickhouse_service" "service" { 36 | name = var.service_name 37 | cloud_provider = "aws" 38 | region = var.region 39 | release_channel = var.release_channel 40 | idle_scaling = true 41 | idle_timeout_minutes = 5 42 | password_hash = "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=" # base64 encoded sha256 hash of "test" 43 | 44 | ip_access = [ 45 | { 46 | source = "0.0.0.0" 47 | description = "Anywhere" 48 | } 49 | ] 50 | 51 | # Required in order to create 'clickhouse_database' resource below. 52 | query_api_endpoints = { 53 | api_key_ids = [ 54 | data.clickhouse_api_key_id.self.id, 55 | ] 56 | roles = [ 57 | "sql_console_admin" 58 | ] 59 | allowed_origins = null 60 | } 61 | 62 | min_replica_memory_gb = 8 63 | max_replica_memory_gb = 120 64 | 65 | backup_configuration = { 66 | backup_period_in_hours = 24 67 | backup_retention_period_in_hours = 24 68 | backup_start_time = null 69 | } 70 | } 71 | 72 | # Requires 'query_api_endpoints' to be enabled in the service. 73 | resource "clickhouse_database" "db1" { 74 | service_id = clickhouse_service.service.id 75 | name = "mydb" 76 | } 77 | -------------------------------------------------------------------------------- /examples/database/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.2.0-alpha1" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/database/provider.tf.template.alpha: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/database/variables.tfvars.sample: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | -------------------------------------------------------------------------------- /examples/full/README.md: -------------------------------------------------------------------------------- 1 | # ClickHouse terraform provider examples 2 | 3 | This directory contains some examples to use the official ClickHouse terraform provider. 4 | 5 | - `basic`: contains examples on how to create a basic ClickHouse service in all supported cloud providers. 6 | - `private_endpoint`: contains examples on how to create a ClickHouse service and connect to supported cloud providers using a private link. 7 | -------------------------------------------------------------------------------- /examples/full/basic/aws/README.md: -------------------------------------------------------------------------------- 1 | ## AWS Basic example 2 | 3 | The Terraform code deploys following resources: 4 | - 1 ClickHouse service on AWS 5 | 6 | The ClickHouse service is available from anywhere. 7 | 8 | ## How to run 9 | 10 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 11 | - Run `terraform init` 12 | - Run `terraform -var-file=variables.tfvars` 13 | -------------------------------------------------------------------------------- /examples/full/basic/aws/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" { 2 | type = string 3 | } 4 | 5 | variable "token_key" { 6 | type = string 7 | } 8 | 9 | variable "token_secret" { 10 | type = string 11 | } 12 | 13 | variable "service_name" { 14 | type = string 15 | default = "My Terraform Service" 16 | } 17 | 18 | variable "region" { 19 | type = string 20 | default = "us-east-2" 21 | } 22 | 23 | variable "release_channel" { 24 | type = string 25 | default = "default" 26 | validation { 27 | condition = var.release_channel == "default" || var.release_channel == "fast" 28 | error_message = "Release channel can be either 'default' or 'fast'." 29 | } 30 | } 31 | 32 | data "clickhouse_api_key_id" "self" { 33 | } 34 | 35 | resource "clickhouse_service" "service" { 36 | name = var.service_name 37 | cloud_provider = "aws" 38 | region = var.region 39 | release_channel = var.release_channel 40 | idle_scaling = true 41 | idle_timeout_minutes = 5 42 | password_hash = "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=" # base64 encoded sha256 hash of "test" 43 | 44 | ip_access = [ 45 | { 46 | source = "0.0.0.0" 47 | description = "Anywhere" 48 | } 49 | ] 50 | 51 | endpoints = { 52 | mysql = { 53 | enabled = true 54 | } 55 | } 56 | 57 | query_api_endpoints = { 58 | api_key_ids = [ 59 | data.clickhouse_api_key_id.self.id, 60 | ] 61 | roles = [ 62 | "sql_console_admin" 63 | ] 64 | allowed_origins = null 65 | } 66 | 67 | min_replica_memory_gb = 8 68 | max_replica_memory_gb = 120 69 | 70 | backup_configuration = { 71 | backup_period_in_hours = 24 72 | backup_retention_period_in_hours = 24 73 | backup_start_time = null 74 | } 75 | } 76 | 77 | output "service_endpoints" { 78 | value = clickhouse_service.service.endpoints 79 | } 80 | 81 | output "service_iam" { 82 | value = clickhouse_service.service.iam_role 83 | } 84 | -------------------------------------------------------------------------------- /examples/full/basic/aws/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.3.3" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/full/basic/aws/provider.tf.template: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/full/basic/aws/variables.tfvars.sample: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | -------------------------------------------------------------------------------- /examples/full/basic/azure/README.md: -------------------------------------------------------------------------------- 1 | ## AWS Basic example 2 | 3 | The Terraform code deploys following resources: 4 | - 1 ClickHouse service on Azure 5 | 6 | The ClickHouse service is available from anywhere. 7 | 8 | ## How to run 9 | 10 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 11 | - Run `terraform init` 12 | - Run `terraform -var-file=variables.tfvars` 13 | -------------------------------------------------------------------------------- /examples/full/basic/azure/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" { 2 | type = string 3 | } 4 | 5 | variable "token_key" { 6 | type = string 7 | } 8 | 9 | variable "token_secret" { 10 | type = string 11 | } 12 | 13 | variable "service_name" { 14 | type = string 15 | default = "My Terraform Service" 16 | } 17 | 18 | variable "region" { 19 | type = string 20 | default = "westus3" 21 | } 22 | 23 | variable "release_channel" { 24 | type = string 25 | default = "fast" 26 | validation { 27 | condition = var.release_channel == "default" || var.release_channel == "fast" 28 | error_message = "Release channel can be either 'default' or 'fast'." 29 | } 30 | } 31 | 32 | data "clickhouse_api_key_id" "self" { 33 | } 34 | 35 | resource "clickhouse_service" "service" { 36 | name = var.service_name 37 | cloud_provider = "azure" 38 | region = var.region 39 | release_channel = var.release_channel 40 | idle_scaling = true 41 | idle_timeout_minutes = 5 42 | password_hash = "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=" # base64 encoded sha256 hash of "test" 43 | 44 | ip_access = [ 45 | { 46 | source = "0.0.0.0" 47 | description = "Anywhere" 48 | } 49 | ] 50 | 51 | endpoints = { 52 | mysql = { 53 | enabled = true 54 | } 55 | } 56 | 57 | query_api_endpoints = { 58 | api_key_ids = [ 59 | data.clickhouse_api_key_id.self.id, 60 | ] 61 | roles = [ 62 | "sql_console_admin" 63 | ] 64 | allowed_origins = null 65 | } 66 | 67 | min_replica_memory_gb = 8 68 | max_replica_memory_gb = 120 69 | 70 | backup_configuration = { 71 | backup_retention_period_in_hours = 24 72 | backup_start_time = "02:00" 73 | } 74 | } 75 | 76 | output "service_endpoints" { 77 | value = clickhouse_service.service.endpoints 78 | } 79 | 80 | output "service_iam" { 81 | value = clickhouse_service.service.iam_role 82 | } 83 | -------------------------------------------------------------------------------- /examples/full/basic/azure/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.3.3" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/full/basic/azure/provider.tf.template: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/full/basic/azure/variables.tfvars.sample: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | -------------------------------------------------------------------------------- /examples/full/basic/gcp/README.md: -------------------------------------------------------------------------------- 1 | ## AWS Basic example 2 | 3 | The Terraform code deploys following resources: 4 | - 1 ClickHouse service on GCP 5 | 6 | The ClickHouse service is available from anywhere. 7 | 8 | ## How to run 9 | 10 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 11 | - Run `terraform init` 12 | - Run `terraform -var-file=variables.tfvars` 13 | -------------------------------------------------------------------------------- /examples/full/basic/gcp/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" { 2 | type = string 3 | } 4 | 5 | variable "token_key" { 6 | type = string 7 | } 8 | 9 | variable "token_secret" { 10 | type = string 11 | } 12 | 13 | variable "service_name" { 14 | type = string 15 | default = "My Terraform Service" 16 | } 17 | 18 | variable "region" { 19 | type = string 20 | default = "europe-west4" 21 | } 22 | 23 | variable "release_channel" { 24 | type = string 25 | default = "default" 26 | validation { 27 | condition = var.release_channel == "default" || var.release_channel == "fast" 28 | error_message = "Release channel can be either 'default' or 'fast'." 29 | } 30 | } 31 | 32 | data "clickhouse_api_key_id" "self" { 33 | } 34 | 35 | resource "clickhouse_service" "service" { 36 | name = var.service_name 37 | cloud_provider = "gcp" 38 | region = var.region 39 | release_channel = var.release_channel 40 | idle_scaling = true 41 | idle_timeout_minutes = 5 42 | password_hash = "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=" # base64 encoded sha256 hash of "test" 43 | 44 | ip_access = [ 45 | { 46 | source = "0.0.0.0" 47 | description = "Anywhere" 48 | } 49 | ] 50 | 51 | endpoints = { 52 | mysql = { 53 | enabled = true 54 | } 55 | } 56 | 57 | query_api_endpoints = { 58 | api_key_ids = [ 59 | data.clickhouse_api_key_id.self.id, 60 | ] 61 | roles = [ 62 | "sql_console_admin" 63 | ] 64 | allowed_origins = null 65 | } 66 | 67 | min_replica_memory_gb = 8 68 | max_replica_memory_gb = 120 69 | 70 | backup_configuration = { 71 | backup_retention_period_in_hours = 48 72 | } 73 | } 74 | 75 | output "service_endpoints" { 76 | value = clickhouse_service.service.endpoints 77 | } 78 | 79 | output "service_iam" { 80 | value = clickhouse_service.service.iam_role 81 | } 82 | -------------------------------------------------------------------------------- /examples/full/basic/gcp/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.3.3" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/full/basic/gcp/provider.tf.template: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/full/basic/gcp/variables.tfvars.sample: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | -------------------------------------------------------------------------------- /examples/full/private_endpoint/aws/README.md: -------------------------------------------------------------------------------- 1 | ## AWS Private Link example 2 | 3 | Tested with HashiCorp/AWS v5.63.0 Terraform provider. 4 | 5 | The Terraform code deploys following resources: 6 | - 1 AWS PrivateLink endpoint with security groups: pl_vpc_foo 7 | - 1 ClickHouse service: red 8 | 9 | The ClickHouse service is available from `pl_vpc_foo` PrivateLink connection only, access from the internet is blocked. 10 | 11 | ## How to run 12 | 13 | - Create a VPC into AWS 14 | - Create 2 subnets within the VPC in 2 different AZs. 15 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 16 | - Run `terraform init` 17 | - Run `terraform -var-file=variables.tfvars` 18 | 19 | ## Needed AWS permissions 20 | 21 | To run this example, the AWS user you provide credentials for needs the following permissions: 22 | 23 | ``` 24 | { 25 | "Version": "2012-10-17", 26 | "Statement": [ 27 | { 28 | "Effect": "Allow", 29 | "Action": [ 30 | "ec2:CreateTags", 31 | "ec2:CreateVpc", 32 | "ec2:DescribeVpcs", 33 | "ec2:ModifyVpcAttribute", 34 | "ec2:DescribeVpcAttribute", 35 | "ec2:CreateSubnet", 36 | "ec2:DescribeSubnets", 37 | "ec2:CreateSecurityGroup", 38 | "ec2:DescribeSecurityGroups", 39 | "ec2:RevokeSecurityGroupEgress", 40 | "ec2:AuthorizeSecurityGroupIngress", 41 | "ec2:CreateVpcEndpoint", 42 | "route53:AssociateVPCWithHostedZone", 43 | "ec2:DescribeVpcEndpoints", 44 | "ec2:DescribePrefixLists", 45 | "ec2:DescribeNetworkInterfaces", 46 | "ec2:DescribeSecurityGroupRules", 47 | "ec2:DeleteVpcEndpoints", 48 | "ec2:RevokeSecurityGroupIngress", 49 | "ec2:DeleteSubnet", 50 | "ec2:DeleteVpc", 51 | "ec2:DeleteSecurityGroup", 52 | "ec2:DescribeAvailabilityZones" 53 | ], 54 | "Resource": "*" 55 | } 56 | ] 57 | } 58 | ``` 59 | -------------------------------------------------------------------------------- /examples/full/private_endpoint/aws/aws.tf: -------------------------------------------------------------------------------- 1 | variable "aws_key" { 2 | type = string 3 | } 4 | 5 | variable "aws_secret" { 6 | type = string 7 | } 8 | 9 | variable "aws_session_token" { 10 | type = string 11 | default = "" 12 | } 13 | 14 | locals { 15 | tags = { 16 | Name = var.service_name 17 | } 18 | } 19 | 20 | provider "aws" { 21 | region = var.region 22 | access_key = var.aws_key 23 | secret_key = var.aws_secret 24 | token = var.aws_session_token 25 | } 26 | 27 | resource "aws_vpc" "vpc" { 28 | cidr_block = "192.168.0.0/16" 29 | 30 | enable_dns_support = true 31 | enable_dns_hostnames = true 32 | 33 | tags = local.tags 34 | } 35 | 36 | data "aws_availability_zones" "available" { 37 | state = "available" 38 | } 39 | 40 | resource "aws_subnet" "subnet1" { 41 | vpc_id = aws_vpc.vpc.id 42 | cidr_block = "192.168.0.0/24" 43 | availability_zone = data.aws_availability_zones.available.names[0] 44 | 45 | tags = local.tags 46 | } 47 | 48 | resource "aws_subnet" "subnet2" { 49 | vpc_id = aws_vpc.vpc.id 50 | cidr_block = "192.168.1.0/24" 51 | availability_zone = data.aws_availability_zones.available.names[1] 52 | 53 | tags = local.tags 54 | } 55 | 56 | // Security group for PrivateLink in VPC foo 57 | resource "aws_security_group" "allow_clickhouse_cloud_foo" { 58 | name = "allow_clickhouse_cloud_foo" 59 | description = "Allow Connections to clickhouse cloud" 60 | vpc_id = aws_vpc.vpc.id 61 | 62 | tags = local.tags 63 | } 64 | 65 | // Allow connections from 0.0.0.0/0, please make adjustments 66 | resource "aws_vpc_security_group_ingress_rule" "allow_clickhouse_native_protocol" { 67 | security_group_id = aws_security_group.allow_clickhouse_cloud_foo.id 68 | cidr_ipv4 = "0.0.0.0/0" 69 | ip_protocol = "tcp" 70 | from_port = 9440 71 | to_port = 9440 72 | } 73 | 74 | // Allow connections from 0.0.0.0/0, please make adjustments 75 | resource "aws_vpc_security_group_ingress_rule" "allow_clickhouse_https_protocol" { 76 | security_group_id = aws_security_group.allow_clickhouse_cloud_foo.id 77 | cidr_ipv4 = "0.0.0.0/0" 78 | ip_protocol = "tcp" 79 | from_port = 8443 80 | to_port = 8443 81 | } 82 | 83 | // Private Link in VPC foo 84 | resource "aws_vpc_endpoint" "pl_vpc_foo" { 85 | vpc_id = aws_vpc.vpc.id 86 | service_name = clickhouse_service.aws_red.private_endpoint_config.endpoint_service_id 87 | vpc_endpoint_type = "Interface" 88 | security_group_ids = [ 89 | aws_security_group.allow_clickhouse_cloud_foo.id 90 | ] 91 | subnet_ids = [ 92 | aws_subnet.subnet1.id, 93 | aws_subnet.subnet2.id 94 | ] 95 | private_dns_enabled = false 96 | 97 | tags = local.tags 98 | } 99 | -------------------------------------------------------------------------------- /examples/full/private_endpoint/aws/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" { 2 | type = string 3 | } 4 | 5 | variable "token_key" { 6 | type = string 7 | } 8 | 9 | variable "token_secret" { 10 | type = string 11 | } 12 | 13 | variable "service_name" { 14 | type = string 15 | default = "red" 16 | } 17 | 18 | variable "region" { 19 | type = string 20 | default = "us-east-2" 21 | } 22 | 23 | resource "clickhouse_service" "aws_red" { 24 | name = var.service_name 25 | cloud_provider = "aws" 26 | region = var.region 27 | idle_scaling = true 28 | idle_timeout_minutes = 5 29 | password_hash = "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=" # base64 encoded sha256 hash of "test" 30 | 31 | // keep it empty to block access from internet 32 | ip_access = [] 33 | 34 | backup_configuration = { 35 | backup_period_in_hours = 24 36 | backup_retention_period_in_hours = 24 37 | backup_start_time = null 38 | } 39 | 40 | min_replica_memory_gb = 8 41 | max_replica_memory_gb = 120 42 | } 43 | 44 | resource "clickhouse_service_private_endpoints_attachment" "red_attachment" { 45 | private_endpoint_ids = [aws_vpc_endpoint.pl_vpc_foo.id] 46 | service_id = clickhouse_service.aws_red.id 47 | } 48 | 49 | # hostname for connecting to instance via PrivateLink from VPC foo 50 | output "red_private_link_endpoint" { 51 | value = clickhouse_service.aws_red.private_endpoint_config.private_dns_hostname 52 | } 53 | -------------------------------------------------------------------------------- /examples/full/private_endpoint/aws/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.3.3" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/full/private_endpoint/aws/provider.tf.template: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/full/private_endpoint/aws/variables.tfvars.sample: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | 6 | # AWS 7 | aws_key = "key" 8 | aws_secret = "secret" 9 | aws_region = "us-west-2" 10 | -------------------------------------------------------------------------------- /examples/full/tde/aws/README.md: -------------------------------------------------------------------------------- 1 | ## AWS Basic example 2 | 3 | The Terraform code deploys following resources: 4 | - 1 ClickHouse service on AWS 5 | 6 | WARNING: this example requires an organization with the Enterprise plan to run. 7 | 8 | ## How to run 9 | 10 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 11 | - Run `terraform init` 12 | - Run `terraform -var-file=variables.tfvars` 13 | -------------------------------------------------------------------------------- /examples/full/tde/aws/aws.tf: -------------------------------------------------------------------------------- 1 | variable "aws_key" { 2 | type = string 3 | } 4 | 5 | variable "aws_secret" { 6 | type = string 7 | } 8 | 9 | variable "aws_session_token" { 10 | type = string 11 | default = "" 12 | } 13 | 14 | locals { 15 | tags = { 16 | Role = "terraform-e2e-test" 17 | ServiceName = replace(var.service_name, "/[^-a-zA-Z0-9_.:/=+@ ]/", "_") 18 | } 19 | } 20 | 21 | provider "aws" { 22 | region = var.region 23 | access_key = var.aws_key 24 | secret_key = var.aws_secret 25 | token = var.aws_session_token 26 | } 27 | 28 | data "aws_caller_identity" "current" {} 29 | 30 | data "aws_iam_policy_document" "policy" { 31 | # Allow root user on the account all access. 32 | statement { 33 | sid = "AllowRoot" 34 | 35 | actions = ["kms:*"] 36 | resources = ["*"] 37 | principals { 38 | type = "AWS" 39 | identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"] 40 | } 41 | } 42 | 43 | # Allow user that runs terraform to manage the KMS key. 44 | statement { 45 | sid = "AllowAdmins" 46 | actions = [ 47 | "kms:Create*", 48 | "kms:Describe*", 49 | "kms:Enable*", 50 | "kms:List*", 51 | "kms:Put*", 52 | "kms:Update*", 53 | "kms:Revoke*", 54 | "kms:Disable*", 55 | "kms:Get*", 56 | "kms:Delete*", 57 | "kms:TagResource", 58 | "kms:UntagResource", 59 | "kms:ScheduleKeyDeletion", 60 | "kms:CancelKeyDeletion", 61 | "kms:RotateKeyOnDemand", 62 | "kms:Encrypt", 63 | "kms:Decrypt", 64 | "kms:ReEncrypt*", 65 | "kms:DescribeKey", 66 | "kms:CreateGrant", 67 | "kms:ListGrants", 68 | "kms:RevokeGrant" 69 | ] 70 | resources = ["*"] 71 | 72 | principals { 73 | type = "AWS" 74 | identifiers = [data.aws_caller_identity.current.arn] 75 | } 76 | } 77 | 78 | # Allow clickhouse's accounts to access the KMS key. 79 | statement { 80 | sid = "AllowClickHouse" 81 | actions = [ 82 | "kms:Encrypt", 83 | "kms:Decrypt", 84 | "kms:ReEncrypt*", 85 | "kms:DescribeKey", 86 | ] 87 | resources = ["*"] 88 | 89 | principals { 90 | type = "AWS" 91 | identifiers = [clickhouse_service.service.transparent_data_encryption.role_id] 92 | } 93 | } 94 | } 95 | 96 | resource "aws_kms_key" "enc" { 97 | customer_master_key_spec = "SYMMETRIC_DEFAULT" 98 | deletion_window_in_days = 7 99 | description = var.service_name 100 | enable_key_rotation = false 101 | is_enabled = true 102 | key_usage = "ENCRYPT_DECRYPT" 103 | multi_region = false 104 | 105 | policy = data.aws_iam_policy_document.policy.json 106 | 107 | tags = local.tags 108 | } 109 | -------------------------------------------------------------------------------- /examples/full/tde/aws/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" { 2 | type = string 3 | } 4 | 5 | variable "token_key" { 6 | type = string 7 | } 8 | 9 | variable "token_secret" { 10 | type = string 11 | } 12 | 13 | variable "service_name" { 14 | type = string 15 | default = "My Terraform Service" 16 | } 17 | 18 | variable "region" { 19 | type = string 20 | default = "us-east-2" 21 | } 22 | 23 | variable "release_channel" { 24 | type = string 25 | default = "default" 26 | validation { 27 | condition = var.release_channel == "default" || var.release_channel == "fast" 28 | error_message = "Release channel can be either 'default' or 'fast'." 29 | } 30 | } 31 | 32 | data "clickhouse_api_key_id" "self" { 33 | } 34 | 35 | resource "clickhouse_service" "service" { 36 | name = var.service_name 37 | cloud_provider = "aws" 38 | region = var.region 39 | release_channel = var.release_channel 40 | idle_scaling = true 41 | idle_timeout_minutes = 5 42 | password_hash = "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=" # base64 encoded sha256 hash of "test" 43 | 44 | ip_access = [ 45 | { 46 | source = "0.0.0.0" 47 | description = "Anywhere" 48 | } 49 | ] 50 | 51 | min_replica_memory_gb = 8 52 | max_replica_memory_gb = 120 53 | 54 | backup_configuration = { 55 | backup_period_in_hours = 24 56 | backup_retention_period_in_hours = 24 57 | backup_start_time = null 58 | } 59 | 60 | transparent_data_encryption = { 61 | enabled = true 62 | } 63 | } 64 | 65 | resource "clickhouse_service_transparent_data_encryption_key_association" "service_key_association" { 66 | service_id = clickhouse_service.service.id 67 | key_id = aws_kms_key.enc.arn 68 | } 69 | 70 | output "service_endpoints" { 71 | value = clickhouse_service.service.endpoints 72 | } 73 | 74 | output "service_iam" { 75 | value = clickhouse_service.service.iam_role 76 | } 77 | -------------------------------------------------------------------------------- /examples/full/tde/aws/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.3.3" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/full/tde/aws/provider.tf.template: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/full/tde/aws/variables.tfvars.sample: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | 6 | # AWS 7 | aws_key = "key" 8 | aws_secret = "secret" 9 | aws_region = "us-west-2" 10 | -------------------------------------------------------------------------------- /examples/full/tde/gcp/README.md: -------------------------------------------------------------------------------- 1 | ## AWS Basic example 2 | 3 | The Terraform code deploys following resources: 4 | - 1 ClickHouse service on GCP with TDE feature enabled 5 | 6 | WARNING: this example requires an organization with the Enterprise plan to run. 7 | 8 | ## How to run 9 | 10 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 11 | - Run `terraform init` 12 | - Run `terraform -var-file=variables.tfvars` 13 | -------------------------------------------------------------------------------- /examples/full/tde/gcp/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" { 2 | type = string 3 | } 4 | 5 | variable "token_key" { 6 | type = string 7 | } 8 | 9 | variable "token_secret" { 10 | type = string 11 | } 12 | 13 | variable "service_name" { 14 | type = string 15 | default = "My Terraform Service" 16 | } 17 | 18 | variable "region" { 19 | type = string 20 | default = "europe-west4" 21 | } 22 | 23 | variable "release_channel" { 24 | type = string 25 | default = "default" 26 | validation { 27 | condition = var.release_channel == "default" || var.release_channel == "fast" 28 | error_message = "Release channel can be either 'default' or 'fast'." 29 | } 30 | } 31 | 32 | data "clickhouse_api_key_id" "self" { 33 | } 34 | 35 | resource "clickhouse_service" "service" { 36 | name = var.service_name 37 | cloud_provider = "gcp" 38 | region = var.region 39 | release_channel = var.release_channel 40 | idle_scaling = true 41 | idle_timeout_minutes = 5 42 | password_hash = "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=" # base64 encoded sha256 hash of "test" 43 | 44 | ip_access = [ 45 | { 46 | source = "0.0.0.0" 47 | description = "Anywhere" 48 | } 49 | ] 50 | 51 | endpoints = { 52 | mysql = { 53 | enabled = true 54 | } 55 | } 56 | 57 | query_api_endpoints = { 58 | api_key_ids = [ 59 | data.clickhouse_api_key_id.self.id, 60 | ] 61 | roles = [ 62 | "sql_console_admin" 63 | ] 64 | allowed_origins = null 65 | } 66 | 67 | min_replica_memory_gb = 8 68 | max_replica_memory_gb = 120 69 | 70 | backup_configuration = { 71 | backup_retention_period_in_hours = 48 72 | } 73 | 74 | transparent_data_encryption = { 75 | enabled = true 76 | } 77 | } 78 | 79 | output "service_endpoints" { 80 | value = clickhouse_service.service.endpoints 81 | } 82 | 83 | output "service_iam" { 84 | value = clickhouse_service.service.iam_role 85 | } 86 | -------------------------------------------------------------------------------- /examples/full/tde/gcp/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.3.3" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/full/tde/gcp/provider.tf.template: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/full/tde/gcp/variables.tfvars.sample: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | -------------------------------------------------------------------------------- /examples/full/warehouse/aws/README.md: -------------------------------------------------------------------------------- 1 | ## AWS Compute-Compute separation example 2 | 3 | The Terraform code deploys following resources: 4 | - 1 ClickHouse service on AWS meant to be the primary service of a data warehouse 5 | - 1 ClickHouse service on AWS meant to be the secondary service in the same data warehouse 6 | 7 | The ClickHouse services will be reachable from anywhere on the internet. 8 | 9 | ## How to run 10 | 11 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 12 | - Run `terraform init` 13 | - Run `terraform -var-file=variables.tfvars` 14 | -------------------------------------------------------------------------------- /examples/full/warehouse/aws/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" { 2 | type = string 3 | } 4 | 5 | variable "token_key" { 6 | type = string 7 | } 8 | 9 | variable "token_secret" { 10 | type = string 11 | } 12 | 13 | variable "service_name" { 14 | type = string 15 | default = "My Data Warehouse" 16 | } 17 | 18 | variable "region" { 19 | type = string 20 | default = "us-east-2" 21 | } 22 | 23 | resource "clickhouse_service" "primary" { 24 | name = "${var.service_name}-pri" 25 | cloud_provider = "aws" 26 | region = var.region 27 | idle_scaling = false 28 | idle_timeout_minutes = null 29 | password_hash = "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=" # base64 encoded sha256 hash of "test" 30 | 31 | ip_access = [ 32 | { 33 | source = "0.0.0.0" 34 | description = "Anywhere" 35 | } 36 | ] 37 | 38 | min_replica_memory_gb = 8 39 | max_replica_memory_gb = 120 40 | 41 | backup_configuration = { 42 | backup_period_in_hours = 24 43 | backup_retention_period_in_hours = 24 44 | backup_start_time = null 45 | } 46 | } 47 | 48 | data "clickhouse_api_key_id" "self" { 49 | } 50 | 51 | resource "clickhouse_service" "secondary" { 52 | warehouse_id = clickhouse_service.primary.warehouse_id 53 | readonly = true 54 | name = "${var.service_name}-sec" 55 | cloud_provider = "aws" 56 | region = var.region 57 | idle_scaling = true 58 | idle_timeout_minutes = 5 59 | 60 | ip_access = [ 61 | { 62 | source = "0.0.0.0" 63 | description = "Anywhere" 64 | } 65 | ] 66 | 67 | query_api_endpoints = { 68 | api_key_ids = [ 69 | data.clickhouse_api_key_id.self.id 70 | ] 71 | roles = [ 72 | "sql_console_admin" 73 | ] 74 | } 75 | 76 | min_replica_memory_gb = 8 77 | max_replica_memory_gb = 120 78 | } 79 | -------------------------------------------------------------------------------- /examples/full/warehouse/aws/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.3.3" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/full/warehouse/aws/provider.tf.template: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/full/warehouse/aws/variables.tfvars.sample: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | -------------------------------------------------------------------------------- /examples/provider/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.3.3" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | # Configuration-based authentication 12 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 13 | provider "clickhouse" { 14 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 15 | token_key = "avhj1U5QCdWAE9CA9" 16 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 17 | } 18 | -------------------------------------------------------------------------------- /examples/provider/provider.tf.template: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | # Configuration-based authentication 11 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 12 | provider "clickhouse" { 13 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 14 | token_key = "avhj1U5QCdWAE9CA9" 15 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 16 | } 17 | -------------------------------------------------------------------------------- /examples/rbac/README.md: -------------------------------------------------------------------------------- 1 | ## Basic example to manage Role Based Access Control 2 | 3 | The Terraform code deploys following resources: 4 | - 1 ClickHouse service on AWS 5 | - 1 database user on the ClickHouse service 6 | - 1 database role on the ClickHouse service 7 | 8 | ## How to run 9 | 10 | - Rename `variables.tfvars.sample` to `variables.tfvars` and fill in all needed data. 11 | - Run `terraform init` 12 | - Run `terraform -var-file=variables.tfvars` 13 | -------------------------------------------------------------------------------- /examples/rbac/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.2.0-alpha1" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /examples/rbac/provider.tf.template.alpha: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /examples/rbac/variables.tfvars.sample: -------------------------------------------------------------------------------- 1 | # these keys are for example only and won't work when pointed to a deployed ClickHouse OpenAPI server 2 | organization_id = "aee076c1-3f83-4637-95b1-ad5a0a825b71" 3 | token_key = "avhj1U5QCdWAE9CA9" 4 | token_secret = "4b1dROiHQEuSXJHlV8zHFd0S7WQj7CGxz5kGJeJnca" 5 | -------------------------------------------------------------------------------- /examples/resources/clickhouse_clickpipe/import.sh: -------------------------------------------------------------------------------- 1 | # ClickPipes can be imported by specifying both service ID and clickpipe ID. 2 | terraform import clickhouse_clickpipe.example xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 3 | -------------------------------------------------------------------------------- /examples/resources/clickhouse_clickpipe/resource.tf: -------------------------------------------------------------------------------- 1 | resource "clickhouse_clickpipe" "kafka_clickpipe" { 2 | name = "My Kafka ClickPipe" 3 | description = "Data pipeline from Kafka to ClickHouse" 4 | 5 | service_id = "e9465b4b-f7e5-4937-8e21-8d508b02843d" 6 | 7 | scaling { 8 | replicas = 1 9 | } 10 | 11 | state = "Running" 12 | 13 | source { 14 | kafka { 15 | type = "confluent" 16 | format = "JSONEachRow" 17 | brokers = "my-kafka-broker:9092" 18 | topics = "my_topic" 19 | 20 | consumer_group = "clickpipe-test" 21 | 22 | credentials { 23 | username = "user" 24 | password = "***" 25 | } 26 | } 27 | } 28 | 29 | destination { 30 | table = "my_table" 31 | managed_table = true 32 | 33 | tableDefinition { 34 | engine { 35 | type = "MergeTree" 36 | } 37 | } 38 | 39 | columns { 40 | name = "my_field1" 41 | type = "String" 42 | } 43 | 44 | columns { 45 | name = "my_field2" 46 | type = "UInt64" 47 | } 48 | } 49 | 50 | field_mappings = [ 51 | { 52 | source_field = "my_field" 53 | destination_field = "my_field1" 54 | } 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /examples/resources/clickhouse_clickpipes_reverse_private_endpoint/import.sh: -------------------------------------------------------------------------------- 1 | # ClickPipes reverse private endpoints can be imported by specifying both service ID and clickpipe ID. 2 | terraform import clickhouse_clickpipes_reverse_private_endpoint.example xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 3 | -------------------------------------------------------------------------------- /examples/resources/clickhouse_clickpipes_reverse_private_endpoint/resource.tf: -------------------------------------------------------------------------------- 1 | resource "clickhouse_clickpipes_reverse_private_endpoint" "vpc_endpoint_service" { 2 | service_id = "3a10a385-ced2-452e-abb8-908c80976a8f" 3 | description = "VPC_ENDPOINT_SERVICE reverse private endpoint for ClickPipes" 4 | type = "VPC_ENDPOINT_SERVICE" 5 | vpc_endpoint_service_name = "com.amazonaws.vpce.eu-west-1.vpce-svc-080826a65b5b27d4e" 6 | } 7 | 8 | resource "clickhouse_clickpipes_reverse_private_endpoint" "vpc_resource" { 9 | service_id = "3a10a385-ced2-452e-abb8-908c80976a8f" 10 | description = "VPC_RESOURCE reverse private endpoint for ClickPipes" 11 | type = "VPC_RESOURCE" 12 | vpc_resource_configuration_id = "rcfg-1a2b3c4d5e6f7g8h9" 13 | vpc_resource_share_arn = "arn:aws:ram:us-east-1:123456789012:resource-share/1a2b3c4d-5e6f-7g8h-9i0j-k1l2m3n4o5p6" 14 | } 15 | 16 | resource "clickhouse_clickpipes_reverse_private_endpoint" "msk_multi_vpc" { 17 | service_id = "3a10a385-ced2-452e-abb8-908c80976a8f" 18 | description = "MSK_MULTI_VPC reverse private endpoint for ClickPipes" 19 | type = "MSK_MULTI_VPC" 20 | msk_cluster_arn = "arn:aws:kafka:us-east-1:123456789012:cluster/ClickHouse-Cluster/1a2b3c4d-5e6f-7g8h-9i0j-k1l2m3n4o5p6-1" 21 | msk_authentication = "SASL_IAM" 22 | } 23 | -------------------------------------------------------------------------------- /examples/resources/clickhouse_service/import.sh: -------------------------------------------------------------------------------- 1 | # Services can be imported by specifying the UUID. 2 | terraform import clickhouse_service.example xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 3 | -------------------------------------------------------------------------------- /examples/resources/clickhouse_service/resource.tf: -------------------------------------------------------------------------------- 1 | resource "clickhouse_service" "service" { 2 | name = "My Service" 3 | cloud_provider = "aws" 4 | region = "us-east-1" 5 | idle_scaling = true 6 | 7 | ip_access = [ 8 | { 9 | source = "192.168.2.63" 10 | description = "Test IP" 11 | } 12 | ] 13 | 14 | min_total_memory_gb = 24 15 | max_total_memory_gb = 360 16 | idle_timeout_minutes = 5 17 | 18 | password_hash = "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=" # base64 encoded sha256 hash of "test" 19 | } 20 | -------------------------------------------------------------------------------- /examples/resources/clickhouse_service_private_endpoints_attachment/import.sh: -------------------------------------------------------------------------------- 1 | # Endpoint Attachments can be imported by specifying the clickhouse service UUID 2 | terraform import clickhouse_service_private_endpoints_attachment.example xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 3 | -------------------------------------------------------------------------------- /examples/resources/clickhouse_service_private_endpoints_attachment/resource.tf: -------------------------------------------------------------------------------- 1 | resource "clickhouse_service" "svc" { 2 | ... 3 | } 4 | 5 | resource "clickhouse_private_endpoint_registration" "endpoint" { 6 | ... 7 | } 8 | 9 | resource "clickhouse_service_private_endpoints_attachment" "attachment" { 10 | private_endpoint_ids = [ 11 | clickhouse_private_endpoint_registration.endpoint.id 12 | ] 13 | service_id = clickhouse_service.svc.id 14 | } 15 | -------------------------------------------------------------------------------- /examples/resources/clickhouse_service_transparent_data_encryption_key_association/import.sh: -------------------------------------------------------------------------------- 1 | # Endpoint Attachments can be imported by specifying the clickhouse service UUID 2 | terraform import clickhouse_service_transparent_data_encryption_key_association.example xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 3 | -------------------------------------------------------------------------------- /examples/resources/clickhouse_service_transparent_data_encryption_key_association/resource.tf: -------------------------------------------------------------------------------- 1 | resource "clickhouse_service" "service" { 2 | ... 3 | } 4 | 5 | resource "aws_kms_key" "enc" { 6 | ... 7 | } 8 | 9 | resource "clickhouse_service_transparent_data_encryption_key_association" "service_key_association" { 10 | service_id = clickhouse_service.service.id 11 | key_id = aws_kms_key.enc.arn 12 | } 13 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ClickHouse/terraform-provider-clickhouse 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/cenkalti/backoff/v4 v4.3.0 7 | github.com/gojuno/minimock/v3 v3.4.5 8 | github.com/google/go-cmp v0.7.0 9 | github.com/hashicorp/terraform-plugin-docs v0.21.0 10 | github.com/hashicorp/terraform-plugin-framework v1.15.0 11 | github.com/hashicorp/terraform-plugin-framework-validators v0.18.0 12 | github.com/hashicorp/terraform-plugin-log v0.9.0 13 | github.com/huandu/go-sqlbuilder v1.35.0 14 | ) 15 | 16 | require ( 17 | github.com/BurntSushi/toml v1.2.1 // indirect 18 | github.com/Kunde21/markdownfmt/v3 v3.1.0 // indirect 19 | github.com/Masterminds/goutils v1.1.1 // indirect 20 | github.com/Masterminds/semver/v3 v3.2.0 // indirect 21 | github.com/Masterminds/sprig/v3 v3.2.3 // indirect 22 | github.com/Microsoft/go-winio v0.6.2 // indirect 23 | github.com/ProtonMail/go-crypto v1.1.3 // indirect 24 | github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect 25 | github.com/armon/go-radix v1.0.0 // indirect 26 | github.com/bgentry/speakeasy v0.1.0 // indirect 27 | github.com/bmatcuk/doublestar/v4 v4.8.1 // indirect 28 | github.com/cloudflare/circl v1.3.7 // indirect 29 | github.com/davecgh/go-spew v1.1.1 // indirect 30 | github.com/fatih/color v1.16.0 // indirect 31 | github.com/golang/protobuf v1.5.4 // indirect 32 | github.com/google/uuid v1.6.0 // indirect 33 | github.com/hashicorp/cli v1.1.7 // indirect 34 | github.com/hashicorp/errwrap v1.1.0 // indirect 35 | github.com/hashicorp/go-checkpoint v0.5.0 // indirect 36 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 37 | github.com/hashicorp/go-hclog v1.6.3 // indirect 38 | github.com/hashicorp/go-multierror v1.1.1 // indirect 39 | github.com/hashicorp/go-plugin v1.6.3 // indirect 40 | github.com/hashicorp/go-retryablehttp v0.7.7 // indirect 41 | github.com/hashicorp/go-uuid v1.0.3 // indirect 42 | github.com/hashicorp/go-version v1.7.0 // indirect 43 | github.com/hashicorp/hc-install v0.9.1 // indirect 44 | github.com/hashicorp/terraform-exec v0.22.0 // indirect 45 | github.com/hashicorp/terraform-json v0.24.0 // indirect 46 | github.com/hashicorp/terraform-plugin-go v0.27.0 // indirect 47 | github.com/hashicorp/terraform-registry-address v0.2.5 // indirect 48 | github.com/hashicorp/terraform-svchost v0.1.1 // indirect 49 | github.com/hashicorp/yamux v0.1.1 // indirect 50 | github.com/huandu/xstrings v1.4.0 // indirect 51 | github.com/imdario/mergo v0.3.15 // indirect 52 | github.com/kr/pretty v0.3.1 // indirect 53 | github.com/mattn/go-colorable v0.1.14 // indirect 54 | github.com/mattn/go-isatty v0.0.20 // indirect 55 | github.com/mattn/go-runewidth v0.0.9 // indirect 56 | github.com/mitchellh/copystructure v1.2.0 // indirect 57 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 58 | github.com/mitchellh/reflectwalk v1.0.2 // indirect 59 | github.com/oklog/run v1.0.0 // indirect 60 | github.com/pmezard/go-difflib v1.0.0 // indirect 61 | github.com/posener/complete v1.2.3 // indirect 62 | github.com/shopspring/decimal v1.4.0 // indirect 63 | github.com/spf13/cast v1.5.0 // indirect 64 | github.com/stretchr/testify v1.9.0 // indirect 65 | github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect 66 | github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect 67 | github.com/yuin/goldmark v1.7.7 // indirect 68 | github.com/yuin/goldmark-meta v1.1.0 // indirect 69 | github.com/zclconf/go-cty v1.16.2 // indirect 70 | go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect 71 | golang.org/x/crypto v0.37.0 // indirect 72 | golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect 73 | golang.org/x/mod v0.22.0 // indirect 74 | golang.org/x/net v0.39.0 // indirect 75 | golang.org/x/sys v0.32.0 // indirect 76 | golang.org/x/text v0.24.0 // indirect 77 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect 78 | google.golang.org/grpc v1.72.1 // indirect 79 | google.golang.org/protobuf v1.36.6 // indirect 80 | gopkg.in/yaml.v2 v2.3.0 // indirect 81 | gopkg.in/yaml.v3 v3.0.1 // indirect 82 | ) 83 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | 7 | "github.com/hashicorp/terraform-plugin-framework/providerserver" 8 | 9 | "github.com/ClickHouse/terraform-provider-clickhouse/pkg/provider" 10 | "github.com/ClickHouse/terraform-provider-clickhouse/pkg/resource" 11 | ) 12 | 13 | // Provider documentation generation. 14 | //go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs generate --provider-name clickhouse 15 | 16 | func main() { 17 | var debug bool 18 | 19 | flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve") 20 | flag.Parse() 21 | providerserver.Serve(context.Background(), provider.NewBuilder(resource.GetResourceFactories()), providerserver.ServeOpts{ //nolint:errcheck 22 | Address: "registry.terraform.io/ClickHouse/clickhouse", 23 | Debug: debug, 24 | }) 25 | } 26 | -------------------------------------------------------------------------------- /pkg/datasource/api_key_id.go: -------------------------------------------------------------------------------- 1 | package datasource 2 | 3 | import ( 4 | "context" 5 | _ "embed" 6 | "fmt" 7 | 8 | "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" 9 | "github.com/hashicorp/terraform-plugin-framework/datasource" 10 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema" 11 | "github.com/hashicorp/terraform-plugin-framework/schema/validator" 12 | "github.com/hashicorp/terraform-plugin-framework/types" 13 | 14 | "github.com/ClickHouse/terraform-provider-clickhouse/pkg/internal/api" 15 | ) 16 | 17 | //go:embed descriptions/api_key_id.md 18 | var apiKeyIdDataSourceDescription string 19 | 20 | // Ensure the implementation satisfies the desired interfaces. 21 | var _ datasource.DataSource = &apiKeyIdDataSource{} 22 | 23 | // NewApiKeyIDDataSource is a helper function to simplify the provider implementation. 24 | func NewApiKeyIDDataSource() datasource.DataSource { 25 | return &apiKeyIdDataSource{} 26 | } 27 | 28 | type apiKeyIdDataSource struct { 29 | client api.Client 30 | } 31 | 32 | func (d *apiKeyIdDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { 33 | // Access DataSourceData from the provider configuration 34 | if req.ProviderData == nil { 35 | return 36 | } 37 | d.client = req.ProviderData.(api.Client) 38 | } 39 | 40 | func (d *apiKeyIdDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { 41 | resp.TypeName = "clickhouse_api_key_id" 42 | } 43 | 44 | type apiKeyIdDataSourceModel struct { 45 | Id types.String `tfsdk:"id"` 46 | Name types.String `tfsdk:"name"` 47 | } 48 | 49 | func (d *apiKeyIdDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { 50 | resp.Schema = schema.Schema{ 51 | Attributes: map[string]schema.Attribute{ 52 | "id": schema.StringAttribute{ 53 | Description: "The ID of the API key used by the provider to connect to the service. This is a read-only attribute.", 54 | Computed: true, 55 | }, 56 | "name": schema.StringAttribute{ 57 | Optional: true, 58 | Computed: true, 59 | Description: "The name of the API key to retrieve information about. If left empty, the API key used by the Terraform provider is used instead.", 60 | Validators: []validator.String{ 61 | stringvalidator.LengthAtLeast(1), 62 | }, 63 | }, 64 | }, 65 | MarkdownDescription: apiKeyIdDataSourceDescription, 66 | } 67 | } 68 | 69 | func (d *apiKeyIdDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { 70 | var data apiKeyIdDataSourceModel 71 | // Read Terraform configuration data into the model 72 | resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) 73 | 74 | var name *string 75 | if !data.Name.IsNull() && !data.Name.IsUnknown() { 76 | name = data.Name.ValueStringPointer() 77 | } 78 | 79 | // Make the API request to get the apiKeyID 80 | apiKeyId, err := d.client.GetApiKeyID(ctx, name) 81 | if err != nil { 82 | resp.Diagnostics.AddError("failed get", fmt.Sprintf("error getting ID of the API key: %v", err)) 83 | return 84 | } 85 | data.Id = types.StringValue(apiKeyId.ID) 86 | data.Name = types.StringValue(apiKeyId.Name) 87 | 88 | // Save data into Terraform state 89 | resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) 90 | } 91 | -------------------------------------------------------------------------------- /pkg/datasource/descriptions/api_key_id.md: -------------------------------------------------------------------------------- 1 | The *clickhouse_api_key_id* data source can be used to retrieve the UUID of a ClickHouse cloud API key. 2 | It is meant to be used in the *clickhouse_service* resource to set the `query_api_endpoints` attribute. 3 | 4 | It can be used in two ways: 5 | 6 | 1) To retrieve information about an API Key, by providing its name 7 | 2) To retrieve information about the API Key currently configured for running the terraform provider 8 | 9 | In both cases the data source will contain the `id` and `name` attributes. 10 | -------------------------------------------------------------------------------- /pkg/datasource/private_endpoint_config.go: -------------------------------------------------------------------------------- 1 | package datasource 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" 8 | "github.com/hashicorp/terraform-plugin-framework/datasource" 9 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema" 10 | "github.com/hashicorp/terraform-plugin-framework/schema/validator" 11 | "github.com/hashicorp/terraform-plugin-framework/types" 12 | 13 | "github.com/ClickHouse/terraform-provider-clickhouse/pkg/internal/api" 14 | ) 15 | 16 | const ( 17 | CloudProviderAWS = "aws" 18 | CloudProviderGCP = "gcp" 19 | CloudProviderAzure = "azure" 20 | ) 21 | 22 | // Ensure the implementation satisfies the desired interfaces. 23 | var _ datasource.DataSource = &privateEndpointConfigDataSource{} 24 | 25 | // NewPrivateEndpointConfigDataSource is a helper function to simplify the provider implementation. 26 | func NewPrivateEndpointConfigDataSource() datasource.DataSource { 27 | return &privateEndpointConfigDataSource{} 28 | } 29 | 30 | type privateEndpointConfigDataSource struct { 31 | client api.Client 32 | } 33 | 34 | func (d *privateEndpointConfigDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { 35 | // Access DataSourceData from the provider configuration 36 | if req.ProviderData == nil { 37 | return 38 | } 39 | d.client = req.ProviderData.(api.Client) 40 | } 41 | 42 | func (d *privateEndpointConfigDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { 43 | resp.TypeName = "clickhouse_private_endpoint_config" 44 | } 45 | 46 | type privateEndpointConfigDataSourceModel struct { 47 | CloudProvider types.String `tfsdk:"cloud_provider"` 48 | Region types.String `tfsdk:"region"` 49 | EndpointServiceID types.String `tfsdk:"endpoint_service_id"` 50 | } 51 | 52 | func (d *privateEndpointConfigDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { 53 | resp.Schema = schema.Schema{ 54 | DeprecationMessage: "This resource is deprecated since version 3.2.0. Please refer to [the docs](https://github.com/ClickHouse/terraform-provider-clickhouse?tab=readme-ov-file#breaking-changes-and-deprecations) for migration steps.", 55 | Attributes: map[string]schema.Attribute{ 56 | "cloud_provider": schema.StringAttribute{ 57 | Description: "The cloud provider for the private endpoint. Valid values are 'aws', 'gcp', or 'azure'.", 58 | Required: true, 59 | Validators: []validator.String{ 60 | stringvalidator.OneOf(CloudProviderAWS, CloudProviderGCP, CloudProviderAzure), 61 | }, 62 | }, 63 | "region": schema.StringAttribute{ 64 | Description: "The region for the private endpoint. Valid values are specific to the cloud provider i.e. us-east-2", 65 | Required: true, 66 | }, 67 | "endpoint_service_id": schema.StringAttribute{ 68 | Description: "The ID of the private endpoint that is used to securely connect to ClickHouse. This is a read-only attribute.", 69 | Computed: true, 70 | }, 71 | }, 72 | } 73 | } 74 | 75 | func (d *privateEndpointConfigDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { 76 | var data privateEndpointConfigDataSourceModel 77 | // Read Terraform configuration data into the model 78 | resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) 79 | 80 | cloudProvider := data.CloudProvider.ValueString() 81 | region := data.Region.ValueString() 82 | 83 | // Make the API request to get the private endpoint config 84 | privateEndpointConfig, err := d.client.GetOrgPrivateEndpointConfig(ctx, cloudProvider, region) 85 | if err != nil { 86 | resp.Diagnostics.AddError("failed get", fmt.Sprintf("error getting privateEndpointConfig: %v", err)) 87 | return 88 | } 89 | data.EndpointServiceID = types.StringValue(privateEndpointConfig.EndpointServiceId) 90 | 91 | // Save data into Terraform state 92 | resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) 93 | } 94 | -------------------------------------------------------------------------------- /pkg/internal/api/api_keys.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "net/http" 8 | "strings" 9 | ) 10 | 11 | type ApiKey struct { 12 | ID string `json:"id"` 13 | Name string `json:"name"` 14 | KeySuffix string `json:"keySuffix"` 15 | } 16 | 17 | func (c *ClientImpl) GetApiKeyID(ctx context.Context, name *string) (*ApiKey, error) { 18 | req, err := http.NewRequest(http.MethodGet, c.getOrgPath("/keys"), nil) 19 | if err != nil { 20 | return nil, err 21 | } 22 | 23 | body, err := c.doRequest(ctx, req) 24 | if err != nil { 25 | return nil, err 26 | } 27 | 28 | apiKeysResponse := ResponseWithResult[[]ApiKey]{} 29 | err = json.Unmarshal(body, &apiKeysResponse) 30 | if err != nil { 31 | return nil, err 32 | } 33 | 34 | for _, key := range apiKeysResponse.Result { 35 | // We want to match a key by name 36 | if name != nil { 37 | if *name == key.Name { 38 | return &key, nil 39 | } 40 | } else { 41 | // Find id of the API key configured for this terraform provider run. 42 | // Since we don't know the ID of the API key on the client side, we need to a pattern match on the KeySuffix. 43 | // This is a very weak check, but that's all we have until https://github.com/ClickHouse/control-plane/issues/13294 is implemented. 44 | if strings.HasSuffix(c.TokenKey, key.KeySuffix) { 45 | return &key, nil 46 | } 47 | } 48 | } 49 | 50 | errorMsg := "key not found" 51 | 52 | if name != nil { 53 | errorMsg = fmt.Sprintf("API key named %q was not found", *name) 54 | } 55 | 56 | return nil, fmt.Errorf(errorMsg) //nolint 57 | } 58 | -------------------------------------------------------------------------------- /pkg/internal/api/backup_configuration.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "net/http" 7 | "strings" 8 | ) 9 | 10 | type BackupConfiguration struct { 11 | BackupPeriodInHours *int32 `json:"backupPeriodInHours"` 12 | BackupRetentionPeriodInHours *int32 `json:"backupRetentionPeriodInHours"` 13 | BackupStartTime *string `json:"backupStartTime"` 14 | } 15 | 16 | func (c *ClientImpl) GetBackupConfiguration(ctx context.Context, serviceId string) (*BackupConfiguration, error) { 17 | req, err := http.NewRequest(http.MethodGet, c.getServicePath(serviceId, "/backupConfiguration"), nil) 18 | if err != nil { 19 | return nil, err 20 | } 21 | 22 | body, err := c.doRequest(ctx, req) 23 | if err != nil { 24 | return nil, err 25 | } 26 | 27 | backupConfigResponse := ResponseWithResult[BackupConfiguration]{} 28 | err = json.Unmarshal(body, &backupConfigResponse) 29 | if err != nil { 30 | return nil, err 31 | } 32 | 33 | return &backupConfigResponse.Result, nil 34 | } 35 | 36 | func (c *ClientImpl) UpdateBackupConfiguration(ctx context.Context, serviceId string, b BackupConfiguration) (*BackupConfiguration, error) { 37 | rb, err := json.Marshal(b) 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | req, err := http.NewRequest(http.MethodPatch, c.getServicePath(serviceId, "/backupConfiguration"), strings.NewReader(string(rb))) 43 | if err != nil { 44 | return nil, err 45 | } 46 | 47 | body, err := c.doRequest(ctx, req) 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | backupConfigResponse := ResponseWithResult[BackupConfiguration]{} 53 | err = json.Unmarshal(body, &backupConfigResponse) 54 | if err != nil { 55 | return nil, err 56 | } 57 | 58 | return &backupConfigResponse.Result, nil 59 | } 60 | -------------------------------------------------------------------------------- /pkg/internal/api/clickpipe_reverse_private_endpoint_models.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | // ReversePrivateEndpoint represents a ClickPipe reverse private endpoint 4 | type ReversePrivateEndpoint struct { 5 | CreateReversePrivateEndpoint 6 | 7 | ID string `json:"id,omitempty"` 8 | ServiceID string `json:"serviceId,omitempty"` 9 | EndpointID string `json:"endpointId,omitempty"` 10 | DNSNames []string `json:"dnsNames,omitempty"` 11 | PrivateDNSNames []string `json:"privateDnsNames,omitempty"` 12 | Status string `json:"status,omitempty"` 13 | } 14 | 15 | // CreateReversePrivateEndpoint is the request payload for creating a reverse private endpoint 16 | type CreateReversePrivateEndpoint struct { 17 | Description string `json:"description,omitempty"` 18 | Type string `json:"type,omitempty"` 19 | VPCEndpointServiceName *string `json:"vpcEndpointServiceName,omitempty"` 20 | VPCResourceConfigurationID *string `json:"vpcResourceConfigurationId,omitempty"` 21 | VPCResourceShareArn *string `json:"vpcResourceShareArn,omitempty"` 22 | MSKClusterArn *string `json:"mskClusterArn,omitempty"` 23 | MSKAuthentication *string `json:"mskAuthentication,omitempty"` 24 | } 25 | -------------------------------------------------------------------------------- /pkg/internal/api/client.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "time" 7 | ) 8 | 9 | type ClientImpl struct { 10 | BaseUrl string 11 | HttpClient *http.Client 12 | OrganizationId string 13 | TokenKey string 14 | TokenSecret string 15 | } 16 | 17 | type ClientConfig struct { 18 | ApiURL string 19 | OrganizationID string 20 | TokenKey string 21 | TokenSecret string 22 | Timeout time.Duration 23 | } 24 | 25 | func NewClient(config ClientConfig) (*ClientImpl, error) { 26 | if config.ApiURL == "" { 27 | return nil, fmt.Errorf("ApiURL cannot be empty") 28 | } 29 | if config.OrganizationID == "" { 30 | return nil, fmt.Errorf("OrganizationID cannot be empty") 31 | } 32 | if config.TokenKey == "" { 33 | return nil, fmt.Errorf("TokenKey cannot be empty") 34 | } 35 | if config.TokenSecret == "" { 36 | return nil, fmt.Errorf("TokenSecret cannot be empty") 37 | } 38 | if config.Timeout == 0 { 39 | config.Timeout = time.Minute * 5 40 | } 41 | 42 | client := &ClientImpl{ 43 | BaseUrl: config.ApiURL, 44 | HttpClient: &http.Client{ 45 | Timeout: config.Timeout, 46 | }, 47 | OrganizationId: config.OrganizationID, 48 | TokenKey: config.TokenKey, 49 | TokenSecret: config.TokenSecret, 50 | } 51 | 52 | return client, nil 53 | } 54 | -------------------------------------------------------------------------------- /pkg/internal/api/client_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | "testing" 6 | "time" 7 | 8 | "github.com/google/go-cmp/cmp" 9 | ) 10 | 11 | func TestNewClient(t *testing.T) { 12 | testClient := &ClientImpl{ 13 | BaseUrl: "https://api.clickhouse.cloud/v1", 14 | HttpClient: &http.Client{ 15 | Timeout: time.Minute * 5, 16 | }, 17 | OrganizationId: "10ead720-7ca1-48c9-aaf7-7230f42b56c0", 18 | TokenKey: "dE8jvpSRVurZCLcLZllb", 19 | TokenSecret: "4b1dZbh9bFV9uHQ7Aay4vHHbsTL1HkD2CyZyFBlOLc", 20 | } 21 | 22 | client, err := NewClient(ClientConfig{ 23 | ApiURL: testClient.BaseUrl, 24 | OrganizationID: testClient.OrganizationId, 25 | TokenKey: testClient.TokenKey, 26 | TokenSecret: testClient.TokenSecret, 27 | }) 28 | if err != nil { 29 | t.Fatalf("new client err: %v", err) 30 | } 31 | if diff := cmp.Diff(testClient, client); diff != "" { 32 | t.Errorf("NewClient() mismatch (-want +got):\n%s", diff) 33 | } 34 | orgPath := "https://api.clickhouse.cloud/v1/organizations/10ead720-7ca1-48c9-aaf7-7230f42b56c0" 35 | if diff := cmp.Diff(client.getOrgPath(""), orgPath); diff != "" { 36 | t.Errorf("getOrgPath() mismatch (-want +got):\n%s", diff) 37 | } 38 | servicePath := "https://api.clickhouse.cloud/v1/organizations/10ead720-7ca1-48c9-aaf7-7230f42b56c0/services" 39 | if diff := cmp.Diff(client.getServicePath("", ""), servicePath); diff != "" { 40 | t.Errorf("getServicePath() mismatch (-want +got):\n%s", diff) 41 | } 42 | servicePath = "https://api.clickhouse.cloud/v1/organizations/10ead720-7ca1-48c9-aaf7-7230f42b56c0/services/1234" 43 | if diff := cmp.Diff(client.getServicePath("1234", ""), servicePath); diff != "" { 44 | t.Errorf("getServicePath() mismatch (-want +got):\n%s", diff) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /pkg/internal/api/constants.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | const ( 4 | TierDevelopment = "development" 5 | TierProduction = "production" 6 | TierPPv2 = "" 7 | 8 | ReleaseChannelDefault = "default" 9 | ReleaseChannelFast = "fast" 10 | 11 | StateProvisioning = "provisioning" 12 | StateStopped = "stopped" 13 | StateStopping = "stopping" 14 | 15 | ResponseHeaderRateLimitReset = "X-RateLimit-Reset" 16 | ) 17 | -------------------------------------------------------------------------------- /pkg/internal/api/database.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | 8 | "github.com/huandu/go-sqlbuilder" 9 | 10 | sqlutil "github.com/ClickHouse/terraform-provider-clickhouse/pkg/internal/sql" 11 | ) 12 | 13 | type Database struct { 14 | Name string `json:"name"` 15 | Comment string `json:"comment"` 16 | } 17 | 18 | func (c *ClientImpl) CreateDatabase(ctx context.Context, serviceID string, db Database) error { 19 | format := "CREATE DATABASE `$?`" 20 | args := []interface{}{ 21 | sqlbuilder.Raw(sqlutil.EscapeBacktick(db.Name)), 22 | } 23 | 24 | if db.Comment != "" { 25 | format = fmt.Sprintf("%s COMMENT ${comment}", format) 26 | args = append(args, sqlbuilder.Named("comment", db.Comment)) 27 | } 28 | sb := sqlbuilder.Build(format, args...) 29 | 30 | sql, args := sb.Build() 31 | 32 | _, err := c.runQuery(ctx, serviceID, sql, args...) 33 | if err != nil { 34 | return err 35 | } 36 | 37 | return nil 38 | } 39 | 40 | func (c *ClientImpl) GetDatabase(ctx context.Context, serviceID string, name string) (*Database, error) { 41 | sb := sqlbuilder.Build("SELECT name, comment FROM system.databases WHERE name=$?;", name) 42 | sql, args := sb.Build() 43 | 44 | body, err := c.runQuery(ctx, serviceID, sql, args...) 45 | if err != nil { 46 | return nil, err 47 | } 48 | 49 | database := Database{} 50 | err = json.Unmarshal(body, &database) 51 | if err != nil { 52 | return nil, err 53 | } 54 | 55 | return &database, nil 56 | } 57 | 58 | func (c *ClientImpl) DeleteDatabase(ctx context.Context, serviceID string, name string) error { 59 | sb := sqlbuilder.Build("DROP DATABASE `$?`;", sqlbuilder.Raw(sqlutil.EscapeBacktick(name))) 60 | sql, args := sb.Build() 61 | _, err := c.runQuery(ctx, serviceID, sql, args...) 62 | if err != nil { 63 | return err 64 | } 65 | 66 | return nil 67 | } 68 | 69 | func (c *ClientImpl) SyncDatabase(ctx context.Context, serviceID string, db Database) error { 70 | // There is no field in the Database spec that allows changing on the fly, so this function is a no-op. 71 | return nil 72 | } 73 | -------------------------------------------------------------------------------- /pkg/internal/api/db_role.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | 7 | "github.com/huandu/go-sqlbuilder" 8 | 9 | sqlutil "github.com/ClickHouse/terraform-provider-clickhouse/pkg/internal/sql" 10 | ) 11 | 12 | type Role struct { 13 | Name string `json:"name"` 14 | } 15 | 16 | func (c *ClientImpl) CreateRole(ctx context.Context, serviceID string, role Role) (*Role, error) { 17 | format := "CREATE ROLE `$?`" 18 | args := []interface{}{ 19 | sqlbuilder.Raw(sqlutil.EscapeBacktick(role.Name)), 20 | } 21 | 22 | sb := sqlbuilder.Build(format, args...) 23 | 24 | sql, args := sb.Build() 25 | 26 | _, err := c.runQuery(ctx, serviceID, sql, args...) 27 | if err != nil { 28 | return nil, err 29 | } 30 | 31 | createdRole, err := c.GetRole(ctx, serviceID, role.Name) 32 | if err != nil { 33 | return nil, err 34 | } 35 | 36 | return createdRole, nil 37 | } 38 | 39 | func (c *ClientImpl) GetRole(ctx context.Context, serviceID string, name string) (*Role, error) { 40 | // Roles we create with terraform are by default created with the 'replicated' storage thus we filter the 41 | // select query to ensure we're not retrieving another role with the same name and a different storage type. 42 | format := "SELECT name FROM system.roles WHERE name = ${name} and storage = 'replicated'" 43 | args := []interface{}{ 44 | sqlbuilder.Named("name", name), 45 | } 46 | 47 | sb := sqlbuilder.Build(format, args...) 48 | 49 | sql, args := sb.Build() 50 | 51 | data, err := c.runQuery(ctx, serviceID, sql, args...) 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | if len(data) == 0 { 57 | // Role not found 58 | return nil, nil 59 | } 60 | 61 | role := Role{} 62 | 63 | err = json.Unmarshal(data, &role) 64 | if err != nil { 65 | return nil, err 66 | } 67 | 68 | return &role, nil 69 | } 70 | 71 | func (c *ClientImpl) DeleteRole(ctx context.Context, serviceID string, name string) error { 72 | format := "DROP ROLE IF EXISTS `$?`" 73 | args := []interface{}{ 74 | sqlbuilder.Raw(sqlutil.EscapeBacktick(name)), 75 | } 76 | 77 | sb := sqlbuilder.Build(format, args...) 78 | 79 | sql, args := sb.Build() 80 | 81 | _, err := c.runQuery(ctx, serviceID, sql, args...) 82 | if err != nil { 83 | return err 84 | } 85 | 86 | return nil 87 | } 88 | -------------------------------------------------------------------------------- /pkg/internal/api/db_user.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | 7 | "github.com/huandu/go-sqlbuilder" 8 | 9 | sqlutil "github.com/ClickHouse/terraform-provider-clickhouse/pkg/internal/sql" 10 | ) 11 | 12 | type User struct { 13 | Name string `json:"name"` 14 | PasswordSha256Hash string `json:"-"` 15 | } 16 | 17 | func (c *ClientImpl) CreateUser(ctx context.Context, serviceID string, user User) (*User, error) { 18 | format := "CREATE USER `$?` IDENTIFIED WITH sha256_hash BY ${hash}" 19 | args := []interface{}{ 20 | sqlbuilder.Raw(sqlutil.EscapeBacktick(user.Name)), 21 | sqlbuilder.Named("hash", user.PasswordSha256Hash), 22 | } 23 | 24 | sb := sqlbuilder.Build(format, args...) 25 | 26 | sql, args := sb.Build() 27 | 28 | _, err := c.runQuery(ctx, serviceID, sql, args...) 29 | if err != nil { 30 | return nil, err 31 | } 32 | 33 | createdUser, err := c.GetUser(ctx, serviceID, user.Name) 34 | if err != nil { 35 | return nil, err 36 | } 37 | 38 | // We don't get the SHA back from clickhouse, so we assume the operation was successful and return it to the client. 39 | createdUser.PasswordSha256Hash = user.PasswordSha256Hash 40 | 41 | return createdUser, nil 42 | } 43 | 44 | func (c *ClientImpl) GetUser(ctx context.Context, serviceID string, name string) (*User, error) { 45 | // Users we create with terraform are by default created with the 'replicated' storage thus we filter the 46 | // select query to ensure we're not retrieving another user with the same username and a different storage type. 47 | format := "SELECT name FROM system.users WHERE name = ${name} and storage = 'replicated'" 48 | args := []interface{}{ 49 | sqlbuilder.Named("name", name), 50 | } 51 | 52 | sb := sqlbuilder.Build(format, args...) 53 | 54 | sql, args := sb.Build() 55 | 56 | data, err := c.runQuery(ctx, serviceID, sql, args...) 57 | if err != nil { 58 | return nil, err 59 | } 60 | 61 | if len(data) == 0 { 62 | // User not found 63 | return nil, nil 64 | } 65 | 66 | user := User{} 67 | 68 | err = json.Unmarshal(data, &user) 69 | if err != nil { 70 | return nil, err 71 | } 72 | 73 | return &user, nil 74 | } 75 | 76 | func (c *ClientImpl) DeleteUser(ctx context.Context, serviceID string, name string) error { 77 | format := "DROP USER IF EXISTS `$?`" 78 | args := []interface{}{ 79 | sqlbuilder.Raw(sqlutil.EscapeBacktick(name)), 80 | } 81 | 82 | sb := sqlbuilder.Build(format, args...) 83 | 84 | sql, args := sb.Build() 85 | 86 | _, err := c.runQuery(ctx, serviceID, sql, args...) 87 | if err != nil { 88 | return err 89 | } 90 | 91 | return nil 92 | } 93 | -------------------------------------------------------------------------------- /pkg/internal/api/errors.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | func IsNotFound(err error) bool { 8 | if err == nil { 9 | return false 10 | } 11 | 12 | return strings.HasPrefix(err.Error(), "status: 404") 13 | } 14 | 15 | func is5xx(err error) bool { 16 | if err == nil { 17 | return false 18 | } 19 | 20 | return strings.HasPrefix(err.Error(), "status: 5") 21 | } 22 | -------------------------------------------------------------------------------- /pkg/internal/api/password.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "net/http" 7 | "strings" 8 | ) 9 | 10 | type ServicePasswordUpdate struct { 11 | NewPasswordHash string `json:"newPasswordHash,omitempty"` 12 | NewDoubleSha1Hash string `json:"newDoubleSha1Hash,omitempty"` 13 | } 14 | 15 | type ServicePasswordUpdateResult struct { 16 | Password string `json:"password,omitempty"` 17 | } 18 | 19 | func (c *ClientImpl) UpdateServicePassword(ctx context.Context, serviceId string, u ServicePasswordUpdate) (*ServicePasswordUpdateResult, error) { 20 | rb, err := json.Marshal(u) 21 | if err != nil { 22 | return nil, err 23 | } 24 | 25 | req, err := http.NewRequest(http.MethodPatch, c.getServicePath(serviceId, "/password"), strings.NewReader(string(rb))) 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | body, err := c.doRequest(ctx, req) 31 | if err != nil { 32 | return nil, err 33 | } 34 | 35 | serviceResponse := ServicePasswordUpdateResult{} 36 | err = json.Unmarshal(body, &serviceResponse) 37 | if err != nil { 38 | return nil, err 39 | } 40 | 41 | return &serviceResponse, nil 42 | } 43 | -------------------------------------------------------------------------------- /pkg/internal/api/private_endpoints.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "net/http" 7 | "strings" 8 | ) 9 | 10 | type PrivateEndpoint struct { 11 | CloudProvider string `json:"cloudProvider,omitempty"` 12 | Description string `json:"description,omitempty"` 13 | EndpointId string `json:"id,omitempty"` 14 | Region string `json:"region,omitempty"` 15 | } 16 | 17 | type OrgPrivateEndpointsUpdate struct { 18 | Add []PrivateEndpoint `json:"add,omitempty"` 19 | Remove []PrivateEndpoint `json:"remove,omitempty"` 20 | } 21 | 22 | type OrganizationUpdate struct { 23 | PrivateEndpoints *OrgPrivateEndpointsUpdate `json:"privateEndpoints"` 24 | } 25 | 26 | type OrgResult struct { 27 | CreatedAt string `json:"createdAt,omitempty"` 28 | ID string `json:"id,omitempty"` 29 | Name string `json:"name,omitempty"` 30 | PrivateEndpoints []PrivateEndpoint `json:"privateEndpoints,omitempty"` 31 | } 32 | 33 | type OrgPrivateEndpointConfig struct { 34 | EndpointServiceId string `json:"endpointServiceId,omitempty"` 35 | } 36 | 37 | func (c *ClientImpl) GetServicePrivateEndpointConfig(ctx context.Context, serviceId string) (*ServicePrivateEndpointConfig, error) { 38 | req, err := http.NewRequest(http.MethodGet, c.getServicePath(serviceId, "/privateEndpointConfig"), nil) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | body, err := c.doRequest(ctx, req) 44 | if err != nil { 45 | return nil, err 46 | } 47 | 48 | endpointConfigResponse := ResponseWithResult[ServicePrivateEndpointConfig]{} 49 | err = json.Unmarshal(body, &endpointConfigResponse) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | return &endpointConfigResponse.Result, nil 55 | } 56 | 57 | func (c *ClientImpl) GetOrgPrivateEndpointConfig(ctx context.Context, cloudProvider string, region string) (*OrgPrivateEndpointConfig, error) { 58 | privateEndpointConfigPath := c.getPrivateEndpointConfigPath(cloudProvider, region) 59 | 60 | req, err := http.NewRequest(http.MethodGet, privateEndpointConfigPath, nil) 61 | if err != nil { 62 | return nil, err 63 | } 64 | 65 | body, err := c.doRequest(ctx, req) 66 | if err != nil { 67 | return nil, err 68 | } 69 | 70 | privateEndpointConfigResponse := ResponseWithResult[OrgPrivateEndpointConfig]{} 71 | if err = json.Unmarshal(body, &privateEndpointConfigResponse); err != nil { 72 | return nil, err 73 | } 74 | 75 | return &privateEndpointConfigResponse.Result, nil 76 | } 77 | 78 | func (c *ClientImpl) GetOrganizationPrivateEndpoints(ctx context.Context) (*[]PrivateEndpoint, error) { 79 | req, err := http.NewRequest(http.MethodGet, c.getOrgPath(""), nil) 80 | if err != nil { 81 | return nil, err 82 | } 83 | 84 | body, err := c.doRequest(ctx, req) 85 | if err != nil { 86 | return nil, err 87 | } 88 | 89 | orgResponse := ResponseWithResult[OrgResult]{} 90 | err = json.Unmarshal(body, &orgResponse) 91 | if err != nil { 92 | return nil, err 93 | } 94 | 95 | return &orgResponse.Result.PrivateEndpoints, nil 96 | } 97 | 98 | func (c *ClientImpl) UpdateOrganizationPrivateEndpoints(ctx context.Context, orgUpdate OrganizationUpdate) (*[]PrivateEndpoint, error) { 99 | rb, err := json.Marshal(orgUpdate) 100 | if err != nil { 101 | return nil, err 102 | } 103 | 104 | req, err := http.NewRequest(http.MethodPatch, c.getOrgPath(""), strings.NewReader(string(rb))) 105 | if err != nil { 106 | return nil, err 107 | } 108 | 109 | body, err := c.doRequest(ctx, req) 110 | if err != nil { 111 | return nil, err 112 | } 113 | 114 | orgResponse := ResponseWithResult[OrgResult]{} 115 | err = json.Unmarshal(body, &orgResponse) 116 | if err != nil { 117 | return nil, err 118 | } 119 | 120 | return &orgResponse.Result.PrivateEndpoints, nil 121 | } 122 | -------------------------------------------------------------------------------- /pkg/internal/api/query_endpoints.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "net/http" 7 | "strings" 8 | ) 9 | 10 | type ServiceQueryEndpoint struct { 11 | Id string `json:"id,omitempty"` 12 | Roles []string `json:"roles"` 13 | OpenApiKeys []string `json:"openApiKeys"` 14 | AllowedOrigins string `json:"allowedOrigins"` 15 | } 16 | 17 | func (c *ClientImpl) GetQueryEndpoint(ctx context.Context, serviceID string) (*ServiceQueryEndpoint, error) { 18 | req, err := http.NewRequest(http.MethodGet, c.getServicePath(serviceID, "/serviceQueryEndpoint"), nil) 19 | if err != nil { 20 | return nil, err 21 | } 22 | 23 | body, err := c.doRequest(ctx, req) 24 | if IsNotFound(err) { 25 | // API respond with 404 when there are no service query endpoints. 26 | // We don't want to treat this as an error, but respond with nil. 27 | // This is a potential source of error, because if the `serviceID` is wrong 28 | // we don't catch the problem here. 29 | return nil, nil 30 | } else if err != nil { 31 | return nil, err 32 | } 33 | 34 | serviceQueryEndpointResponse := ResponseWithResult[ServiceQueryEndpoint]{} 35 | err = json.Unmarshal(body, &serviceQueryEndpointResponse) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | return &serviceQueryEndpointResponse.Result, nil 41 | } 42 | 43 | func (c *ClientImpl) CreateQueryEndpoint(ctx context.Context, serviceID string, endpoint ServiceQueryEndpoint) (*ServiceQueryEndpoint, error) { 44 | rb, err := json.Marshal(endpoint) 45 | if err != nil { 46 | return nil, err 47 | } 48 | 49 | req, err := http.NewRequest(http.MethodPost, c.getServicePath(serviceID, "/serviceQueryEndpoint"), strings.NewReader(string(rb))) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | body, err := c.doRequest(ctx, req) 55 | if err != nil { 56 | return nil, err 57 | } 58 | 59 | response := ResponseWithResult[ServiceQueryEndpoint]{} 60 | err = json.Unmarshal(body, &response) 61 | if err != nil { 62 | return nil, err 63 | } 64 | 65 | return &response.Result, nil 66 | } 67 | 68 | func (c *ClientImpl) DeleteQueryEndpoint(ctx context.Context, serviceID string) error { 69 | req, err := http.NewRequest(http.MethodDelete, c.getServicePath(serviceID, "/serviceQueryEndpoint"), nil) 70 | if err != nil { 71 | return err 72 | } 73 | 74 | _, err = c.doRequest(ctx, req) 75 | if IsNotFound(err) { 76 | // This is what we want 77 | return nil 78 | } else if err != nil { 79 | return err 80 | } 81 | 82 | return nil 83 | } 84 | -------------------------------------------------------------------------------- /pkg/internal/api/scaling.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "net/http" 7 | "strings" 8 | ) 9 | 10 | type ReplicaScalingUpdate struct { 11 | IdleScaling *bool `json:"idleScaling,omitempty"` // bool pointer so that `false`` is not omitted 12 | MinReplicaMemoryGb *int `json:"minReplicaMemoryGb,omitempty"` 13 | MaxReplicaMemoryGb *int `json:"maxReplicaMemoryGb,omitempty"` 14 | NumReplicas *int `json:"numReplicas,omitempty"` 15 | IdleTimeoutMinutes *int `json:"idleTimeoutMinutes,omitempty"` 16 | } 17 | 18 | func (c *ClientImpl) UpdateReplicaScaling(ctx context.Context, serviceId string, s ReplicaScalingUpdate) (*Service, error) { 19 | rb, err := json.Marshal(s) 20 | if err != nil { 21 | return nil, err 22 | } 23 | 24 | req, err := http.NewRequest(http.MethodPatch, c.getServicePath(serviceId, "/replicaScaling"), strings.NewReader(string(rb))) 25 | if err != nil { 26 | return nil, err 27 | } 28 | 29 | body, err := c.doRequest(ctx, req) 30 | if err != nil { 31 | return nil, err 32 | } 33 | 34 | serviceResponse := ResponseWithResult[Service]{} 35 | err = json.Unmarshal(body, &serviceResponse) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | return &serviceResponse.Result, nil 41 | } 42 | -------------------------------------------------------------------------------- /pkg/internal/planmodifier/usestateforunknownexcept.go: -------------------------------------------------------------------------------- 1 | package planmodifier 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/hashicorp/terraform-plugin-framework/attr" 7 | "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" 8 | "github.com/hashicorp/terraform-plugin-framework/types" 9 | "github.com/hashicorp/terraform-plugin-framework/types/basetypes" 10 | ) 11 | 12 | // UseStateForUnknownExcept is a factory function for a plan modifier to be applied to Computed NestedObjects. 13 | // The goal of this Plan Modifier is to keep some of the NestedObject fields as immutable (like it happens when using 14 | // built-in UseStateForUnknown Plan Modifier) while leaving other fields modifiable. 15 | // This modifiable fields are passed to this constructor. 16 | func UseStateForUnknownExcept(fields map[string]map[string]attr.Type) planmodifier.Object { 17 | return useStateForUnknownExceptPlanModifier{ 18 | fields: fields, 19 | } 20 | } 21 | 22 | // useStateForUnknownExceptPlanModifier implements the plan modifier. 23 | type useStateForUnknownExceptPlanModifier struct { 24 | fields map[string]map[string]attr.Type 25 | } 26 | 27 | func (m useStateForUnknownExceptPlanModifier) Description(_ context.Context) string { 28 | return "The plan modifier for status attribute. It will apply useStateForUnknownModifier to all the nested attributes except the cluster_status attribute." 29 | } 30 | 31 | // MarkdownDescription returns a markdown description of the plan modifier. 32 | func (m useStateForUnknownExceptPlanModifier) MarkdownDescription(_ context.Context) string { 33 | return "The plan modifier for status attribute. It will apply useStateForUnknownModifier to all the nested attributes except the cluster_status attribute." 34 | } 35 | 36 | // PlanModifyObject implements the plan modification logic. 37 | func (m useStateForUnknownExceptPlanModifier) PlanModifyObject(ctx context.Context, req planmodifier.ObjectRequest, resp *planmodifier.ObjectResponse) { 38 | // Do nothing if there is no state value. 39 | if req.StateValue.IsNull() { 40 | return 41 | } 42 | 43 | // Do nothing if there is a known planned value. 44 | if !req.PlanValue.IsUnknown() { 45 | return 46 | } 47 | 48 | // Do nothing if there is an unknown configuration value, otherwise interpolation gets messed up. 49 | if req.ConfigValue.IsUnknown() { 50 | return 51 | } 52 | 53 | // Mark desired attributes as unknown. 54 | attributes := req.StateValue.Attributes() 55 | for name, attrTypes := range m.fields { 56 | attributes[name] = types.ObjectUnknown(attrTypes) 57 | } 58 | 59 | newStateValue, diag := basetypes.NewObjectValue(req.StateValue.AttributeTypes(ctx), attributes) 60 | 61 | resp.Diagnostics.Append(diag...) 62 | resp.PlanValue = newStateValue 63 | } 64 | -------------------------------------------------------------------------------- /pkg/internal/sql/sql.go: -------------------------------------------------------------------------------- 1 | package sql 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | // EscapeBacktick escapes the ` characted in strings to make them safe for use in SQL queries as literal values. 8 | func EscapeBacktick(s string) string { 9 | return strings.ReplaceAll(s, "`", "\\`") 10 | } 11 | -------------------------------------------------------------------------------- /pkg/internal/test/updater.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | // Updater allows to pass an object and get a changed copy of it in a single line. 4 | // Useful during tests for quick object manipulation. 5 | /* Example: 6 | type changeme struct { 7 | Field string 8 | } 9 | 10 | func main() { 11 | c := changeme{} 12 | NewUpdater(c).Update(func(src *changeme) { 13 | c.Field = "test" 14 | }).Get() 15 | } 16 | */ 17 | 18 | type Updater[T any] struct { 19 | data *T 20 | } 21 | 22 | func NewUpdater[T any](src T) *Updater[T] { 23 | return &Updater[T]{data: &src} 24 | } 25 | 26 | func (m *Updater[T]) Update(transformer func(src *T)) *Updater[T] { 27 | transformer(m.data) 28 | 29 | return m 30 | } 31 | 32 | func (m *Updater[T]) Get() T { 33 | return *m.data 34 | } 35 | 36 | func (m *Updater[T]) GetPtr() *T { 37 | return m.data 38 | } 39 | -------------------------------------------------------------------------------- /pkg/internal/tfutils/utils.go: -------------------------------------------------------------------------------- 1 | package tfutils 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-framework/attr" 5 | "github.com/hashicorp/terraform-plugin-framework/types" 6 | ) 7 | 8 | func CreateEmptyList(listType attr.Type) types.List { 9 | emptyList, _ := types.ListValue(listType, []attr.Value{}) 10 | return emptyList 11 | } 12 | -------------------------------------------------------------------------------- /pkg/internal/tools/tools.go: -------------------------------------------------------------------------------- 1 | //go:build tools 2 | 3 | package tools 4 | 5 | import ( 6 | // Ensure documentation generator is not removed from go.mod. 7 | _ "github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs" 8 | ) 9 | -------------------------------------------------------------------------------- /pkg/project/project.go: -------------------------------------------------------------------------------- 1 | package project 2 | 3 | var ( 4 | version = "dirty" 5 | commit = "NA" 6 | ) 7 | 8 | func Version() string { 9 | return version 10 | } 11 | 12 | func Commit() string { 13 | return commit 14 | } 15 | -------------------------------------------------------------------------------- /pkg/provider/README.md: -------------------------------------------------------------------------------- 1 | # This is the official provider for ClickHouse Cloud. 2 | 3 | With this provider you can deploy a ClickHouse instance on AWS, Google Cloud or Azure Cloud. 4 | 5 | To use this provider, you need to [Sign In](https://clickhouse.cloud/signIn) for a ClickHouse Cloud account and generate an [API key](https://clickhouse.com/docs/en/cloud/manage/openapi). 6 | 7 | You can find more example on how to use this provider on [Github](https://github.com/ClickHouse/terraform-provider-clickhouse/tree/main/examples/full). 8 | 9 | Visit [https://clickhouse.com/docs/en/cloud-quick-start](https://clickhouse.com/docs/en/cloud-quick-start) now to get started using ClickHouse Cloud. 10 | 11 | ## Breaking changes 12 | 13 | Note: we only provide upgrade path from consecutive major releases of our terraform provider. 14 | If you are upgrading, please be sure to not skip any major release while you do so. 15 | 16 | For example: 17 | 18 | - `0.3.0` to `1.0.0` is a valid upgrade path 19 | - `0.3.0` to `1.1.0` is a valid upgrade path 20 | - `0.3.0` to `2.0.0` is NOT a valid upgrade path 21 | 22 | ### Upgrading to version >= 3.0.0 of the Clickhouse Terraform Provider 23 | 24 | In version 3.0.0 we revisited how to deal with `clickhouse_service` endpoints. 25 | If you are using the `endpoint_config` attribute or the `endpoints` read only attribute, this breaking change affects you. 26 | Please visit [https://github.com/ClickHouse/terraform-provider-clickhouse#breaking-changes-and-deprecations](https://github.com/ClickHouse/terraform-provider-clickhouse#breaking-changes-and-deprecations) for more details. 27 | 28 | ### Upgrading to version >= 1.0.0 of the Clickhouse Terraform Provider 29 | 30 | If you are upgrading from version < 1.0.0 to anything >= 1.0.0 and you are using the `clickhouse_private_endpoint_registration` resource or the `private_endpoint_ids` attribute of the `clickhouse_service` resource, 31 | then a manual process is required after the upgrade. Please visit [https://github.com/ClickHouse/terraform-provider-clickhouse#breaking-changes-and-deprecations](https://github.com/ClickHouse/terraform-provider-clickhouse#breaking-changes-and-deprecations) for more details. 32 | -------------------------------------------------------------------------------- /pkg/resource/descriptions/database.md: -------------------------------------------------------------------------------- 1 | Use the *clickhouse_database* resource to create a database in a ClickHouse cloud *service*. 2 | 3 | Attention: in order to use the `clickhouse_database` resource you need to set the `query_api_endpoint` attribute in the `clickhouse_service`. 4 | Please check [full example](https://github.com/ClickHouse/terraform-provider-clickhouse/blob/main/examples/database/main.tf). 5 | 6 | Known limitations: 7 | 8 | - Changing the comment on a `database` resource is unsupported and will cause the database to be destroyed and recreated. WARNING: you will lose any content of the database if you do so! 9 | 10 | -------------------------------------------------------------------------------- /pkg/resource/descriptions/grant_privilege.md: -------------------------------------------------------------------------------- 1 | *WARNING:* This is an alpha resource. Specification can change at any time and no backward compatibilty is guaranteed at this stage. 2 | 3 | You can use the `clickhouse_grant_privilege` resource to grant privileges on databases and tables to either a `clickhouse_user` or a `clickhouse_role`. 4 | 5 | Please note that in order to grant privileges to all database and/or all tables, the `database` and/or `table` fields must be set to null, and not to "*". 6 | 7 | Attention: in order to use the `clickhouse_grant_privilege` resource you need to set the `query_api_endpoint` attribute in the `clickhouse_service`. 8 | Please check [full example](https://github.com/ClickHouse/terraform-provider-clickhouse/blob/main/examples/rbac/main.tf). 9 | 10 | Known limitations: 11 | 12 | - Only a subset of privileges can be granted on ClickHouse cloud. For example the `ALL` privilege can't be granted. See https://clickhouse.com/docs/en/sql-reference/statements/grant#all 13 | - It's not possible to grant the same `clickhouse_grant_privilege` to both a `clickhouse_user` and a `clickhouse_role` using a single `clickhouse_grant_privilege` stanza. You can do that using two different stanzas, one with `grantee_user_name` and the other with `grantee_role_name` fields set. 14 | - It's not possible to grant the same privilege (example 'SELECT') to multiple entities (for example tables) with a single stanza. You can do that my creating one stanza for each entity you want to grant privileges on. 15 | - Importing `clickhouse_grant_privilege` resources into terraform is not supported. 16 | -------------------------------------------------------------------------------- /pkg/resource/descriptions/grant_role.md: -------------------------------------------------------------------------------- 1 | *WARNING:* This is an alpha resource. Specification can change at any time and no backward compatibilty is guaranteed at this stage. 2 | 3 | You can use the `clickhouse_grant_role` resource to grant a `clickhouse_role` to either a `clickhouse_user` or to another `clickhouse_role`. 4 | 5 | Attention: in order to use the `clickhouse_grant_role` resource you need to set the `query_api_endpoint` attribute in the `clickhouse_service`. 6 | Please check [full example](https://github.com/ClickHouse/terraform-provider-clickhouse/blob/main/examples/rbac/main.tf). 7 | 8 | Known limitations: 9 | 10 | - It's not possible to grant the same `clickhouse_role` to both a `clickhouse_user` and a `clickhouse_role` using a single `clickhouse_grant_role` stanza. You can do that using two different stanzas, one with `grantee_user_name` and the other with `grantee_role_name` fields set. 11 | - Importing `clickhouse_grant_role` resources into terraform is not supported. 12 | -------------------------------------------------------------------------------- /pkg/resource/descriptions/role.md: -------------------------------------------------------------------------------- 1 | *WARNING:* This is an alpha resource. Specification can change at any time and no backward compatibilty is guaranteed at this stage. 2 | 3 | You can use the `clickhouse_role` resource to create a `role` in a `ClickHouse cloud` service. 4 | 5 | Attention: in order to use the `clickhouse_role` resource you need to set the `query_api_endpoint` attribute in the `clickhouse_service`. 6 | Please check [full example](https://github.com/ClickHouse/terraform-provider-clickhouse/blob/main/examples/rbac/main.tf). 7 | -------------------------------------------------------------------------------- /pkg/resource/descriptions/service.md: -------------------------------------------------------------------------------- 1 | You can use the *clickhouse_service* resource to deploy ClickHouse cloud instances on supported cloud providers. 2 | 3 | Known limitations: 4 | 5 | - If you create a service with `warehouse_id` set and then remove `warehouse_id` attribute completely, the provider won't detect the change. If you want to make a secondary service become primary, remove the `warehouse_id` and taint it before applying. 6 | - If you create a service with `readonly` flag set to true and then remove `readonly` flag completely, the provider won't detect the change. If you want to make a secondary service read write, explicitly set the `readonly` flag to false. 7 | -------------------------------------------------------------------------------- /pkg/resource/descriptions/service_transparent_data_encryption_key_association.md: -------------------------------------------------------------------------------- 1 | You can use the *clickhouse_service_transparent_data_encryption_key_association* resource to associate your own Encryption Key with a Clickhouse Service with the Transparent Data Encryption (TDE) feature enabled. 2 | Please note that this feature requires an organization with the `Enterprise` plan. 3 | -------------------------------------------------------------------------------- /pkg/resource/descriptions/user.md: -------------------------------------------------------------------------------- 1 | *WARNING:* This is an alpha resource. Specification can change at any time and no backward compatibilty is guaranteed at this stage. 2 | 3 | You can use the `clickhouse_user` resource to create a user in a `ClickHouse cloud` service. 4 | 5 | Attention: in order to use the `clickhouse_user` resource you need to set the `query_api_endpoint` attribute in the `clickhouse_service`. 6 | Please check [full example](https://github.com/ClickHouse/terraform-provider-clickhouse/blob/main/examples/rbac/main.tf). 7 | 8 | Known limitations: 9 | 10 | - For security reasons, it is not possible to detect if the password for a user was changed outside terraform. Once first created, the password will not be checked for external changes. 11 | - Any change to the `user` resource definition will cause the user to be deleted and recreated. 12 | - Import of a `user` resource is not supported. 13 | -------------------------------------------------------------------------------- /pkg/resource/models/clickpipe_reverse_private_endpoint_resource.go: -------------------------------------------------------------------------------- 1 | //go:build alpha 2 | 3 | package models 4 | 5 | import ( 6 | "github.com/hashicorp/terraform-plugin-framework/types" 7 | ) 8 | 9 | // ClickPipeReversePrivateEndpointResourceModel describes the resource data model. 10 | type ClickPipeReversePrivateEndpointResourceModel struct { 11 | ID types.String `tfsdk:"id"` 12 | ServiceID types.String `tfsdk:"service_id"` 13 | Description types.String `tfsdk:"description"` 14 | Type types.String `tfsdk:"type"` 15 | VPCEndpointServiceName types.String `tfsdk:"vpc_endpoint_service_name"` 16 | VPCResourceConfigurationID types.String `tfsdk:"vpc_resource_configuration_id"` 17 | VPCResourceShareArn types.String `tfsdk:"vpc_resource_share_arn"` 18 | MSKClusterArn types.String `tfsdk:"msk_cluster_arn"` 19 | MSKAuthentication types.String `tfsdk:"msk_authentication"` 20 | EndpointID types.String `tfsdk:"endpoint_id"` 21 | DNSNames types.List `tfsdk:"dns_names"` 22 | PrivateDNSNames types.List `tfsdk:"private_dns_names"` 23 | Status types.String `tfsdk:"status"` 24 | } 25 | -------------------------------------------------------------------------------- /pkg/resource/models/database_resource.go: -------------------------------------------------------------------------------- 1 | //go:build alpha 2 | 3 | package models 4 | 5 | import ( 6 | "github.com/hashicorp/terraform-plugin-framework/types" 7 | ) 8 | 9 | type DatabaseResourceModel struct { 10 | ServiceID types.String `tfsdk:"service_id"` 11 | Name types.String `tfsdk:"name"` 12 | Comment types.String `tfsdk:"comment"` 13 | } 14 | -------------------------------------------------------------------------------- /pkg/resource/models/grant_privilege.go: -------------------------------------------------------------------------------- 1 | //go:build alpha 2 | 3 | package models 4 | 5 | import ( 6 | "github.com/hashicorp/terraform-plugin-framework/types" 7 | ) 8 | 9 | type GrantPrivilege struct { 10 | ServiceID types.String `tfsdk:"service_id"` 11 | Privilege types.String `tfsdk:"privilege_name"` 12 | Database types.String `tfsdk:"database_name"` 13 | Table types.String `tfsdk:"table_name"` 14 | Column types.String `tfsdk:"column_name"` 15 | GranteeUserName types.String `tfsdk:"grantee_user_name"` 16 | GranteeRoleName types.String `tfsdk:"grantee_role_name"` 17 | GrantOption types.Bool `tfsdk:"grant_option"` 18 | } 19 | -------------------------------------------------------------------------------- /pkg/resource/models/grant_role.go: -------------------------------------------------------------------------------- 1 | //go:build alpha 2 | 3 | package models 4 | 5 | import ( 6 | "github.com/hashicorp/terraform-plugin-framework/types" 7 | ) 8 | 9 | type GrantRole struct { 10 | ServiceID types.String `tfsdk:"service_id"` 11 | RoleName types.String `tfsdk:"role_name"` 12 | GranteeUserName types.String `tfsdk:"grantee_user_name"` 13 | GranteeRoleName types.String `tfsdk:"grantee_role_name"` 14 | AdminOption types.Bool `tfsdk:"admin_option"` 15 | } 16 | -------------------------------------------------------------------------------- /pkg/resource/models/private_endpoint_registration.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-framework/types" 5 | ) 6 | 7 | type PrivateEndpointRegistration struct { 8 | CloudProvider types.String `tfsdk:"cloud_provider"` 9 | Description types.String `tfsdk:"description"` 10 | EndpointId types.String `tfsdk:"private_endpoint_id"` 11 | Region types.String `tfsdk:"region"` 12 | } 13 | -------------------------------------------------------------------------------- /pkg/resource/models/role.go: -------------------------------------------------------------------------------- 1 | //go:build alpha 2 | 3 | package models 4 | 5 | import ( 6 | "github.com/hashicorp/terraform-plugin-framework/types" 7 | ) 8 | 9 | type Role struct { 10 | ServiceID types.String `tfsdk:"service_id"` 11 | Name types.String `tfsdk:"name"` 12 | } 13 | -------------------------------------------------------------------------------- /pkg/resource/models/service_private_endpoints_attachment.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-framework/types" 5 | ) 6 | 7 | type ServicePrivateEndpointsAttachment struct { 8 | PrivateEndpointIDs types.List `tfsdk:"private_endpoint_ids"` 9 | ServiceID types.String `tfsdk:"service_id"` 10 | } 11 | -------------------------------------------------------------------------------- /pkg/resource/models/service_transparent_data_encryption_key_association.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-framework/types" 5 | ) 6 | 7 | type ServiceTransparentDataEncryptionKeyAssociation struct { 8 | ServiceID types.String `tfsdk:"service_id"` 9 | KeyID types.String `tfsdk:"key_id"` 10 | } 11 | -------------------------------------------------------------------------------- /pkg/resource/models/user.go: -------------------------------------------------------------------------------- 1 | //go:build alpha 2 | 3 | package models 4 | 5 | import ( 6 | "github.com/hashicorp/terraform-plugin-framework/types" 7 | ) 8 | 9 | type User struct { 10 | ServiceID types.String `tfsdk:"service_id"` 11 | Name types.String `tfsdk:"name"` 12 | PasswordSha256Hash types.String `tfsdk:"password_sha256_hash"` 13 | } 14 | -------------------------------------------------------------------------------- /pkg/resource/register_debug.go: -------------------------------------------------------------------------------- 1 | //go:build alpha 2 | 3 | package resource 4 | 5 | import ( 6 | upstreamresource "github.com/hashicorp/terraform-plugin-framework/resource" 7 | ) 8 | 9 | func GetResourceFactories() []func() upstreamresource.Resource { 10 | return []func() upstreamresource.Resource{ 11 | NewServiceResource, 12 | NewPrivateEndpointRegistrationResource, 13 | NewServicePrivateEndpointsAttachmentResource, 14 | NewServiceTransparentDataEncryptionKeyAssociationResource, 15 | NewDatabaseResource, 16 | NewClickPipeResource, 17 | NewClickPipeReversePrivateEndpointResource, 18 | NewUserResource, 19 | NewRoleResource, 20 | NewGrantRoleResource, 21 | NewGrantPrivilegeResource, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /pkg/resource/register_stable.go: -------------------------------------------------------------------------------- 1 | //go:build !alpha 2 | 3 | package resource 4 | 5 | import ( 6 | upstreamresource "github.com/hashicorp/terraform-plugin-framework/resource" 7 | ) 8 | 9 | func GetResourceFactories() []func() upstreamresource.Resource { 10 | return []func() upstreamresource.Resource{ 11 | NewServiceResource, 12 | NewPrivateEndpointRegistrationResource, 13 | NewServicePrivateEndpointsAttachmentResource, 14 | NewServiceTransparentDataEncryptionKeyAssociationResource, 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /terraform-registry-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "metadata": { 4 | "protocol_versions": [ 5 | "6.0" 6 | ] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/import/service/main.tf: -------------------------------------------------------------------------------- 1 | variable "organization_id" { 2 | type = string 3 | } 4 | 5 | variable "token_key" { 6 | type = string 7 | } 8 | 9 | variable "token_secret" { 10 | type = string 11 | } 12 | 13 | variable "service_name" { 14 | type = string 15 | } 16 | 17 | variable "cloud_provider" { 18 | type = string 19 | } 20 | 21 | variable "region" { 22 | type = string 23 | } 24 | 25 | variable "release_channel" { 26 | type = string 27 | default = "default" 28 | validation { 29 | condition = var.release_channel == "default" || var.release_channel == "fast" 30 | error_message = "Release channel can be either 'default' or 'fast'." 31 | } 32 | } 33 | 34 | resource "clickhouse_service" "import" { 35 | name = var.service_name 36 | cloud_provider = var.cloud_provider 37 | region = var.region 38 | release_channel = var.release_channel 39 | idle_scaling = true 40 | idle_timeout_minutes = 15 41 | password_hash = "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=" # base64 encoded sha256 hash of "test" 42 | 43 | ip_access = [ 44 | { 45 | source = "0.0.0.0/0" 46 | description = "Anywhere" 47 | } 48 | ] 49 | 50 | min_replica_memory_gb = 8 51 | max_replica_memory_gb = 120 52 | 53 | backup_configuration = { 54 | backup_period_in_hours = 24 55 | backup_retention_period_in_hours = 24 56 | backup_start_time = null 57 | } 58 | } 59 | 60 | output "service_uuid" { 61 | value = clickhouse_service.import.id 62 | } 63 | -------------------------------------------------------------------------------- /tests/import/service/provider.tf: -------------------------------------------------------------------------------- 1 | # This file is generated automatically please do not edit 2 | terraform { 3 | required_providers { 4 | clickhouse = { 5 | version = "3.3.3" 6 | source = "ClickHouse/clickhouse" 7 | } 8 | } 9 | } 10 | 11 | provider "clickhouse" { 12 | organization_id = var.organization_id 13 | token_key = var.token_key 14 | token_secret = var.token_secret 15 | } 16 | -------------------------------------------------------------------------------- /tests/import/service/provider.tf.template: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | clickhouse = { 4 | version = "${CLICKHOUSE_TERRAFORM_PROVIDER_VERSION}" 5 | source = "ClickHouse/clickhouse" 6 | } 7 | } 8 | } 9 | 10 | provider "clickhouse" { 11 | organization_id = var.organization_id 12 | token_key = var.token_key 13 | token_secret = var.token_secret 14 | } 15 | -------------------------------------------------------------------------------- /tmp/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | --------------------------------------------------------------------------------