diff --git a/common/common_volcengine_version.go b/common/common_volcengine_version.go index b2c66c34..c3aec012 100644 --- a/common/common_volcengine_version.go +++ b/common/common_volcengine_version.go @@ -2,5 +2,5 @@ package common const ( TerraformProviderName = "terraform-provider-volcengine" - TerraformProviderVersion = "0.0.101" + TerraformProviderVersion = "0.0.102" ) diff --git a/docgen/main.go b/docgen/main.go index 54f1b378..e7218b06 100644 --- a/docgen/main.go +++ b/docgen/main.go @@ -146,6 +146,7 @@ var resourceKeys = map[string]string{ "privatelink": "PRIVATELINK", "redis": "REDIS", "tls": "TLS", + "cloudfs": "CLOUDFS", } type Products struct { diff --git a/example/cloudfsAccess/main.tf b/example/cloudfsAccess/main.tf new file mode 100644 index 00000000..76bed025 --- /dev/null +++ b/example/cloudfsAccess/main.tf @@ -0,0 +1,7 @@ +resource "volcengine_cloudfs_access" "foo1" { + fs_name = "tftest2" + + subnet_id = "subnet-13fca1crr5d6o3n6nu46cyb5m" + security_group_id = "sg-rrv1klfg5s00v0x578mx14m" + vpc_route_enabled = false +} \ No newline at end of file diff --git a/example/cloudfsFileSystem/main.tf b/example/cloudfsFileSystem/main.tf new file mode 100644 index 00000000..52a9741d --- /dev/null +++ b/example/cloudfsFileSystem/main.tf @@ -0,0 +1,31 @@ +resource "volcengine_cloudfs_file_system" "foo" { + fs_name = "tffile" + zone_id = "cn-beijing-b" + cache_plan = "T2" + mode = "HDFS_MODE" + read_only = true + + subnet_id = "subnet-13fca1crr5d6o3n6nu46cyb5m" + security_group_id = "sg-rrv1klfg5s00v0x578mx14m" + cache_capacity_tib = 10 + vpc_route_enabled = true + + tos_bucket = "tfacc" + tos_prefix = "pre/" +} + + +resource "volcengine_cloudfs_file_system" "foo1" { + fs_name = "tffileu" + zone_id = "cn-beijing-b" + cache_plan = "T2" + mode = "ACC_MODE" + read_only = true + + subnet_id = "subnet-13fca1crr5d6o3n6nu46cyb5m" + security_group_id = "sg-rrv1klfg5s00v0x578mx14m" + cache_capacity_tib = 15 + vpc_route_enabled = false + + tos_bucket = "tfacc" +} \ No newline at end of file diff --git a/example/cloudfsNamespace/main.tf b/example/cloudfsNamespace/main.tf new file mode 100644 index 00000000..ecc77012 --- /dev/null +++ b/example/cloudfsNamespace/main.tf @@ -0,0 +1,5 @@ +resource "volcengine_cloudfs_namespace" "foo" { + fs_name = "tf-test-fs" + tos_bucket = "tf-test" + read_only = true +} diff --git a/example/dataCloudfsAccesses/main.tf b/example/dataCloudfsAccesses/main.tf new file mode 100644 index 00000000..7c3248ca --- /dev/null +++ b/example/dataCloudfsAccesses/main.tf @@ -0,0 +1,3 @@ +data "volcengine_cloudfs_accesses" "default" { + fs_name = "tftest2" +} \ No newline at end of file diff --git a/example/dataCloudfsFileSystems/main.tf b/example/dataCloudfsFileSystems/main.tf new file mode 100644 index 00000000..745788e3 --- /dev/null +++ b/example/dataCloudfsFileSystems/main.tf @@ -0,0 +1,3 @@ +data "volcengine_cloudfs_file_systems" "default" { + fs_name = "tftest2" +} \ No newline at end of file diff --git a/example/dataCloudfsNamespaces/main.tf b/example/dataCloudfsNamespaces/main.tf new file mode 100644 index 00000000..f04385cd --- /dev/null +++ b/example/dataCloudfsNamespaces/main.tf @@ -0,0 +1,4 @@ +data "volcengine_cloudfs_namespaces" "default" { + fs_name = "tf-test-fs" + ns_id = "1801439850948****" +} \ No newline at end of file diff --git a/example/dataCloudfsNsQuotas/main.tf b/example/dataCloudfsNsQuotas/main.tf new file mode 100644 index 00000000..9c0fe5f4 --- /dev/null +++ b/example/dataCloudfsNsQuotas/main.tf @@ -0,0 +1,3 @@ +data "volcengine_cloudfs_ns_quotas" "default" { + fs_names = ["tffile", "tftest2"] +} \ No newline at end of file diff --git a/example/dataCloudfsQuotas/main.tf b/example/dataCloudfsQuotas/main.tf new file mode 100644 index 00000000..161923b9 --- /dev/null +++ b/example/dataCloudfsQuotas/main.tf @@ -0,0 +1,2 @@ +data "volcengine_cloudfs_quotas" "default" { +} \ No newline at end of file diff --git a/volcengine/cloudfs/cloudfs_access/data_source_volcengine_cloudfs_accesses.go b/volcengine/cloudfs/cloudfs_access/data_source_volcengine_cloudfs_accesses.go new file mode 100644 index 00000000..fbf1e073 --- /dev/null +++ b/volcengine/cloudfs/cloudfs_access/data_source_volcengine_cloudfs_accesses.go @@ -0,0 +1,98 @@ +package cloudfs_access + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +func DataSourceVolcengineCloudfsAccesses() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcengineCloudfsAccessesRead, + Schema: map[string]*schema.Schema{ + "fs_name": { + Type: schema.TypeString, + Required: true, + Description: "The name of file system.", + }, + "output_file": { + Type: schema.TypeString, + Optional: true, + Description: "File name where to save data source results.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total count of query.", + }, + "accesses": { + Description: "The collection of query.", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "fs_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of cloud fs.", + }, + "access_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of access.", + }, + "access_account_id": { + Type: schema.TypeInt, + Computed: true, + Description: "The account id of access.", + }, + "access_service_name": { + Type: schema.TypeString, + Computed: true, + Description: "The service name of access.", + }, + "vpc_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of vpc.", + }, + "subnet_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of subnet.", + }, + "security_group_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of security group.", + }, + "is_default": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether is default access.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "The creation time.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of access.", + }, + "vpc_route_enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to enable all vpc route.", + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcengineCloudfsAccessesRead(d *schema.ResourceData, meta interface{}) error { + service := NewService(meta.(*ve.SdkClient)) + return ve.DefaultDispatcher().Data(service, d, DataSourceVolcengineCloudfsAccesses()) +} diff --git a/volcengine/cloudfs/cloudfs_access/resource_volcengine_cloudfs_access.go b/volcengine/cloudfs/cloudfs_access/resource_volcengine_cloudfs_access.go new file mode 100644 index 00000000..9f43f716 --- /dev/null +++ b/volcengine/cloudfs/cloudfs_access/resource_volcengine_cloudfs_access.go @@ -0,0 +1,157 @@ +package cloudfs_access + +import ( + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +CloudFs Access can be imported using the FsName:AccessId, e.g. +``` +$ terraform import volcengine_cloudfs_file_system.default tfname:access-**rdgmedx3fow +``` + +*/ + +func ResourceVolcengineCloudfsAccess() *schema.Resource { + resource := &schema.Resource{ + Create: resourceVolcengineCloudfsAccessCreate, + Read: resourceVolcengineCloudfsAccessRead, + Update: resourceVolcengineCloudfsAccessUpdate, + Delete: resourceVolcengineCloudfsAccessDelete, + Importer: &schema.ResourceImporter{ + State: func(data *schema.ResourceData, i interface{}) ([]*schema.ResourceData, error) { + items := strings.Split(data.Id(), ":") + if len(items) != 2 { + return []*schema.ResourceData{data}, fmt.Errorf("import id must split with ':'") + } + if err := data.Set("fs_name", items[0]); err != nil { + return []*schema.ResourceData{data}, err + } + if err := data.Set("access_id", items[1]); err != nil { + return []*schema.ResourceData{data}, err + } + return []*schema.ResourceData{data}, nil + }, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "fs_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The name of file system.", + }, + "access_account_id": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ForceNew: true, + Description: "The account id of access.", + }, + "access_iam_role": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The iam role of access. If the VPC of another account is attached, " + + "the other account needs to create a role with CFSCacheAccess permission, " + + "and enter the role name as a parameter.", + }, + "subnet_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The id of subnet.", + }, + "security_group_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The id of security group.", + }, + "vpc_route_enabled": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether enable all vpc route.", + }, + + "status": { + Type: schema.TypeString, + Computed: true, + Description: "Status of access.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "The creation time.", + }, + "is_default": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether is default access.", + }, + "access_service_name": { + Type: schema.TypeString, + Computed: true, + Description: "The service name of access.", + }, + "vpc_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of vpc.", + }, + "access_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of access.", + }, + }, + } + return resource +} + +func resourceVolcengineCloudfsAccessCreate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Create(service, d, ResourceVolcengineCloudfsAccess()) + if err != nil { + return fmt.Errorf("error on creating access %q, %s", d.Id(), err) + } + return resourceVolcengineCloudfsAccessRead(d, meta) +} + +func resourceVolcengineCloudfsAccessRead(d *schema.ResourceData, meta interface{}) (err error) { + service := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Read(service, d, ResourceVolcengineCloudfsAccess()) + if err != nil { + return fmt.Errorf("error on reading access %q, %s", d.Id(), err) + } + return err +} + +func resourceVolcengineCloudfsAccessUpdate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Update(service, d, ResourceVolcengineCloudfsAccess()) + if err != nil { + return fmt.Errorf("error on updating access %q, %s", d.Id(), err) + } + return resourceVolcengineCloudfsAccessRead(d, meta) +} + +func resourceVolcengineCloudfsAccessDelete(d *schema.ResourceData, meta interface{}) (err error) { + service := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Delete(service, d, ResourceVolcengineCloudfsAccess()) + if err != nil { + return fmt.Errorf("error on deleting access %q, %s", d.Id(), err) + } + return err +} diff --git a/volcengine/cloudfs/cloudfs_access/service_volcengine_cloudfs_access.go b/volcengine/cloudfs/cloudfs_access/service_volcengine_cloudfs_access.go new file mode 100644 index 00000000..8aaee309 --- /dev/null +++ b/volcengine/cloudfs/cloudfs_access/service_volcengine_cloudfs_access.go @@ -0,0 +1,284 @@ +package cloudfs_access + +import ( + "errors" + "fmt" + "github.com/volcengine/volcengine-go-sdk/service/vpc" + "github.com/volcengine/volcengine-go-sdk/volcengine" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" +) + +type VolcengineCloudfsAccessService struct { + Client *ve.SdkClient +} + +func NewService(c *ve.SdkClient) *VolcengineCloudfsAccessService { + return &VolcengineCloudfsAccessService{ + Client: c, + } +} + +func (s *VolcengineCloudfsAccessService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineCloudfsAccessService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + return ve.WithSimpleQuery(m, func(condition map[string]interface{}) ([]interface{}, error) { + action := "ListAccess" + logger.Debug(logger.ReqFormat, action, condition) + if condition == nil { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), nil) + if err != nil { + return data, err + } + } else { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &condition) + if err != nil { + return data, err + } + } + logger.Debug(logger.RespFormat, action, resp) + results, err = ve.ObtainSdkValue("Result.Items", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.Items is not Slice") + } + return data, err + }) +} + +func (s *VolcengineCloudfsAccessService) ReadResource(resourceData *schema.ResourceData, id string) (data map[string]interface{}, err error) { + var ( + results []interface{} + ok bool + ) + if id == "" { + id = s.ReadResourceId(resourceData.Id()) + } + + ids := strings.Split(id, ":") + + req := map[string]interface{}{ + "FsName": ids[0], + } + results, err = s.ReadResources(req) + if err != nil { + return nil, err + } + for _, v := range results { + if data, ok = v.(map[string]interface{}); ok { + if data["AccessId"] == ids[1] { + return data, nil + } + } + } + return data, fmt.Errorf("access not exist: %s", id) +} + +func (s *VolcengineCloudfsAccessService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return &resource.StateChangeConf{ + Pending: []string{}, + Delay: 1 * time.Second, + MinTimeout: 1 * time.Second, + Target: target, + Timeout: timeout, + Refresh: func() (result interface{}, state string, err error) { + var ( + d map[string]interface{} + status interface{} + failStates []string + ) + failStates = append(failStates, "ERROR", "DOWN", "CREATE_FAILED", + "DELETE_FAILED", "ENABLE_VPC_ROUTE_FAILED", "DISABLE_VPC_ROUTE_FAILED") + d, err = s.ReadResource(resourceData, id) + if err != nil { + return nil, "", err + } + status, err = ve.ObtainSdkValue("Status", d) + if err != nil { + return nil, "", err + } + for _, v := range failStates { + if v == status.(string) { + return nil, "", fmt.Errorf("Access status error, status:%s", status.(string)) + } + } + return d, status.(string), err + }, + } + +} + +func (VolcengineCloudfsAccessService) WithResourceResponseHandlers(data map[string]interface{}) []ve.ResourceResponseHandler { + return []ve.ResourceResponseHandler{} +} + +func (s *VolcengineCloudfsAccessService) describeTask(taskId interface{}) (string, error) { + req := map[string]interface{}{ + "TaskId": taskId, + } + resp, err := s.Client.UniversalClient.DoCall(getUniversalInfo("DescribeTask"), &req) + if err != nil { + return "", err + } + logger.Debug(logger.RespFormat, "DescribeTask", req, *resp) + id, err := ve.ObtainSdkValue("Result.AccessId", *resp) + if err != nil { + return "", err + } + return id.(string), nil +} + +func (s *VolcengineCloudfsAccessService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "EnableCacheAccess", + ConvertMode: ve.RequestConvertAll, + ContentType: ve.ContentTypeJson, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + if v, ok := (*call.SdkParam)["SubnetId"]; ok { + subnetAttr, err := client.VpcClient.DescribeSubnetAttributes(&vpc.DescribeSubnetAttributesInput{ + SubnetId: volcengine.String(v.(string))}) + if err != nil { + return false, err + } + (*call.SdkParam)["VpcId"] = *subnetAttr.VpcId + } + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getPostUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + // 通过 taskId 获取对应的 AccessId + taskId, err := ve.ObtainSdkValue("Result.TaskId", *resp) + if err != nil { + return err + } + accessId, err := s.describeTask(taskId) + if err != nil { + return err + } + + d.SetId(fmt.Sprintf("%s:%s", d.Get("fs_name"), accessId)) + return nil + }, + Refresh: &ve.StateRefresh{ + Target: []string{"UP"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + }, + LockId: func(d *schema.ResourceData) string { + return d.Get("fs_name").(string) + }, + }, + } + return []ve.Callback{callback} + +} + +func (s *VolcengineCloudfsAccessService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + + if resourceData.HasChange("vpc_route_enabled") { + _, n := resourceData.GetChange("vpc_route_enabled") + action := "DisableVpcRoute" + if n.(bool) { + action = "EnableVpcRoute" + } + enableCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: action, + ConvertMode: ve.RequestConvertIgnore, + ContentType: ve.ContentTypeJson, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["AccessId"] = strings.Split(resourceData.Id(), ":")[1] + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getPostUniversalInfo(call.Action), call.SdkParam) + }, + Refresh: &ve.StateRefresh{ + Target: []string{"UP"}, + Timeout: resourceData.Timeout(schema.TimeoutUpdate), + }, + LockId: func(d *schema.ResourceData) string { + return d.Get("fs_name").(string) + }, + }, + } + callbacks = append(callbacks, enableCallback) + } + return callbacks +} + +func (s *VolcengineCloudfsAccessService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "DisableCacheAccess", + ConvertMode: ve.RequestConvertIgnore, + SdkParam: &map[string]interface{}{ + "AccessId": strings.Split(resourceData.Id(), ":")[1], + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getPostUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + return ve.CheckResourceUtilRemoved(d, s.ReadResource, 10*time.Minute) + }, + LockId: func(d *schema.ResourceData) string { + return d.Get("fs_name").(string) + }, + }, + } + return []ve.Callback{callback} +} + +func (s *VolcengineCloudfsAccessService) DatasourceResources(*schema.ResourceData, *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{ + IdField: "AccessId", + CollectField: "accesses", + } +} + +func (s *VolcengineCloudfsAccessService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "cfs", + Version: "2022-02-02", + HttpMethod: ve.GET, + ContentType: ve.Default, + Action: actionName, + } +} + +func getPostUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "cfs", + Version: "2022-02-02", + HttpMethod: ve.POST, + ContentType: ve.ApplicationJSON, + Action: actionName, + } +} diff --git a/volcengine/cloudfs/cloudfs_file_system/data_source_volcengine_cloudfs_file_systems.go b/volcengine/cloudfs/cloudfs_file_system/data_source_volcengine_cloudfs_file_systems.go new file mode 100644 index 00000000..c5cfc226 --- /dev/null +++ b/volcengine/cloudfs/cloudfs_file_system/data_source_volcengine_cloudfs_file_systems.go @@ -0,0 +1,130 @@ +package cloudfs_file_system + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +func DataSourceVolcengineCloudfsFileSystems() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcengineCloudfsFileSystemsRead, + Schema: map[string]*schema.Schema{ + "fs_name": { + Type: schema.TypeString, + Optional: true, + Description: "The name of file system.", + }, + "meta_status": { + Type: schema.TypeString, + Optional: true, + Description: "The status of file system.", + }, + "name_regex": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsValidRegExp, + Description: "A Name Regex of cloudfs.", + }, + "output_file": { + Type: schema.TypeString, + Optional: true, + Description: "File name where to save data source results.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total count of query.", + }, + "file_systems": { + Description: "The collection of query.", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of file system.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of file system.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of file system.", + }, + "region_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of region.", + }, + "zone_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of zone.", + }, + "cache_plan": { + Type: schema.TypeString, + Computed: true, + Description: "The plan of cache.", + }, + "cache_capacity_tib": { + Type: schema.TypeInt, + Computed: true, + Description: "The capacity of cache.", + }, + "vpc_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of vpc.", + }, + "subnet_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of subnet.", + }, + "security_group_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of security group.", + }, + "mode": { + Type: schema.TypeString, + Computed: true, + Description: "The mode of file system.", + }, + "tos_bucket": { + Type: schema.TypeString, + Computed: true, + Description: "The tos bucket.", + }, + "tos_prefix": { + Type: schema.TypeString, + Computed: true, + Description: "The tos prefix.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "The creation time.", + }, + "mount_point": { + Type: schema.TypeString, + Computed: true, + Description: "The point mount.", + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcengineCloudfsFileSystemsRead(d *schema.ResourceData, meta interface{}) error { + service := NewService(meta.(*ve.SdkClient)) + return ve.DefaultDispatcher().Data(service, d, DataSourceVolcengineCloudfsFileSystems()) +} diff --git a/volcengine/cloudfs/cloudfs_file_system/resource_volcengine_cloudfs_file_system.go b/volcengine/cloudfs/cloudfs_file_system/resource_volcengine_cloudfs_file_system.go new file mode 100644 index 00000000..bc8eea9f --- /dev/null +++ b/volcengine/cloudfs/cloudfs_file_system/resource_volcengine_cloudfs_file_system.go @@ -0,0 +1,208 @@ +package cloudfs_file_system + +import ( + "fmt" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +CloudFileSystem can be imported using the FsName, e.g. +``` +$ terraform import volcengine_cloudfs_file_system.default tfname +``` + +*/ + +func ResourceVolcengineCloudfsFileSystem() *schema.Resource { + resource := &schema.Resource{ + Create: resourceVolcengineCloudfsFileSystemCreate, + Read: resourceVolcengineCloudfsFileSystemRead, + Update: resourceVolcengineCloudfsFileSystemUpdate, + Delete: resourceVolcengineCloudfsFileSystemDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "fs_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The name of file system.", + }, + "zone_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The id of zone.", + }, + "cache_plan": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"T2", "T4", "DISABLED"}, false), + Description: "The cache plan. The value can be `DISABLED` or `T2` or `T4`. " + + "When expanding the cache size, the cache plan should remain the same. For data lakes, cache must be enabled.", + }, + "cache_capacity_tib": { + Type: schema.TypeInt, + Optional: true, + DiffSuppressFunc: diffCache, + Description: "The capacity of cache. This parameter is required when cache acceleration is enabled.", + }, + "subnet_id": { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: diffCache, + Description: "The id of subnet. This parameter is required when cache acceleration is enabled.", + }, + "security_group_id": { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: diffCache, + Description: "The id of security group. This parameter is required when cache acceleration is enabled.", + }, + "vpc_route_enabled": { + Type: schema.TypeBool, + Optional: true, + DiffSuppressFunc: diffCache, + Description: "Whether enable all vpc route.", + }, + "mode": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"HDFS_MODE", "ACC_MODE"}, false), + Description: "The mode of file system. The value can be `HDFS_MODE` or `ACC_MODE`.", + }, + "tos_bucket": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The tos bucket. When importing ACC_MODE resources, this attribute will not be imported.", + }, + "tos_prefix": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The tos prefix. Must not start with /, but must end with /, such as prefix/. When it is empty, it means the root path. " + + "When importing ACC_MODE resources, this attribute will not be imported.", + }, + "tos_account_id": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: "When a data lake scenario instance chooses to associate a bucket under another account, you need to set the ID of the account. " + + "When importing resources, this attribute will not be imported.", + }, + "tos_ak": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The tos ak. When the data lake scenario chooses to associate buckets under other accounts, need to set the Access Key ID of the account. " + + "When importing resources, this attribute will not be imported.", + }, + "tos_sk": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The tos sk. When the data lake scenario chooses to associate buckets under other accounts, need to set the Secret Access Key of the account. " + + "When importing resources, this attribute will not be imported.", + }, + "read_only": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Description: "Whether the Namespace created automatically when mounting the TOS Bucket is read-only. " + + "When importing resources, this attribute will not be imported. " + + "If this attribute is set, please use lifecycle and ignore_changes ignore changes in fields.", + }, + + "status": { + Type: schema.TypeString, + Computed: true, + Description: "Status of file system.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "The creation time.", + }, + "mount_point": { + Type: schema.TypeString, + Computed: true, + Description: "The point mount.", + }, + "vpc_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of vpc.", + }, + "access_id": { + Type: schema.TypeString, + Computed: true, + Description: "The default vpc access id.", + }, + }, + } + return resource +} + +func resourceVolcengineCloudfsFileSystemCreate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Create(service, d, ResourceVolcengineCloudfsFileSystem()) + if err != nil { + return fmt.Errorf("error on creating file system %q, %s", d.Id(), err) + } + return resourceVolcengineCloudfsFileSystemRead(d, meta) +} + +func resourceVolcengineCloudfsFileSystemRead(d *schema.ResourceData, meta interface{}) (err error) { + service := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Read(service, d, ResourceVolcengineCloudfsFileSystem()) + if err != nil { + return fmt.Errorf("error on reading file system %q, %s", d.Id(), err) + } + return err +} + +func resourceVolcengineCloudfsFileSystemUpdate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Update(service, d, ResourceVolcengineCloudfsFileSystem()) + if err != nil { + return fmt.Errorf("error on updating file system %q, %s", d.Id(), err) + } + return resourceVolcengineCloudfsFileSystemRead(d, meta) +} + +func resourceVolcengineCloudfsFileSystemDelete(d *schema.ResourceData, meta interface{}) (err error) { + service := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Delete(service, d, ResourceVolcengineCloudfsFileSystem()) + if err != nil { + return fmt.Errorf("error on deleting file system %q, %s", d.Id(), err) + } + return err +} + +func diffCache(k, old, new string, d *schema.ResourceData) bool { + // 禁用缓存时,不起作用 + if d.Get("cache_plan").(string) == "DISABLED" { + return true + } + // cache_plan 没有发生变化,只是扩容,忽略变更 + if d.Id() != "" && !d.HasChange("cache_plan") { + if k == "subnet_id" || k == "security_group_id" { + return true + } + } + return false +} diff --git a/volcengine/cloudfs/cloudfs_file_system/service_volcengine_cloudfs_file_system.go b/volcengine/cloudfs/cloudfs_file_system/service_volcengine_cloudfs_file_system.go new file mode 100644 index 00000000..22e629d5 --- /dev/null +++ b/volcengine/cloudfs/cloudfs_file_system/service_volcengine_cloudfs_file_system.go @@ -0,0 +1,413 @@ +package cloudfs_file_system + +import ( + "errors" + "fmt" + "github.com/volcengine/volcengine-go-sdk/service/vpc" + "github.com/volcengine/volcengine-go-sdk/volcengine" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" +) + +type VolcengineCloudfsFileSystemService struct { + Client *ve.SdkClient +} + +func NewService(c *ve.SdkClient) *VolcengineCloudfsFileSystemService { + return &VolcengineCloudfsFileSystemService{ + Client: c, + } +} + +func (s *VolcengineCloudfsFileSystemService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineCloudfsFileSystemService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + return ve.WithPageNumberQuery(m, "PageSize", "PageNumber", 50, 1, func(condition map[string]interface{}) ([]interface{}, error) { + action := "ListFs" + logger.Debug(logger.ReqFormat, action, condition) + if condition == nil { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), nil) + if err != nil { + return data, err + } + } else { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &condition) + if err != nil { + return data, err + } + } + logger.Debug(logger.RespFormat, action, resp) + results, err = ve.ObtainSdkValue("Result.Items", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.Items is not Slice") + } + return data, err + }) +} + +func (s *VolcengineCloudfsFileSystemService) ReadResource(resourceData *schema.ResourceData, id string) (data map[string]interface{}, err error) { + var ( + results []interface{} + ok bool + ) + if id == "" { + id = s.ReadResourceId(resourceData.Id()) + } + req := map[string]interface{}{ + "FsName": id, + } + results, err = s.ReadResources(req) + if err != nil { + return data, err + } + for _, v := range results { + if data, ok = v.(map[string]interface{}); !ok { + return data, errors.New("Value is not map ") + } + } + if len(data) == 0 { + return data, fmt.Errorf("File System %s not exist ", id) + } + + // 针对数据湖的字段单独进行处理,无法读取出来,只能使用用户原先的参数进行替换 + if data["Mode"] == "ACC_MODE" { + if tosBucket := resourceData.Get("tos_bucket"); len(tosBucket.(string)) > 0 { + data["TosBucket"] = tosBucket + } + if tosPrefix := resourceData.Get("tos_prefix"); len(tosPrefix.(string)) > 0 { + data["TosPrefix"] = tosPrefix + } + if tosAk := resourceData.Get("tos_ak"); len(tosAk.(string)) > 0 { + data["TosAk"] = tosAk + } + if tosSk := resourceData.Get("tos_sk"); len(tosSk.(string)) > 0 { + data["TosSk"] = tosSk + } + data["TosAccountId"] = resourceData.Get("tos_account_id") + } + + // get cache access id + defaultAccess, err := s.getDefaultAccess(id) + if err != nil { + return nil, err + } + if defaultAccess != nil { + data["AccessId"] = defaultAccess["AccessId"] + data["VpcRouteEnabled"] = defaultAccess["VpcRouteEnabled"] + } + return data, err +} + +func (s *VolcengineCloudfsFileSystemService) getDefaultAccess(fsName interface{}) (map[string]interface{}, error) { + result, err := s.Client.UniversalClient.DoCall(getUniversalInfo("ListAccess"), &map[string]interface{}{ + "FsName": fsName, + }) + if err != nil { + return nil, err + } + logger.Debug(logger.ReqFormat, "ListAccess", *result) + accesses := (*result)["Result"].(map[string]interface{})["Items"].([]interface{}) + for _, access := range accesses { + accessMap := access.(map[string]interface{}) + if v, ok := accessMap["IsDefault"]; ok { + if v.(bool) { + return accessMap, nil + } + } + } + return nil, nil +} + +func (s *VolcengineCloudfsFileSystemService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return &resource.StateChangeConf{ + Pending: []string{}, + Delay: 1 * time.Second, + MinTimeout: 1 * time.Second, + Target: target, + Timeout: timeout, + Refresh: func() (result interface{}, state string, err error) { + var ( + d map[string]interface{} + status interface{} + failStates []string + ) + failStates = append(failStates, "ERROR", "DOWN", "CREATE_FAILED", "ENABLE_CACHE_FAILED", + "SCALE_UP_CACHE_FAILED", "UPDATE_FAILED", "DELETE_FAILED") + d, err = s.ReadResource(resourceData, id) + if err != nil { + return nil, "", err + } + status, err = ve.ObtainSdkValue("Status", d) + if err != nil { + return nil, "", err + } + for _, v := range failStates { + if v == status.(string) { + return nil, "", fmt.Errorf("File System status error, status:%s", status.(string)) + } + } + //注意 返回的第一个参数不能为空 否则会一直等下去 + return d, status.(string), err + }, + } + +} + +func (VolcengineCloudfsFileSystemService) WithResourceResponseHandlers(data map[string]interface{}) []ve.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]ve.ResponseConvert, error) { + return data, map[string]ve.ResponseConvert{ + "CacheCapacityTiB": { + TargetField: "cache_capacity_tib", + }, + "Name": { + TargetField: "fs_name", + }, + }, nil + } + return []ve.ResourceResponseHandler{handler} +} + +func (s *VolcengineCloudfsFileSystemService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "CreateFs", + ConvertMode: ve.RequestConvertAll, + ContentType: ve.ContentTypeJson, + Convert: map[string]ve.RequestConvert{ + "cache_capacity_tib": { + TargetField: "CacheCapacityTiB", + }, + }, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + if v, ok := (*call.SdkParam)["SubnetId"]; ok { + subnetAttr, err := client.VpcClient.DescribeSubnetAttributes(&vpc.DescribeSubnetAttributesInput{ + SubnetId: volcengine.String(v.(string))}) + if err != nil { + return false, err + } + (*call.SdkParam)["VpcId"] = *subnetAttr.VpcId + } + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getPostUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + d.SetId(d.Get("fs_name").(string)) + return nil + }, + Refresh: &ve.StateRefresh{ + Target: []string{"UP"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + }, + }, + } + return []ve.Callback{callback} + +} + +func (s *VolcengineCloudfsFileSystemService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "UpdateFs", + ConvertMode: ve.RequestConvertInConvert, + ContentType: ve.ContentTypeJson, + Convert: map[string]ve.RequestConvert{ + "fs_name": { + ForceGet: true, + }, + "cache_plan": { + ForceGet: true, + }, + "cache_capacity_tib": { + TargetField: "CacheCapacityTiB", + }, + "subnet_id": { + TargetField: "SubnetId", + }, + "security_group_id": { + TargetField: "SecurityGroupId", + }, + }, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + if resourceData.HasChange("cache_plan") { + o, n := resourceData.GetChange("cache_plan") + if strings.Contains(n.(string), "T") && strings.Contains(o.(string), "T") { + return false, fmt.Errorf("cache plan should remain the same") + } + + if n.(string) == "DISABLED" { + return false, fmt.Errorf("cannot disable cache") + } + + if o.(string) == "DISABLED" { + if _, ok := (*call.SdkParam)["SubnetId"]; !ok { + return false, fmt.Errorf("need subnet id") + } + if _, ok := (*call.SdkParam)["SecurityGroupId"]; !ok { + return false, fmt.Errorf("need security group id") + } + if _, ok := (*call.SdkParam)["CacheCapacityTiB"]; !ok { + return false, fmt.Errorf("need cache capacity tib") + } + } + } + + if v, ok := (*call.SdkParam)["SubnetId"]; ok { + subnetAttr, err := client.VpcClient.DescribeSubnetAttributes(&vpc.DescribeSubnetAttributesInput{ + SubnetId: volcengine.String(v.(string))}) + if err != nil { + return false, err + } + (*call.SdkParam)["VpcId"] = *subnetAttr.VpcId + } + + if len(*call.SdkParam) <= 2 { + return false, nil + } + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getPostUniversalInfo(call.Action), call.SdkParam) + }, + Refresh: &ve.StateRefresh{ + Target: []string{"UP"}, + Timeout: resourceData.Timeout(schema.TimeoutUpdate), + }, + }, + } + callbacks = append(callbacks, callback) + + if resourceData.Get("cache_plan") != "DISABLED" && resourceData.HasChange("vpc_route_enabled") { + _, n := resourceData.GetChange("vpc_route_enabled") + action := "DisableVpcRoute" + if n.(bool) { + action = "EnableVpcRoute" + } + enableCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: action, + ConvertMode: ve.RequestConvertIgnore, + ContentType: ve.ContentTypeJson, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + defaultAccess, err := s.getDefaultAccess(d.Get("fs_name")) + if err != nil { + return false, err + } + if defaultAccess == nil { + return false, fmt.Errorf("cannot find default access: %s", d.Id()) + } + (*call.SdkParam)["AccessId"] = defaultAccess["AccessId"] + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getPostUniversalInfo(call.Action), call.SdkParam) + }, + Refresh: &ve.StateRefresh{ + Target: []string{"UP"}, + Timeout: resourceData.Timeout(schema.TimeoutUpdate), + }, + }, + } + callbacks = append(callbacks, enableCallback) + } + return callbacks +} + +func (s *VolcengineCloudfsFileSystemService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "DeleteFs", + ConvertMode: ve.RequestConvertIgnore, + SdkParam: &map[string]interface{}{ + "FsName": resourceData.Id(), + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getPostUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + return ve.CheckResourceUtilRemoved(d, s.ReadResource, 10*time.Minute) + }, + CallError: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall, baseErr error) error { + //出现错误后重试 + return resource.Retry(15*time.Minute, func() *resource.RetryError { + _, callErr := s.ReadResource(d, "") + if callErr != nil { + if ve.ResourceNotFoundError(callErr) { + return nil + } else { + return resource.NonRetryableError(fmt.Errorf("error on reading vpc on delete %q, %w", d.Id(), callErr)) + } + } + _, callErr = call.ExecuteCall(d, client, call) + if callErr == nil { + return nil + } + return resource.RetryableError(callErr) + }) + }, + }, + } + return []ve.Callback{callback} +} + +func (s *VolcengineCloudfsFileSystemService) DatasourceResources(*schema.ResourceData, *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{ + NameField: "Name", + IdField: "Id", + CollectField: "file_systems", + ResponseConverts: map[string]ve.ResponseConvert{ + "CacheCapacityTiB": { + TargetField: "cache_capacity_tib", + }, + }, + } +} + +func (s *VolcengineCloudfsFileSystemService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "cfs", + Version: "2022-02-02", + HttpMethod: ve.GET, + ContentType: ve.Default, + Action: actionName, + } +} + +func getPostUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "cfs", + Version: "2022-02-02", + HttpMethod: ve.POST, + ContentType: ve.ApplicationJSON, + Action: actionName, + } +} diff --git a/volcengine/cloudfs/cloudfs_namespace/data_source_volcengine_cloudfs_namespaces.go b/volcengine/cloudfs/cloudfs_namespace/data_source_volcengine_cloudfs_namespaces.go new file mode 100644 index 00000000..f8b7087f --- /dev/null +++ b/volcengine/cloudfs/cloudfs_namespace/data_source_volcengine_cloudfs_namespaces.go @@ -0,0 +1,93 @@ +package cloudfs_namespace + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +func DataSourceVolcengineCloudfsNamespaces() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcengineCloudfsNamespacesRead, + Schema: map[string]*schema.Schema{ + "fs_name": { + Type: schema.TypeString, + Required: true, + Description: "The name of file system.", + }, + "ns_id": { + Type: schema.TypeString, + Optional: true, + Description: "The id of namespace.", + }, + "tos_bucket": { + Type: schema.TypeString, + Optional: true, + Description: "The name of tos bucket.", + }, + "output_file": { + Type: schema.TypeString, + Optional: true, + Description: "File name where to save data source results.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total count of query.", + }, + "namespaces": { + Description: "The collection of query.", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the namespace.", + }, + "tos_bucket": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the tos bucket.", + }, + "tos_prefix": { + Type: schema.TypeString, + Computed: true, + Description: "The tos prefix.", + }, + "read_only": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether the namespace is read-only.", + }, + "is_my_bucket": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether the tos bucket is your own bucket.", + }, + "service_managed": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether the namespace is the official service for volcengine.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "The creation time of the namespace.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the namespace.", + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcengineCloudfsNamespacesRead(d *schema.ResourceData, meta interface{}) error { + service := NewCloudfsNamespaceService(meta.(*ve.SdkClient)) + return ve.DefaultDispatcher().Data(service, d, DataSourceVolcengineCloudfsNamespaces()) +} diff --git a/volcengine/cloudfs/cloudfs_namespace/resource_volcengine_cloudfs_namespace.go b/volcengine/cloudfs/cloudfs_namespace/resource_volcengine_cloudfs_namespace.go new file mode 100644 index 00000000..e75e2fbd --- /dev/null +++ b/volcengine/cloudfs/cloudfs_namespace/resource_volcengine_cloudfs_namespace.go @@ -0,0 +1,161 @@ +package cloudfs_namespace + +import ( + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +CloudfsNamespace can be imported using the FsName:NsId, e.g. +``` +$ terraform import volcengine_cloudfs_namespace.default tfname:1801439850948**** +``` + +*/ + +func ResourceVolcengineCloudfsNamespace() *schema.Resource { + resource := &schema.Resource{ + Create: resourceVolcengineCloudfsNamespaceCreate, + Read: resourceVolcengineCloudfsNamespaceRead, + Delete: resourceVolcengineCloudfsNamespaceDelete, + Importer: &schema.ResourceImporter{ + State: func(data *schema.ResourceData, i interface{}) ([]*schema.ResourceData, error) { + items := strings.Split(data.Id(), ":") + if len(items) != 2 { + return []*schema.ResourceData{data}, fmt.Errorf("import id must split with ':'") + } + if err := data.Set("fs_name", items[0]); err != nil { + return []*schema.ResourceData{data}, err + } + if err := data.Set("ns_id", items[1]); err != nil { + return []*schema.ResourceData{data}, err + } + return []*schema.ResourceData{data}, nil + }, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "fs_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The name of file system.", + }, + "tos_bucket": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The name of tos bucket.", + }, + "tos_prefix": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The tos prefix. Must not start with /, but must end with /, such as prefix/. When it is empty, it means the root path.", + }, + "tos_account_id": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: "When a data lake scenario instance chooses to associate a bucket under another account, you need to set the ID of the account. " + + "When importing resources, this attribute will not be imported. " + + "If this attribute is set, please use lifecycle and ignore_changes ignore changes in fields.", + }, + "tos_ak": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The tos ak. When the data lake scenario chooses to associate buckets under other accounts, need to set the Access Key ID of the account. " + + "When importing resources, this attribute will not be imported. " + + "If this attribute is set, please use lifecycle and ignore_changes ignore changes in fields.", + }, + "tos_sk": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The tos sk. When the data lake scenario chooses to associate buckets under other accounts, need to set the Secret Access Key of the account. " + + "When importing resources, this attribute will not be imported. " + + "If this attribute is set, please use lifecycle and ignore_changes ignore changes in fields.", + }, + "read_only": { + Type: schema.TypeBool, + Optional: true, + Default: false, + ForceNew: true, + Description: "Whether the namespace is read-only.", + }, + + "ns_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of namespace.", + }, + "is_my_bucket": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether the tos bucket is your own bucket.", + }, + "service_managed": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether the namespace is the official service for volcengine.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "The creation time of the namespace.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the namespace.", + }, + }, + } + return resource +} + +func resourceVolcengineCloudfsNamespaceCreate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewCloudfsNamespaceService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Create(service, d, ResourceVolcengineCloudfsNamespace()) + if err != nil { + return fmt.Errorf("error on creating cloudfs namespace %q, %s", d.Id(), err) + } + return resourceVolcengineCloudfsNamespaceRead(d, meta) +} + +func resourceVolcengineCloudfsNamespaceRead(d *schema.ResourceData, meta interface{}) (err error) { + service := NewCloudfsNamespaceService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Read(service, d, ResourceVolcengineCloudfsNamespace()) + if err != nil { + return fmt.Errorf("error on reading cloudfs namespace %q, %s", d.Id(), err) + } + return err +} + +func resourceVolcengineCloudfsNamespaceUpdate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewCloudfsNamespaceService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Update(service, d, ResourceVolcengineCloudfsNamespace()) + if err != nil { + return fmt.Errorf("error on updating cloudfs namespace %q, %s", d.Id(), err) + } + return resourceVolcengineCloudfsNamespaceRead(d, meta) +} + +func resourceVolcengineCloudfsNamespaceDelete(d *schema.ResourceData, meta interface{}) (err error) { + service := NewCloudfsNamespaceService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Delete(service, d, ResourceVolcengineCloudfsNamespace()) + if err != nil { + return fmt.Errorf("error on deleting cloudfs namespace %q, %s", d.Id(), err) + } + return err +} diff --git a/volcengine/cloudfs/cloudfs_namespace/service_volcengine_cloudfs_namespace.go b/volcengine/cloudfs/cloudfs_namespace/service_volcengine_cloudfs_namespace.go new file mode 100644 index 00000000..f6ad808b --- /dev/null +++ b/volcengine/cloudfs/cloudfs_namespace/service_volcengine_cloudfs_namespace.go @@ -0,0 +1,278 @@ +package cloudfs_namespace + +import ( + "errors" + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" +) + +type VolcengineCloudfsNamespaceService struct { + Client *ve.SdkClient +} + +func NewCloudfsNamespaceService(c *ve.SdkClient) *VolcengineCloudfsNamespaceService { + return &VolcengineCloudfsNamespaceService{ + Client: c, + } +} + +func (s *VolcengineCloudfsNamespaceService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineCloudfsNamespaceService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + return ve.WithPageNumberQuery(m, "PageSize", "PageNumber", 50, 1, func(condition map[string]interface{}) ([]interface{}, error) { + action := "ListNs" + logger.Debug(logger.ReqFormat, action, condition) + if condition == nil { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), nil) + if err != nil { + return data, err + } + } else { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &condition) + if err != nil { + return data, err + } + } + logger.Debug(logger.RespFormat, action, resp) + results, err = ve.ObtainSdkValue("Result.Items", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.Items is not Slice") + } + return data, err + }) +} + +func (s *VolcengineCloudfsNamespaceService) ReadResource(resourceData *schema.ResourceData, namespaceId string) (data map[string]interface{}, err error) { + var ( + results []interface{} + ok bool + ) + if namespaceId == "" { + namespaceId = s.ReadResourceId(resourceData.Id()) + } + + ids := strings.Split(namespaceId, ":") + if len(ids) != 2 { + return map[string]interface{}{}, fmt.Errorf("invalid cloudfs namespace id") + } + req := map[string]interface{}{ + "FsName": ids[0], + "NsId": ids[1], + } + results, err = s.ReadResources(req) + if err != nil { + return data, err + } + for _, v := range results { + if data, ok = v.(map[string]interface{}); !ok { + return data, errors.New("Value is not map ") + } + } + if len(data) == 0 { + return data, fmt.Errorf("cloudfs namespace %s not exist ", namespaceId) + } + + // 针对无法读取的字段单独进行处理,使用用户原先的参数进行替换 + if tosAk := resourceData.Get("tos_ak"); len(tosAk.(string)) > 0 { + data["TosAk"] = tosAk + } + if tosSk := resourceData.Get("tos_sk"); len(tosSk.(string)) > 0 { + data["TosSk"] = tosSk + } + data["TosAccountId"] = resourceData.Get("tos_account_id") + data["NsId"] = ids[1] + + return data, err +} + +func (s *VolcengineCloudfsNamespaceService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return &resource.StateChangeConf{ + Pending: []string{}, + Delay: 1 * time.Second, + MinTimeout: 1 * time.Second, + Target: target, + Timeout: timeout, + Refresh: func() (result interface{}, state string, err error) { + var ( + d map[string]interface{} + status interface{} + failStates []string + ) + failStates = append(failStates, "ERROR", "DOWN", "CREATE_FAILED", "DELETE_FAILED") + d, err = s.ReadResource(resourceData, id) + if err != nil { + return nil, "", err + } + status, err = ve.ObtainSdkValue("Status", d) + if err != nil { + return nil, "", err + } + for _, v := range failStates { + if v == status.(string) { + return nil, "", fmt.Errorf("cloudfs namespace status error, status:%s", status.(string)) + } + } + //注意 返回的第一个参数不能为空 否则会一直等下去 + return d, status.(string), err + }, + } + +} + +func (VolcengineCloudfsNamespaceService) WithResourceResponseHandlers(data map[string]interface{}) []ve.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]ve.ResponseConvert, error) { + return data, nil, nil + } + return []ve.ResourceResponseHandler{handler} +} + +func (s *VolcengineCloudfsNamespaceService) describeTask(taskId interface{}) (string, error) { + req := map[string]interface{}{ + "TaskId": taskId, + } + resp, err := s.Client.UniversalClient.DoCall(getUniversalInfo("DescribeTask"), &req) + if err != nil { + return "", err + } + logger.Debug(logger.RespFormat, "DescribeTask", req, *resp) + id, err := ve.ObtainSdkValue("Result.Id", *resp) + if err != nil { + return "", err + } + return id.(string), nil +} + +func (s *VolcengineCloudfsNamespaceService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "CreateNs", + ConvertMode: ve.RequestConvertAll, + ContentType: ve.ContentTypeJson, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getPostUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + // 通过 taskId 获取对应的 AccessId + taskId, err := ve.ObtainSdkValue("Result.TaskId", *resp) + if err != nil { + return err + } + nsId, err := s.describeTask(taskId) + if err != nil { + return err + } + + d.SetId(fmt.Sprintf("%s:%s", d.Get("fs_name"), nsId)) + return nil + }, + Refresh: &ve.StateRefresh{ + Target: []string{"UP"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + }, + LockId: func(d *schema.ResourceData) string { + return d.Get("fs_name").(string) + }, + }, + } + return []ve.Callback{callback} + +} + +func (s *VolcengineCloudfsNamespaceService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + return []ve.Callback{} +} + +func (s *VolcengineCloudfsNamespaceService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "DeleteNs", + ConvertMode: ve.RequestConvertIgnore, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + tmpId := d.Id() + ids := strings.Split(tmpId, ":") + if len(ids) != 2 { + return false, fmt.Errorf("error cloudfs namespace id: %s", tmpId) + } + (*call.SdkParam)["NsId"] = ids[1] + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getPostUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + return ve.CheckResourceUtilRemoved(d, s.ReadResource, 10*time.Minute) + }, + CallError: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall, baseErr error) error { + //出现错误后重试 + return resource.Retry(15*time.Minute, func() *resource.RetryError { + _, callErr := s.ReadResource(d, "") + if callErr != nil { + if ve.ResourceNotFoundError(callErr) { + return nil + } else { + return resource.NonRetryableError(fmt.Errorf("error on reading cloudfs namespace on delete %q, %w", d.Id(), callErr)) + } + } + _, callErr = call.ExecuteCall(d, client, call) + if callErr == nil { + return nil + } + return resource.RetryableError(callErr) + }) + }, + }, + } + return []ve.Callback{callback} +} + +func (s *VolcengineCloudfsNamespaceService) DatasourceResources(*schema.ResourceData, *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{ + IdField: "Id", + CollectField: "namespaces", + } +} + +func (s *VolcengineCloudfsNamespaceService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "cfs", + Version: "2022-02-02", + HttpMethod: ve.GET, + ContentType: ve.Default, + Action: actionName, + } +} + +func getPostUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "cfs", + Version: "2022-02-02", + HttpMethod: ve.POST, + ContentType: ve.ApplicationJSON, + Action: actionName, + } +} diff --git a/volcengine/cloudfs/cloudfs_ns_quota/data_source_volcengine_cloudfs_ns_quotas.go b/volcengine/cloudfs/cloudfs_ns_quota/data_source_volcengine_cloudfs_ns_quotas.go new file mode 100644 index 00000000..36c08409 --- /dev/null +++ b/volcengine/cloudfs/cloudfs_ns_quota/data_source_volcengine_cloudfs_ns_quotas.go @@ -0,0 +1,82 @@ +package cloudfs_ns_quota + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +func DataSourceVolcengineCloudfsNsQuotas() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcengineCloudfsNsQuotasRead, + Schema: map[string]*schema.Schema{ + "fs_names": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + Description: "A list of fs name.", + }, + "output_file": { + Type: schema.TypeString, + Optional: true, + Description: "File name where to save data source results.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total count of cloud fs quota query.", + }, + "quotas": { + Description: "The collection of query.", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "account_id": { + Type: schema.TypeInt, + Computed: true, + Description: "The ID of account.", + }, + "ns_quota": { + Type: schema.TypeInt, + Computed: true, + Description: "The quota of cloud fs namespace.", + }, + "ns_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The count of cloud fs namespace.", + }, + "ns_count_per_fs": { + Type: schema.TypeInt, + Computed: true, + Description: "This file stores the number of namespaces under the instance.", + }, + "ns_quota_per_fs": { + Type: schema.TypeInt, + Computed: true, + Description: "This file stores the total namespace quota under the instance.", + }, + "fs_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of fs.", + }, + "quota_enough": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether is enough of cloud fs namespace.", + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcengineCloudfsNsQuotasRead(d *schema.ResourceData, meta interface{}) error { + service := NewService(meta.(*ve.SdkClient)) + return ve.DefaultDispatcher().Data(service, d, DataSourceVolcengineCloudfsNsQuotas()) +} diff --git a/volcengine/cloudfs/cloudfs_ns_quota/service_volcengine_cloudfs_ns_quota.go b/volcengine/cloudfs/cloudfs_ns_quota/service_volcengine_cloudfs_ns_quota.go new file mode 100644 index 00000000..1a0a3304 --- /dev/null +++ b/volcengine/cloudfs/cloudfs_ns_quota/service_volcengine_cloudfs_ns_quota.go @@ -0,0 +1,110 @@ +package cloudfs_ns_quota + +import ( + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" +) + +type VolcengineCloudfsNsQuotaService struct { + Client *ve.SdkClient +} + +func NewService(c *ve.SdkClient) *VolcengineCloudfsNsQuotaService { + return &VolcengineCloudfsNsQuotaService{ + Client: c, + } +} + +func (s *VolcengineCloudfsNsQuotaService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineCloudfsNsQuotaService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + ) + return ve.WithSimpleQuery(m, func(condition map[string]interface{}) ([]interface{}, error) { + action := "GetNsQuota" + logger.Debug(logger.ReqFormat, action, condition) + + fs, ok := condition["FsNames"] + if !ok { + return data, nil + } + for _, fsName := range fs.([]interface{}) { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &map[string]interface{}{ + "FsName": fsName, + }) + if err != nil { + return data, err + } + logger.Debug(logger.RespFormat, action, resp) + res, err := ve.ObtainSdkValue("Result", *resp) + if err != nil { + return data, err + } + data = append(data, res) + } + return data, nil + }) +} + +func (s *VolcengineCloudfsNsQuotaService) ReadResource(resourceData *schema.ResourceData, id string) (data map[string]interface{}, err error) { + return data, err +} + +func (s *VolcengineCloudfsNsQuotaService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return nil +} + +func (VolcengineCloudfsNsQuotaService) WithResourceResponseHandlers(d map[string]interface{}) []ve.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]ve.ResponseConvert, error) { + return d, nil, nil + } + return []ve.ResourceResponseHandler{handler} + +} + +func (s *VolcengineCloudfsNsQuotaService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + return []ve.Callback{} + +} + +func (s *VolcengineCloudfsNsQuotaService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + return []ve.Callback{} +} + +func (s *VolcengineCloudfsNsQuotaService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + return []ve.Callback{} +} + +func (s *VolcengineCloudfsNsQuotaService) DatasourceResources(*schema.ResourceData, *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{ + RequestConverts: map[string]ve.RequestConvert{ + "fs_names": { + TargetField: "FsNames", + ConvertType: ve.ConvertJsonArray, + }, + }, + ContentType: ve.ContentTypeJson, + CollectField: "quotas", + } +} + +func (s *VolcengineCloudfsNsQuotaService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "cfs", + Version: "2022-02-02", + HttpMethod: ve.GET, + ContentType: ve.Default, + Action: actionName, + } +} diff --git a/volcengine/cloudfs/cloudfs_quota/data_source_volcengine_cloudfs_quotas.go b/volcengine/cloudfs/cloudfs_quota/data_source_volcengine_cloudfs_quotas.go new file mode 100644 index 00000000..44a0f693 --- /dev/null +++ b/volcengine/cloudfs/cloudfs_quota/data_source_volcengine_cloudfs_quotas.go @@ -0,0 +1,58 @@ +package cloudfs_quota + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +func DataSourceVolcengineCloudfsQuotas() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcengineCloudfsQuotasRead, + Schema: map[string]*schema.Schema{ + "output_file": { + Type: schema.TypeString, + Optional: true, + Description: "File name where to save data source results.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total count of cloud fs quota query.", + }, + "quotas": { + Description: "The collection of query.", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "account_id": { + Type: schema.TypeInt, + Computed: true, + Description: "The ID of account.", + }, + "fs_quota": { + Type: schema.TypeInt, + Computed: true, + Description: "The quota of cloud fs.", + }, + "fs_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The count of cloud fs.", + }, + "quota_enough": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether is enough of cloud fs.", + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcengineCloudfsQuotasRead(d *schema.ResourceData, meta interface{}) error { + service := NewService(meta.(*ve.SdkClient)) + return ve.DefaultDispatcher().Data(service, d, DataSourceVolcengineCloudfsQuotas()) +} diff --git a/volcengine/cloudfs/cloudfs_quota/service_volcengine_cloudfs_quota.go b/volcengine/cloudfs/cloudfs_quota/service_volcengine_cloudfs_quota.go new file mode 100644 index 00000000..fd3836d9 --- /dev/null +++ b/volcengine/cloudfs/cloudfs_quota/service_volcengine_cloudfs_quota.go @@ -0,0 +1,104 @@ +package cloudfs_quota + +import ( + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" +) + +type VolcengineCloudfsQuotaService struct { + Client *ve.SdkClient +} + +func NewService(c *ve.SdkClient) *VolcengineCloudfsQuotaService { + return &VolcengineCloudfsQuotaService{ + Client: c, + } +} + +func (s *VolcengineCloudfsQuotaService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineCloudfsQuotaService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ) + return ve.WithSimpleQuery(m, func(condition map[string]interface{}) ([]interface{}, error) { + action := "GetFsQuota" + logger.Debug(logger.ReqFormat, action, condition) + if condition == nil { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), nil) + if err != nil { + return data, err + } + } else { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &condition) + if err != nil { + return data, err + } + } + logger.Debug(logger.RespFormat, action, resp) + results, err = ve.ObtainSdkValue("Result", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + return []interface{}{results}, err + }) +} + +func (s *VolcengineCloudfsQuotaService) ReadResource(resourceData *schema.ResourceData, id string) (data map[string]interface{}, err error) { + return data, err +} + +func (s *VolcengineCloudfsQuotaService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return nil +} + +func (VolcengineCloudfsQuotaService) WithResourceResponseHandlers(d map[string]interface{}) []ve.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]ve.ResponseConvert, error) { + return d, nil, nil + } + return []ve.ResourceResponseHandler{handler} + +} + +func (s *VolcengineCloudfsQuotaService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + return []ve.Callback{} + +} + +func (s *VolcengineCloudfsQuotaService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + return []ve.Callback{} +} + +func (s *VolcengineCloudfsQuotaService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + return []ve.Callback{} +} + +func (s *VolcengineCloudfsQuotaService) DatasourceResources(*schema.ResourceData, *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{ + CollectField: "quotas", + } +} + +func (s *VolcengineCloudfsQuotaService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "cfs", + Version: "2022-02-02", + HttpMethod: ve.GET, + ContentType: ve.Default, + Action: actionName, + } +} diff --git a/volcengine/provider.go b/volcengine/provider.go index 7bfdb627..81501ab4 100644 --- a/volcengine/provider.go +++ b/volcengine/provider.go @@ -2,6 +2,11 @@ package volcengine import ( "github.com/volcengine/terraform-provider-volcengine/volcengine/cen/cen_service_route_entry" + "github.com/volcengine/terraform-provider-volcengine/volcengine/cloudfs/cloudfs_access" + "github.com/volcengine/terraform-provider-volcengine/volcengine/cloudfs/cloudfs_file_system" + "github.com/volcengine/terraform-provider-volcengine/volcengine/cloudfs/cloudfs_namespace" + "github.com/volcengine/terraform-provider-volcengine/volcengine/cloudfs/cloudfs_ns_quota" + "github.com/volcengine/terraform-provider-volcengine/volcengine/cloudfs/cloudfs_quota" "strings" "github.com/volcengine/terraform-provider-volcengine/volcengine/rds/rds_parameter_template" @@ -387,6 +392,13 @@ func Provider() terraform.ResourceProvider { "volcengine_tls_projects": tlsProject.DataSourceVolcengineTlsProjects(), "volcengine_tls_topics": tlsTopic.DataSourceVolcengineTlsTopics(), "volcengine_tls_indexes": tlsIndex.DataSourceVolcengineTlsIndexes(), + + // ================ Cloudfs ================ + "volcengine_cloudfs_quotas": cloudfs_quota.DataSourceVolcengineCloudfsQuotas(), + "volcengine_cloudfs_file_systems": cloudfs_file_system.DataSourceVolcengineCloudfsFileSystems(), + "volcengine_cloudfs_accesses": cloudfs_access.DataSourceVolcengineCloudfsAccesses(), + "volcengine_cloudfs_ns_quotas": cloudfs_ns_quota.DataSourceVolcengineCloudfsNsQuotas(), + "volcengine_cloudfs_namespaces": cloudfs_namespace.DataSourceVolcengineCloudfsNamespaces(), }, ResourcesMap: map[string]*schema.Resource{ "volcengine_vpc": vpc.ResourceVolcengineVpc(), @@ -563,6 +575,11 @@ func Provider() terraform.ResourceProvider { "volcengine_tls_project": tlsProject.ResourceVolcengineTlsProject(), "volcengine_tls_topic": tlsTopic.ResourceVolcengineTlsTopic(), "volcengine_tls_index": tlsIndex.ResourceVolcengineTlsIndex(), + + // ================ Cloudfs ================ + "volcengine_cloudfs_file_system": cloudfs_file_system.ResourceVolcengineCloudfsFileSystem(), + "volcengine_cloudfs_access": cloudfs_access.ResourceVolcengineCloudfsAccess(), + "volcengine_cloudfs_namespace": cloudfs_namespace.ResourceVolcengineCloudfsNamespace(), }, ConfigureFunc: ProviderConfigure, } diff --git a/volcengine/rds_mysql/allowlist/service_volcengine_rds_mysql_allowlist.go b/volcengine/rds_mysql/allowlist/service_volcengine_rds_mysql_allowlist.go index 5a7d5bd3..fcacb6bb 100644 --- a/volcengine/rds_mysql/allowlist/service_volcengine_rds_mysql_allowlist.go +++ b/volcengine/rds_mysql/allowlist/service_volcengine_rds_mysql_allowlist.go @@ -68,6 +68,12 @@ func (s *VolcengineRdsMysqlAllowListService) ReadResources(condition map[string] return data, err } data[index].(map[string]interface{})["AssociatedInstances"] = instances + allowListIp, err := volc.ObtainSdkValue("Result.AllowList", *resp) + if err != nil { + return data, err + } + allowListIpArr := strings.Split(allowListIp.(string), ",") + data[index].(map[string]interface{})["AllowList"] = allowListIpArr } return data, err }) diff --git a/volcengine/rds_mysql/rds_mysql_instance/service_volcengine_rds_mysql_instance.go b/volcengine/rds_mysql/rds_mysql_instance/service_volcengine_rds_mysql_instance.go index d60b7b0c..a588820b 100644 --- a/volcengine/rds_mysql/rds_mysql_instance/service_volcengine_rds_mysql_instance.go +++ b/volcengine/rds_mysql/rds_mysql_instance/service_volcengine_rds_mysql_instance.go @@ -121,6 +121,40 @@ func (s *VolcengineRdsMysqlInstanceService) ReadResources(m map[string]interface } } rdsInstance["Nodes"] = nodes + + // query rds instance allow list ids + allowListInfo, err := s.Client.UniversalClient.DoCall(getUniversalInfo("DescribeAllowLists"), &map[string]interface{}{ + "InstanceId": rdsInstance["InstanceId"], + "RegionId": *(s.Client.ClbClient.Config.Region), + }) + if err != nil { + logger.Info("DescribeAllowLists error:", err) + continue + } + + allowLists, err := ve.ObtainSdkValue("Result.AllowLists", *allowListInfo) + if err != nil { + logger.Info("ObtainSdkValue Result.AllowLists error:", err) + continue + } + if allowLists == nil { + allowLists = []interface{}{} + } + allowListsArr, ok := allowLists.([]interface{}) + if !ok { + logger.Info(" Result.AllowLists is not slice") + continue + } + allowListIds := make([]interface{}, 0) + for _, allowList := range allowListsArr { + allowListMap, ok := allowList.(map[string]interface{}) + if !ok { + logger.Info(" AllowList is not map") + continue + } + allowListIds = append(allowListIds, allowListMap["AllowListId"]) + } + rdsInstance["AllowListIds"] = allowListIds } } @@ -163,6 +197,15 @@ func (s *VolcengineRdsMysqlInstanceService) ReadResource(resourceData *schema.Re } } + if parameterSet, ok := resourceData.GetOk("parameters"); ok { + data["Parameters"] = parameterSet.(*schema.Set).List() + } + + // DescribeDBInstances 不再返回 MaintenanceWindow 字段,需手动赋值为空数组 + if _, ok := data["MaintenanceWindow"]; !ok { + data["MaintenanceWindow"] = []interface{}{} + } + data["ChargeInfo"] = data["ChargeDetail"] return data, err diff --git a/website/docs/d/cloudfs_accesses.html.markdown b/website/docs/d/cloudfs_accesses.html.markdown new file mode 100644 index 00000000..e11664e3 --- /dev/null +++ b/website/docs/d/cloudfs_accesses.html.markdown @@ -0,0 +1,38 @@ +--- +subcategory: "CLOUDFS" +layout: "volcengine" +page_title: "Volcengine: volcengine_cloudfs_accesses" +sidebar_current: "docs-volcengine-datasource-cloudfs_accesses" +description: |- + Use this data source to query detailed information of cloudfs accesses +--- +# volcengine_cloudfs_accesses +Use this data source to query detailed information of cloudfs accesses +## Example Usage +```hcl +data "volcengine_cloudfs_accesses" "default" { + fs_name = "tftest2" +} +``` +## Argument Reference +The following arguments are supported: +* `fs_name` - (Required) The name of file system. +* `output_file` - (Optional) File name where to save data source results. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `accesses` - The collection of query. + * `access_account_id` - The account id of access. + * `access_id` - The id of access. + * `access_service_name` - The service name of access. + * `created_time` - The creation time. + * `fs_name` - The name of cloud fs. + * `is_default` - Whether is default access. + * `security_group_id` - The id of security group. + * `status` - The status of access. + * `subnet_id` - The id of subnet. + * `vpc_id` - The id of vpc. + * `vpc_route_enabled` - Whether to enable all vpc route. +* `total_count` - The total count of query. + + diff --git a/website/docs/d/cloudfs_file_systems.html.markdown b/website/docs/d/cloudfs_file_systems.html.markdown new file mode 100644 index 00000000..258c8de1 --- /dev/null +++ b/website/docs/d/cloudfs_file_systems.html.markdown @@ -0,0 +1,44 @@ +--- +subcategory: "CLOUDFS" +layout: "volcengine" +page_title: "Volcengine: volcengine_cloudfs_file_systems" +sidebar_current: "docs-volcengine-datasource-cloudfs_file_systems" +description: |- + Use this data source to query detailed information of cloudfs file systems +--- +# volcengine_cloudfs_file_systems +Use this data source to query detailed information of cloudfs file systems +## Example Usage +```hcl +data "volcengine_cloudfs_file_systems" "default" { + fs_name = "tftest2" +} +``` +## Argument Reference +The following arguments are supported: +* `fs_name` - (Optional) The name of file system. +* `meta_status` - (Optional) The status of file system. +* `name_regex` - (Optional) A Name Regex of cloudfs. +* `output_file` - (Optional) File name where to save data source results. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `file_systems` - The collection of query. + * `cache_capacity_tib` - The capacity of cache. + * `cache_plan` - The plan of cache. + * `created_time` - The creation time. + * `id` - The ID of file system. + * `mode` - The mode of file system. + * `mount_point` - The point mount. + * `name` - The name of file system. + * `region_id` - The id of region. + * `security_group_id` - The id of security group. + * `status` - The status of file system. + * `subnet_id` - The id of subnet. + * `tos_bucket` - The tos bucket. + * `tos_prefix` - The tos prefix. + * `vpc_id` - The id of vpc. + * `zone_id` - The id of zone. +* `total_count` - The total count of query. + + diff --git a/website/docs/d/cloudfs_namespaces.html.markdown b/website/docs/d/cloudfs_namespaces.html.markdown new file mode 100644 index 00000000..f2b6affc --- /dev/null +++ b/website/docs/d/cloudfs_namespaces.html.markdown @@ -0,0 +1,38 @@ +--- +subcategory: "CLOUDFS" +layout: "volcengine" +page_title: "Volcengine: volcengine_cloudfs_namespaces" +sidebar_current: "docs-volcengine-datasource-cloudfs_namespaces" +description: |- + Use this data source to query detailed information of cloudfs namespaces +--- +# volcengine_cloudfs_namespaces +Use this data source to query detailed information of cloudfs namespaces +## Example Usage +```hcl +data "volcengine_cloudfs_namespaces" "default" { + fs_name = "tf-test-fs" + ns_id = "1801439850948****" +} +``` +## Argument Reference +The following arguments are supported: +* `fs_name` - (Required) The name of file system. +* `ns_id` - (Optional) The id of namespace. +* `output_file` - (Optional) File name where to save data source results. +* `tos_bucket` - (Optional) The name of tos bucket. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `namespaces` - The collection of query. + * `created_time` - The creation time of the namespace. + * `id` - The ID of the namespace. + * `is_my_bucket` - Whether the tos bucket is your own bucket. + * `read_only` - Whether the namespace is read-only. + * `service_managed` - Whether the namespace is the official service for volcengine. + * `status` - The status of the namespace. + * `tos_bucket` - The name of the tos bucket. + * `tos_prefix` - The tos prefix. +* `total_count` - The total count of query. + + diff --git a/website/docs/d/cloudfs_ns_quotas.html.markdown b/website/docs/d/cloudfs_ns_quotas.html.markdown new file mode 100644 index 00000000..f2720a08 --- /dev/null +++ b/website/docs/d/cloudfs_ns_quotas.html.markdown @@ -0,0 +1,34 @@ +--- +subcategory: "CLOUDFS" +layout: "volcengine" +page_title: "Volcengine: volcengine_cloudfs_ns_quotas" +sidebar_current: "docs-volcengine-datasource-cloudfs_ns_quotas" +description: |- + Use this data source to query detailed information of cloudfs ns quotas +--- +# volcengine_cloudfs_ns_quotas +Use this data source to query detailed information of cloudfs ns quotas +## Example Usage +```hcl +data "volcengine_cloudfs_ns_quotas" "default" { + fs_names = ["tffile", "tftest2"] +} +``` +## Argument Reference +The following arguments are supported: +* `fs_names` - (Required) A list of fs name. +* `output_file` - (Optional) File name where to save data source results. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `quotas` - The collection of query. + * `account_id` - The ID of account. + * `fs_name` - The name of fs. + * `ns_count_per_fs` - This file stores the number of namespaces under the instance. + * `ns_count` - The count of cloud fs namespace. + * `ns_quota_per_fs` - This file stores the total namespace quota under the instance. + * `ns_quota` - The quota of cloud fs namespace. + * `quota_enough` - Whether is enough of cloud fs namespace. +* `total_count` - The total count of cloud fs quota query. + + diff --git a/website/docs/d/cloudfs_quotas.html.markdown b/website/docs/d/cloudfs_quotas.html.markdown new file mode 100644 index 00000000..b3e167af --- /dev/null +++ b/website/docs/d/cloudfs_quotas.html.markdown @@ -0,0 +1,29 @@ +--- +subcategory: "CLOUDFS" +layout: "volcengine" +page_title: "Volcengine: volcengine_cloudfs_quotas" +sidebar_current: "docs-volcengine-datasource-cloudfs_quotas" +description: |- + Use this data source to query detailed information of cloudfs quotas +--- +# volcengine_cloudfs_quotas +Use this data source to query detailed information of cloudfs quotas +## Example Usage +```hcl +data "volcengine_cloudfs_quotas" "default" { +} +``` +## Argument Reference +The following arguments are supported: +* `output_file` - (Optional) File name where to save data source results. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `quotas` - The collection of query. + * `account_id` - The ID of account. + * `fs_count` - The count of cloud fs. + * `fs_quota` - The quota of cloud fs. + * `quota_enough` - Whether is enough of cloud fs. +* `total_count` - The total count of cloud fs quota query. + + diff --git a/website/docs/r/cloudfs_access.html.markdown b/website/docs/r/cloudfs_access.html.markdown new file mode 100644 index 00000000..d6959011 --- /dev/null +++ b/website/docs/r/cloudfs_access.html.markdown @@ -0,0 +1,46 @@ +--- +subcategory: "CLOUDFS" +layout: "volcengine" +page_title: "Volcengine: volcengine_cloudfs_access" +sidebar_current: "docs-volcengine-resource-cloudfs_access" +description: |- + Provides a resource to manage cloudfs access +--- +# volcengine_cloudfs_access +Provides a resource to manage cloudfs access +## Example Usage +```hcl +resource "volcengine_cloudfs_access" "foo1" { + fs_name = "tftest2" + + subnet_id = "subnet-13fca1crr5d6o3n6nu46cyb5m" + security_group_id = "sg-rrv1klfg5s00v0x578mx14m" + vpc_route_enabled = false +} +``` +## Argument Reference +The following arguments are supported: +* `fs_name` - (Required, ForceNew) The name of file system. +* `security_group_id` - (Required, ForceNew) The id of security group. +* `subnet_id` - (Required, ForceNew) The id of subnet. +* `access_account_id` - (Optional, ForceNew) The account id of access. +* `access_iam_role` - (Optional, ForceNew) The iam role of access. If the VPC of another account is attached, the other account needs to create a role with CFSCacheAccess permission, and enter the role name as a parameter. +* `vpc_route_enabled` - (Optional) Whether enable all vpc route. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. +* `access_id` - The id of access. +* `access_service_name` - The service name of access. +* `created_time` - The creation time. +* `is_default` - Whether is default access. +* `status` - Status of access. +* `vpc_id` - The id of vpc. + + +## Import +CloudFs Access can be imported using the FsName:AccessId, e.g. +``` +$ terraform import volcengine_cloudfs_file_system.default tfname:access-**rdgmedx3fow +``` + diff --git a/website/docs/r/cloudfs_file_system.html.markdown b/website/docs/r/cloudfs_file_system.html.markdown new file mode 100644 index 00000000..b636562d --- /dev/null +++ b/website/docs/r/cloudfs_file_system.html.markdown @@ -0,0 +1,77 @@ +--- +subcategory: "CLOUDFS" +layout: "volcengine" +page_title: "Volcengine: volcengine_cloudfs_file_system" +sidebar_current: "docs-volcengine-resource-cloudfs_file_system" +description: |- + Provides a resource to manage cloudfs file system +--- +# volcengine_cloudfs_file_system +Provides a resource to manage cloudfs file system +## Example Usage +```hcl +resource "volcengine_cloudfs_file_system" "foo" { + fs_name = "tffile" + zone_id = "cn-beijing-b" + cache_plan = "T2" + mode = "HDFS_MODE" + read_only = true + + subnet_id = "subnet-13fca1crr5d6o3n6nu46cyb5m" + security_group_id = "sg-rrv1klfg5s00v0x578mx14m" + cache_capacity_tib = 10 + vpc_route_enabled = true + + tos_bucket = "tfacc" + tos_prefix = "pre/" +} + + +resource "volcengine_cloudfs_file_system" "foo1" { + fs_name = "tffileu" + zone_id = "cn-beijing-b" + cache_plan = "T2" + mode = "ACC_MODE" + read_only = true + + subnet_id = "subnet-13fca1crr5d6o3n6nu46cyb5m" + security_group_id = "sg-rrv1klfg5s00v0x578mx14m" + cache_capacity_tib = 15 + vpc_route_enabled = false + + tos_bucket = "tfacc" +} +``` +## Argument Reference +The following arguments are supported: +* `cache_plan` - (Required) The cache plan. The value can be `DISABLED` or `T2` or `T4`. When expanding the cache size, the cache plan should remain the same. For data lakes, cache must be enabled. +* `fs_name` - (Required, ForceNew) The name of file system. +* `mode` - (Required, ForceNew) The mode of file system. The value can be `HDFS_MODE` or `ACC_MODE`. +* `zone_id` - (Required, ForceNew) The id of zone. +* `cache_capacity_tib` - (Optional) The capacity of cache. This parameter is required when cache acceleration is enabled. +* `read_only` - (Optional, ForceNew) Whether the Namespace created automatically when mounting the TOS Bucket is read-only. When importing resources, this attribute will not be imported. If this attribute is set, please use lifecycle and ignore_changes ignore changes in fields. +* `security_group_id` - (Optional) The id of security group. This parameter is required when cache acceleration is enabled. +* `subnet_id` - (Optional) The id of subnet. This parameter is required when cache acceleration is enabled. +* `tos_account_id` - (Optional, ForceNew) When a data lake scenario instance chooses to associate a bucket under another account, you need to set the ID of the account. When importing resources, this attribute will not be imported. +* `tos_ak` - (Optional, ForceNew) The tos ak. When the data lake scenario chooses to associate buckets under other accounts, need to set the Access Key ID of the account. When importing resources, this attribute will not be imported. +* `tos_bucket` - (Optional, ForceNew) The tos bucket. When importing ACC_MODE resources, this attribute will not be imported. +* `tos_prefix` - (Optional, ForceNew) The tos prefix. Must not start with /, but must end with /, such as prefix/. When it is empty, it means the root path. When importing ACC_MODE resources, this attribute will not be imported. +* `tos_sk` - (Optional, ForceNew) The tos sk. When the data lake scenario chooses to associate buckets under other accounts, need to set the Secret Access Key of the account. When importing resources, this attribute will not be imported. +* `vpc_route_enabled` - (Optional) Whether enable all vpc route. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. +* `access_id` - The default vpc access id. +* `created_time` - The creation time. +* `mount_point` - The point mount. +* `status` - Status of file system. +* `vpc_id` - The id of vpc. + + +## Import +CloudFileSystem can be imported using the FsName, e.g. +``` +$ terraform import volcengine_cloudfs_file_system.default tfname +``` + diff --git a/website/docs/r/cloudfs_namespace.html.markdown b/website/docs/r/cloudfs_namespace.html.markdown new file mode 100644 index 00000000..8760cb69 --- /dev/null +++ b/website/docs/r/cloudfs_namespace.html.markdown @@ -0,0 +1,44 @@ +--- +subcategory: "CLOUDFS" +layout: "volcengine" +page_title: "Volcengine: volcengine_cloudfs_namespace" +sidebar_current: "docs-volcengine-resource-cloudfs_namespace" +description: |- + Provides a resource to manage cloudfs namespace +--- +# volcengine_cloudfs_namespace +Provides a resource to manage cloudfs namespace +## Example Usage +```hcl +resource "volcengine_cloudfs_namespace" "foo" { + fs_name = "tf-test-fs" + tos_bucket = "tf-test" + read_only = true +} +``` +## Argument Reference +The following arguments are supported: +* `fs_name` - (Required, ForceNew) The name of file system. +* `tos_bucket` - (Required, ForceNew) The name of tos bucket. +* `read_only` - (Optional, ForceNew) Whether the namespace is read-only. +* `tos_account_id` - (Optional, ForceNew) When a data lake scenario instance chooses to associate a bucket under another account, you need to set the ID of the account. When importing resources, this attribute will not be imported. If this attribute is set, please use lifecycle and ignore_changes ignore changes in fields. +* `tos_ak` - (Optional, ForceNew) The tos ak. When the data lake scenario chooses to associate buckets under other accounts, need to set the Access Key ID of the account. When importing resources, this attribute will not be imported. If this attribute is set, please use lifecycle and ignore_changes ignore changes in fields. +* `tos_prefix` - (Optional, ForceNew) The tos prefix. Must not start with /, but must end with /, such as prefix/. When it is empty, it means the root path. +* `tos_sk` - (Optional, ForceNew) The tos sk. When the data lake scenario chooses to associate buckets under other accounts, need to set the Secret Access Key of the account. When importing resources, this attribute will not be imported. If this attribute is set, please use lifecycle and ignore_changes ignore changes in fields. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. +* `created_time` - The creation time of the namespace. +* `is_my_bucket` - Whether the tos bucket is your own bucket. +* `ns_id` - The id of namespace. +* `service_managed` - Whether the namespace is the official service for volcengine. +* `status` - The status of the namespace. + + +## Import +CloudfsNamespace can be imported using the FsName:NsId, e.g. +``` +$ terraform import volcengine_cloudfs_namespace.default tfname:1801439850948**** +``` +