diff --git a/README.md b/README.md
index 41d31df..816fbf4 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ using Terraform Bytebase Provider to prepare those instances ready for applicati
- [Go](https://golang.org/doc/install) (1.19 or later)
- [Terraform](https://developer.hashicorp.com/terraform/downloads?product_intent=terraform) (1.3.5 or later)
-- [Bytebase](https://github.com/bytebase/bytebase) (3.5.0 or later)
+- [Bytebase](https://github.com/bytebase/bytebase) (3.6.0 or later)
> If you have problems running `terraform` in MacOS with Apple Silicon, you can following https://stackoverflow.com/questions/66281882/how-can-i-get-terraform-init-to-run-on-my-apple-silicon-macbook-pro-for-the-go and use the `tfenv`.
diff --git a/VERSION b/VERSION
index 1c2de38..321816a 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.23
\ No newline at end of file
+1.0.24
\ No newline at end of file
diff --git a/api/client.go b/api/client.go
index 17048eb..63bebcc 100644
--- a/api/client.go
+++ b/api/client.go
@@ -56,20 +56,6 @@ type Client interface {
// GetCaller returns the API caller.
GetCaller() *v1pb.User
- // Environment
- // CreateEnvironment creates the environment.
- CreateEnvironment(ctx context.Context, environmentID string, create *v1pb.Environment) (*v1pb.Environment, error)
- // GetEnvironment gets the environment by full name.
- GetEnvironment(ctx context.Context, environmentName string) (*v1pb.Environment, error)
- // ListEnvironment finds all environments.
- ListEnvironment(ctx context.Context, showDeleted bool) (*v1pb.ListEnvironmentsResponse, error)
- // UpdateEnvironment updates the environment.
- UpdateEnvironment(ctx context.Context, patch *v1pb.Environment, updateMask []string) (*v1pb.Environment, error)
- // DeleteEnvironment deletes the environment.
- DeleteEnvironment(ctx context.Context, environmentName string) error
- // UndeleteEnvironment undeletes the environment.
- UndeleteEnvironment(ctx context.Context, environmentName string) (*v1pb.Environment, error)
-
// Instance
// ListInstance will return instances.
ListInstance(ctx context.Context, filter *InstanceFilter) ([]*v1pb.Instance, error)
diff --git a/api/setting.go b/api/setting.go
index 9cc1c36..53cc959 100644
--- a/api/setting.go
+++ b/api/setting.go
@@ -12,6 +12,8 @@ const (
SettingDataClassification SettingName = "bb.workspace.data-classification"
// SettingSemanticTypes is the setting name for semantic types.
SettingSemanticTypes SettingName = "bb.workspace.semantic-types"
+ // SettingEnvironment is the setting name for environments.
+ SettingEnvironment SettingName = "bb.workspace.environment"
)
// RiskLevel is the approval risk level.
@@ -41,13 +43,3 @@ func (r RiskLevel) Int() int {
return 0
}
}
-
-// ApprovalNodeType is the type for approval node.
-type ApprovalNodeType string
-
-const (
- // ApprovalNodeTypeGroup means the approval node is a group.
- ApprovalNodeTypeGroup ApprovalNodeType = "GROUP"
- // ApprovalNodeTypeRole means the approval node is a role, the value should be role fullname.
- ApprovalNodeTypeRole ApprovalNodeType = "ROLE"
-)
diff --git a/client/environment.go b/client/environment.go
deleted file mode 100644
index eb9bbf3..0000000
--- a/client/environment.go
+++ /dev/null
@@ -1,106 +0,0 @@
-package client
-
-import (
- "context"
- "fmt"
- "net/http"
- "strings"
-
- v1pb "github.com/bytebase/bytebase/proto/generated-go/v1"
- "google.golang.org/protobuf/encoding/protojson"
-)
-
-// CreateEnvironment creates the environment.
-func (c *client) CreateEnvironment(ctx context.Context, environmentID string, create *v1pb.Environment) (*v1pb.Environment, error) {
- payload, err := protojson.Marshal(create)
- if err != nil {
- return nil, err
- }
-
- req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s/%s/environments?environmentId=%s", c.url, c.version, environmentID), strings.NewReader(string(payload)))
- if err != nil {
- return nil, err
- }
-
- body, err := c.doRequest(req)
- if err != nil {
- return nil, err
- }
-
- var env v1pb.Environment
- if err := ProtojsonUnmarshaler.Unmarshal(body, &env); err != nil {
- return nil, err
- }
-
- return &env, nil
-}
-
-// GetEnvironment gets the environment by full name.
-func (c *client) GetEnvironment(ctx context.Context, environmentName string) (*v1pb.Environment, error) {
- body, err := c.getResource(ctx, environmentName)
- if err != nil {
- return nil, err
- }
-
- var env v1pb.Environment
- if err := ProtojsonUnmarshaler.Unmarshal(body, &env); err != nil {
- return nil, err
- }
-
- return &env, nil
-}
-
-// ListEnvironment finds all environments.
-func (c *client) ListEnvironment(ctx context.Context, showDeleted bool) (*v1pb.ListEnvironmentsResponse, error) {
- req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/%s/environments?showDeleted=%v", c.url, c.version, showDeleted), nil)
- if err != nil {
- return nil, err
- }
-
- body, err := c.doRequest(req)
- if err != nil {
- return nil, err
- }
-
- var res v1pb.ListEnvironmentsResponse
- if err := ProtojsonUnmarshaler.Unmarshal(body, &res); err != nil {
- return nil, err
- }
-
- return &res, nil
-}
-
-// UpdateEnvironment updates the environment.
-func (c *client) UpdateEnvironment(ctx context.Context, patch *v1pb.Environment, updateMasks []string) (*v1pb.Environment, error) {
- body, err := c.updateResource(ctx, patch.Name, patch, updateMasks, false /* allow missing = false*/)
- if err != nil {
- return nil, err
- }
-
- var env v1pb.Environment
- if err := ProtojsonUnmarshaler.Unmarshal(body, &env); err != nil {
- return nil, err
- }
-
- return &env, nil
-}
-
-// DeleteEnvironment deletes the environment.
-func (c *client) DeleteEnvironment(ctx context.Context, environmentName string) error {
- return c.deleteResource(ctx, environmentName)
-}
-
-// UndeleteEnvironment undeletes the environment.
-func (c *client) UndeleteEnvironment(ctx context.Context, environmentName string) (*v1pb.Environment, error) {
- body, err := c.undeleteResource(ctx, environmentName)
- if err != nil {
- return nil, err
- }
-
- var res v1pb.Environment
- if err := ProtojsonUnmarshaler.Unmarshal(body, &res); err != nil {
- return nil, err
- }
-
- return &res, nil
-}
diff --git a/docs/data-sources/environment.md b/docs/data-sources/environment.md
deleted file mode 100644
index e4e5a64..0000000
--- a/docs/data-sources/environment.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-# generated by https://github.com/hashicorp/terraform-plugin-docs
-page_title: "bytebase_environment Data Source - terraform-provider-bytebase"
-subcategory: ""
-description: |-
- The environment data source.
----
-
-# bytebase_environment (Data Source)
-
-The environment data source.
-
-
-
-
-## Schema
-
-### Required
-
-- `resource_id` (String) The environment unique resource id.
-
-### Read-Only
-
-- `environment_tier_policy` (String) If marked as PROTECTED, developers cannot execute any query on this environment's databases using SQL Editor by default.
-- `id` (String) The ID of this resource.
-- `name` (String) The environment full name in environments/{resource id} format.
-- `order` (Number) The environment sorting order.
-- `title` (String) The environment unique name.
-
-
diff --git a/docs/data-sources/environment_list.md b/docs/data-sources/environment_list.md
deleted file mode 100644
index 4c120c0..0000000
--- a/docs/data-sources/environment_list.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-# generated by https://github.com/hashicorp/terraform-plugin-docs
-page_title: "bytebase_environment_list Data Source - terraform-provider-bytebase"
-subcategory: ""
-description: |-
- The environment data source list.
----
-
-# bytebase_environment_list (Data Source)
-
-The environment data source list.
-
-
-
-
-## Schema
-
-### Optional
-
-- `show_deleted` (Boolean) Including removed instance in the response.
-
-### Read-Only
-
-- `environments` (List of Object) (see [below for nested schema](#nestedatt--environments))
-- `id` (String) The ID of this resource.
-
-
-### Nested Schema for `environments`
-
-Read-Only:
-
-- `environment_tier_policy` (String)
-- `name` (String)
-- `order` (Number)
-- `resource_id` (String)
-- `title` (String)
-
-
diff --git a/docs/data-sources/policy.md b/docs/data-sources/policy.md
index 0f576cd..0ca5b20 100644
--- a/docs/data-sources/policy.md
+++ b/docs/data-sources/policy.md
@@ -42,7 +42,7 @@ Optional:
### Nested Schema for `global_masking_policy.rules`
-Optional:
+Required:
- `condition` (String) The condition expression
- `id` (String) The unique rule id
@@ -60,13 +60,16 @@ Optional:
### Nested Schema for `masking_exception_policy.exceptions`
-Optional:
+Required:
- `action` (String)
-- `column` (String)
- `database` (String) The database full name in instances/{instance resource id}/databases/{database name} format
-- `expire_timestamp` (String) The expiration timestamp in YYYY-MM-DDThh:mm:ss.000Z format
- `member` (String) The member in user:{email} or group:{email} format.
+
+Optional:
+
+- `column` (String)
+- `expire_timestamp` (String) The expiration timestamp in YYYY-MM-DDThh:mm:ss.000Z format
- `schema` (String)
- `table` (String)
diff --git a/docs/data-sources/setting.md b/docs/data-sources/setting.md
index 8d0a8fd..89cc515 100644
--- a/docs/data-sources/setting.md
+++ b/docs/data-sources/setting.md
@@ -28,39 +28,49 @@ The setting data source.
### Read-Only
- `approval_flow` (Block List) Configure risk level and approval flow for different tasks. Require ENTERPRISE subscription. (see [below for nested schema](#nestedblock--approval_flow))
+- `environment_setting` (Block List) The environment (see [below for nested schema](#nestedblock--environment_setting))
- `id` (String) The ID of this resource.
### Nested Schema for `classification`
-Optional:
+Required:
-- `classification_from_config` (Boolean) If true, we will only store the classification in the config. Otherwise we will get the classification from table/column comment, and write back to the schema metadata.
-- `classifications` (Block Set) (see [below for nested schema](#nestedblock--classification--classifications))
+- `classifications` (Block Set, Min: 1) (see [below for nested schema](#nestedblock--classification--classifications))
- `id` (String) The classification unique uuid.
-- `levels` (Block Set) (see [below for nested schema](#nestedblock--classification--levels))
+- `levels` (Block Set, Min: 1) (see [below for nested schema](#nestedblock--classification--levels))
- `title` (String) The classification title. Optional.
+Optional:
+
+- `classification_from_config` (Boolean) If true, we will only store the classification in the config. Otherwise we will get the classification from table/column comment, and write back to the schema metadata.
+
### Nested Schema for `classification.classifications`
+Required:
+
+- `id` (String) The classification unique id, must in {number}-{number} format.
+- `title` (String) The classification title.
+
Optional:
- `description` (String) The classification description.
-- `id` (String) The classification unique id, must in {number}-{number} format.
- `level` (String) The classification level id.
-- `title` (String) The classification title.
### Nested Schema for `classification.levels`
-Optional:
+Required:
-- `description` (String) The classification level description.
- `id` (String) The classification level unique uuid.
- `title` (String) The classification level title.
+Optional:
+
+- `description` (String) The classification level description.
+
@@ -184,7 +194,28 @@ Read-Only:
Read-Only:
-- `node` (String)
-- `type` (String)
+- `role` (String)
+
+
+
+
+
+
+### Nested Schema for `environment_setting`
+
+Read-Only:
+
+- `environment` (List of Object) (see [below for nested schema](#nestedatt--environment_setting--environment))
+
+
+### Nested Schema for `environment_setting.environment`
+
+Read-Only:
+
+- `color` (String)
+- `id` (String)
+- `name` (String)
+- `protected` (Boolean)
+- `title` (String)
diff --git a/docs/resources/environment.md b/docs/resources/environment.md
deleted file mode 100644
index d78ac86..0000000
--- a/docs/resources/environment.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-# generated by https://github.com/hashicorp/terraform-plugin-docs
-page_title: "bytebase_environment Resource - terraform-provider-bytebase"
-subcategory: ""
-description: |-
- The environment resource.
----
-
-# bytebase_environment (Resource)
-
-The environment resource.
-
-
-
-
-## Schema
-
-### Required
-
-- `environment_tier_policy` (String) If marked as PROTECTED, developers cannot execute any query on this environment's databases using SQL Editor by default. Require ENTERPRISE subscription.
-- `order` (Number) The environment sorting order.
-- `resource_id` (String) The environment unique resource id.
-- `title` (String) The environment title.
-
-### Read-Only
-
-- `id` (String) The ID of this resource.
-- `name` (String) The environment full name in environments/{resource id} format.
-
-
diff --git a/docs/resources/policy.md b/docs/resources/policy.md
index dde2225..7e57836 100644
--- a/docs/resources/policy.md
+++ b/docs/resources/policy.md
@@ -42,7 +42,7 @@ Optional:
### Nested Schema for `global_masking_policy.rules`
-Optional:
+Required:
- `condition` (String) The condition expression
- `id` (String) The unique rule id
@@ -60,13 +60,16 @@ Optional:
### Nested Schema for `masking_exception_policy.exceptions`
-Optional:
+Required:
- `action` (String)
-- `column` (String)
- `database` (String) The database full name in instances/{instance resource id}/databases/{database name} format
-- `expire_timestamp` (String) The expiration timestamp in YYYY-MM-DDThh:mm:ss.000Z format
- `member` (String) The member in user:{email} or group:{email} format.
+
+Optional:
+
+- `column` (String)
+- `expire_timestamp` (String) The expiration timestamp in YYYY-MM-DDThh:mm:ss.000Z format
- `schema` (String)
- `table` (String)
diff --git a/docs/resources/setting.md b/docs/resources/setting.md
index b282a8e..c3de427 100644
--- a/docs/resources/setting.md
+++ b/docs/resources/setting.md
@@ -23,6 +23,7 @@ The setting resource.
- `approval_flow` (Block List) Configure risk level and approval flow for different tasks. Require ENTERPRISE subscription. (see [below for nested schema](#nestedblock--approval_flow))
- `classification` (Block List, Max: 1) Classification for data masking. Require ENTERPRISE subscription. (see [below for nested schema](#nestedblock--classification))
+- `environment_setting` (Block List) The environment (see [below for nested schema](#nestedblock--environment_setting))
- `semantic_types` (Block Set) Semantic types for data masking. Require ENTERPRISE subscription. (see [below for nested schema](#nestedblock--semantic_types))
- `workspace_profile` (Block List, Max: 1) (see [below for nested schema](#nestedblock--workspace_profile))
@@ -66,11 +67,7 @@ Optional:
Required:
-- `node` (String)
-
-Optional:
-
-- `type` (String)
+- `role` (String) The role require to review in this step
@@ -88,34 +85,69 @@ Optional:
### Nested Schema for `classification`
-Optional:
+Required:
-- `classification_from_config` (Boolean) If true, we will only store the classification in the config. Otherwise we will get the classification from table/column comment, and write back to the schema metadata.
-- `classifications` (Block Set) (see [below for nested schema](#nestedblock--classification--classifications))
+- `classifications` (Block Set, Min: 1) (see [below for nested schema](#nestedblock--classification--classifications))
- `id` (String) The classification unique uuid.
-- `levels` (Block Set) (see [below for nested schema](#nestedblock--classification--levels))
+- `levels` (Block Set, Min: 1) (see [below for nested schema](#nestedblock--classification--levels))
- `title` (String) The classification title. Optional.
+Optional:
+
+- `classification_from_config` (Boolean) If true, we will only store the classification in the config. Otherwise we will get the classification from table/column comment, and write back to the schema metadata.
+
### Nested Schema for `classification.classifications`
+Required:
+
+- `id` (String) The classification unique id, must in {number}-{number} format.
+- `title` (String) The classification title.
+
Optional:
- `description` (String) The classification description.
-- `id` (String) The classification unique id, must in {number}-{number} format.
- `level` (String) The classification level id.
-- `title` (String) The classification title.
### Nested Schema for `classification.levels`
-Optional:
+Required:
-- `description` (String) The classification level description.
- `id` (String) The classification level unique uuid.
- `title` (String) The classification level title.
+Optional:
+
+- `description` (String) The classification level description.
+
+
+
+
+### Nested Schema for `environment_setting`
+
+Required:
+
+- `environment` (Block List, Min: 1) (see [below for nested schema](#nestedblock--environment_setting--environment))
+
+
+### Nested Schema for `environment_setting.environment`
+
+Required:
+
+- `id` (String) The environment unique id.
+- `title` (String) The environment display name.
+
+Optional:
+
+- `color` (String) The environment color.
+- `protected` (Boolean) The environment is protected or not.
+
+Read-Only:
+
+- `name` (String) The environment readonly name in environments/{id} format.
+
diff --git a/examples/database/main.tf b/examples/database/main.tf
index 2ef4fe9..014bbb0 100644
--- a/examples/database/main.tf
+++ b/examples/database/main.tf
@@ -2,7 +2,7 @@
terraform {
required_providers {
bytebase = {
- version = "1.0.23"
+ version = "1.0.24"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/environments/README.md b/examples/environments/README.md
index 19418bb..2f7de87 100644
--- a/examples/environments/README.md
+++ b/examples/environments/README.md
@@ -7,13 +7,7 @@ You should replace the provider initial variables with your own and exec the [se
## List environment
```terraform
-data "bytebase_environment_list" "all" {}
-```
-
-## Find environment by id
-
-```terraform
-data "bytebase_environment" "find_env" {
- resource_id = ""
+data "bytebase_setting" "environments" {
+ name = "bb.workspace.environment"
}
```
diff --git a/examples/environments/main.tf b/examples/environments/main.tf
index 655382f..b116aad 100644
--- a/examples/environments/main.tf
+++ b/examples/environments/main.tf
@@ -1,8 +1,7 @@
-# Examples for query the environments
terraform {
required_providers {
bytebase = {
- version = "1.0.23"
+ version = "1.0.24"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
@@ -18,31 +17,11 @@ provider "bytebase" {
url = "https://bytebase.example.com"
}
-locals {
- environment_id_test = "test"
- environment_id_prod = "prod"
-}
-
# List all environment
-data "bytebase_environment_list" "all" {}
-
-output "all_environments" {
- value = data.bytebase_environment_list.all
-}
-
-// Find a specific environment by the name
-data "bytebase_environment" "test" {
- resource_id = local.environment_id_test
+data "bytebase_setting" "environments" {
+ name = "bb.workspace.environment"
}
-output "test_environment" {
- value = data.bytebase_environment.test
-}
-
-data "bytebase_environment" "prod" {
- resource_id = local.environment_id_prod
-}
-
-output "prod_environment" {
- value = data.bytebase_environment.prod
+output "all_environments" {
+ value = data.bytebase_setting.environments
}
diff --git a/examples/groups/main.tf b/examples/groups/main.tf
index 306b2ba..606ec19 100644
--- a/examples/groups/main.tf
+++ b/examples/groups/main.tf
@@ -1,7 +1,7 @@
terraform {
required_providers {
bytebase = {
- version = "1.0.23"
+ version = "1.0.24"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/iamPolicy/main.tf b/examples/iamPolicy/main.tf
index 8b1f4e0..9b5b8bf 100644
--- a/examples/iamPolicy/main.tf
+++ b/examples/iamPolicy/main.tf
@@ -1,7 +1,7 @@
terraform {
required_providers {
bytebase = {
- version = "1.0.23"
+ version = "1.0.24"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/instances/main.tf b/examples/instances/main.tf
index 6ee057d..a2bdeec 100644
--- a/examples/instances/main.tf
+++ b/examples/instances/main.tf
@@ -2,7 +2,7 @@
terraform {
required_providers {
bytebase = {
- version = "1.0.23"
+ version = "1.0.24"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/policies/main.tf b/examples/policies/main.tf
index 4660ef3..d2767cf 100644
--- a/examples/policies/main.tf
+++ b/examples/policies/main.tf
@@ -1,7 +1,7 @@
terraform {
required_providers {
bytebase = {
- version = "1.0.23"
+ version = "1.0.24"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/projects/main.tf b/examples/projects/main.tf
index f45471a..33d8fb8 100644
--- a/examples/projects/main.tf
+++ b/examples/projects/main.tf
@@ -2,7 +2,7 @@
terraform {
required_providers {
bytebase = {
- version = "1.0.23"
+ version = "1.0.24"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/roles/main.tf b/examples/roles/main.tf
index b183285..42e3464 100644
--- a/examples/roles/main.tf
+++ b/examples/roles/main.tf
@@ -1,7 +1,7 @@
terraform {
required_providers {
bytebase = {
- version = "1.0.23"
+ version = "1.0.24"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/settings/main.tf b/examples/settings/main.tf
index a3cddd2..f79e136 100644
--- a/examples/settings/main.tf
+++ b/examples/settings/main.tf
@@ -1,7 +1,7 @@
terraform {
required_providers {
bytebase = {
- version = "1.0.23"
+ version = "1.0.24"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/setup/approval_flow.tf b/examples/setup/approval_flow.tf
index 79201e9..4a4f799 100644
--- a/examples/setup/approval_flow.tf
+++ b/examples/setup/approval_flow.tf
@@ -3,19 +3,21 @@ resource "bytebase_setting" "approval_flow" {
approval_flow {
rules {
flow {
- title = "DBA -> OWNER"
- description = "Need DBA and workspace owner approval"
+ title = "Project Owner -> DBA -> Admin"
+ description = "Need DBA and workspace admin approval"
creator = "users/support@bytebase.com"
# Approval flow following the step order.
steps {
- type = "GROUP"
- node = "WORKSPACE_DBA"
+ role = "roles/projectOwner"
}
steps {
- type = "GROUP"
- node = "WORKSPACE_OWNER"
+ role = "roles/workspaceDBA"
+ }
+
+ steps {
+ role = "roles/workspaceAdmin"
}
}
diff --git a/examples/setup/data_masking.tf b/examples/setup/data_masking.tf
index 7aead21..af07e2c 100644
--- a/examples/setup/data_masking.tf
+++ b/examples/setup/data_masking.tf
@@ -129,10 +129,10 @@ resource "bytebase_policy" "masking_exception_policy" {
resource "bytebase_policy" "global_masking_policy" {
depends_on = [
bytebase_instance.prod,
- bytebase_environment.test
+ bytebase_setting.environments
]
- parent = ""
+ parent = "workspaces/-"
type = "MASKING_RULE"
enforce = true
inherit_from_parent = false
diff --git a/examples/setup/database.tf b/examples/setup/database.tf
index b8183a3..fbb54c8 100644
--- a/examples/setup/database.tf
+++ b/examples/setup/database.tf
@@ -2,12 +2,12 @@ resource "bytebase_database" "database" {
depends_on = [
bytebase_instance.test,
bytebase_project.sample_project,
- bytebase_environment.test
+ bytebase_setting.environments
]
name = "instances/test-sample-instance/databases/employee"
project = bytebase_project.sample_project.name
- environment = bytebase_environment.test.name
+ environment = bytebase_setting.environments.environment_setting[0].environment[0].name
catalog {
schemas {
diff --git a/examples/setup/environment.tf b/examples/setup/environment.tf
index 92b8d07..c175259 100644
--- a/examples/setup/environment.tf
+++ b/examples/setup/environment.tf
@@ -1,15 +1,16 @@
-# Create a new environment named "Test"
-resource "bytebase_environment" "test" {
- resource_id = local.environment_id_test
- title = "Test"
- order = 0
- environment_tier_policy = "UNPROTECTED"
-}
+resource "bytebase_setting" "environments" {
+ name = "bb.workspace.environment"
+ environment_setting {
+ environment {
+ id = local.environment_id_test
+ title = "Test"
+ protected = false
+ }
-# Create another environment named "Prod"
-resource "bytebase_environment" "prod" {
- resource_id = local.environment_id_prod
- title = "Prod"
- order = 1
- environment_tier_policy = "PROTECTED"
+ environment {
+ id = local.environment_id_prod
+ title = "Prod"
+ protected = true
+ }
+ }
}
diff --git a/examples/setup/instance.tf b/examples/setup/instance.tf
index 5494ef4..b624b0b 100644
--- a/examples/setup/instance.tf
+++ b/examples/setup/instance.tf
@@ -3,10 +3,11 @@
# You can replace the parameters with your real instance
resource "bytebase_instance" "test" {
depends_on = [
- bytebase_environment.test
+ bytebase_setting.environments
]
+
resource_id = local.instance_id_test
- environment = bytebase_environment.test.name
+ environment = bytebase_setting.environments.environment_setting[0].environment[0].name
title = "test instance"
engine = "MYSQL"
activation = true
@@ -44,11 +45,11 @@ resource "bytebase_instance" "test" {
# Create a new instance named "prod instance"
resource "bytebase_instance" "prod" {
depends_on = [
- bytebase_environment.prod
+ bytebase_setting.environments
]
resource_id = local.instance_id_prod
- environment = bytebase_environment.prod.name
+ environment = bytebase_setting.environments.environment_setting[0].environment[1].name
title = "prod instance"
engine = "POSTGRES"
diff --git a/examples/setup/sql_review.tf b/examples/setup/sql_review.tf
index 786d4c3..c017046 100644
--- a/examples/setup/sql_review.tf
+++ b/examples/setup/sql_review.tf
@@ -1,15 +1,14 @@
resource "bytebase_review_config" "sample" {
depends_on = [
- bytebase_environment.test,
- bytebase_environment.prod
+ bytebase_setting.environments
]
resource_id = "review-config-sample"
title = "Sample SQL Review Config"
enabled = true
resources = toset([
- bytebase_environment.test.name,
- bytebase_environment.prod.name
+ bytebase_setting.environments.environment_setting[0].environment[0].name,
+ bytebase_setting.environments.environment_setting[0].environment[1].name
])
rules {
type = "column.no-null"
diff --git a/examples/sql_review/main.tf b/examples/sql_review/main.tf
index 4328808..96e8edf 100644
--- a/examples/sql_review/main.tf
+++ b/examples/sql_review/main.tf
@@ -1,7 +1,7 @@
terraform {
required_providers {
bytebase = {
- version = "1.0.23"
+ version = "1.0.24"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/examples/users/main.tf b/examples/users/main.tf
index 5206a3f..15acb14 100644
--- a/examples/users/main.tf
+++ b/examples/users/main.tf
@@ -2,7 +2,7 @@
terraform {
required_providers {
bytebase = {
- version = "1.0.23"
+ version = "1.0.24"
# For local development, please use "terraform.local/bytebase/bytebase" instead
source = "registry.terraform.io/bytebase/bytebase"
}
diff --git a/go.mod b/go.mod
index 87066bd..e471b0c 100644
--- a/go.mod
+++ b/go.mod
@@ -1,11 +1,9 @@
module github.com/bytebase/terraform-provider-bytebase
-go 1.24.0
-
-toolchain go1.24.1
+go 1.24.2
require (
- github.com/bytebase/bytebase v0.0.0-20250313084449-2ed26990a507
+ github.com/bytebase/bytebase v0.0.0-20250424073126-d57cbba37d61
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320
github.com/hashicorp/terraform-plugin-docs v0.13.0
github.com/hashicorp/terraform-plugin-log v0.7.0
@@ -13,7 +11,7 @@ require (
github.com/pkg/errors v0.9.1
google.golang.org/genproto v0.0.0-20250311190419-81fb87f6b8bf
google.golang.org/genproto/googleapis/api v0.0.0-20250311190419-81fb87f6b8bf
- google.golang.org/protobuf v1.36.5
+ google.golang.org/protobuf v1.36.6
)
require (
@@ -49,7 +47,7 @@ require (
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/imdario/mergo v0.3.13 // indirect
- github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/cli v1.1.4 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
@@ -66,10 +64,10 @@ require (
github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect
github.com/vmihailenco/tagparser v0.1.1 // indirect
github.com/zclconf/go-cty v1.11.0 // indirect
- golang.org/x/crypto v0.36.0 // indirect
- golang.org/x/net v0.37.0 // indirect
- golang.org/x/sys v0.31.0 // indirect
- golang.org/x/text v0.23.0 // indirect
+ golang.org/x/crypto v0.37.0 // indirect
+ golang.org/x/net v0.39.0 // indirect
+ golang.org/x/sys v0.32.0 // indirect
+ golang.org/x/text v0.24.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250311190419-81fb87f6b8bf // indirect
google.golang.org/grpc v1.71.0 // indirect
diff --git a/go.sum b/go.sum
index cc30097..118c4c1 100644
--- a/go.sum
+++ b/go.sum
@@ -30,8 +30,8 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/bytebase/bytebase v0.0.0-20250313084449-2ed26990a507 h1:JMBYOPpRjoeWZt8QsFvzKe/JvelebOGhEkAJapkT1NM=
-github.com/bytebase/bytebase v0.0.0-20250313084449-2ed26990a507/go.mod h1:yGEPeD42x5lqzB5FwA2H87/eWPZKfU7vyMN8xF+HYC0=
+github.com/bytebase/bytebase v0.0.0-20250424073126-d57cbba37d61 h1:+ptgPqM2aSzlPjeauecETOwbuGcoSKd5wUsNLLtMuCQ=
+github.com/bytebase/bytebase v0.0.0-20250424073126-d57cbba37d61/go.mod h1:Gu5A9lSsc8OMJ5nUbKAxOn5X8gDj1Rxuzy0NwxVt90k=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -156,12 +156,11 @@ github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlW
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
-github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
-github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
+github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
-github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/cli v1.1.4 h1:qj8czE26AU4PbiaPXK5uVmMSM+V5BYsFBiM9HhGRLUA=
@@ -254,8 +253,8 @@ golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
-golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
+golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
+golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -266,8 +265,8 @@ golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
-golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
-golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
+golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
+golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -287,17 +286,16 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
-golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
+golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
-golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
+golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
+golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -312,8 +310,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250311190419-81fb87f6b8bf h1:
google.golang.org/genproto/googleapis/rpc v0.0.0-20250311190419-81fb87f6b8bf/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
-google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
-google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
+google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
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-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/provider/data_source_environment.go b/provider/data_source_environment.go
deleted file mode 100644
index f6734e4..0000000
--- a/provider/data_source_environment.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package provider
-
-import (
- "context"
- "fmt"
-
- "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-
- "github.com/bytebase/terraform-provider-bytebase/api"
- "github.com/bytebase/terraform-provider-bytebase/provider/internal"
-)
-
-func dataSourceEnvironment() *schema.Resource {
- return &schema.Resource{
- Description: "The environment data source.",
- ReadContext: dataSourceEnvironmentRead,
- Schema: map[string]*schema.Schema{
- "resource_id": {
- Type: schema.TypeString,
- Required: true,
- ValidateFunc: internal.ResourceIDValidation,
- Description: "The environment unique resource id.",
- },
- "name": {
- Type: schema.TypeString,
- Computed: true,
- Description: "The environment full name in environments/{resource id} format.",
- },
- "title": {
- Type: schema.TypeString,
- Computed: true,
- Description: "The environment unique name.",
- },
- "order": {
- Type: schema.TypeInt,
- Computed: true,
- Description: "The environment sorting order.",
- },
- "environment_tier_policy": {
- Type: schema.TypeString,
- Computed: true,
- Description: "If marked as PROTECTED, developers cannot execute any query on this environment's databases using SQL Editor by default.",
- },
- },
- }
-}
-
-func dataSourceEnvironmentRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- c := m.(api.Client)
- environmentName := fmt.Sprintf("%s%s", internal.EnvironmentNamePrefix, d.Get("resource_id").(string))
-
- environment, err := c.GetEnvironment(ctx, environmentName)
- if err != nil {
- return diag.FromErr(err)
- }
-
- d.SetId(environment.Name)
-
- return setEnvironment(d, environment)
-}
diff --git a/provider/data_source_environment_list.go b/provider/data_source_environment_list.go
deleted file mode 100644
index 6940413..0000000
--- a/provider/data_source_environment_list.go
+++ /dev/null
@@ -1,99 +0,0 @@
-package provider
-
-import (
- "context"
- "strconv"
- "time"
-
- "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-
- "github.com/bytebase/terraform-provider-bytebase/api"
- "github.com/bytebase/terraform-provider-bytebase/provider/internal"
-)
-
-func dataSourceEnvironmentList() *schema.Resource {
- return &schema.Resource{
- Description: "The environment data source list.",
- ReadContext: dataSourceEnvironmentListRead,
- Schema: map[string]*schema.Schema{
- "show_deleted": {
- Type: schema.TypeBool,
- Optional: true,
- Default: false,
- Description: "Including removed instance in the response.",
- },
- "environments": {
- Type: schema.TypeList,
- Computed: true,
- Elem: &schema.Resource{
- Schema: map[string]*schema.Schema{
- "resource_id": {
- Type: schema.TypeString,
- Computed: true,
- Description: "The environment unique resource id.",
- },
- "name": {
- Type: schema.TypeString,
- Computed: true,
- Description: "The environment full name in environments/{resource id} format.",
- },
- "title": {
- Type: schema.TypeString,
- Computed: true,
- Description: "The environment unique name.",
- },
- "order": {
- Type: schema.TypeInt,
- Computed: true,
- Description: "The environment sorting order.",
- },
- "environment_tier_policy": {
- Type: schema.TypeString,
- Computed: true,
- Description: "If marked as PROTECTED, developers cannot execute any query on this environment's databases using SQL Editor by default.",
- },
- },
- },
- },
- },
- }
-}
-
-func dataSourceEnvironmentListRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- c := m.(api.Client)
-
- // Warning or errors can be collected in a slice type
- var diags diag.Diagnostics
-
- response, err := c.ListEnvironment(ctx, d.Get("show_deleted").(bool))
- if err != nil {
- return diag.FromErr(err)
- }
-
- environments := []map[string]interface{}{}
- for _, environment := range response.Environments {
- envID, err := internal.GetEnvironmentID(environment.Name)
- if err != nil {
- return diag.FromErr(err)
- }
-
- env := make(map[string]interface{})
- env["resource_id"] = envID
- env["title"] = environment.Title
- env["name"] = environment.Name
- env["order"] = environment.Order
- env["environment_tier_policy"] = environment.Tier.String()
-
- environments = append(environments, env)
- }
-
- if err := d.Set("environments", environments); err != nil {
- return diag.FromErr(err)
- }
-
- // always refresh
- d.SetId(strconv.FormatInt(time.Now().Unix(), 10))
-
- return diags
-}
diff --git a/provider/data_source_environment_list_test.go b/provider/data_source_environment_list_test.go
deleted file mode 100644
index 708bf70..0000000
--- a/provider/data_source_environment_list_test.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package provider
-
-import (
- "fmt"
- "testing"
-
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
-
- "github.com/bytebase/terraform-provider-bytebase/provider/internal"
-)
-
-func TestAccEnvironmentListDataSource(t *testing.T) {
- identifier := "new-environment"
-
- resource.Test(t, resource.TestCase{
- PreCheck: func() {
- testAccPreCheck(t)
- },
- Providers: testAccProviders,
- CheckDestroy: testAccCheckEnvironmentDestroy,
- Steps: []resource.TestStep{
- internal.GetTestStepForDataSourceList(
- "",
- "",
- "bytebase_environment_list",
- "before",
- "environments",
- 0,
- ),
- internal.GetTestStepForDataSourceList(
- testAccCheckEnvironmentResource(identifier, "test", 1),
- fmt.Sprintf("bytebase_environment.%s", identifier),
- "bytebase_environment_list",
- "after",
- "environments",
- 1,
- ),
- },
- })
-}
diff --git a/provider/data_source_environment_test.go b/provider/data_source_environment_test.go
deleted file mode 100644
index ac1f2f0..0000000
--- a/provider/data_source_environment_test.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package provider
-
-import (
- "fmt"
- "regexp"
- "testing"
-
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
-
- "github.com/bytebase/terraform-provider-bytebase/provider/internal"
-)
-
-func TestAccEnvironmentDataSource(t *testing.T) {
- identifier := "test"
- resourceName := fmt.Sprintf("bytebase_environment.%s", identifier)
- title := "test"
- order := 1
-
- resource.Test(t, resource.TestCase{
- PreCheck: func() {
- testAccPreCheck(t)
- },
- Providers: testAccProviders,
- CheckDestroy: testAccCheckEnvironmentDestroy,
- Steps: []resource.TestStep{
- // get single environment test
- {
- Config: testAccCheckEnvironmentDataSource(
- testAccCheckEnvironmentResource(identifier, title, order),
- resourceName,
- identifier,
- ),
- Check: resource.ComposeTestCheckFunc(
- internal.TestCheckResourceExists(fmt.Sprintf("data.%s", resourceName)),
- resource.TestCheckResourceAttr(fmt.Sprintf("data.%s", resourceName), "title", title),
- resource.TestCheckResourceAttr(fmt.Sprintf("data.%s", resourceName), "order", fmt.Sprintf("%d", order)),
- resource.TestCheckResourceAttr(fmt.Sprintf("data.%s", resourceName), "environment_tier_policy", "PROTECTED"),
- ),
- },
- },
- })
-}
-
-func TestAccEnvironmentDataSource_NotFound(t *testing.T) {
- identifier := "dev-notfound"
-
- resource.Test(t, resource.TestCase{
- PreCheck: func() {
- testAccPreCheck(t)
- },
- Providers: testAccProviders,
- CheckDestroy: testAccCheckEnvironmentDestroy,
- Steps: []resource.TestStep{
- {
- Config: testAccCheckEnvironmentDataSource(
- "",
- "",
- identifier,
- ),
- ExpectError: regexp.MustCompile("Cannot found environment"),
- },
- },
- })
-}
-
-func testAccCheckEnvironmentDataSource(
- resource,
- dependsOn,
- identifier string,
-) string {
- return fmt.Sprintf(`
- %s
-
- data "bytebase_environment" "%s" {
- resource_id = "%s"
- depends_on = [
- %s
- ]
- }
- `, resource, identifier, identifier, dependsOn)
-}
diff --git a/provider/data_source_policy.go b/provider/data_source_policy.go
index 699cd9a..829dab9 100644
--- a/provider/data_source_policy.go
+++ b/provider/data_source_policy.go
@@ -29,7 +29,7 @@ func dataSourcePolicy() *schema.Resource {
Default: "",
ValidateDiagFunc: internal.ResourceNameValidation(
// workspace policy
- regexp.MustCompile("^workspaces/-$"),
+ regexp.MustCompile(fmt.Sprintf("^%s$", internal.WorkspaceName)),
// environment policy
regexp.MustCompile(fmt.Sprintf("^%s%s$", internal.EnvironmentNamePrefix, internal.ResourceIDPattern)),
// instance policy
@@ -91,8 +91,7 @@ func getMaskingExceptionPolicySchema(computed bool) *schema.Schema {
Schema: map[string]*schema.Schema{
"database": {
Type: schema.TypeString,
- Computed: computed,
- Optional: true,
+ Required: true,
ValidateFunc: validation.StringIsNotEmpty,
Description: "The database full name in instances/{instance resource id}/databases/{database name} format",
},
@@ -115,15 +114,13 @@ func getMaskingExceptionPolicySchema(computed bool) *schema.Schema {
},
"member": {
Type: schema.TypeString,
- Computed: computed,
- Optional: true,
+ Required: true,
ValidateFunc: validation.StringIsNotEmpty,
Description: "The member in user:{email} or group:{email} format.",
},
"action": {
Type: schema.TypeString,
- Computed: computed,
- Optional: true,
+ Required: true,
ValidateFunc: validation.StringInSlice([]string{
v1pb.MaskingExceptionPolicy_MaskingException_QUERY.String(),
v1pb.MaskingExceptionPolicy_MaskingException_EXPORT.String(),
@@ -164,22 +161,19 @@ func getGlobalMaskingPolicySchema(computed bool) *schema.Schema {
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
- Computed: computed,
- Optional: true,
+ Required: true,
ValidateFunc: validation.StringIsNotEmpty,
Description: "The unique rule id",
},
"semantic_type": {
Type: schema.TypeString,
- Computed: computed,
- Optional: true,
+ Required: true,
ValidateFunc: validation.StringIsNotEmpty,
Description: "The semantic type id",
},
"condition": {
Type: schema.TypeString,
- Computed: computed,
- Optional: true,
+ Required: true,
ValidateFunc: validation.StringIsNotEmpty,
Description: "The condition expression",
},
@@ -195,6 +189,10 @@ func dataSourcePolicyRead(ctx context.Context, d *schema.ResourceData, m interfa
c := m.(api.Client)
policyName := fmt.Sprintf("%s/%s%s", d.Get("parent").(string), internal.PolicyNamePrefix, d.Get("type").(string))
+ if strings.HasPrefix(policyName, internal.WorkspaceName) {
+ policyName = strings.TrimPrefix(policyName, fmt.Sprintf("%s/", internal.WorkspaceName))
+ }
+
policy, err := c.GetPolicy(ctx, policyName)
if err != nil {
return diag.FromErr(err)
diff --git a/provider/data_source_policy_list.go b/provider/data_source_policy_list.go
index b4d3a5f..cf51cf8 100644
--- a/provider/data_source_policy_list.go
+++ b/provider/data_source_policy_list.go
@@ -27,7 +27,7 @@ func dataSourcePolicyList() *schema.Resource {
Default: "",
ValidateDiagFunc: internal.ResourceNameValidation(
// workspace policy
- regexp.MustCompile("^workspaces/-$"),
+ regexp.MustCompile(fmt.Sprintf("^%s$", internal.WorkspaceName)),
// environment policy
regexp.MustCompile(fmt.Sprintf("^%s%s$", internal.EnvironmentNamePrefix, internal.ResourceIDPattern)),
// instance policy
@@ -76,7 +76,12 @@ func dataSourcePolicyList() *schema.Resource {
func dataSourcePolicyListRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
c := m.(api.Client)
- response, err := c.ListPolicies(ctx, d.Get("parent").(string))
+ parent := d.Get("parent").(string)
+ if parent == internal.WorkspaceName {
+ parent = ""
+ }
+
+ response, err := c.ListPolicies(ctx, parent)
if err != nil {
return diag.FromErr(err)
}
diff --git a/provider/data_source_setting.go b/provider/data_source_setting.go
index 65dae93..2c409be 100644
--- a/provider/data_source_setting.go
+++ b/provider/data_source_setting.go
@@ -3,6 +3,7 @@ package provider
import (
"context"
"fmt"
+ "regexp"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -29,12 +30,14 @@ func dataSourceSetting() *schema.Resource {
string(api.SettingWorkspaceProfile),
string(api.SettingDataClassification),
string(api.SettingSemanticTypes),
+ string(api.SettingEnvironment),
}, false),
},
- "approval_flow": getWorkspaceApprovalSetting(true),
- "workspace_profile": getWorkspaceProfileSetting(true),
- "classification": getClassificationSetting(true),
- "semantic_types": getSemanticTypesSetting(true),
+ "approval_flow": getWorkspaceApprovalSetting(true),
+ "workspace_profile": getWorkspaceProfileSetting(true),
+ "classification": getClassificationSetting(true),
+ "semantic_types": getSemanticTypesSetting(true),
+ "environment_setting": getEnvironmentSetting(true),
},
}
}
@@ -198,14 +201,12 @@ func getClassificationSetting(computed bool) *schema.Schema {
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
- Computed: computed,
- Optional: true,
+ Required: true,
Description: "The classification unique uuid.",
},
"title": {
Type: schema.TypeString,
- Computed: computed,
- Optional: true,
+ Required: true,
Description: "The classification title. Optional.",
},
"classification_from_config": {
@@ -215,22 +216,19 @@ func getClassificationSetting(computed bool) *schema.Schema {
Description: "If true, we will only store the classification in the config. Otherwise we will get the classification from table/column comment, and write back to the schema metadata.",
},
"levels": {
- Computed: computed,
- Optional: true,
+ Required: true,
Type: schema.TypeSet,
MinItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
- Computed: computed,
- Optional: true,
+ Required: true,
Description: "The classification level unique uuid.",
},
"title": {
Type: schema.TypeString,
- Computed: computed,
- Optional: true,
+ Required: true,
Description: "The classification level title.",
},
"description": {
@@ -244,22 +242,19 @@ func getClassificationSetting(computed bool) *schema.Schema {
Set: itemIDHash,
},
"classifications": {
- Computed: computed,
- Optional: true,
+ Required: true,
Type: schema.TypeSet,
MinItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
- Computed: computed,
- Optional: true,
+ Required: true,
Description: "The classification unique id, must in {number}-{number} format.",
},
"title": {
Type: schema.TypeString,
- Computed: computed,
- Optional: true,
+ Required: true,
Description: "The classification title.",
},
"description": {
@@ -331,7 +326,55 @@ func getWorkspaceProfileSetting(computed bool) *schema.Schema {
}
}
-// TODO(ed): API changed.
+func getEnvironmentSetting(computed bool) *schema.Schema {
+ return &schema.Schema{
+ Computed: computed,
+ Optional: true,
+ Default: nil,
+ Type: schema.TypeList,
+ Description: "The environment",
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "environment": {
+ Type: schema.TypeList,
+ Computed: computed,
+ Required: !computed,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "id": {
+ Type: schema.TypeString,
+ Required: true,
+ ValidateFunc: internal.ResourceIDValidation,
+ Description: "The environment unique id.",
+ },
+ "name": {
+ Type: schema.TypeString,
+ Computed: true,
+ Description: "The environment readonly name in environments/{id} format.",
+ },
+ "title": {
+ Type: schema.TypeString,
+ Required: true,
+ Description: "The environment display name.",
+ },
+ "color": {
+ Type: schema.TypeString,
+ Optional: true,
+ Description: "The environment color.",
+ },
+ "protected": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Description: "The environment is protected or not.",
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
func getWorkspaceApprovalSetting(computed bool) *schema.Schema {
return &schema.Schema{
Computed: computed,
@@ -376,20 +419,13 @@ func getWorkspaceApprovalSetting(computed bool) *schema.Schema {
Description: "Approval flow following the step order.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
- "type": {
- Type: schema.TypeString,
- Computed: computed,
- Optional: true,
- ValidateFunc: validation.StringInSlice([]string{
- string(api.ApprovalNodeTypeGroup),
- string(api.ApprovalNodeTypeRole),
- }, false),
- },
- "node": {
- Required: !computed,
- Default: nil,
- Computed: computed,
+ "role": {
Type: schema.TypeString,
+ Required: true,
+ ValidateDiagFunc: internal.ResourceNameValidation(
+ regexp.MustCompile(fmt.Sprintf("^%s", internal.RoleNamePrefix)),
+ ),
+ Description: "The role require to review in this step",
},
},
},
@@ -454,7 +490,7 @@ func dataSourceSettingRead(ctx context.Context, d *schema.ResourceData, m interf
}
func setSettingMessage(ctx context.Context, d *schema.ResourceData, client api.Client, setting *v1pb.Setting) diag.Diagnostics {
- if value := setting.Value.GetWorkspaceApprovalSettingValue(); value != nil {
+ if value := setting.GetValue().GetWorkspaceApprovalSettingValue(); value != nil {
settingVal, err := flattenWorkspaceApprovalSetting(ctx, client, value)
if err != nil {
return diag.Errorf("failed to parse workspace_approval_setting: %s", err.Error())
@@ -463,28 +499,54 @@ func setSettingMessage(ctx context.Context, d *schema.ResourceData, client api.C
return diag.Errorf("cannot set workspace_approval_setting: %s", err.Error())
}
}
- if value := setting.Value.GetWorkspaceProfileSettingValue(); value != nil {
+ if value := setting.GetValue().GetWorkspaceProfileSettingValue(); value != nil {
settingVal := flattenWorkspaceProfileSetting(value)
if err := d.Set("workspace_profile", settingVal); err != nil {
return diag.Errorf("cannot set workspace_profile: %s", err.Error())
}
}
- if value := setting.Value.GetDataClassificationSettingValue(); value != nil {
+ if value := setting.GetValue().GetDataClassificationSettingValue(); value != nil {
settingVal := flattenClassificationSetting(value)
if err := d.Set("classification", settingVal); err != nil {
return diag.Errorf("cannot set classification: %s", err.Error())
}
}
- if value := setting.Value.GetSemanticTypeSettingValue(); value != nil {
+ if value := setting.GetValue().GetSemanticTypeSettingValue(); value != nil {
settingVal := flattenSemanticTypesSetting(value)
if err := d.Set("semantic_types", schema.NewSet(itemIDHash, settingVal)); err != nil {
return diag.Errorf("cannot set semantic_types: %s", err.Error())
}
}
+ if value := setting.GetValue().GetEnvironmentSetting(); value != nil {
+ settingVal := flattenEnvironmentSetting(value)
+ if err := d.Set("environment_setting", settingVal); err != nil {
+ return diag.Errorf("cannot set environment_setting: %s", err.Error())
+ }
+ }
return nil
}
+func flattenEnvironmentSetting(setting *v1pb.EnvironmentSetting) []interface{} {
+ environmentList := []interface{}{}
+
+ for _, environment := range setting.GetEnvironments() {
+ raw := map[string]interface{}{
+ "id": environment.Id,
+ "name": environment.Name,
+ "color": environment.Color,
+ "title": environment.Title,
+ "protected": environment.Tags["protected"] == "protected",
+ }
+ environmentList = append(environmentList, raw)
+ }
+
+ environmentSetting := map[string]interface{}{
+ "environment": environmentList,
+ }
+ return []interface{}{environmentSetting}
+}
+
func parseApprovalExpression(callExpr *v1alpha1.Expr_Call) ([]map[string]interface{}, error) {
if callExpr == nil {
return nil, errors.Errorf("failed to parse the expression")
@@ -552,18 +614,12 @@ func flattenWorkspaceApprovalSetting(ctx context.Context, client api.Client, set
for _, rule := range setting.Rules {
stepList := []interface{}{}
for _, step := range rule.Template.Flow.Steps {
+ rawStep := map[string]interface{}{}
for _, node := range step.Nodes {
- rawNode := map[string]interface{}{}
- switch payload := node.Payload.(type) {
- case *v1pb.ApprovalNode_Role:
- rawNode["type"] = string(api.ApprovalNodeTypeRole)
- rawNode["node"] = payload.Role
- case *v1pb.ApprovalNode_GroupValue_:
- rawNode["type"] = string(api.ApprovalNodeTypeGroup)
- rawNode["node"] = payload.GroupValue.String()
- }
- stepList = append(stepList, rawNode)
+ rawStep["role"] = node.Role
+ break
}
+ stepList = append(stepList, rawStep)
}
conditionList := []map[string]interface{}{}
diff --git a/provider/internal/mock_client.go b/provider/internal/mock_client.go
index 8b8a277..4dc84e1 100644
--- a/provider/internal/mock_client.go
+++ b/provider/internal/mock_client.go
@@ -14,7 +14,6 @@ import (
v1alpha1 "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
-var environmentMap map[string]*v1pb.Environment
var instanceMap map[string]*v1pb.Instance
var policyMap map[string]*v1pb.Policy
var projectMap map[string]*v1pb.Project
@@ -27,7 +26,6 @@ var roleMap map[string]*v1pb.Role
var groupMap map[string]*v1pb.Group
func init() {
- environmentMap = map[string]*v1pb.Environment{}
instanceMap = map[string]*v1pb.Instance{}
policyMap = map[string]*v1pb.Policy{}
projectMap = map[string]*v1pb.Project{}
@@ -41,7 +39,6 @@ func init() {
}
type mockClient struct {
- environmentMap map[string]*v1pb.Environment
instanceMap map[string]*v1pb.Instance
policyMap map[string]*v1pb.Policy
projectMap map[string]*v1pb.Project
@@ -58,7 +55,6 @@ type mockClient struct {
// newMockClient returns the new Bytebase API mock client.
func newMockClient(_, _, _ string) (api.Client, error) {
return &mockClient{
- environmentMap: environmentMap,
instanceMap: instanceMap,
policyMap: policyMap,
projectMap: projectMap,
@@ -81,96 +77,6 @@ func (*mockClient) GetCaller() *v1pb.User {
}
}
-// CreateEnvironment creates the environment.
-func (c *mockClient) CreateEnvironment(_ context.Context, environmentID string, create *v1pb.Environment) (*v1pb.Environment, error) {
- env := &v1pb.Environment{
- Name: fmt.Sprintf("%s%s", EnvironmentNamePrefix, environmentID),
- Order: create.Order,
- Title: create.Title,
- State: v1pb.State_ACTIVE,
- Tier: create.Tier,
- }
-
- if _, ok := c.environmentMap[env.Name]; ok {
- return nil, errors.Errorf("Environment %s already exists", env.Name)
- }
-
- c.environmentMap[env.Name] = env
-
- return env, nil
-}
-
-// GetEnvironment gets the environment by id.
-func (c *mockClient) GetEnvironment(_ context.Context, environmentName string) (*v1pb.Environment, error) {
- env, ok := c.environmentMap[environmentName]
- if !ok {
- return nil, errors.Errorf("Cannot found environment %s", environmentName)
- }
-
- return env, nil
-}
-
-// ListEnvironment finds all environments.
-func (c *mockClient) ListEnvironment(_ context.Context, showDeleted bool) (*v1pb.ListEnvironmentsResponse, error) {
- environments := make([]*v1pb.Environment, 0)
- for _, env := range c.environmentMap {
- if env.State == v1pb.State_DELETED && !showDeleted {
- continue
- }
- environments = append(environments, env)
- }
-
- return &v1pb.ListEnvironmentsResponse{
- Environments: environments,
- }, nil
-}
-
-// UpdateEnvironment updates the environment.
-func (c *mockClient) UpdateEnvironment(ctx context.Context, patch *v1pb.Environment, updateMasks []string) (*v1pb.Environment, error) {
- env, err := c.GetEnvironment(ctx, patch.Name)
- if err != nil {
- return nil, err
- }
-
- if slices.Contains(updateMasks, "title") {
- env.Title = patch.Title
- }
- if slices.Contains(updateMasks, "order") {
- env.Order = patch.Order
- }
- if slices.Contains(updateMasks, "tier") {
- env.Tier = patch.Tier
- }
-
- c.environmentMap[env.Name] = env
-
- return env, nil
-}
-
-// DeleteEnvironment deletes the environment.
-func (c *mockClient) DeleteEnvironment(ctx context.Context, environmentName string) error {
- env, err := c.GetEnvironment(ctx, environmentName)
- if err != nil {
- return err
- }
-
- env.State = v1pb.State_DELETED
- c.environmentMap[env.Name] = env
- return nil
-}
-
-// UndeleteEnvironment undeletes the environment.
-func (c *mockClient) UndeleteEnvironment(ctx context.Context, environmentName string) (*v1pb.Environment, error) {
- env, err := c.GetEnvironment(ctx, environmentName)
- if err != nil {
- return nil, err
- }
-
- env.State = v1pb.State_ACTIVE
- c.environmentMap[env.Name] = env
- return env, nil
-}
-
// ListInstance will return instances in environment.
func (c *mockClient) ListInstance(_ context.Context, filter *api.InstanceFilter) ([]*v1pb.Instance, error) {
instances := make([]*v1pb.Instance, 0)
diff --git a/provider/internal/utils.go b/provider/internal/utils.go
index 24a9e8d..0df7d06 100644
--- a/provider/internal/utils.go
+++ b/provider/internal/utils.go
@@ -43,14 +43,17 @@ const (
DatabaseCatalogNameSuffix = "/catalog"
// ResourceIDPattern is the pattern for resource id.
ResourceIDPattern = "[a-z]([a-z0-9-]{0,61}[a-z0-9])?"
+ // WorkspaceName is the name for workspace resource.
+ WorkspaceName = "workspaces/-"
)
var (
- resourceIDRegex = regexp.MustCompile(fmt.Sprintf("^%s$", ResourceIDPattern))
+ // ResourceIDRegex is the regex for resource id.
+ ResourceIDRegex = regexp.MustCompile(fmt.Sprintf("^%s$", ResourceIDPattern))
)
// ResourceIDValidation is the resource id regexp validation.
-var ResourceIDValidation = validation.StringMatch(resourceIDRegex, fmt.Sprintf("resource id must matches %v", resourceIDRegex))
+var ResourceIDValidation = validation.StringMatch(ResourceIDRegex, fmt.Sprintf("resource id must matches %v", ResourceIDRegex))
// ResourceNameValidation validate the resource name with prefix.
func ResourceNameValidation(regexs ...*regexp.Regexp) schema.SchemaValidateDiagFunc {
diff --git a/provider/provider.go b/provider/provider.go
index 5d39023..04bf561 100644
--- a/provider/provider.go
+++ b/provider/provider.go
@@ -51,8 +51,6 @@ func NewProvider() *schema.Provider {
DataSourcesMap: map[string]*schema.Resource{
"bytebase_instance": dataSourceInstance(),
"bytebase_instance_list": dataSourceInstanceList(),
- "bytebase_environment": dataSourceEnvironment(),
- "bytebase_environment_list": dataSourceEnvironmentList(),
"bytebase_policy": dataSourcePolicy(),
"bytebase_policy_list": dataSourcePolicyList(),
"bytebase_project": dataSourceProject(),
@@ -71,7 +69,6 @@ func NewProvider() *schema.Provider {
"bytebase_iam_policy": dataSourceIAMPolicy(),
},
ResourcesMap: map[string]*schema.Resource{
- "bytebase_environment": resourceEnvironment(),
"bytebase_instance": resourceInstance(),
"bytebase_policy": resourcePolicy(),
"bytebase_project": resourceProjct(),
diff --git a/provider/resource_environment.go b/provider/resource_environment.go
deleted file mode 100644
index 9a017b3..0000000
--- a/provider/resource_environment.go
+++ /dev/null
@@ -1,275 +0,0 @@
-package provider
-
-import (
- "context"
- "fmt"
- "regexp"
-
- "github.com/hashicorp/terraform-plugin-log/tflog"
- "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
-
- v1pb "github.com/bytebase/bytebase/proto/generated-go/v1"
-
- "github.com/bytebase/terraform-provider-bytebase/api"
- "github.com/bytebase/terraform-provider-bytebase/provider/internal"
-)
-
-var environmentTitleRegex = regexp.MustCompile(`^[a-zA-Z0-9]+$`)
-
-// TODO(ed): API changed.
-func resourceEnvironment() *schema.Resource {
- return &schema.Resource{
- Description: "The environment resource.",
- CreateContext: resourceEnvironmentCreate,
- ReadContext: resourceEnvironmentRead,
- UpdateContext: resourceEnvironmentUpdate,
- DeleteContext: resourceEnvironmentDelete,
- Importer: &schema.ResourceImporter{
- StateContext: schema.ImportStatePassthroughContext,
- },
- Schema: map[string]*schema.Schema{
- "resource_id": {
- Type: schema.TypeString,
- Required: true,
- ValidateFunc: internal.ResourceIDValidation,
- Description: "The environment unique resource id.",
- },
- "title": {
- Type: schema.TypeString,
- Required: true,
- Description: "The environment title.",
- ValidateFunc: validation.StringMatch(environmentTitleRegex, fmt.Sprintf("environment title must matches %v", environmentTitleRegex)),
- },
- "name": {
- Type: schema.TypeString,
- Computed: true,
- Description: "The environment full name in environments/{resource id} format.",
- },
- "order": {
- Type: schema.TypeInt,
- Required: true,
- Description: "The environment sorting order.",
- ValidateFunc: validation.IntAtLeast(0),
- },
- "environment_tier_policy": {
- Type: schema.TypeString,
- Required: true,
- ValidateFunc: validation.StringInSlice([]string{
- v1pb.EnvironmentTier_PROTECTED.String(),
- v1pb.EnvironmentTier_UNPROTECTED.String(),
- }, false),
- Description: "If marked as PROTECTED, developers cannot execute any query on this environment's databases using SQL Editor by default. Require ENTERPRISE subscription.",
- },
- },
- }
-}
-
-func resourceEnvironmentCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- c := m.(api.Client)
-
- environmentID := d.Get("resource_id").(string)
- environmentName := fmt.Sprintf("%s%s", internal.EnvironmentNamePrefix, environmentID)
-
- existedEnv, err := c.GetEnvironment(ctx, environmentName)
- if err != nil {
- tflog.Debug(ctx, fmt.Sprintf("get environment %s failed with error: %v", environmentName, err))
- }
-
- title := d.Get("title").(string)
- order := d.Get("order").(int)
- tier := v1pb.EnvironmentTier(v1pb.EnvironmentTier_value[d.Get("environment_tier_policy").(string)])
-
- var diags diag.Diagnostics
- if existedEnv != nil && err == nil {
- diags = append(diags, diag.Diagnostic{
- Severity: diag.Warning,
- Summary: "Environment already exists",
- Detail: fmt.Sprintf("Environment %s already exists, try to exec the update operation", environmentID),
- })
-
- if existedEnv.State == v1pb.State_DELETED {
- diags = append(diags, diag.Diagnostic{
- Severity: diag.Warning,
- Summary: "Environment is deleted",
- Detail: fmt.Sprintf("Environment %s already deleted, try to undelete the environment", environmentID),
- })
- if _, err := c.UndeleteEnvironment(ctx, environmentName); err != nil {
- diags = append(diags, diag.Diagnostic{
- Severity: diag.Error,
- Summary: "Failed to undelete environment",
- Detail: fmt.Sprintf("Undelete environment %s failed, error: %v", environmentName, err),
- })
- return diags
- }
- }
-
- updateMasks := []string{}
- if title != "" && title != existedEnv.Title {
- updateMasks = append(updateMasks, "title")
- }
- if order != int(existedEnv.Order) {
- updateMasks = append(updateMasks, "order")
- }
- if tier != existedEnv.Tier {
- updateMasks = append(updateMasks, "tier")
- }
-
- if len(updateMasks) > 0 {
- if _, err := c.UpdateEnvironment(ctx, &v1pb.Environment{
- Name: environmentName,
- Title: title,
- Order: int32(order),
- Tier: tier,
- State: v1pb.State_ACTIVE,
- }, updateMasks); err != nil {
- diags = append(diags, diag.Diagnostic{
- Severity: diag.Error,
- Summary: "Failed to update environment",
- Detail: fmt.Sprintf("Update environment %s failed, error: %v", environmentName, err),
- })
- return diags
- }
- }
- } else {
- if _, err := c.CreateEnvironment(ctx, environmentID, &v1pb.Environment{
- Name: environmentName,
- Title: title,
- Order: int32(order),
- Tier: tier,
- State: v1pb.State_ACTIVE,
- }); err != nil {
- return diag.FromErr(err)
- }
- }
-
- d.SetId(environmentName)
-
- diag := resourceEnvironmentRead(ctx, d, m)
- if diag != nil {
- diags = append(diags, diag...)
- }
-
- return diags
-}
-
-func resourceEnvironmentRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- c := m.(api.Client)
- environmentName := d.Id()
-
- env, err := c.GetEnvironment(ctx, environmentName)
- if err != nil {
- return diag.FromErr(err)
- }
-
- return setEnvironment(d, env)
-}
-
-func resourceEnvironmentUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- if d.HasChange("resource_id") {
- return diag.Errorf("cannot change the resource id")
- }
-
- c := m.(api.Client)
- environmentName := d.Id()
-
- existedEnv, err := c.GetEnvironment(ctx, environmentName)
- if err != nil {
- return diag.FromErr(err)
- }
-
- var diags diag.Diagnostics
- if existedEnv.State == v1pb.State_DELETED {
- diags = append(diags, diag.Diagnostic{
- Severity: diag.Warning,
- Summary: "Environment is deleted",
- Detail: fmt.Sprintf("Environment %s already deleted, try to undelete the environment", environmentName),
- })
- if _, err := c.UndeleteEnvironment(ctx, environmentName); err != nil {
- diags = append(diags, diag.Diagnostic{
- Severity: diag.Error,
- Summary: "Failed to undelete environment",
- Detail: fmt.Sprintf("Undelete environment %s failed, error: %v", environmentName, err),
- })
- return diags
- }
- }
-
- paths := []string{}
- if d.HasChange("title") {
- paths = append(paths, "title")
- }
-
- if d.HasChange("order") {
- paths = append(paths, "order")
- }
-
- if d.HasChange("environment_tier_policy") {
- paths = append(paths, "tier")
- }
-
- if len(paths) > 0 {
- title := d.Get("title").(string)
- order := d.Get("order").(int)
- tier := v1pb.EnvironmentTier(v1pb.EnvironmentTier_value[d.Get("environment_tier_policy").(string)])
-
- if _, err := c.UpdateEnvironment(ctx, &v1pb.Environment{
- Name: environmentName,
- Title: title,
- Order: int32(order),
- Tier: tier,
- State: v1pb.State_ACTIVE,
- }, paths); err != nil {
- return diag.FromErr(err)
- }
- }
-
- diag := resourceEnvironmentRead(ctx, d, m)
- if diag != nil {
- diags = append(diags, diag...)
- }
-
- return diags
-}
-
-func resourceEnvironmentDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- c := m.(api.Client)
-
- // Warning or errors can be collected in a slice type
- var diags diag.Diagnostics
- environmentName := d.Id()
-
- if err := c.DeleteEnvironment(ctx, environmentName); err != nil {
- return diag.FromErr(err)
- }
-
- d.SetId("")
-
- return diags
-}
-
-func setEnvironment(d *schema.ResourceData, env *v1pb.Environment) diag.Diagnostics {
- environmentID, err := internal.GetEnvironmentID(env.Name)
- if err != nil {
- return diag.FromErr(err)
- }
-
- if err := d.Set("resource_id", environmentID); err != nil {
- return diag.Errorf("cannot set resource_id for environment: %s", err.Error())
- }
- if err := d.Set("title", env.Title); err != nil {
- return diag.Errorf("cannot set title for environment: %s", err.Error())
- }
- if err := d.Set("name", env.Name); err != nil {
- return diag.Errorf("cannot set name for environment: %s", err.Error())
- }
- if err := d.Set("order", env.Order); err != nil {
- return diag.Errorf("cannot set order for environment: %s", err.Error())
- }
- if err := d.Set("environment_tier_policy", env.Tier.String()); err != nil {
- return diag.Errorf("cannot set environment_tier_policy for environment: %s", err.Error())
- }
-
- return nil
-}
diff --git a/provider/resource_environment_test.go b/provider/resource_environment_test.go
deleted file mode 100644
index 267a9a3..0000000
--- a/provider/resource_environment_test.go
+++ /dev/null
@@ -1,129 +0,0 @@
-package provider
-
-import (
- "context"
- "fmt"
- "regexp"
- "testing"
-
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
- "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
- "github.com/pkg/errors"
-
- "github.com/bytebase/terraform-provider-bytebase/api"
- "github.com/bytebase/terraform-provider-bytebase/provider/internal"
-)
-
-func TestAccEnvironment(t *testing.T) {
- identifier := "new-environment"
- resourceName := fmt.Sprintf("bytebase_environment.%s", identifier)
-
- title := "test"
- order := 1
- titleUpdated := fmt.Sprintf("%supdated", title)
-
- resource.Test(t, resource.TestCase{
- PreCheck: func() {
- testAccPreCheck(t)
- },
- Providers: testAccProviders,
- CheckDestroy: testAccCheckEnvironmentDestroy,
- Steps: []resource.TestStep{
- // resource create test
- {
- Config: testAccCheckEnvironmentResource(identifier, title, order),
- Check: resource.ComposeTestCheckFunc(
- internal.TestCheckResourceExists(resourceName),
- resource.TestCheckResourceAttr(resourceName, "title", title),
- resource.TestCheckResourceAttr(resourceName, "order", fmt.Sprintf("%d", order)),
- ),
- },
- // resource update test
- {
- Config: testAccCheckEnvironmentResource(identifier, titleUpdated, order+1),
- Check: resource.ComposeTestCheckFunc(
- internal.TestCheckResourceExists(resourceName),
- resource.TestCheckResourceAttr(resourceName, "title", titleUpdated),
- resource.TestCheckResourceAttr(resourceName, "order", fmt.Sprintf("%d", order+1)),
- ),
- },
- },
- })
-}
-
-func TestAccEnvironment_InvalidInput(t *testing.T) {
- resource.Test(t, resource.TestCase{
- PreCheck: func() {
- testAccPreCheck(t)
- },
- Providers: testAccProviders,
- CheckDestroy: testAccCheckEnvironmentDestroy,
- Steps: []resource.TestStep{
- // Invalid environment order
- {
- Config: `
- resource "bytebase_environment" "new_env" {
- resource_id = "test"
- title = "Test"
- environment_tier_policy = "PROTECTED"
- }
- `,
- ExpectError: regexp.MustCompile("The argument \"order\" is required, but no definition was found"),
- },
- // Invalid environment name
- {
- Config: `
- resource "bytebase_environment" "new_env" {
- resource_id = "test"
- title = ""
- order = 1
- environment_tier_policy = "PROTECTED"
- }
- `,
- ExpectError: regexp.MustCompile("environment title must matches"),
- },
- // Invalid policy
- {
- Config: `
- resource "bytebase_environment" "new_env" {
- resource_id = "test"
- title = "Test"
- order = 1
- environment_tier_policy = "UNKNOWN"
- }
- `,
- ExpectError: regexp.MustCompile("expected environment_tier_policy to be one of"),
- },
- },
- })
-}
-
-func testAccCheckEnvironmentDestroy(s *terraform.State) error {
- c, ok := testAccProvider.Meta().(api.Client)
- if !ok {
- return errors.Errorf("cannot get the api client")
- }
-
- for _, rs := range s.RootModule().Resources {
- if rs.Type != "bytebase_environment" {
- continue
- }
-
- if err := c.DeleteEnvironment(context.Background(), rs.Primary.ID); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func testAccCheckEnvironmentResource(identifier, envName string, order int) string {
- return fmt.Sprintf(`
- resource "bytebase_environment" "%s" {
- resource_id = "%s"
- title = "%s"
- order = %d
- environment_tier_policy = "PROTECTED"
- }
- `, identifier, identifier, envName, order)
-}
diff --git a/provider/resource_policy.go b/provider/resource_policy.go
index d9ad87c..70ada04 100644
--- a/provider/resource_policy.go
+++ b/provider/resource_policy.go
@@ -35,7 +35,7 @@ func resourcePolicy() *schema.Resource {
Required: true,
ValidateDiagFunc: internal.ResourceNameValidation(
// workspace policy
- regexp.MustCompile("^workspaces/-$"),
+ regexp.MustCompile(fmt.Sprintf("^%s$", internal.WorkspaceName)),
// environment policy
regexp.MustCompile(fmt.Sprintf("^%s%s$", internal.EnvironmentNamePrefix, internal.ResourceIDPattern)),
// instance policy
@@ -82,8 +82,11 @@ func resourcePolicy() *schema.Resource {
func resourcePolicyRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
c := m.(api.Client)
- parent := fmt.Sprintf("%s/%s%s", d.Get("parent").(string), internal.PolicyNamePrefix, d.Get("type").(string))
- policy, err := c.GetPolicy(ctx, parent)
+ policyName := fmt.Sprintf("%s/%s%s", d.Get("parent").(string), internal.PolicyNamePrefix, d.Get("type").(string))
+ if strings.HasPrefix(policyName, internal.WorkspaceName) {
+ policyName = strings.TrimPrefix(policyName, fmt.Sprintf("%s/", internal.WorkspaceName))
+ }
+ policy, err := c.GetPolicy(ctx, policyName)
if err != nil {
return diag.FromErr(err)
}
@@ -109,6 +112,9 @@ func resourcePolicyCreate(ctx context.Context, d *schema.ResourceData, m interfa
c := m.(api.Client)
policyName := fmt.Sprintf("%s/%s%s", d.Get("parent").(string), internal.PolicyNamePrefix, d.Get("type").(string))
+ if strings.HasPrefix(policyName, internal.WorkspaceName) {
+ policyName = strings.TrimPrefix(policyName, fmt.Sprintf("%s/", internal.WorkspaceName))
+ }
inheritFromParent := d.Get("inherit_from_parent").(bool)
enforce := d.Get("enforce").(bool)
diff --git a/provider/resource_setting.go b/provider/resource_setting.go
index e5543a1..a6f71a3 100644
--- a/provider/resource_setting.go
+++ b/provider/resource_setting.go
@@ -36,12 +36,14 @@ func resourceSetting() *schema.Resource {
string(api.SettingWorkspaceProfile),
string(api.SettingDataClassification),
string(api.SettingSemanticTypes),
+ string(api.SettingEnvironment),
}, false),
},
- "approval_flow": getWorkspaceApprovalSetting(false),
- "workspace_profile": getWorkspaceProfileSetting(false),
- "classification": getClassificationSetting(false),
- "semantic_types": getSemanticTypesSetting(false),
+ "approval_flow": getWorkspaceApprovalSetting(false),
+ "workspace_profile": getWorkspaceProfileSetting(false),
+ "classification": getClassificationSetting(false),
+ "semantic_types": getSemanticTypesSetting(false),
+ "environment_setting": getEnvironmentSetting(false),
},
}
}
@@ -100,6 +102,16 @@ func resourceSettingUpsert(ctx context.Context, d *schema.ResourceData, m interf
SemanticTypeSettingValue: classificationSetting,
},
}
+ case api.SettingEnvironment:
+ environmentSetting, err := convertToV1EnvironmentSetting(d)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ setting.Value = &v1pb.Value{
+ Value: &v1pb.Value_EnvironmentSetting{
+ EnvironmentSetting: environmentSetting,
+ },
+ }
default:
return diag.FromErr(errors.Errorf("Unsupport setting: %v", name))
}
@@ -280,42 +292,19 @@ func convertToV1ApprovalSetting(d *schema.ResourceData) (*v1pb.WorkspaceApproval
}
for _, step := range stepList {
- rawStep := step.(map[string]interface{})
- stepType := api.ApprovalNodeType(rawStep["type"].(string))
- node := rawStep["node"].(string)
-
- approvalNode := &v1pb.ApprovalNode{
- Type: v1pb.ApprovalNode_ANY_IN_GROUP,
- }
- switch stepType {
- case api.ApprovalNodeTypeRole:
- if !strings.HasPrefix(node, "roles/") {
- return nil, errors.Errorf("invalid role name: %v, role name should in roles/{role} format", node)
- }
- approvalNode.Payload = &v1pb.ApprovalNode_Role{
- Role: node,
- }
- case api.ApprovalNodeTypeGroup:
- group, ok := v1pb.ApprovalNode_GroupValue_value[node]
- if !ok {
- return nil, errors.Errorf(
- "invalid group: %v, group should be one of: %s, %s, %s, %s",
- node,
- v1pb.ApprovalNode_WORKSPACE_OWNER.String(),
- v1pb.ApprovalNode_WORKSPACE_DBA.String(),
- v1pb.ApprovalNode_PROJECT_OWNER.String(),
- v1pb.ApprovalNode_PROJECT_MEMBER.String(),
- )
- }
- approvalNode.Payload = &v1pb.ApprovalNode_GroupValue_{
- GroupValue: v1pb.ApprovalNode_GroupValue(group),
- }
+ approvalStep := &v1pb.ApprovalStep{
+ Type: v1pb.ApprovalStep_ANY,
}
- approvalStep := &v1pb.ApprovalStep{
- Type: v1pb.ApprovalStep_ANY,
- Nodes: []*v1pb.ApprovalNode{approvalNode},
+ rawStep := step.(map[string]interface{})
+ role := rawStep["role"].(string)
+ if !strings.HasPrefix(role, "roles/") {
+ return nil, errors.Errorf("invalid role name: %v, role name should in roles/{role} format", role)
}
+ approvalStep.Nodes = append(approvalStep.Nodes, &v1pb.ApprovalNode{
+ Type: v1pb.ApprovalNode_ANY_IN_GROUP,
+ Role: role,
+ })
approvalRule.Template.Flow.Steps = append(approvalRule.Template.Flow.Steps, approvalStep)
}
@@ -326,6 +315,39 @@ func convertToV1ApprovalSetting(d *schema.ResourceData) (*v1pb.WorkspaceApproval
return workspaceApprovalSetting, nil
}
+func convertToV1EnvironmentSetting(d *schema.ResourceData) (*v1pb.EnvironmentSetting, error) {
+ rawList, ok := d.Get("environment_setting").([]interface{})
+ if !ok || len(rawList) != 1 {
+ return nil, errors.Errorf("invalid environment_setting")
+ }
+
+ raw := rawList[0].(map[string]interface{})
+ environments := raw["environment"].([]interface{})
+
+ environmentSetting := &v1pb.EnvironmentSetting{}
+ for _, environment := range environments {
+ rawEnv := environment.(map[string]interface{})
+ id := rawEnv["id"].(string)
+ protected := rawEnv["protected"].(bool)
+ if !internal.ResourceIDRegex.MatchString(id) {
+ return nil, errors.Errorf("invalid environment id")
+ }
+ v1Env := &v1pb.EnvironmentSetting_Environment{
+ Id: id,
+ Title: rawEnv["title"].(string),
+ Color: rawEnv["color"].(string),
+ Tags: map[string]string{
+ "protected": "protected",
+ },
+ }
+ if !protected {
+ v1Env.Tags["protected"] = "unprotected"
+ }
+ environmentSetting.Environments = append(environmentSetting.Environments, v1Env)
+ }
+ return environmentSetting, nil
+}
+
func convertToV1SemanticTypeSetting(d *schema.ResourceData) (*v1pb.SemanticTypeSetting, error) {
set, ok := d.Get("semantic_types").(*schema.Set)
if !ok {