diff --git a/.gitignore b/.gitignore index 4b8f0ed..1369874 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ website/.bundle website/build website/node_modules .vagrant/ +.vscode/ *.backup ./*.tfstate .terraform/ diff --git a/GNUmakefile b/GNUmakefile deleted file mode 100644 index 7771cd6..0000000 --- a/GNUmakefile +++ /dev/null @@ -1,6 +0,0 @@ -default: testacc - -# Run acceptance tests -.PHONY: testacc -testacc: - TF_ACC=1 go test ./... -v $(TESTARGS) -timeout 120m diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..09293b4 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +default: testacc + +# Run acceptance tests +.PHONY: testacc +testacc: + TF_ACC=1 go test ./... -v $(TESTARGS) -timeout 120m + +.PHONY: generate-mocks +generate-mocks: ## Generate mock objects + @echo "==> Generating mock objects" + go install github.com/vektra/mockery/v2@v2.50.0 + # mockery --name TiDBCloudClient --recursive --output=mock --outpkg mock --filename api_client.go + mockery --name TiDBCloudDedicatedClient --recursive --output=mock --outpkg mock --filename dedicated_api_client.go \ No newline at end of file diff --git a/docs/data-sources/dedicated_cloud_providers.md b/docs/data-sources/dedicated_cloud_providers.md new file mode 100644 index 0000000..74ce25e --- /dev/null +++ b/docs/data-sources/dedicated_cloud_providers.md @@ -0,0 +1,39 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "tidbcloud_dedicated_cloud_providers Data Source - terraform-provider-tidbcloud" +subcategory: "" +description: |- + dedicated cloud providers data source +--- + +# tidbcloud_dedicated_cloud_providers (Data Source) + +dedicated cloud providers data source + +## Example Usage + +```terraform +variable "project_id" { + type = string + nullable = true +} + +data "tidbcloud_dedicated_cloud_providers" "example" { + project_id = var.project_id +} + +output "output" { + value = data.tidbcloud_dedicated_cloud_providers.example +} +``` + + +## Schema + +### Optional + +- `project_id` (String) The ID of the project. If not set, it will return the cloud providers that can be selected under the default project. + +### Read-Only + +- `cloud_providers` (List of String) The cloud providers. diff --git a/docs/data-sources/dedicated_region.md b/docs/data-sources/dedicated_region.md new file mode 100644 index 0000000..deab992 --- /dev/null +++ b/docs/data-sources/dedicated_region.md @@ -0,0 +1,40 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "tidbcloud_dedicated_region Data Source - terraform-provider-tidbcloud" +subcategory: "" +description: |- + dedicated region data source +--- + +# tidbcloud_dedicated_region (Data Source) + +dedicated region data source + +## Example Usage + +```terraform +variable "region_id" { + type = string + nullable = false +} + +data "tidbcloud_dedicated_region" "example" { + region_id = var.region_id +} + +output "output" { + value = data.tidbcloud_dedicated_region.example +} +``` + + +## Schema + +### Required + +- `region_id` (String) The ID of the region. + +### Read-Only + +- `cloud_provider` (String) The cloud provider of the region. +- `display_name` (String) The display name of the region. diff --git a/docs/data-sources/dedicated_regions.md b/docs/data-sources/dedicated_regions.md new file mode 100644 index 0000000..47cb2e7 --- /dev/null +++ b/docs/data-sources/dedicated_regions.md @@ -0,0 +1,55 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "tidbcloud_dedicated_regions Data Source - terraform-provider-tidbcloud" +subcategory: "" +description: |- + dedicated regions data source +--- + +# tidbcloud_dedicated_regions (Data Source) + +dedicated regions data source + +## Example Usage + +```terraform +variable "project_id" { + type = string + nullable = true +} + +variable "cloud_provider" { + type = string + nullable = true +} + +data "tidbcloud_dedicated_regions" "example" { + project_id = var.project_id + cloud_provider = var.cloud_provider +} + +output "output" { + value = data.tidbcloud_dedicated_regions.example +} +``` + + +## Schema + +### Optional + +- `cloud_provider` (String) The cloud provider of the regions. If not set, it will return the regions that can be selected from all cloud providers. +- `project_id` (String) The ID of the project. If not set, it will return the regions that can be selected under the default project. + +### Read-Only + +- `regions` (Attributes List) The regions. (see [below for nested schema](#nestedatt--regions)) + + +### Nested Schema for `regions` + +Read-Only: + +- `cloud_provider` (String) The cloud provider of the region. +- `display_name` (String) The display name of the region. +- `region_id` (String) The ID of the region. diff --git a/examples/data-sources/tidbcloud_dedicated_cloud_providers/data-source.tf b/examples/data-sources/tidbcloud_dedicated_cloud_providers/data-source.tf new file mode 100644 index 0000000..2955b35 --- /dev/null +++ b/examples/data-sources/tidbcloud_dedicated_cloud_providers/data-source.tf @@ -0,0 +1,12 @@ +variable "project_id" { + type = string + nullable = true +} + +data "tidbcloud_dedicated_cloud_providers" "example" { + project_id = var.project_id +} + +output "output" { + value = data.tidbcloud_dedicated_cloud_providers.example +} \ No newline at end of file diff --git a/examples/data-sources/tidbcloud_dedicated_region/data-source.tf b/examples/data-sources/tidbcloud_dedicated_region/data-source.tf new file mode 100644 index 0000000..97f89a2 --- /dev/null +++ b/examples/data-sources/tidbcloud_dedicated_region/data-source.tf @@ -0,0 +1,12 @@ +variable "region_id" { + type = string + nullable = false +} + +data "tidbcloud_dedicated_region" "example" { + region_id = var.region_id +} + +output "output" { + value = data.tidbcloud_dedicated_region.example +} \ No newline at end of file diff --git a/examples/data-sources/tidbcloud_dedicated_regions/data-source.tf b/examples/data-sources/tidbcloud_dedicated_regions/data-source.tf new file mode 100644 index 0000000..5eb3fe6 --- /dev/null +++ b/examples/data-sources/tidbcloud_dedicated_regions/data-source.tf @@ -0,0 +1,18 @@ +variable "project_id" { + type = string + nullable = true +} + +variable "cloud_provider" { + type = string + nullable = true +} + +data "tidbcloud_dedicated_regions" "example" { + project_id = var.project_id + cloud_provider = var.cloud_provider +} + +output "output" { + value = data.tidbcloud_dedicated_regions.example +} \ No newline at end of file diff --git a/go.mod b/go.mod index aea12d0..724b238 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/tidbcloud/terraform-provider-tidbcloud -go 1.21 +go 1.23 require ( github.com/c4pt0r/go-tidbcloud-sdk-v1 v0.0.0-20240415110020-a27efb454da5 @@ -11,11 +11,13 @@ require ( github.com/go-openapi/validate v0.24.0 github.com/golang/mock v1.6.0 github.com/hashicorp/terraform-plugin-docs v0.19.4 - github.com/hashicorp/terraform-plugin-framework v1.9.0 - github.com/hashicorp/terraform-plugin-go v0.23.0 + github.com/hashicorp/terraform-plugin-framework v1.13.0 + github.com/hashicorp/terraform-plugin-go v0.25.0 github.com/hashicorp/terraform-plugin-log v0.9.0 - github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 + github.com/hashicorp/terraform-plugin-sdk/v2 v2.35.0 github.com/icholy/digest v0.1.15 + github.com/stretchr/testify v1.9.0 + github.com/tidbcloud/tidbcloud-cli/pkg v0.0.0-20241125120734-8e2a11bc41c5 ) require ( @@ -32,6 +34,7 @@ require ( github.com/bgentry/speakeasy v0.1.0 // indirect github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect github.com/cloudflare/circl v1.3.7 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.16.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -48,16 +51,18 @@ require ( github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect - github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-plugin v1.6.0 // indirect + github.com/hashicorp/go-plugin v1.6.2 // indirect + github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/go-version v1.7.0 // indirect - github.com/hashicorp/hc-install v0.7.0 // indirect - github.com/hashicorp/hcl/v2 v2.20.1 // indirect + github.com/hashicorp/hc-install v0.9.0 // indirect + github.com/hashicorp/hcl/v2 v2.23.0 // indirect github.com/hashicorp/logutils v1.0.0 // indirect github.com/hashicorp/terraform-exec v0.21.0 // indirect - github.com/hashicorp/terraform-json v0.22.1 // indirect + github.com/hashicorp/terraform-json v0.23.0 // indirect + github.com/hashicorp/terraform-plugin-testing v1.11.0 // indirect github.com/hashicorp/terraform-registry-address v0.2.3 // indirect github.com/hashicorp/terraform-svchost v0.1.1 // indirect github.com/hashicorp/yamux v0.1.1 // indirect @@ -76,32 +81,34 @@ require ( github.com/oklog/run v1.0.0 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/posener/complete v1.2.3 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/spf13/cast v1.5.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/yuin/goldmark v1.7.1 // indirect github.com/yuin/goldmark-meta v1.1.0 // indirect - github.com/zclconf/go-cty v1.14.4 // indirect + github.com/zclconf/go-cty v1.15.0 // indirect go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect - golang.org/x/crypto v0.23.0 // indirect + golang.org/x/crypto v0.29.0 // indirect golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect - golang.org/x/tools v0.13.0 // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.27.0 // indirect + golang.org/x/text v0.20.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect - google.golang.org/grpc v1.63.2 // indirect - google.golang.org/protobuf v1.34.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/grpc v1.67.1 // indirect + google.golang.org/protobuf v1.35.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index b6063bb..77ad8b3 100644 --- a/go.sum +++ b/go.sum @@ -107,38 +107,42 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI= github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-plugin v1.6.0 h1:wgd4KxHJTVGGqWBq4QPB1i5BZNEx9BR8+OFmHDmTk8A= -github.com/hashicorp/go-plugin v1.6.0/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI= +github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog= +github.com/hashicorp/go-plugin v1.6.2/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q= +github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/hc-install v0.7.0 h1:Uu9edVqjKQxxuD28mR5TikkKDd/p55S8vzPC1659aBk= -github.com/hashicorp/hc-install v0.7.0/go.mod h1:ELmmzZlGnEcqoUMKUuykHaPCIR1sYLYX+KSggWSKZuA= -github.com/hashicorp/hcl/v2 v2.20.1 h1:M6hgdyz7HYt1UN9e61j+qKJBqR3orTWbI1HKBJEdxtc= -github.com/hashicorp/hcl/v2 v2.20.1/go.mod h1:TZDqQ4kNKCbh1iJp99FdPiUaVDDUPivbqxZulxDYqL4= +github.com/hashicorp/hc-install v0.9.0 h1:2dIk8LcvANwtv3QZLckxcjyF5w8KVtiMxu6G6eLhghE= +github.com/hashicorp/hc-install v0.9.0/go.mod h1:+6vOP+mf3tuGgMApVYtmsnDoKWMDcFXeTxCACYZ8SFg= +github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos= +github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/terraform-exec v0.21.0 h1:uNkLAe95ey5Uux6KJdua6+cv8asgILFVWkd/RG0D2XQ= github.com/hashicorp/terraform-exec v0.21.0/go.mod h1:1PPeMYou+KDUSSeRE9szMZ/oHf4fYUmB923Wzbq1ICg= -github.com/hashicorp/terraform-json v0.22.1 h1:xft84GZR0QzjPVWs4lRUwvTcPnegqlyS7orfb5Ltvec= -github.com/hashicorp/terraform-json v0.22.1/go.mod h1:JbWSQCLFSXFFhg42T7l9iJwdGXBYV8fmmD6o/ML4p3A= +github.com/hashicorp/terraform-json v0.23.0 h1:sniCkExU4iKtTADReHzACkk8fnpQXrdD2xoR+lppBkI= +github.com/hashicorp/terraform-json v0.23.0/go.mod h1:MHdXbBAbSg0GvzuWazEGKAn/cyNfIB7mN6y7KJN6y2c= github.com/hashicorp/terraform-plugin-docs v0.19.4 h1:G3Bgo7J22OMtegIgn8Cd/CaSeyEljqjH3G39w28JK4c= github.com/hashicorp/terraform-plugin-docs v0.19.4/go.mod h1:4pLASsatTmRynVzsjEhbXZ6s7xBlUw/2Kt0zfrq8HxA= -github.com/hashicorp/terraform-plugin-framework v1.9.0 h1:caLcDoxiRucNi2hk8+j3kJwkKfvHznubyFsJMWfZqKU= -github.com/hashicorp/terraform-plugin-framework v1.9.0/go.mod h1:qBXLDn69kM97NNVi/MQ9qgd1uWWsVftGSnygYG1tImM= -github.com/hashicorp/terraform-plugin-go v0.23.0 h1:AALVuU1gD1kPb48aPQUjug9Ir/125t+AAurhqphJ2Co= -github.com/hashicorp/terraform-plugin-go v0.23.0/go.mod h1:1E3Cr9h2vMlahWMbsSEcNrOCxovCZhOOIXjFHbjc/lQ= +github.com/hashicorp/terraform-plugin-framework v1.13.0 h1:8OTG4+oZUfKgnfTdPTJwZ532Bh2BobF4H+yBiYJ/scw= +github.com/hashicorp/terraform-plugin-framework v1.13.0/go.mod h1:j64rwMGpgM3NYXTKuxrCnyubQb/4VKldEKlcG8cvmjU= +github.com/hashicorp/terraform-plugin-go v0.25.0 h1:oi13cx7xXA6QciMcpcFi/rwA974rdTxjqEhXJjbAyks= +github.com/hashicorp/terraform-plugin-go v0.25.0/go.mod h1:+SYagMYadJP86Kvn+TGeV+ofr/R3g4/If0O5sO96MVw= github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 h1:kJiWGx2kiQVo97Y5IOGR4EMcZ8DtMswHhUuFibsCQQE= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0/go.mod h1:sl/UoabMc37HA6ICVMmGO+/0wofkVIRxf+BMb/dnoIg= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.35.0 h1:wyKCCtn6pBBL46c1uIIBNUOWlNfYXfXpVo16iDyLp8Y= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.35.0/go.mod h1:B0Al8NyYVr8Mp/KLwssKXG1RqnTk7FySqSn4fRuLNgw= +github.com/hashicorp/terraform-plugin-testing v1.11.0 h1:MeDT5W3YHbONJt2aPQyaBsgQeAIckwPX41EUHXEn29A= +github.com/hashicorp/terraform-plugin-testing v1.11.0/go.mod h1:WNAHQ3DcgV/0J+B15WTE6hDvxcUdkPPpnB1FR3M910U= github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI= github.com/hashicorp/terraform-registry-address v0.2.3/go.mod h1:lFHA76T8jfQteVfT7caREqguFrW3c4MFSPhZB7HHgUM= github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ= @@ -220,6 +224,8 @@ github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -227,6 +233,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tidbcloud/tidbcloud-cli/pkg v0.0.0-20241125120734-8e2a11bc41c5 h1:GhfOtxISf6CLjiBdx/02a+J3typ6C3U53ZWfgtf3rEM= +github.com/tidbcloud/tidbcloud-cli/pkg v0.0.0-20241125120734-8e2a11bc41c5/go.mod h1:ckUJi2ZhPQItzndsHOWfCnNBW7MlHHLHWEGOyKpN/kE= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= @@ -242,10 +250,10 @@ github.com/yuin/goldmark v1.7.1 h1:3bajkSilaCbjdKVsKdZjZCLBNPL9pYzrCakKaf4U49U= github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc= github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0= -github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8= -github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= -github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI= -github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= +github.com/zclconf/go-cty v1.15.0 h1:tTCRWxsexYUmtt/wVxgDClUe+uQusuI443uL6e+5sXQ= +github.com/zclconf/go-cty v1.15.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= +github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= go.abhg.dev/goldmark/frontmatter v0.2.0 h1:P8kPG0YkL12+aYk2yU3xHv4tcXzeVnN+gU0tJ5JnxRw= go.abhg.dev/goldmark/frontmatter v0.2.0/go.mod h1:XqrEkZuM57djk7zrlRUB02x8I5J0px76YjkOzhB4YlU= go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= @@ -262,14 +270,14 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -277,14 +285,14 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -301,8 +309,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -312,15 +320,15 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -328,14 +336,14 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= -google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.0 h1:Qo/qEd2RZPCf2nKuorzksSknv0d3ERwp1vFG38gSmH4= -google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/internal/provider/backup_resource.go b/internal/provider/backup_resource.go index d12e0a0..0352a9f 100644 --- a/internal/provider/backup_resource.go +++ b/internal/provider/backup_resource.go @@ -3,6 +3,8 @@ package provider import ( "context" "fmt" + "strings" + backupApi "github.com/c4pt0r/go-tidbcloud-sdk-v1/client/backup" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -11,7 +13,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" - "strings" ) type backupResourceData struct { @@ -188,7 +189,7 @@ func refreshBackupResourceData(resp *backupApi.GetBackupOfClusterOKBody, data *b } func (r *backupResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Unsupported", fmt.Sprintf("backup can't be updated")) + resp.Diagnostics.AddError("Unsupported", "backup can't be updated") } func (r *backupResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { diff --git a/internal/provider/backups_data_source.go b/internal/provider/backups_data_source.go index 13a430d..94e1a7f 100644 --- a/internal/provider/backups_data_source.go +++ b/internal/provider/backups_data_source.go @@ -3,13 +3,14 @@ package provider import ( "context" "fmt" + "math/rand" + "strconv" + backupApi "github.com/c4pt0r/go-tidbcloud-sdk-v1/client/backup" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" - "math/rand" - "strconv" ) type backupsDataSourceData struct { @@ -149,7 +150,7 @@ func (d *backupsDataSource) Read(ctx context.Context, req datasource.ReadRequest tflog.Trace(ctx, "read backups data source") listBackUpOfClusterOK, err := d.provider.client.ListBackUpOfCluster(backupApi.NewListBackUpOfClusterParams().WithProjectID(data.ProjectId).WithClusterID(data.ClusterId).WithPage(&page).WithPageSize(&pageSize)) if err != nil { - resp.Diagnostics.AddError("Read Error", fmt.Sprintf("Unable to call GetBackups, got error: %s", err)) + resp.Diagnostics.AddError("Read Error", fmt.Sprintf("Unable to call ListBackups, got error: %s", err)) return } diff --git a/internal/provider/cluster_resource.go b/internal/provider/cluster_resource.go index aef0e35..2f60c72 100644 --- a/internal/provider/cluster_resource.go +++ b/internal/provider/cluster_resource.go @@ -672,7 +672,7 @@ func (r clusterResource) Update(ctx context.Context, req resource.UpdateRequest, ) return } - if !data.Config.Port.IsNull() && !data.Config.Port.IsNull() && data.Config.Port.ValueInt64() != state.Config.Port.ValueInt64() { + if !data.Config.Port.IsNull() && data.Config.Port.ValueInt64() != state.Config.Port.ValueInt64() { resp.Diagnostics.AddError( "Update error", "port can not be changed, only components can be changed now", diff --git a/internal/provider/cluster_specs_data_source.go b/internal/provider/cluster_specs_data_source.go index 103c112..6e26f2f 100644 --- a/internal/provider/cluster_specs_data_source.go +++ b/internal/provider/cluster_specs_data_source.go @@ -3,13 +3,14 @@ package provider import ( "context" "fmt" + "math/rand" + "strconv" + clusterApi "github.com/c4pt0r/go-tidbcloud-sdk-v1/client/cluster" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" - "math/rand" - "strconv" ) type clusterSpecsDataSourceData struct { diff --git a/internal/provider/clusters_data_source.go b/internal/provider/clusters_data_source.go index 581399c..a1b9c6c 100644 --- a/internal/provider/clusters_data_source.go +++ b/internal/provider/clusters_data_source.go @@ -3,13 +3,14 @@ package provider import ( "context" "fmt" + "math/rand" + "strconv" + clusterApi "github.com/c4pt0r/go-tidbcloud-sdk-v1/client/cluster" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" - "math/rand" - "strconv" ) type clustersDataSourceData struct { diff --git a/internal/provider/dedicated_cloud_providers_data_source.go b/internal/provider/dedicated_cloud_providers_data_source.go new file mode 100644 index 0000000..77d68af --- /dev/null +++ b/internal/provider/dedicated_cloud_providers_data_source.go @@ -0,0 +1,82 @@ +package provider + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +type dedicatedCloudProvidersDataSourceData struct { + CloudProviders []types.String `tfsdk:"cloud_providers"` + ProjectId types.String `tfsdk:"project_id"` +} + +var _ datasource.DataSource = &dedicatedCloudProvidersDataSource{} + +type dedicatedCloudProvidersDataSource struct { + provider *tidbcloudProvider +} + +func NewDedicatedCloudProvidersDataSource() datasource.DataSource { + return &dedicatedCloudProvidersDataSource{} +} + +func (d *dedicatedCloudProvidersDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_dedicated_cloud_providers" +} + +func (d *dedicatedCloudProvidersDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + var ok bool + if d.provider, ok = req.ProviderData.(*tidbcloudProvider); !ok { + resp.Diagnostics.AddError("Internal provider error", + fmt.Sprintf("Error in Configure: expected %T but got %T", tidbcloudProvider{}, req.ProviderData)) + } +} + +func (d *dedicatedCloudProvidersDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: "dedicated cloud providers data source", + Attributes: map[string]schema.Attribute{ + "project_id": schema.StringAttribute{ + MarkdownDescription: "The ID of the project. If not set, it will return the cloud providers that can be selected under the default project.", + Optional: true, + }, + "cloud_providers": schema.ListAttribute{ + MarkdownDescription: "The cloud providers.", + Computed: true, + ElementType: types.StringType, + }, + }, + } +} + +func (d *dedicatedCloudProvidersDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data dedicatedCloudProvidersDataSourceData + diags := req.Config.Get(ctx, &data) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, "read regions data source") + cloudProviders, err := d.provider.DedicatedClient.ListCloudProviders(ctx, data.ProjectId.ValueString()) + if err != nil { + resp.Diagnostics.AddError("Read Error", fmt.Sprintf("Unable to call ListCloudProviders, got error: %s", err)) + return + } + var items []types.String + for _, c := range cloudProviders { + items = append(items, types.StringValue(string(c))) + } + data.CloudProviders = items + + diags = resp.State.Set(ctx, &data) + resp.Diagnostics.Append(diags...) +} diff --git a/internal/provider/dedicated_cloud_providers_data_source_test.go b/internal/provider/dedicated_cloud_providers_data_source_test.go new file mode 100644 index 0000000..4999f5d --- /dev/null +++ b/internal/provider/dedicated_cloud_providers_data_source_test.go @@ -0,0 +1,43 @@ +package provider + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" +) + +func TestAccDedicatedCloudProvidersDataSource(t *testing.T) { + t.Parallel() + + testDedicatedCloudProvidersDataSource(t) +} + +func testDedicatedCloudProvidersDataSource(t *testing.T) { + dedicatedCloudProvidersDataSourceName := "data.tidbcloud_dedicated_cloud_providers.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + + Steps: []resource.TestStep{ + { + Config: testDedicatedCloudProvidersConfig, + Check: resource.ComposeTestCheckFunc( + func(s *terraform.State) error { + _, ok := s.RootModule().Resources[dedicatedCloudProvidersDataSourceName] + if !ok { + return fmt.Errorf("Not found: %s", dedicatedCloudProvidersDataSourceName) + } + return nil + }, + ), + }, + }, + }) +} + +const testDedicatedCloudProvidersConfig = ` +data "tidbcloud_dedicated_cloud_providers" "test" {} +` diff --git a/internal/provider/dedicated_region_data_source.go b/internal/provider/dedicated_region_data_source.go new file mode 100644 index 0000000..11201b4 --- /dev/null +++ b/internal/provider/dedicated_region_data_source.go @@ -0,0 +1,84 @@ +package provider + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +type dedicatedRegion struct { + RegionId types.String `tfsdk:"region_id"` + CloudProvider types.String `tfsdk:"cloud_provider"` + DisplayName types.String `tfsdk:"display_name"` +} + +var _ datasource.DataSource = &dedicatedRegionDataSource{} + +type dedicatedRegionDataSource struct { + provider *tidbcloudProvider +} + +func NewDedicatedRegionDataSource() datasource.DataSource { + return &dedicatedRegionDataSource{} +} + +func (d *dedicatedRegionDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_dedicated_region" +} + +func (d *dedicatedRegionDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + var ok bool + if d.provider, ok = req.ProviderData.(*tidbcloudProvider); !ok { + resp.Diagnostics.AddError("Internal provider error", + fmt.Sprintf("Error in Configure: expected %T but got %T", tidbcloudProvider{}, req.ProviderData)) + } +} + +func (d *dedicatedRegionDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: "dedicated region data source", + Attributes: map[string]schema.Attribute{ + "region_id": schema.StringAttribute{ + MarkdownDescription: "The ID of the region.", + Required: true, + }, + "cloud_provider": schema.StringAttribute{ + MarkdownDescription: "The cloud provider of the region.", + Computed: true, + }, + "display_name": schema.StringAttribute{ + MarkdownDescription: "The display name of the region.", + Computed: true, + }, + }, + } +} + +func (d *dedicatedRegionDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data dedicatedRegion + diags := req.Config.Get(ctx, &data) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, "read region data source") + region, err := d.provider.DedicatedClient.GetRegion(ctx, data.RegionId.ValueString()) + if err != nil { + resp.Diagnostics.AddError("Read Error", fmt.Sprintf("Unable to call GetRegion, got error: %s", err)) + return + } + + data.CloudProvider = types.StringValue(string(*region.CloudProvider)) + data.DisplayName = types.StringValue(string(*region.DisplayName)) + + diags = resp.State.Set(ctx, &data) + resp.Diagnostics.Append(diags...) +} diff --git a/internal/provider/dedicated_region_data_source_test.go b/internal/provider/dedicated_region_data_source_test.go new file mode 100644 index 0000000..6c6924e --- /dev/null +++ b/internal/provider/dedicated_region_data_source_test.go @@ -0,0 +1,39 @@ +package provider + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccDedicatedRegionDataSource(t *testing.T) { + t.Parallel() + + testDedicatedRegionDataSource(t) +} + +func testDedicatedRegionDataSource(t *testing.T) { + dedicatedRegionDataSourceName := "data.tidbcloud_dedicated_region.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + + Steps: []resource.TestStep{ + { + Config: testDedicatedRegionConfig, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(dedicatedRegionDataSourceName, "cloud_provider", "aws"), + resource.TestCheckResourceAttrSet(dedicatedRegionDataSourceName, "display_name"), + resource.TestCheckResourceAttrSet(dedicatedRegionDataSourceName, "region_id"), + ), + }, + }, + }) +} + +const testDedicatedRegionConfig = ` +data "tidbcloud_dedicated_region" "test" { + region_id = "aws-us-east-1" +} +` diff --git a/internal/provider/dedicated_regions_data_source.go b/internal/provider/dedicated_regions_data_source.go new file mode 100644 index 0000000..93cfe3d --- /dev/null +++ b/internal/provider/dedicated_regions_data_source.go @@ -0,0 +1,106 @@ +package provider + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +type dedicatedRegionsDataSourceData struct { + CloudProvider types.String `tfsdk:"cloud_provider"` + ProjectId types.String `tfsdk:"project_id"` + Regions []dedicatedRegion `tfsdk:"regions"` +} + +var _ datasource.DataSource = &dedicatedRegionsDataSource{} + +type dedicatedRegionsDataSource struct { + provider *tidbcloudProvider +} + +func NewDedicatedRegionsDataSource() datasource.DataSource { + return &dedicatedRegionsDataSource{} +} + +func (d *dedicatedRegionsDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_dedicated_regions" +} + +func (d *dedicatedRegionsDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + var ok bool + if d.provider, ok = req.ProviderData.(*tidbcloudProvider); !ok { + resp.Diagnostics.AddError("Internal provider error", + fmt.Sprintf("Error in Configure: expected %T but got %T", tidbcloudProvider{}, req.ProviderData)) + } +} + +func (d *dedicatedRegionsDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: "dedicated regions data source", + Attributes: map[string]schema.Attribute{ + "cloud_provider": schema.StringAttribute{ + MarkdownDescription: "The cloud provider of the regions. If not set, it will return the regions that can be selected from all cloud providers.", + Optional: true, + }, + "project_id": schema.StringAttribute{ + MarkdownDescription: "The ID of the project. If not set, it will return the regions that can be selected under the default project.", + Optional: true, + }, + "regions": schema.ListNestedAttribute{ + MarkdownDescription: "The regions.", + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "region_id": schema.StringAttribute{ + MarkdownDescription: "The ID of the region.", + Computed: true, + }, + "cloud_provider": schema.StringAttribute{ + MarkdownDescription: "The cloud provider of the region.", + Computed: true, + }, + "display_name": schema.StringAttribute{ + MarkdownDescription: "The display name of the region.", + Computed: true, + }, + }, + }, + }, + }, + } +} + +func (d *dedicatedRegionsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data dedicatedRegionsDataSourceData + diags := req.Config.Get(ctx, &data) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + tflog.Trace(ctx, "read regions data source") + regions, err := d.provider.DedicatedClient.ListRegions(ctx, data.CloudProvider.ValueString(), data.ProjectId.ValueString()) + if err != nil { + resp.Diagnostics.AddError("Read Error", fmt.Sprintf("Unable to call ListRegions, got error: %s", err)) + return + } + var items []dedicatedRegion + for _, r := range regions { + items = append(items, dedicatedRegion{ + RegionId: types.StringValue(*r.RegionId), + CloudProvider: types.StringValue(string(*r.CloudProvider)), + DisplayName: types.StringValue(*r.DisplayName), + }) + } + data.Regions = items + + diags = resp.State.Set(ctx, &data) + resp.Diagnostics.Append(diags...) +} diff --git a/internal/provider/dedicated_regions_data_source_test.go b/internal/provider/dedicated_regions_data_source_test.go new file mode 100644 index 0000000..761a28b --- /dev/null +++ b/internal/provider/dedicated_regions_data_source_test.go @@ -0,0 +1,43 @@ +package provider + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" +) + +func TestAccDedicatedRegionsDataSource(t *testing.T) { + t.Parallel() + + testDedicatedRegionsDataSource(t) +} + +func testDedicatedRegionsDataSource(t *testing.T) { + dedicatedRegionsDataSourceName := "data.tidbcloud_dedicated_regions.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + + Steps: []resource.TestStep{ + { + Config: testDedicatedRegionsConfig, + Check: resource.ComposeTestCheckFunc( + func(s *terraform.State) error { + _, ok := s.RootModule().Resources[dedicatedRegionsDataSourceName] + if !ok { + return fmt.Errorf("Not found: %s", dedicatedRegionsDataSourceName) + } + return nil + }, + ), + }, + }, + }) +} + +const testDedicatedRegionsConfig = ` +data "tidbcloud_dedicated_regions" "test" {} +` diff --git a/internal/provider/import_resource.go b/internal/provider/import_resource.go index 8e3bdc7..b19bfbf 100644 --- a/internal/provider/import_resource.go +++ b/internal/provider/import_resource.go @@ -4,6 +4,9 @@ import ( "context" "errors" "fmt" + "os" + "strconv" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -16,8 +19,6 @@ import ( "github.com/hashicorp/terraform-plugin-log/tflog" importService "github.com/tidbcloud/terraform-provider-tidbcloud/pkg/import/client/import_service" importModel "github.com/tidbcloud/terraform-provider-tidbcloud/pkg/import/models" - "os" - "strconv" ) // Ensure provider defined types fully satisfy framework interfaces. @@ -545,7 +546,7 @@ func refreshImportResource(ctx context.Context, data *ImportResourceModel, paylo } func (r *ImportResource) Update(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Unsupported", fmt.Sprintf("import resource can't be updated")) + resp.Diagnostics.AddError("Unsupported", "import resource can't be updated") } func (r *ImportResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { diff --git a/internal/provider/import_resource_test.go b/internal/provider/import_resource_test.go deleted file mode 100644 index 1ad77f8..0000000 --- a/internal/provider/import_resource_test.go +++ /dev/null @@ -1,312 +0,0 @@ -package provider - -import ( - "fmt" - "github.com/golang/mock/gomock" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - mockClient "github.com/tidbcloud/terraform-provider-tidbcloud/mock" - importService "github.com/tidbcloud/terraform-provider-tidbcloud/pkg/import/client/import_service" - importModel "github.com/tidbcloud/terraform-provider-tidbcloud/pkg/import/models" - "github.com/tidbcloud/terraform-provider-tidbcloud/tidbcloud" - "os" - "testing" -) - -// Please Fill pass the projectID and clusterID and fill in the file_name to run the acc test -func TestACCImportResourceLOCAL(t *testing.T) { - config := fmt.Sprintf(` - resource "tidbcloud_import" "local" { - project_id = "%s" - cluster_id = "%s" - type = "LOCAL" - data_format = "CSV" - target_table = { - schema = "test" - table = "import_test_%s" - } - file_name = "fake_file" - } - `, os.Getenv(TiDBCloudProjectID), os.Getenv(TiDBCloudClusterID), GenerateRandomString(3)) - testImportResourceLocal(t, config, false) -} - -// Please Fill pass the projectID and clusterID and fill in the aws_role_arn and source url to run the acc test -func TestACCImportResourceS3(t *testing.T) { - config := fmt.Sprintf(` - resource "tidbcloud_import" "s3" { - project_id = "%s" - cluster_id = "%s" - type = "S3" - data_format = "CSV" - aws_role_arn = "fake_arn" - source_url = "fake_url" - } - `, os.Getenv(TiDBCloudProjectID), os.Getenv(TiDBCloudClusterID)) - testImportResourceS3(t, config, false) -} - -func TestUTImportResourceLOCAL(t *testing.T) { - if os.Getenv(TiDBCloudPublicKey) == "" { - os.Setenv(TiDBCloudPublicKey, "fake") - } - if os.Getenv(TiDBCloudPrivateKey) == "" { - os.Setenv(TiDBCloudPrivateKey, "fake") - } - if os.Getenv(TiDBCloudProjectID) == "" { - os.Setenv(TiDBCloudProjectID, "fake") - } - - ctrl := gomock.NewController(t) - s := mockClient.NewMockTiDBCloudClient(ctrl) - - defer HookGlobal(&NewClient, func(publicKey string, privateKey string, apiUrl string, userAgent string) (tidbcloud.TiDBCloudClient, error) { - return s, nil - })() - - clusterId := "cluster-id" - importId := "import-id" - fileName := "fake.csv" - file, _ := os.Create(fileName) - defer file.Close() - - createImportOK := &importService.CreateImportOK{ - Payload: &importModel.OpenapiCreateImportResp{ - ID: &importId, - }, - } - - getImportResp := importModel.OpenapiGetImportResp{} - getImportResp.UnmarshalBinary([]byte(fmt.Sprintf(`{ - "cluster_id": "%s", - "total_size": "20", - "total_files": 0, - "source_url": "", - "completed_tables": 1, - "pending_tables": 0, - "created_at": "2023-01-31T05:27:50Z", - "status": "COMPLETED", - "completed_percent": 100, - "current_tables": [], - "data_format": "CSV", - "message": "", - "elapsed_time_seconds": 35, - "id": "%s", - "processed_source_data_size": "20", - "total_tables_count": 1, - "post_import_completed_percent": 100, - "all_completed_tables": [ - { - "table_name": "test.r", - "result": "SUCCESS", - "message": "" - } - ], - "creation_details": { - "project_id": "%s", - "cluster_id": "%s", - "type": "LOCAL", - "data_format": "CSV", - "csv_format": { - "separator": ",", - "delimiter": "\"", - "header": true, - "not_null": false, - "null": "", - "backslash_escape": true, - "trim_last_separator": false - }, - "source_url": "", - "aws_role_arn": "", - "file_name": "fake.csv", - "target_table": { - "database": "test", - "table": "r" - } - }}`, clusterId, importId, os.Getenv(TiDBCloudProjectID), clusterId))) - - getImportOK := &importService.GetImportOK{ - Payload: &getImportResp, - } - - cancelImportOK := &importService.CancelImportOK{} - - generateUploadURL := &importService.GenerateUploadURLOK{ - Payload: &importModel.OpenapiGenerateUploadURLResq{ - NewFileName: Ptr("fake_new_file_name"), - UploadURL: Ptr("fake_upload_url"), - }, - } - - s.EXPECT().CreateImport(gomock.Any()). - Return(createImportOK, nil) - s.EXPECT().GetImport(gomock.Any()). - Return(getImportOK, nil).MinTimes(1).MaxTimes(3) - s.EXPECT().CancelImport(gomock.Any()). - Return(cancelImportOK, nil) - s.EXPECT().GenerateUploadURL(gomock.Any()). - Return(generateUploadURL, nil) - s.EXPECT().PreSignedUrlUpload(gomock.Any(), gomock.Any(), gomock.Any()). - Return(nil) - - config := fmt.Sprintf(` - resource "tidbcloud_import" "local" { - project_id = "%s" - cluster_id = "cluster-id" - type = "LOCAL" - data_format = "CSV" - target_table = { - database = "test" - table = "r" - } - file_name = "fake.csv" - } - `, os.Getenv(TiDBCloudProjectID)) - testImportResourceLocal(t, config, true) -} - -func testImportResourceLocal(t *testing.T, config string, useMock bool) { - resource.Test(t, resource.TestCase{ - IsUnitTest: useMock, - PreCheck: func() { testAccPreCheck(t) }, - ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, - Steps: []resource.TestStep{ - // Create and Read import resource - { - Config: config, - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttrSet("tidbcloud_import.local", "id"), - resource.TestCheckResourceAttr("tidbcloud_import.local", "type", "LOCAL"), - resource.TestCheckResourceAttrSet("tidbcloud_import.local", "file_name"), - resource.TestCheckResourceAttrSet("tidbcloud_import.local", "new_file_name"), - ), - }, - // Delete testing automatically occurs in TestCase - }, - }) -} - -func TestUTImportResourceS3(t *testing.T) { - if os.Getenv(TiDBCloudPublicKey) == "" { - os.Setenv(TiDBCloudPublicKey, "fake") - } - if os.Getenv(TiDBCloudPrivateKey) == "" { - os.Setenv(TiDBCloudPrivateKey, "fake") - } - if os.Getenv(TiDBCloudProjectID) == "" { - os.Setenv(TiDBCloudProjectID, "fake") - } - - ctrl := gomock.NewController(t) - s := mockClient.NewMockTiDBCloudClient(ctrl) - - defer HookGlobal(&NewClient, func(publicKey string, privateKey string, apiUrl string, userAgent string) (tidbcloud.TiDBCloudClient, error) { - return s, nil - })() - - clusterId := "cluster-id" - importId := "import-id" - - createImportOK := &importService.CreateImportOK{ - Payload: &importModel.OpenapiCreateImportResp{ - ID: &importId, - }, - } - - getImportResp := importModel.OpenapiGetImportResp{} - getImportResp.UnmarshalBinary([]byte(fmt.Sprintf(`{ - "cluster_id": "%s", - "total_size": "20", - "total_files": 0, - "source_url": "fake_source_url", - "completed_tables": 1, - "pending_tables": 0, - "created_at": "2023-01-31T05:27:50Z", - "status": "COMPLETED", - "completed_percent": 100, - "current_tables": [], - "data_format": "CSV", - "message": "", - "elapsed_time_seconds": 35, - "id": "%s", - "processed_source_data_size": "20", - "total_tables_count": 1, - "post_import_completed_percent": 100, - "all_completed_tables": [], - "creation_details": { - "project_id": "%s", - "cluster_id": "%s", - "type": "S3", - "data_format": "CSV", - "csv_format": { - "separator": ",", - "delimiter": "\"", - "header": true, - "not_null": false, - "null": "", - "backslash_escape": true, - "trim_last_separator": false - }, - "source_url": "fake_url", - "aws_role_arn": "fake_aws_role_arn", - "file_name": "", - "target_table": null - }}`, clusterId, importId, os.Getenv(TiDBCloudProjectID), clusterId))) - - getImportOK := &importService.GetImportOK{ - Payload: &getImportResp, - } - - cancelImportOK := &importService.CancelImportOK{} - - generateUploadURL := &importService.GenerateUploadURLOK{ - Payload: &importModel.OpenapiGenerateUploadURLResq{ - NewFileName: Ptr("fake_new_file_name"), - UploadURL: Ptr("fake_upload_url"), - }, - } - - s.EXPECT().CreateImport(gomock.Any()). - Return(createImportOK, nil).AnyTimes() - s.EXPECT().GetImport(gomock.Any()). - Return(getImportOK, nil).AnyTimes() - s.EXPECT().CancelImport(gomock.Any()). - Return(cancelImportOK, nil).AnyTimes() - s.EXPECT().GenerateUploadURL(gomock.Any()). - Return(generateUploadURL, nil).AnyTimes() - s.EXPECT().PreSignedUrlUpload(gomock.Any(), gomock.Any(), gomock.Any()). - Return(nil).AnyTimes() - - config := fmt.Sprintf(` - resource "tidbcloud_import" "s3" { - project_id = "%s" - cluster_id = "cluster-id" - type = "S3" - data_format = "Parquet" - aws_role_arn = "fake_arn" - source_url = "fake_url" - } - `, os.Getenv(TiDBCloudProjectID)) - - testImportResourceS3(t, config, true) -} - -func testImportResourceS3(t *testing.T, config string, useMock bool) { - resource.Test(t, resource.TestCase{ - IsUnitTest: useMock, - PreCheck: func() { testAccPreCheck(t) }, - ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, - Steps: []resource.TestStep{ - // Create and Read import resource - { - Config: config, - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttrSet("tidbcloud_import.s3", "id"), - resource.TestCheckResourceAttr("tidbcloud_import.s3", "type", "S3"), - resource.TestCheckResourceAttrSet("tidbcloud_import.s3", "source_url"), - resource.TestCheckResourceAttrSet("tidbcloud_import.s3", "aws_role_arn"), - ), - }, - // Delete testing automatically occurs in TestCase - }, - }) -} diff --git a/internal/provider/projects_data_source.go b/internal/provider/projects_data_source.go index 4c843d3..19d44bf 100644 --- a/internal/provider/projects_data_source.go +++ b/internal/provider/projects_data_source.go @@ -3,13 +3,14 @@ package provider import ( "context" "fmt" + "math/rand" + "strconv" + projectApi "github.com/c4pt0r/go-tidbcloud-sdk-v1/client/project" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" - "math/rand" - "strconv" ) type projectsDataSourceData struct { diff --git a/internal/provider/provider.go b/internal/provider/provider.go index b756bee..2383b74 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -19,6 +19,8 @@ var _ provider.Provider = &tidbcloudProvider{} // NewClient overrides the NewClientDelegate method for testing. var NewClient = tidbcloud.NewClientDelegate +var NewDedicatedClient = tidbcloud.NewDedicatedClientDelegate + // provider satisfies the tfsdk.Provider interface and usually is included // with all Resource and DataSource implementations. type tidbcloudProvider struct { @@ -27,6 +29,8 @@ type tidbcloudProvider struct { // implementations can then make calls using this client. client tidbcloud.TiDBCloudClient + DedicatedClient tidbcloud.TiDBCloudDedicatedClient + // configured is set to true at the end of the Configure method. // This can be used in Resource and DataSource implementations to verify // that the provider was previously configured. @@ -96,21 +100,31 @@ func (p *tidbcloudProvider) Configure(ctx context.Context, req provider.Configur // Create a new tidb client and set it to the provider client var host = tidbcloud.DefaultApiUrl - if os.Getenv(TiDBCloudHOST) != "" { - host = os.Getenv(TiDBCloudHOST) + if os.Getenv(TiDBCloudHost) != "" { + host = os.Getenv(TiDBCloudHost) } c, err := NewClient(publicKey, privateKey, host, fmt.Sprintf("%s/%s", UserAgent, p.version)) if err != nil { resp.Diagnostics.AddError( "Unable to create client", - "Unable to create tidb client:\n\n"+err.Error(), + "Unable to create TiDB client:\n\n"+err.Error(), ) return } + // Create a new dedicated client and set it to the provider dedicated client + dc, err := NewDedicatedClient(publicKey, privateKey, os.Getenv(TiDBCloudDedicatedEndpoint), fmt.Sprintf("%s/%s", UserAgent, p.version)) + if err != nil { + resp.Diagnostics.AddError( + "Unable to create client", + "Unable to create TiDB Cloud Dedicated client:\n\n"+err.Error(), + ) + return + } // sync p.sync = data.Sync.ValueBool() p.client = c + p.DedicatedClient = dc p.configured = true resp.ResourceData = p resp.DataSourceData = p @@ -132,6 +146,10 @@ func (p *tidbcloudProvider) DataSources(ctx context.Context) []func() datasource NewBackupsDataSource, NewRestoresDataSource, NewClustersDataSource, + + NewDedicatedRegionsDataSource, + NewDedicatedRegionDataSource, + NewDedicatedCloudProvidersDataSource, } } diff --git a/internal/provider/restore_resource.go b/internal/provider/restore_resource.go index bae98b7..ff66aea 100644 --- a/internal/provider/restore_resource.go +++ b/internal/provider/restore_resource.go @@ -371,9 +371,9 @@ func refreshRestoreResourceData(resp *restoreApi.GetRestoreTaskOKBody, data *res } func (r restoreResource) Update(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Unsupported", fmt.Sprintf("restore can't be updated")) + resp.Diagnostics.AddError("Unsupported", "restore can't be updated") } func (r restoreResource) Delete(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddWarning("Unsupported", fmt.Sprintf("restore can't be deleted")) + resp.Diagnostics.AddWarning("Unsupported", "restore can't be deleted") } diff --git a/internal/provider/restores_data_source.go b/internal/provider/restores_data_source.go index bcb3758..9302a2b 100644 --- a/internal/provider/restores_data_source.go +++ b/internal/provider/restores_data_source.go @@ -3,13 +3,14 @@ package provider import ( "context" "fmt" + "math/rand" + "strconv" + restoreApi "github.com/c4pt0r/go-tidbcloud-sdk-v1/client/restore" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" - "math/rand" - "strconv" ) type restoresDataSourceData struct { diff --git a/internal/provider/util.go b/internal/provider/util.go index bb9c483..846341c 100644 --- a/internal/provider/util.go +++ b/internal/provider/util.go @@ -3,17 +3,17 @@ package provider import ( cryptorand "crypto/rand" "math/big" - "math/rand" - "time" ) const ( - TiDBCloudPublicKey string = "TIDBCLOUD_PUBLIC_KEY" - TiDBCloudPrivateKey string = "TIDBCLOUD_PRIVATE_KEY" - TiDBCloudHOST string = "TIDBCLOUD_HOST" - TiDBCloudProjectID string = "TIDBCLOUD_PROJECT_ID" - TiDBCloudClusterID string = "TIDBCLOUD_CLUSTER_ID" - UserAgent string = "terraform-provider-tidbcloud" + TiDBCloudPublicKey string = "TIDBCLOUD_PUBLIC_KEY" + TiDBCloudPrivateKey string = "TIDBCLOUD_PRIVATE_KEY" + TiDBCloudHost string = "TIDBCLOUD_HOST" + TiDBCloudDedicatedEndpoint string = "TIDBCLOUD_DEDICATED_ENDPOINT" + TiDBCloudIAMEndpoint string = "TIDBCLOUD_IAM_ENDPOINT" + TiDBCloudProjectID string = "TIDBCLOUD_PROJECT_ID" + TiDBCloudClusterID string = "TIDBCLOUD_CLUSTER_ID" + UserAgent string = "terraform-provider-tidbcloud" ) // HookGlobal sets `*ptr = val` and returns a closure for restoring `*ptr` to @@ -31,7 +31,6 @@ func Ptr[T any](v T) *T { func GenerateRandomString(n int) string { letters := "abcdefghijklmnopqrstuvwxyz" - rand.Seed(time.Now().UnixNano()) letterRunes := []rune(letters) b := make([]rune, n) for i := range b { diff --git a/mock/build.go b/mock/build.go index 4cd952c..26f713f 100644 --- a/mock/build.go +++ b/mock/build.go @@ -1,2 +1,2 @@ // mockgen -package mock_client -destination ./mock_client.go github.com/tidbcloud/terraform-provider-tidbcloud/tidbcloud TiDBCloudClient -package mock_client +package mock diff --git a/mock/dedicated_api_client.go b/mock/dedicated_api_client.go new file mode 100644 index 0000000..c338f15 --- /dev/null +++ b/mock/dedicated_api_client.go @@ -0,0 +1,119 @@ +// Code generated by mockery v2.50.0. DO NOT EDIT. + +package mock + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + dedicated "github.com/tidbcloud/tidbcloud-cli/pkg/tidbcloud/v1beta1/dedicated" +) + +// TiDBCloudDedicatedClient is an autogenerated mock type for the TiDBCloudDedicatedClient type +type TiDBCloudDedicatedClient struct { + mock.Mock +} + +// GetRegion provides a mock function with given fields: ctx, regionId +func (_m *TiDBCloudDedicatedClient) GetRegion(ctx context.Context, regionId string) (*dedicated.Commonv1beta1Region, error) { + ret := _m.Called(ctx, regionId) + + if len(ret) == 0 { + panic("no return value specified for GetRegion") + } + + var r0 *dedicated.Commonv1beta1Region + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*dedicated.Commonv1beta1Region, error)); ok { + return rf(ctx, regionId) + } + if rf, ok := ret.Get(0).(func(context.Context, string) *dedicated.Commonv1beta1Region); ok { + r0 = rf(ctx, regionId) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*dedicated.Commonv1beta1Region) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, regionId) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ListCloudProviders provides a mock function with given fields: ctx, projectId +func (_m *TiDBCloudDedicatedClient) ListCloudProviders(ctx context.Context, projectId string) ([]dedicated.V1beta1RegionCloudProvider, error) { + ret := _m.Called(ctx, projectId) + + if len(ret) == 0 { + panic("no return value specified for ListCloudProviders") + } + + var r0 []dedicated.V1beta1RegionCloudProvider + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) ([]dedicated.V1beta1RegionCloudProvider, error)); ok { + return rf(ctx, projectId) + } + if rf, ok := ret.Get(0).(func(context.Context, string) []dedicated.V1beta1RegionCloudProvider); ok { + r0 = rf(ctx, projectId) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]dedicated.V1beta1RegionCloudProvider) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, projectId) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ListRegions provides a mock function with given fields: ctx, cloudProvider, projectId +func (_m *TiDBCloudDedicatedClient) ListRegions(ctx context.Context, cloudProvider string, projectId string) ([]dedicated.Commonv1beta1Region, error) { + ret := _m.Called(ctx, cloudProvider, projectId) + + if len(ret) == 0 { + panic("no return value specified for ListRegions") + } + + var r0 []dedicated.Commonv1beta1Region + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) ([]dedicated.Commonv1beta1Region, error)); ok { + return rf(ctx, cloudProvider, projectId) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string) []dedicated.Commonv1beta1Region); ok { + r0 = rf(ctx, cloudProvider, projectId) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]dedicated.Commonv1beta1Region) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = rf(ctx, cloudProvider, projectId) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewTiDBCloudDedicatedClient creates a new instance of TiDBCloudDedicatedClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewTiDBCloudDedicatedClient(t interface { + mock.TestingT + Cleanup(func()) +}) *TiDBCloudDedicatedClient { + mock := &TiDBCloudDedicatedClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mock/mock_client.go b/mock/mock_client.go index 4dfc3cd..1aa5b5c 100644 --- a/mock/mock_client.go +++ b/mock/mock_client.go @@ -2,7 +2,7 @@ // Source: github.com/tidbcloud/terraform-provider-tidbcloud/tidbcloud (interfaces: TiDBCloudClient) // Package mock_client is a generated GoMock package. -package mock_client +package mock import ( os "os" diff --git a/tidbcloud/api_client.go b/tidbcloud/api_client.go index fb967c3..161e07c 100644 --- a/tidbcloud/api_client.go +++ b/tidbcloud/api_client.go @@ -2,13 +2,14 @@ package tidbcloud import ( "fmt" - "github.com/c4pt0r/go-tidbcloud-sdk-v1/client/backup" - "github.com/c4pt0r/go-tidbcloud-sdk-v1/client/restore" - importService "github.com/tidbcloud/terraform-provider-tidbcloud/pkg/import/client/import_service" "net/http" "net/url" "os" + "github.com/c4pt0r/go-tidbcloud-sdk-v1/client/backup" + "github.com/c4pt0r/go-tidbcloud-sdk-v1/client/restore" + importService "github.com/tidbcloud/terraform-provider-tidbcloud/pkg/import/client/import_service" + apiClient "github.com/c4pt0r/go-tidbcloud-sdk-v1/client" "github.com/c4pt0r/go-tidbcloud-sdk-v1/client/cluster" "github.com/c4pt0r/go-tidbcloud-sdk-v1/client/project" diff --git a/tidbcloud/dedicated_api_client.go b/tidbcloud/dedicated_api_client.go new file mode 100644 index 0000000..6903cc7 --- /dev/null +++ b/tidbcloud/dedicated_api_client.go @@ -0,0 +1,117 @@ +package tidbcloud + +import ( + "context" + "fmt" + "io" + "net/http" + "net/url" + + "github.com/icholy/digest" + "github.com/tidbcloud/tidbcloud-cli/pkg/tidbcloud/v1beta1/dedicated" +) + +const ( + DefaultDedicatedEndpoint = "https://dedicated.tidbapi.com" +) + +type TiDBCloudDedicatedClient interface { + ListRegions(ctx context.Context, cloudProvider string, projectId string) ([]dedicated.Commonv1beta1Region, error) + GetRegion(ctx context.Context, regionId string) (*dedicated.Commonv1beta1Region, error) + ListCloudProviders(ctx context.Context, projectId string) ([]dedicated.V1beta1RegionCloudProvider, error) +} + +func NewDedicatedApiClient(rt http.RoundTripper, dedicatedEndpoint string, userAgent string) (*dedicated.APIClient, error) { + httpClient := &http.Client{ + Transport: rt, + } + + // v1beta1 api (dedicated) + if dedicatedEndpoint == "" { + dedicatedEndpoint = DefaultDedicatedEndpoint + } + dedicatedURL, err := url.ParseRequestURI(dedicatedEndpoint) + if err != nil { + return nil, err + } + + dedicatedCfg := dedicated.NewConfiguration() + dedicatedCfg.HTTPClient = httpClient + dedicatedCfg.Host = dedicatedURL.Host + dedicatedCfg.UserAgent = userAgent + return dedicated.NewAPIClient(dedicatedCfg), nil +} + +type DedicatedClientDelegate struct { + dc *dedicated.APIClient +} + +func NewDedicatedClientDelegate(publicKey string, privateKey string, dedicatedEndpoint string, userAgent string) (*DedicatedClientDelegate, error) { + transport := NewTransportWithAgent(&digest.Transport{ + Username: publicKey, + Password: privateKey, + }, userAgent) + + dc, err := NewDedicatedApiClient(transport, dedicatedEndpoint, userAgent) + if err != nil { + return nil, err + } + return &DedicatedClientDelegate{ + dc: dc, + }, nil +} + +func (d *DedicatedClientDelegate) ListRegions(ctx context.Context, cloudProvider string, projectId string) ([]dedicated.Commonv1beta1Region, error) { + req := d.dc.RegionServiceAPI.RegionServiceListRegions(ctx).PageSize(100) + if cloudProvider != "" { + req = req.CloudProvider(cloudProvider) + } + if projectId != "" { + req = req.ProjectId(projectId) + } + + resp, h, err := req.Execute() + return resp.Regions, parseError(err, h) +} + +func (d *DedicatedClientDelegate) GetRegion(ctx context.Context, regionId string) (*dedicated.Commonv1beta1Region, error) { + resp, h, err := d.dc.RegionServiceAPI.RegionServiceGetRegion(ctx, regionId).Execute() + return resp, parseError(err, h) +} + +func (d *DedicatedClientDelegate) ListCloudProviders(ctx context.Context, projectId string) ([]dedicated.V1beta1RegionCloudProvider, error) { + req := d.dc.RegionServiceAPI.RegionServiceShowCloudProviders(ctx) + if projectId != "" { + req = req.ProjectId(projectId) + } + + resp, h, err := req.Execute() + return resp.CloudProviders, parseError(err, h) +} + +func parseError(err error, resp *http.Response) error { + defer func() { + if resp != nil { + resp.Body.Close() + } + }() + if err == nil { + return nil + } + if resp == nil { + return err + } + body, err1 := io.ReadAll(resp.Body) + if err1 != nil { + return err + } + path := "" + if resp.Request != nil { + path = fmt.Sprintf("[%s %s]", resp.Request.Method, resp.Request.URL.Path) + } + traceId := "" + if resp.Header.Get("X-Debug-Trace-Id") != "" { + traceId = resp.Header.Get("X-Debug-Trace-Id") + } + return fmt.Errorf("%s[%s][%s] %s", path, err.Error(), traceId, body) +}