From 351deaa4df05757dc5ccd44a4c5414236a9ad843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=93=B2=E9=93=AD?= Date: Tue, 30 Jan 2024 18:15:25 +0800 Subject: [PATCH 01/13] feat: vke node pool and cluster add Deprecated --- common/common_volcengine_version.go | 2 +- .../vke/cluster/data_source_volcengine_vke_clusters.go | 1 + .../vke/node_pool/data_source_volcengine_vke_node_pools.go | 3 +++ .../vke/node_pool/resource_volcengine_vke_node_pool.go | 3 +++ website/docs/d/vke_clusters.html.markdown | 2 +- website/docs/d/vke_node_pools.html.markdown | 6 +++--- website/docs/r/vke_node_pool.html.markdown | 6 +++--- 7 files changed, 15 insertions(+), 8 deletions(-) diff --git a/common/common_volcengine_version.go b/common/common_volcengine_version.go index d2b29dc8..90f1855b 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.139" + TerraformProviderVersion = "0.0.140" ) diff --git a/volcengine/vke/cluster/data_source_volcengine_vke_clusters.go b/volcengine/vke/cluster/data_source_volcengine_vke_clusters.go index a82abd3c..d3664b16 100644 --- a/volcengine/vke/cluster/data_source_volcengine_vke_clusters.go +++ b/volcengine/vke/cluster/data_source_volcengine_vke_clusters.go @@ -413,6 +413,7 @@ func DataSourceVolcengineVkeVkeClusters() *schema.Resource { "stopped_count": { Type: schema.TypeInt, Computed: true, + Deprecated: "This field has been deprecated and is not recommended for use.", Description: "Phase=Stopped total number of nodes.", }, "updating_count": { diff --git a/volcengine/vke/node_pool/data_source_volcengine_vke_node_pools.go b/volcengine/vke/node_pool/data_source_volcengine_vke_node_pools.go index 7b981bae..03e8f4df 100644 --- a/volcengine/vke/node_pool/data_source_volcengine_vke_node_pools.go +++ b/volcengine/vke/node_pool/data_source_volcengine_vke_node_pools.go @@ -279,16 +279,19 @@ func DataSourceVolcengineNodePools() *schema.Resource { "stopped_count": { Type: schema.TypeInt, Computed: true, + Deprecated: "This field has been deprecated and is not recommended for use.", Description: "The StoppedCount of Node.", }, "stopping_count": { Type: schema.TypeInt, Computed: true, + Deprecated: "This field has been deprecated and is not recommended for use.", Description: "The StoppingCount of Node.", }, "starting_count": { Type: schema.TypeInt, Computed: true, + Deprecated: "This field has been deprecated and is not recommended for use.", Description: "The StartingCount of Node.", }, }, diff --git a/volcengine/vke/node_pool/resource_volcengine_vke_node_pool.go b/volcengine/vke/node_pool/resource_volcengine_vke_node_pool.go index 709a0d2f..da3d1ebd 100644 --- a/volcengine/vke/node_pool/resource_volcengine_vke_node_pool.go +++ b/volcengine/vke/node_pool/resource_volcengine_vke_node_pool.go @@ -413,16 +413,19 @@ func ResourceVolcengineNodePool() *schema.Resource { "stopped_count": { Type: schema.TypeInt, Computed: true, + Deprecated: "This field has been deprecated and is not recommended for use.", Description: "The StoppedCount of Node.", }, "stopping_count": { Type: schema.TypeInt, Computed: true, + Deprecated: "This field has been deprecated and is not recommended for use.", Description: "The StoppingCount of Node.", }, "starting_count": { Type: schema.TypeInt, Computed: true, + Deprecated: "This field has been deprecated and is not recommended for use.", Description: "The StartingCount of Node.", }, }, diff --git a/website/docs/d/vke_clusters.html.markdown b/website/docs/d/vke_clusters.html.markdown index c86b38f6..923d7edf 100644 --- a/website/docs/d/vke_clusters.html.markdown +++ b/website/docs/d/vke_clusters.html.markdown @@ -141,7 +141,7 @@ In addition to all arguments above, the following attributes are exported: * `deleting_count` - Phase=Deleting total number of nodes. * `failed_count` - Phase=Failed total number of nodes. * `running_count` - Phase=Running total number of nodes. - * `stopped_count` - Phase=Stopped total number of nodes. + * `stopped_count` - (**Deprecated**) This field has been deprecated and is not recommended for use. Phase=Stopped total number of nodes. * `total_count` - Total number of nodes. * `updating_count` - Phase=Updating total number of nodes. * `pods_config` - The config of the pods. diff --git a/website/docs/d/vke_node_pools.html.markdown b/website/docs/d/vke_node_pools.html.markdown index 932a2d47..01f2fa5c 100644 --- a/website/docs/d/vke_node_pools.html.markdown +++ b/website/docs/d/vke_node_pools.html.markdown @@ -197,9 +197,9 @@ In addition to all arguments above, the following attributes are exported: * `deleting_count` - The DeletingCount of Node. * `failed_count` - The FailedCount of Node. * `running_count` - The RunningCount of Node. - * `starting_count` - The StartingCount of Node. - * `stopped_count` - The StoppedCount of Node. - * `stopping_count` - The StoppingCount of Node. + * `starting_count` - (**Deprecated**) This field has been deprecated and is not recommended for use. The StartingCount of Node. + * `stopped_count` - (**Deprecated**) This field has been deprecated and is not recommended for use. The StoppedCount of Node. + * `stopping_count` - (**Deprecated**) This field has been deprecated and is not recommended for use. The StoppingCount of Node. * `total_count` - The TotalCount of Node. * `updating_count` - The UpdatingCount of Node. * `period` - The period of the PrePaid instance of NodeConfig. diff --git a/website/docs/r/vke_node_pool.html.markdown b/website/docs/r/vke_node_pool.html.markdown index f7681a8d..f0667c6e 100644 --- a/website/docs/r/vke_node_pool.html.markdown +++ b/website/docs/r/vke_node_pool.html.markdown @@ -222,9 +222,9 @@ In addition to all arguments above, the following attributes are exported: * `deleting_count` - The DeletingCount of Node. * `failed_count` - The FailedCount of Node. * `running_count` - The RunningCount of Node. - * `starting_count` - The StartingCount of Node. - * `stopped_count` - The StoppedCount of Node. - * `stopping_count` - The StoppingCount of Node. + * `starting_count` - (**Deprecated**) This field has been deprecated and is not recommended for use. The StartingCount of Node. + * `stopped_count` - (**Deprecated**) This field has been deprecated and is not recommended for use. The StoppedCount of Node. + * `stopping_count` - (**Deprecated**) This field has been deprecated and is not recommended for use. The StoppingCount of Node. * `total_count` - The TotalCount of Node. * `updating_count` - The UpdatingCount of Node. From 5aa11ce44825533ac54cf70975e16a3b20d74786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=93=B2=E9=93=AD?= Date: Mon, 4 Dec 2023 20:01:45 +0800 Subject: [PATCH 02/13] feat: add iam saml provider --- common/common_volcengine_client.go | 2 + common/common_volcengine_config.go | 2 + example/dataIamSamlProviders/main.tf | 2 + example/iamSamlProvider/main.tf | 6 + ...ta_source_volcengine_iam_saml_providers.go | 79 ++++++ .../resource_volcengine_iam_saml_provider.go | 121 +++++++++ .../service_volcengine_iam_saml_provider.go | 244 ++++++++++++++++++ volcengine/provider.go | 3 + 8 files changed, 459 insertions(+) create mode 100644 example/dataIamSamlProviders/main.tf create mode 100644 example/iamSamlProvider/main.tf create mode 100644 volcengine/iam/iam_saml_provider/data_source_volcengine_iam_saml_providers.go create mode 100644 volcengine/iam/iam_saml_provider/resource_volcengine_iam_saml_provider.go create mode 100644 volcengine/iam/iam_saml_provider/service_volcengine_iam_saml_provider.go diff --git a/common/common_volcengine_client.go b/common/common_volcengine_client.go index 1596d1b4..feef733a 100644 --- a/common/common_volcengine_client.go +++ b/common/common_volcengine_client.go @@ -4,6 +4,7 @@ import ( "github.com/volcengine/volcengine-go-sdk/service/autoscaling" "github.com/volcengine/volcengine-go-sdk/service/clb" "github.com/volcengine/volcengine-go-sdk/service/ecs" + "github.com/volcengine/volcengine-go-sdk/service/iam" "github.com/volcengine/volcengine-go-sdk/service/natgateway" "github.com/volcengine/volcengine-go-sdk/service/rdsmysql" "github.com/volcengine/volcengine-go-sdk/service/rdsmysqlv2" @@ -23,6 +24,7 @@ type SdkClient struct { AutoScalingClient *autoscaling.AUTOSCALING RdsClient *rdsmysql.RDSMYSQL RdsClientV2 *rdsmysqlv2.RDSMYSQLV2 + IamClient *iam.IAM UniversalClient *Universal BypassSvcClient *BypassSvc } diff --git a/common/common_volcengine_config.go b/common/common_volcengine_config.go index 69dde773..33869b7c 100644 --- a/common/common_volcengine_config.go +++ b/common/common_volcengine_config.go @@ -9,6 +9,7 @@ import ( "github.com/volcengine/volcengine-go-sdk/service/autoscaling" "github.com/volcengine/volcengine-go-sdk/service/clb" "github.com/volcengine/volcengine-go-sdk/service/ecs" + "github.com/volcengine/volcengine-go-sdk/service/iam" "github.com/volcengine/volcengine-go-sdk/service/natgateway" "github.com/volcengine/volcengine-go-sdk/service/rdsmysql" "github.com/volcengine/volcengine-go-sdk/service/rdsmysqlv2" @@ -75,6 +76,7 @@ func (c *Config) Client() (*SdkClient, error) { client.AutoScalingClient = autoscaling.New(sess) client.RdsClient = rdsmysql.New(sess) client.RdsClientV2 = rdsmysqlv2.New(sess) + client.IamClient = iam.New(sess) client.UniversalClient = NewUniversalClient(sess, c.CustomerEndpoints) client.BypassSvcClient = NewBypassClient(sess) diff --git a/example/dataIamSamlProviders/main.tf b/example/dataIamSamlProviders/main.tf new file mode 100644 index 00000000..9a069df3 --- /dev/null +++ b/example/dataIamSamlProviders/main.tf @@ -0,0 +1,2 @@ +data "volcengine_iam_saml_providers" "foo"{ +} \ No newline at end of file diff --git a/example/iamSamlProvider/main.tf b/example/iamSamlProvider/main.tf new file mode 100644 index 00000000..385b8146 --- /dev/null +++ b/example/iamSamlProvider/main.tf @@ -0,0 +1,6 @@ +resource "volcengine_iam_saml_provider" "foo" { + encoded_saml_metadata_document = "your document" + saml_provider_name = "terraform" + sso_type = 2 + status = 1 +} \ No newline at end of file diff --git a/volcengine/iam/iam_saml_provider/data_source_volcengine_iam_saml_providers.go b/volcengine/iam/iam_saml_provider/data_source_volcengine_iam_saml_providers.go new file mode 100644 index 00000000..2193319e --- /dev/null +++ b/volcengine/iam/iam_saml_provider/data_source_volcengine_iam_saml_providers.go @@ -0,0 +1,79 @@ +package iam_saml_provider + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +func DataSourceVolcengineIamSamlProviders() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcengineIamSamlProvidersRead, + 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 query.", + }, + "providers": { + Description: "The collection of query.", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "saml_provider_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the SAML provider.", + }, + "encoded_saml_metadata_document": { + Type: schema.TypeString, + Computed: true, + Description: "Metadata document, encoded in Base64.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the SAML provider.", + }, + "sso_type": { + Type: schema.TypeInt, + Computed: true, + Description: "SSO types, 1. Role-based SSO, 2. User-based SSO.", + }, + "status": { + Type: schema.TypeInt, + Computed: true, + Description: "User SSO status, 1. Enabled, 2. Disable other console login methods after enabling, " + + "3. Disabled, is a required field when creating user SSO.", + }, + "trn": { + Type: schema.TypeString, + Computed: true, + Description: "The format for the resource name of an identity provider is trn:iam::${accountID}:saml-provider/{$SAMLProviderName}.", + }, + "create_date": { + Type: schema.TypeString, + Computed: true, + Description: "Identity provider creation time, such as 20150123T123318Z.", + }, + "update_date": { + Type: schema.TypeString, + Computed: true, + Description: "Identity provider update time, such as: 20150123T123318Z.", + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcengineIamSamlProvidersRead(d *schema.ResourceData, meta interface{}) error { + service := NewIamSamlProviderService(meta.(*ve.SdkClient)) + return service.Dispatcher.Data(service, d, DataSourceVolcengineIamSamlProviders()) +} diff --git a/volcengine/iam/iam_saml_provider/resource_volcengine_iam_saml_provider.go b/volcengine/iam/iam_saml_provider/resource_volcengine_iam_saml_provider.go new file mode 100644 index 00000000..9623cdee --- /dev/null +++ b/volcengine/iam/iam_saml_provider/resource_volcengine_iam_saml_provider.go @@ -0,0 +1,121 @@ +package iam_saml_provider + +import ( + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +IamSamlProvider can be imported using the id, e.g. +``` +$ terraform import volcengine_iam_saml_provider.default SAMLProviderName +``` + +*/ + +func ResourceVolcengineIamSamlProvider() *schema.Resource { + resource := &schema.Resource{ + Create: resourceVolcengineIamSamlProviderCreate, + Read: resourceVolcengineIamSamlProviderRead, + Update: resourceVolcengineIamSamlProviderUpdate, + Delete: resourceVolcengineIamSamlProviderDelete, + 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{ + "saml_provider_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The name of the SAML provider.", + }, + "encoded_saml_metadata_document": { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + return strings.Replace(old, "\n", "", -1) == strings.Replace(new, "\n", "", -1) + }, + Description: "Metadata document, encoded in Base64.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The description of the SAML provider.", + }, + "sso_type": { + Type: schema.TypeInt, + Required: true, + Description: "SSO types, 1. Role-based SSO, 2. User-based SSO.", + }, + "status": { + Type: schema.TypeInt, + Optional: true, + Description: "User SSO status, 1. Enabled, 2. Disable other console login methods after enabling, " + + "3. Disabled, is a required field when creating user SSO.", + }, + "trn": { + Type: schema.TypeString, + Computed: true, + Description: "The format for the resource name of an identity provider is trn:iam::${accountID}:saml-provider/{$SAMLProviderName}.", + }, + "create_date": { + Type: schema.TypeString, + Computed: true, + Description: "Identity provider creation time, such as 20150123T123318Z.", + }, + "update_date": { + Type: schema.TypeString, + Computed: true, + Description: "Identity provider update time, such as: 20150123T123318Z.", + }, + }, + } + return resource +} + +func resourceVolcengineIamSamlProviderCreate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewIamSamlProviderService(meta.(*ve.SdkClient)) + err = service.Dispatcher.Create(service, d, ResourceVolcengineIamSamlProvider()) + if err != nil { + return fmt.Errorf("error on creating iam_saml_provider %q, %s", d.Id(), err) + } + return resourceVolcengineIamSamlProviderRead(d, meta) +} + +func resourceVolcengineIamSamlProviderRead(d *schema.ResourceData, meta interface{}) (err error) { + service := NewIamSamlProviderService(meta.(*ve.SdkClient)) + err = service.Dispatcher.Read(service, d, ResourceVolcengineIamSamlProvider()) + if err != nil { + return fmt.Errorf("error on reading iam_saml_provider %q, %s", d.Id(), err) + } + return err +} + +func resourceVolcengineIamSamlProviderUpdate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewIamSamlProviderService(meta.(*ve.SdkClient)) + err = service.Dispatcher.Update(service, d, ResourceVolcengineIamSamlProvider()) + if err != nil { + return fmt.Errorf("error on updating iam_saml_provider %q, %s", d.Id(), err) + } + return resourceVolcengineIamSamlProviderRead(d, meta) +} + +func resourceVolcengineIamSamlProviderDelete(d *schema.ResourceData, meta interface{}) (err error) { + service := NewIamSamlProviderService(meta.(*ve.SdkClient)) + err = service.Dispatcher.Delete(service, d, ResourceVolcengineIamSamlProvider()) + if err != nil { + return fmt.Errorf("error on deleting iam_saml_provider %q, %s", d.Id(), err) + } + return err +} diff --git a/volcengine/iam/iam_saml_provider/service_volcengine_iam_saml_provider.go b/volcengine/iam/iam_saml_provider/service_volcengine_iam_saml_provider.go new file mode 100644 index 00000000..d0c0dc88 --- /dev/null +++ b/volcengine/iam/iam_saml_provider/service_volcengine_iam_saml_provider.go @@ -0,0 +1,244 @@ +package iam_saml_provider + +import ( + "encoding/json" + "errors" + "fmt" + "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 VolcengineIamSamlProviderService struct { + Client *ve.SdkClient + Dispatcher *ve.Dispatcher +} + +func NewIamSamlProviderService(c *ve.SdkClient) *VolcengineIamSamlProviderService { + return &VolcengineIamSamlProviderService{ + Client: c, + Dispatcher: &ve.Dispatcher{}, + } +} + +func (s *VolcengineIamSamlProviderService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineIamSamlProviderService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + return ve.WithPageOffsetQuery(m, "Limit", "Offset", 100, 0, func(condition map[string]interface{}) ([]interface{}, error) { + action := "ListSAMLProviders" + + bytes, _ := json.Marshal(condition) + logger.Debug(logger.ReqFormat, action, string(bytes)) + 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 + } + } + respBytes, _ := json.Marshal(resp) + logger.Debug(logger.RespFormat, action, condition, string(respBytes)) + results, err = ve.ObtainSdkValue("Result.SAMLProviders", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.SAMLProviders is not Slice") + } + for index, ele := range data { + provider := ele.(map[string]interface{}) + query := map[string]interface{}{ + // 跟API文档不对应,文档写的返回字段为SAMLProviderName,实际为ProviderName + "SAMLProviderName": provider["ProviderName"], + } + action = "GetSAMLProvider" + logger.Debug(logger.ReqFormat, action, query) + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &query) + if err != nil { + return data, err + } + logger.Debug(logger.RespFormat, action, query, *resp) + document, err := ve.ObtainSdkValue("Result.EncodedSAMLMetadataDocument", *resp) + if err != nil { + return data, err + } + data[index].(map[string]interface{})["EncodedSAMLMetadataDocument"] = document + } + return data, err + }) +} + +func (s *VolcengineIamSamlProviderService) ReadResource(resourceData *schema.ResourceData, id string) (data map[string]interface{}, err error) { + var ( + results []interface{} + temp map[string]interface{} + ok bool + ) + if id == "" { + id = s.ReadResourceId(resourceData.Id()) + } + req := map[string]interface{}{} + results, err = s.ReadResources(req) + if err != nil { + return data, err + } + for _, v := range results { + if temp, ok = v.(map[string]interface{}); !ok { + return data, errors.New("Value is not map ") + } else if temp["ProviderName"].(string) == id { + data = temp + } + } + if len(data) == 0 { + return data, fmt.Errorf("iam_saml_provider %s not exist ", id) + } + return data, err +} + +func (s *VolcengineIamSamlProviderService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return &resource.StateChangeConf{} +} + +func (s *VolcengineIamSamlProviderService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "CreateSAMLProvider", + ConvertMode: ve.RequestConvertAll, + ContentType: ve.ContentTypeJson, + Convert: map[string]ve.RequestConvert{ + "encoded_saml_metadata_document": { + TargetField: "EncodedSAMLMetadataDocument", + }, + "saml_provider_name": { + TargetField: "SAMLProviderName", + }, + "sso_type": { + TargetField: "SSOType", + }, + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + resp, err := s.Client.IamClient.CreateSAMLProviderCommon(call.SdkParam) + logger.Debug(logger.RespFormat, call.Action, resp, err) + return resp, err + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + id := d.Get("saml_provider_name") + d.SetId(id.(string)) + return nil + }, + }, + } + return []ve.Callback{callback} +} + +func (VolcengineIamSamlProviderService) 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 *VolcengineIamSamlProviderService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "UpdateSAMLProvider", + ConvertMode: ve.RequestConvertInConvert, + Convert: map[string]ve.RequestConvert{ + "encoded_saml_metadata_document": { + TargetField: "NewEncodedSAMLMetadataDocument", + }, + "description": { + TargetField: "Description", + }, + "status": { + TargetField: "Status", + }, + "sso_type": { + TargetField: "SSOType", + }, + }, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["SAMLProviderName"] = d.Id() + 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) + resp, err := s.Client.IamClient.UpdateSAMLProviderCommon(call.SdkParam) + logger.Debug(logger.RespFormat, call.Action, resp, err) + return resp, err + }, + }, + } + return []ve.Callback{callback} +} + +func (s *VolcengineIamSamlProviderService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "DeleteSAMLProvider", + ConvertMode: ve.RequestConvertIgnore, + SdkParam: &map[string]interface{}{ + "SAMLProviderName": 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(getUniversalInfo(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, 5*time.Minute) + }, + }, + } + return []ve.Callback{callback} +} + +func (s *VolcengineIamSamlProviderService) DatasourceResources(*schema.ResourceData, *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{ + NameField: "SAMLProviderName", + IdField: "Trn", + CollectField: "providers", + ResponseConverts: map[string]ve.ResponseConvert{ + "ProviderName": { + TargetField: "saml_provider_name", + }, + "EncodedSAMLMetadataDocument": { + TargetField: "encoded_saml_metadata_document", + }, + "SSOType": { + TargetField: "sso_type", + }, + }, + } +} + +func (s *VolcengineIamSamlProviderService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "iam", + Version: "2018-01-01", + HttpMethod: ve.GET, + ContentType: ve.Default, + Action: actionName, + } +} diff --git a/volcengine/provider.go b/volcengine/provider.go index 2e6b006c..249ef7b6 100644 --- a/volcengine/provider.go +++ b/volcengine/provider.go @@ -152,6 +152,7 @@ import ( "github.com/volcengine/terraform-provider-volcengine/volcengine/iam/iam_policy" "github.com/volcengine/terraform-provider-volcengine/volcengine/iam/iam_role" "github.com/volcengine/terraform-provider-volcengine/volcengine/iam/iam_role_policy_attachment" + "github.com/volcengine/terraform-provider-volcengine/volcengine/iam/iam_saml_provider" "github.com/volcengine/terraform-provider-volcengine/volcengine/iam/iam_user" "github.com/volcengine/terraform-provider-volcengine/volcengine/iam/iam_user_group" "github.com/volcengine/terraform-provider-volcengine/volcengine/iam/iam_user_group_attachment" @@ -390,6 +391,7 @@ func Provider() terraform.ResourceProvider { "volcengine_iam_users": iam_user.DataSourceVolcengineIamUsers(), "volcengine_iam_user_groups": iam_user_group.DataSourceVolcengineIamUserGroups(), "volcengine_iam_user_group_policy_attachments": iam_user_group_policy_attachment.DataSourceVolcengineIamUserGroupPolicyAttachments(), + "volcengine_iam_saml_providers": iam_saml_provider.DataSourceVolcengineIamSamlProviders(), // ================ RDS V1 ============== "volcengine_rds_instances": rds_instance.DataSourceVolcengineRdsInstances(), @@ -646,6 +648,7 @@ func Provider() terraform.ResourceProvider { "volcengine_iam_user_group": iam_user_group.ResourceVolcengineIamUserGroup(), "volcengine_iam_user_group_attachment": iam_user_group_attachment.ResourceVolcengineIamUserGroupAttachment(), "volcengine_iam_user_group_policy_attachment": iam_user_group_policy_attachment.ResourceVolcengineIamUserGroupPolicyAttachment(), + "volcengine_iam_saml_provider": iam_saml_provider.ResourceVolcengineIamSamlProvider(), // ================ RDS V1 ============== "volcengine_rds_instance": rds_instance.ResourceVolcengineRdsInstance(), From 4325cb5f13e4a155cad7d75ebbf1480c0e80a3c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=93=B2=E9=93=AD?= Date: Tue, 5 Dec 2023 10:54:32 +0800 Subject: [PATCH 03/13] feat: add organization unit --- example/dataOrganizationUnits/main.tf | 2 + example/organizationUnit/main.tf | 5 + ...ta_source_volcengine_organization_units.go | 98 +++++++++ .../resource_volcengine_organization_unit.go | 111 ++++++++++ .../service_volcengine_organization_unit.go | 206 ++++++++++++++++++ volcengine/provider.go | 8 + 6 files changed, 430 insertions(+) create mode 100644 example/dataOrganizationUnits/main.tf create mode 100644 example/organizationUnit/main.tf create mode 100644 volcengine/organization/organization_unit/data_source_volcengine_organization_units.go create mode 100644 volcengine/organization/organization_unit/resource_volcengine_organization_unit.go create mode 100644 volcengine/organization/organization_unit/service_volcengine_organization_unit.go diff --git a/example/dataOrganizationUnits/main.tf b/example/dataOrganizationUnits/main.tf new file mode 100644 index 00000000..6278341e --- /dev/null +++ b/example/dataOrganizationUnits/main.tf @@ -0,0 +1,2 @@ +data "volcengine_organization_units" "foo"{ +} \ No newline at end of file diff --git a/example/organizationUnit/main.tf b/example/organizationUnit/main.tf new file mode 100644 index 00000000..844b8533 --- /dev/null +++ b/example/organizationUnit/main.tf @@ -0,0 +1,5 @@ +resource "volcengine_organization_unit" "foo" { + name = "tftest2" + parent_id = "7306629044253098034" + description = "test" +} \ No newline at end of file diff --git a/volcengine/organization/organization_unit/data_source_volcengine_organization_units.go b/volcengine/organization/organization_unit/data_source_volcengine_organization_units.go new file mode 100644 index 00000000..f2ce3625 --- /dev/null +++ b/volcengine/organization/organization_unit/data_source_volcengine_organization_units.go @@ -0,0 +1,98 @@ +package organization_unit + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +func DataSourceVolcengineOrganizationUnits() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcengineOrganizationUnitsRead, + 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 query.", + }, + "units": { + 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 organization unit.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "The created time of the organization unit.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "The updated time of the organization unit.", + }, + "deleted_time": { + Type: schema.TypeString, + Computed: true, + Description: "The deleted time of the organization unit.", + }, + "owner": { + Type: schema.TypeString, + Computed: true, + Description: "The owner of the organization unit.", + }, + "org_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the organization.", + }, + "org_type": { + Type: schema.TypeInt, + Computed: true, + Description: "The organization type.", + }, + "parent_id": { + Type: schema.TypeString, + Computed: true, + Description: "Parent Unit ID.", + }, + "depth": { + Type: schema.TypeInt, + Computed: true, + Description: "The depth of the organization unit.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the organization unit.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the organization unit.", + }, + "delete_uk": { + Type: schema.TypeString, + Computed: true, + Description: "Delete marker.", + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcengineOrganizationUnitsRead(d *schema.ResourceData, meta interface{}) error { + service := NewOrganizationUnitService(meta.(*ve.SdkClient)) + return service.Dispatcher.Data(service, d, DataSourceVolcengineOrganizationUnits()) +} diff --git a/volcengine/organization/organization_unit/resource_volcengine_organization_unit.go b/volcengine/organization/organization_unit/resource_volcengine_organization_unit.go new file mode 100644 index 00000000..6bacb9b4 --- /dev/null +++ b/volcengine/organization/organization_unit/resource_volcengine_organization_unit.go @@ -0,0 +1,111 @@ +package organization_unit + +import ( + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +OrganizationUnit can be imported using the id, e.g. +``` +$ terraform import volcengine_organization_unit.default ID +``` + +*/ + +func ResourceVolcengineOrganizationUnit() *schema.Resource { + resource := &schema.Resource{ + Create: resourceVolcengineOrganizationUnitCreate, + Read: resourceVolcengineOrganizationUnitRead, + Update: resourceVolcengineOrganizationUnitUpdate, + Delete: resourceVolcengineOrganizationUnitDelete, + 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{ + "parent_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Parent Organization Unit ID.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "Name of the organization unit.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Description of the organization unit.", + }, + "org_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the organization.", + }, + "org_type": { + Type: schema.TypeInt, + Computed: true, + Description: "The organization type.", + }, + "depth": { + Type: schema.TypeInt, + Computed: true, + Description: "The depth of the organization unit.", + }, + "owner": { + Type: schema.TypeString, + Computed: true, + Description: "The owner of the organization unit.", + }, + }, + } + return resource +} + +func resourceVolcengineOrganizationUnitCreate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewOrganizationUnitService(meta.(*ve.SdkClient)) + err = service.Dispatcher.Create(service, d, ResourceVolcengineOrganizationUnit()) + if err != nil { + return fmt.Errorf("error on creating organization_unit %q, %s", d.Id(), err) + } + return resourceVolcengineOrganizationUnitRead(d, meta) +} + +func resourceVolcengineOrganizationUnitRead(d *schema.ResourceData, meta interface{}) (err error) { + service := NewOrganizationUnitService(meta.(*ve.SdkClient)) + err = service.Dispatcher.Read(service, d, ResourceVolcengineOrganizationUnit()) + if err != nil { + return fmt.Errorf("error on reading organization_unit %q, %s", d.Id(), err) + } + return err +} + +func resourceVolcengineOrganizationUnitUpdate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewOrganizationUnitService(meta.(*ve.SdkClient)) + err = service.Dispatcher.Update(service, d, ResourceVolcengineOrganizationUnit()) + if err != nil { + return fmt.Errorf("error on updating organization_unit %q, %s", d.Id(), err) + } + return resourceVolcengineOrganizationUnitRead(d, meta) +} + +func resourceVolcengineOrganizationUnitDelete(d *schema.ResourceData, meta interface{}) (err error) { + service := NewOrganizationUnitService(meta.(*ve.SdkClient)) + err = service.Dispatcher.Delete(service, d, ResourceVolcengineOrganizationUnit()) + if err != nil { + return fmt.Errorf("error on deleting organization_unit %q, %s", d.Id(), err) + } + return err +} diff --git a/volcengine/organization/organization_unit/service_volcengine_organization_unit.go b/volcengine/organization/organization_unit/service_volcengine_organization_unit.go new file mode 100644 index 00000000..cd978722 --- /dev/null +++ b/volcengine/organization/organization_unit/service_volcengine_organization_unit.go @@ -0,0 +1,206 @@ +package organization_unit + +import ( + "encoding/json" + "errors" + "fmt" + "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 VolcengineOrganizationUnitService struct { + Client *ve.SdkClient + Dispatcher *ve.Dispatcher +} + +func NewOrganizationUnitService(c *ve.SdkClient) *VolcengineOrganizationUnitService { + return &VolcengineOrganizationUnitService{ + Client: c, + Dispatcher: &ve.Dispatcher{}, + } +} + +func (s *VolcengineOrganizationUnitService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineOrganizationUnitService) 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 := "ListOrganizationalUnits" + + bytes, _ := json.Marshal(condition) + logger.Debug(logger.ReqFormat, action, string(bytes)) + 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 + } + } + respBytes, _ := json.Marshal(resp) + logger.Debug(logger.RespFormat, action, condition, string(respBytes)) + results, err = ve.ObtainSdkValue("Result.SubUnitList", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.SubUnitList is not Slice") + } + return data, err + }) +} + +func (s *VolcengineOrganizationUnitService) ReadResource(resourceData *schema.ResourceData, id string) (data map[string]interface{}, err error) { + var ( + results []interface{} + temp map[string]interface{} + ok bool + ) + if id == "" { + id = s.ReadResourceId(resourceData.Id()) + } + req := map[string]interface{}{} + results, err = s.ReadResources(req) + if err != nil { + return data, err + } + for _, v := range results { + if temp, ok = v.(map[string]interface{}); !ok { + return data, errors.New("Value is not map ") + } else if temp["ID"].(string) == id { + data = temp + } + } + if len(data) == 0 { + return data, fmt.Errorf("organization_unit %s not exist ", id) + } + return data, err +} + +func (s *VolcengineOrganizationUnitService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return &resource.StateChangeConf{} +} + +func (s *VolcengineOrganizationUnitService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "CreateOrganizationalUnit", + ConvertMode: ve.RequestConvertAll, + Convert: map[string]ve.RequestConvert{}, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + resp, err := s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + logger.Debug(logger.RespFormat, call.Action, resp, err) + return resp, err + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + id, _ := ve.ObtainSdkValue("Result.ID", *resp) + d.SetId(id.(string)) + return nil + }, + }, + } + return []ve.Callback{callback} +} + +func (VolcengineOrganizationUnitService) 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 *VolcengineOrganizationUnitService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "UpdateOrganizationalUnit", + ConvertMode: ve.RequestConvertInConvert, + Convert: map[string]ve.RequestConvert{ + "description": { + TargetField: "Description", + }, + }, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["OrgUnitId"] = d.Id() + (*call.SdkParam)["Name"] = d.Get("name") + 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) + resp, err := s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + logger.Debug(logger.RespFormat, call.Action, resp, err) + return resp, err + }, + }, + } + return []ve.Callback{callback} +} + +func (s *VolcengineOrganizationUnitService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "DeleteOrganizationalUnit", + ConvertMode: ve.RequestConvertIgnore, + SdkParam: &map[string]interface{}{ + "OrgUnitId": 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(getUniversalInfo(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, 5*time.Minute) + }, + }, + } + return []ve.Callback{callback} +} + +func (s *VolcengineOrganizationUnitService) DatasourceResources(*schema.ResourceData, *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{ + NameField: "Name", + IdField: "ID", + CollectField: "units", + ResponseConverts: map[string]ve.ResponseConvert{ + "ID": { + TargetField: "id", + }, + "OrgID": { + TargetField: "org_id", + }, + "ParentID": { + TargetField: "parent_id", + }, + }, + } +} + +func (s *VolcengineOrganizationUnitService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "organization", + Version: "2022-01-01", + HttpMethod: ve.GET, + ContentType: ve.Default, + Action: actionName, + } +} diff --git a/volcengine/provider.go b/volcengine/provider.go index 249ef7b6..4155bbcd 100644 --- a/volcengine/provider.go +++ b/volcengine/provider.go @@ -1,6 +1,8 @@ package volcengine import ( + "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_unit" + "github.com/volcengine/terraform-provider-volcengine/volcengine/alb/alb" "github.com/volcengine/terraform-provider-volcengine/volcengine/alb/alb_acl" "github.com/volcengine/terraform-provider-volcengine/volcengine/alb/alb_certificate" @@ -547,6 +549,9 @@ func Provider() terraform.ResourceProvider { "volcengine_rds_postgresql_databases": rds_postgresql_database.DataSourceVolcengineRdsPostgresqlDatabases(), "volcengine_rds_postgresql_accounts": rds_postgresql_account.DataSourceVolcengineRdsPostgresqlAccounts(), "volcengine_rds_postgresql_instances": rds_postgresql_instance.DataSourceVolcengineRdsPostgresqlInstances(), + + // ================ Organization ================ + "volcengine_organization_units": organization_unit.DataSourceVolcengineOrganizationUnits(), }, ResourcesMap: map[string]*schema.Resource{ "volcengine_vpc": vpc.ResourceVolcengineVpc(), @@ -800,6 +805,9 @@ func Provider() terraform.ResourceProvider { "volcengine_rds_postgresql_account": rds_postgresql_account.ResourceVolcengineRdsPostgresqlAccount(), "volcengine_rds_postgresql_instance": rds_postgresql_instance.ResourceVolcengineRdsPostgresqlInstance(), "volcengine_rds_postgresql_instance_readonly_node": rds_postgresql_instance_readonly_node.ResourceVolcengineRdsPostgresqlInstanceReadonlyNode(), + + // ================ Organization ================ + "volcengine_organization_unit": organization_unit.ResourceVolcengineOrganizationUnit(), }, ConfigureFunc: ProviderConfigure, } From 5902d2b9bb7d41debe153de3fb9e58b7ac4f9335 Mon Sep 17 00:00:00 2001 From: zhangpeihua Date: Tue, 5 Dec 2023 14:06:02 +0800 Subject: [PATCH 04/13] feat: support policy enabler --- .../main.tf | 3 + ...nization_service_control_policy_enabler.go | 57 ++++++++ ...nization_service_control_policy_enabler.go | 129 ++++++++++++++++++ volcengine/provider.go | 4 +- 4 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 example/organizationServiceControlPolicyEnabler/main.tf create mode 100644 volcengine/organization/organization_service_control_policy_enabler/resource_volcengine_organization_service_control_policy_enabler.go create mode 100644 volcengine/organization/organization_service_control_policy_enabler/service_volcengine_organization_service_control_policy_enabler.go diff --git a/example/organizationServiceControlPolicyEnabler/main.tf b/example/organizationServiceControlPolicyEnabler/main.tf new file mode 100644 index 00000000..2c32f058 --- /dev/null +++ b/example/organizationServiceControlPolicyEnabler/main.tf @@ -0,0 +1,3 @@ +resource "volcengine_organization_service_control_policy_enabler" "foo" { + +} \ No newline at end of file diff --git a/volcengine/organization/organization_service_control_policy_enabler/resource_volcengine_organization_service_control_policy_enabler.go b/volcengine/organization/organization_service_control_policy_enabler/resource_volcengine_organization_service_control_policy_enabler.go new file mode 100644 index 00000000..7b7c55af --- /dev/null +++ b/volcengine/organization/organization_service_control_policy_enabler/resource_volcengine_organization_service_control_policy_enabler.go @@ -0,0 +1,57 @@ +package organization_service_control_policy_enabler + +import ( + "fmt" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +ServiceControlPolicy enabler can be imported using the default_id (organization:service_control_policy_enable) , e.g. +``` +$ terraform import volcengine_organization_service_control_policy_enabler.default organization:service_control_policy_enable +``` + +*/ + +func ResourceVolcengineOrganizationServiceControlPolicyEnabler() *schema.Resource { + resource := &schema.Resource{ + Create: resourceVolcengineOrganizationServiceControlPolicyEnablerCreate, + Read: resourceVolcengineOrganizationServiceControlPolicyEnablerRead, + Delete: resourceVolcengineOrganizationServiceControlPolicyEnablerDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{}, + } + return resource +} + +func resourceVolcengineOrganizationServiceControlPolicyEnablerCreate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Create(service, d, ResourceVolcengineOrganizationServiceControlPolicyEnabler()) + if err != nil { + return fmt.Errorf("error on creating organization_service_control_policy_enabler: %q, %s", d.Id(), err) + } + return resourceVolcengineOrganizationServiceControlPolicyEnablerRead(d, meta) +} + +func resourceVolcengineOrganizationServiceControlPolicyEnablerRead(d *schema.ResourceData, meta interface{}) (err error) { + service := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Read(service, d, ResourceVolcengineOrganizationServiceControlPolicyEnabler()) + if err != nil { + return fmt.Errorf("error on reading organization_service_control_policy_enabler: %q, %s", d.Id(), err) + } + return err +} + +func resourceVolcengineOrganizationServiceControlPolicyEnablerDelete(d *schema.ResourceData, meta interface{}) (err error) { + service := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Delete(service, d, ResourceVolcengineOrganizationServiceControlPolicyEnabler()) + if err != nil { + return fmt.Errorf("erron on deleting organization_service_control_policy_enabler: %q, %s", d.Id(), err) + } + return err +} diff --git a/volcengine/organization/organization_service_control_policy_enabler/service_volcengine_organization_service_control_policy_enabler.go b/volcengine/organization/organization_service_control_policy_enabler/service_volcengine_organization_service_control_policy_enabler.go new file mode 100644 index 00000000..0a9d1af4 --- /dev/null +++ b/volcengine/organization/organization_service_control_policy_enabler/service_volcengine_organization_service_control_policy_enabler.go @@ -0,0 +1,129 @@ +package organization_service_control_policy_enabler + +import ( + "fmt" + "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 VolcengineOrganizationServiceControlPolicyEnablerService struct { + Client *ve.SdkClient +} + +func (s *VolcengineOrganizationServiceControlPolicyEnablerService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + return nil, nil +} + +func (s *VolcengineOrganizationServiceControlPolicyEnablerService) ReadResource(resourceData *schema.ResourceData, id string) (data map[string]interface{}, err error) { + universalClient := s.Client.UniversalClient + action := "GetServiceControlPolicyEnablement" + resp, err := universalClient.DoCall(getUniversalInfo(action), &map[string]interface{}{}) + if err != nil { + return nil, err + } + logger.Debug(logger.ReqFormat, action, *resp) + status, err := ve.ObtainSdkValue("Result.Status", *resp) + if err != nil { + return nil, err + } + + if status != "Enabled" { + return data, fmt.Errorf(" Organization Service Control Policy is not Enabled") + } + return map[string]interface{}{ + "Status": status, + }, nil +} + +func (s *VolcengineOrganizationServiceControlPolicyEnablerService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return nil +} + +func (s *VolcengineOrganizationServiceControlPolicyEnablerService) WithResourceResponseHandlers(m map[string]interface{}) []ve.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]ve.ResponseConvert, error) { + return m, nil, nil + } + return []ve.ResourceResponseHandler{handler} +} + +func (s *VolcengineOrganizationServiceControlPolicyEnablerService) CreateResource(data *schema.ResourceData, resource *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "EnableServiceControlPolicy", + ConvertMode: ve.RequestConvertIgnore, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + // 先检查是否开启 + resp, err := s.Client.UniversalClient.DoCall(getUniversalInfo("GetServiceControlPolicyEnablement"), &map[string]interface{}{}) + if err != nil { + return nil, err + } + logger.Debug(logger.ReqFormat, "GetServiceControlPolicyEnablement", *resp) + status, err := ve.ObtainSdkValue("Result.Status", *resp) + if err != nil { + return nil, err + } + if status == "Enabled" { + return nil, nil // 不需要再重复开启了 + } + + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + d.SetId("organization:service_control_policy_enable") + return nil + }, + }, + } + return []ve.Callback{callback} +} + +func (s *VolcengineOrganizationServiceControlPolicyEnablerService) ModifyResource(data *schema.ResourceData, resource *schema.Resource) []ve.Callback { + return []ve.Callback{} +} + +func (s *VolcengineOrganizationServiceControlPolicyEnablerService) RemoveResource(data *schema.ResourceData, r *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "DisableServiceControlPolicy", + ConvertMode: ve.RequestConvertIgnore, + 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(getUniversalInfo(call.Action), call.SdkParam) + }, + }, + } + return []ve.Callback{callback} +} + +func (s *VolcengineOrganizationServiceControlPolicyEnablerService) DatasourceResources(data *schema.ResourceData, resource *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{} +} + +func (s *VolcengineOrganizationServiceControlPolicyEnablerService) ReadResourceId(id string) string { + return id +} + +func NewService(client *ve.SdkClient) *VolcengineOrganizationServiceControlPolicyEnablerService { + return &VolcengineOrganizationServiceControlPolicyEnablerService{ + Client: client, + } +} + +func (s *VolcengineOrganizationServiceControlPolicyEnablerService) GetClient() *ve.SdkClient { + return s.Client +} + +func getUniversalInfo(action string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "organization", + Action: action, + Version: "2022-01-01", + HttpMethod: ve.GET, + ContentType: ve.Default, + } +} diff --git a/volcengine/provider.go b/volcengine/provider.go index 4155bbcd..2e43bf6d 100644 --- a/volcengine/provider.go +++ b/volcengine/provider.go @@ -1,6 +1,7 @@ package volcengine import ( + "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_service_control_policy_enabler" "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_unit" "github.com/volcengine/terraform-provider-volcengine/volcengine/alb/alb" @@ -807,7 +808,8 @@ func Provider() terraform.ResourceProvider { "volcengine_rds_postgresql_instance_readonly_node": rds_postgresql_instance_readonly_node.ResourceVolcengineRdsPostgresqlInstanceReadonlyNode(), // ================ Organization ================ - "volcengine_organization_unit": organization_unit.ResourceVolcengineOrganizationUnit(), + "volcengine_organization_unit": organization_unit.ResourceVolcengineOrganizationUnit(), + "volcengine_organization_service_control_policy_enabler": organization_service_control_policy_enabler.ResourceVolcengineOrganizationServiceControlPolicyEnabler(), }, ConfigureFunc: ProviderConfigure, } From 00d136453921128fe4e5bf8caf004254e9c84310 Mon Sep 17 00:00:00 2001 From: zhangpeihua Date: Tue, 5 Dec 2023 15:10:19 +0800 Subject: [PATCH 05/13] feat: add service support --- .../main.tf | 4 + .../organizationServiceControlPolicy/main.tf | 10 + ...e_organization_service_control_policies.go | 83 +++++++ ...ine_organization_service_control_policy.go | 112 +++++++++ ...ine_organization_service_control_policy.go | 217 ++++++++++++++++++ volcengine/provider.go | 5 +- 6 files changed, 430 insertions(+), 1 deletion(-) create mode 100644 example/dataOrganizationServiceControlPolicies/main.tf create mode 100644 example/organizationServiceControlPolicy/main.tf create mode 100644 volcengine/organization/organization_service_control_policy/data_source_volcengine_organization_service_control_policies.go create mode 100644 volcengine/organization/organization_service_control_policy/resource_volcengine_organization_service_control_policy.go create mode 100644 volcengine/organization/organization_service_control_policy/service_volcengine_organization_service_control_policy.go diff --git a/example/dataOrganizationServiceControlPolicies/main.tf b/example/dataOrganizationServiceControlPolicies/main.tf new file mode 100644 index 00000000..50ca3921 --- /dev/null +++ b/example/dataOrganizationServiceControlPolicies/main.tf @@ -0,0 +1,4 @@ +data "volcengine_organization_service_control_policies" "foo" { + policy_type = "Custom" + query = "test" +} \ No newline at end of file diff --git a/example/organizationServiceControlPolicy/main.tf b/example/organizationServiceControlPolicy/main.tf new file mode 100644 index 00000000..fb3c59a2 --- /dev/null +++ b/example/organizationServiceControlPolicy/main.tf @@ -0,0 +1,10 @@ +resource "volcengine_organization_service_control_policy" "foo" { + policy_name = "tfpolicy11" + description = "tftest1" + statement = "{\"Statement\":[{\"Effect\":\"Deny\",\"Action\":[\"ecs:RunInstances\"],\"Resource\":[\"*\"]}]}" +} + +resource "volcengine_organization_service_control_policy" "foo2" { + policy_name = "tfpolicy21" + statement = "{\"Statement\":[{\"Effect\":\"Deny\",\"Action\":[\"ecs:DeleteInstance\"],\"Resource\":[\"*\"]}]}" +} \ No newline at end of file diff --git a/volcengine/organization/organization_service_control_policy/data_source_volcengine_organization_service_control_policies.go b/volcengine/organization/organization_service_control_policy/data_source_volcengine_organization_service_control_policies.go new file mode 100644 index 00000000..0f999ba0 --- /dev/null +++ b/volcengine/organization/organization_service_control_policy/data_source_volcengine_organization_service_control_policies.go @@ -0,0 +1,83 @@ +package organization_service_control_policy + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +func DataSourceVolcengineServiceControlPolicies() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcengineServiceControlPoliciesRead, + 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 Policy query.", + }, + "query": { + Type: schema.TypeString, + Optional: true, + Description: "Query policies, support policy name or description.", + }, + "policy_type": { + Type: schema.TypeString, + Optional: true, + Description: "The type of policy. The value can be System or Custom", + }, + "policies": { + Description: "The collection of Policy 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 Policy.", + }, + "policy_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the Policy.", + }, + "policy_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the Policy.", + }, + "create_date": { + Type: schema.TypeString, + Computed: true, + Description: "The create time of the Policy.", + }, + "update_date": { + Type: schema.TypeString, + Computed: true, + Description: "The update time of the Policy.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the Policy.", + }, + "statement": { + Type: schema.TypeString, + Computed: true, + Description: "The statement of the Policy.", + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcengineServiceControlPoliciesRead(d *schema.ResourceData, meta interface{}) error { + iamPolicyService := NewService(meta.(*ve.SdkClient)) + return ve.DefaultDispatcher().Data(iamPolicyService, d, DataSourceVolcengineServiceControlPolicies()) +} diff --git a/volcengine/organization/organization_service_control_policy/resource_volcengine_organization_service_control_policy.go b/volcengine/organization/organization_service_control_policy/resource_volcengine_organization_service_control_policy.go new file mode 100644 index 00000000..66381b6e --- /dev/null +++ b/volcengine/organization/organization_service_control_policy/resource_volcengine_organization_service_control_policy.go @@ -0,0 +1,112 @@ +package organization_service_control_policy + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +Service Control Policy can be imported using the id, e.g. +``` +$ terraform import volcengine_organization_service_control_policy.default 1000001 +``` + +*/ + +func ResourceVolcengineServiceControlPolicy() *schema.Resource { + return &schema.Resource{ + Create: resourceVolcengineServiceControlPolicyCreate, + Read: resourceVolcengineServiceControlPolicyRead, + Update: resourceVolcengineServiceControlPolicyUpdate, + Delete: resourceVolcengineServiceControlPolicyDelete, + 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{ + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The description of the Policy.", + }, + "statement": { + Type: schema.TypeString, + Required: true, + Description: "The statement of the Policy.", + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + oldMap := make(map[string]interface{}) + newMap := make(map[string]interface{}) + + _ = json.Unmarshal([]byte(old), &oldMap) + _ = json.Unmarshal([]byte(new), &newMap) + + oldStr, _ := json.MarshalIndent(oldMap, "", "\t") + newStr, _ := json.MarshalIndent(newMap, "", "\t") + return string(oldStr) == string(newStr) + }, + }, + "policy_name": { + Type: schema.TypeString, + Required: true, + Description: "The name of the Policy.", + }, + "policy_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the Policy.", + }, + "create_date": { + Type: schema.TypeString, + Computed: true, + Description: "The create time of the Policy.", + }, + "update_date": { + Type: schema.TypeString, + Computed: true, + Description: "The update time of the Policy.", + }, + }, + } +} + +func resourceVolcengineServiceControlPolicyCreate(d *schema.ResourceData, meta interface{}) error { + iamPolicyService := NewService(meta.(*ve.SdkClient)) + if err := ve.DefaultDispatcher().Create(iamPolicyService, d, ResourceVolcengineServiceControlPolicy()); err != nil { + return fmt.Errorf("error on creating policy %q, %w", d.Id(), err) + } + return resourceVolcengineServiceControlPolicyRead(d, meta) +} + +func resourceVolcengineServiceControlPolicyRead(d *schema.ResourceData, meta interface{}) error { + iamPolicyService := NewService(meta.(*ve.SdkClient)) + if err := ve.DefaultDispatcher().Read(iamPolicyService, d, ResourceVolcengineServiceControlPolicy()); err != nil { + return fmt.Errorf("error on reading policy %q, %w", d.Id(), err) + } + return nil +} + +func resourceVolcengineServiceControlPolicyUpdate(d *schema.ResourceData, meta interface{}) error { + iamPolicyService := NewService(meta.(*ve.SdkClient)) + if err := ve.DefaultDispatcher().Update(iamPolicyService, d, ResourceVolcengineServiceControlPolicy()); err != nil { + return fmt.Errorf("error on updating policy %q, %w", d.Id(), err) + } + return resourceVolcengineServiceControlPolicyRead(d, meta) +} + +func resourceVolcengineServiceControlPolicyDelete(d *schema.ResourceData, meta interface{}) error { + iamPolicyService := NewService(meta.(*ve.SdkClient)) + if err := ve.DefaultDispatcher().Delete(iamPolicyService, d, ResourceVolcengineServiceControlPolicy()); err != nil { + return fmt.Errorf("error on deleting policy %q, %w", d.Id(), err) + } + return nil +} diff --git a/volcengine/organization/organization_service_control_policy/service_volcengine_organization_service_control_policy.go b/volcengine/organization/organization_service_control_policy/service_volcengine_organization_service_control_policy.go new file mode 100644 index 00000000..9227920f --- /dev/null +++ b/volcengine/organization/organization_service_control_policy/service_volcengine_organization_service_control_policy.go @@ -0,0 +1,217 @@ +package organization_service_control_policy + +import ( + "errors" + "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 VolcenginePolicyService struct { + Client *ve.SdkClient +} + +func NewService(c *ve.SdkClient) *VolcenginePolicyService { + return &VolcenginePolicyService{ + Client: c, + } +} + +func (s *VolcenginePolicyService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcenginePolicyService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + + return ve.WithPageNumberQuery(m, "PageSize", "PageNumber", 100, 1, func(condition map[string]interface{}) (data []interface{}, err error) { + action := "ListServiceControlPolicies" + logger.Debug(logger.ReqFormat, action, condition) + if condition == nil { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), nil) + if err != nil { + return nil, err + } + } else { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &condition) + if err != nil { + return nil, err + } + } + + results, err = ve.ObtainSdkValue("Result.ServiceControlPolicies", *resp) + if err != nil { + return nil, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.ServiceControlPolicies is not Slice") + } + + // 获取每一个策略内容 + for _, ele := range data { + temp, err := s.Client.UniversalClient.DoCall(getUniversalInfo("GetServiceControlPolicy"), &map[string]interface{}{ + "PolicyID": ele.(map[string]interface{})["PolicyID"], + }) + if err != nil { + return nil, err + } + statement, err := ve.ObtainSdkValue("Result.Statement", *temp) + if err != nil { + return nil, err + } + ele.(map[string]interface{})["Statement"] = statement + } + return data, err + }) +} + +func (s *VolcenginePolicyService) ReadResource(resourceData *schema.ResourceData, policyId string) (data map[string]interface{}, err error) { + if policyId == "" { + policyId = s.ReadResourceId(resourceData.Id()) + } + req := map[string]interface{}{ + "PolicyID": policyId, + } + temp, err := s.Client.UniversalClient.DoCall(getUniversalInfo("GetServiceControlPolicy"), &req) + if err != nil { + return nil, err + } + res, err := ve.ObtainSdkValue("Result", *temp) + if err != nil { + return nil, err + } + return res.(map[string]interface{}), nil +} + +func (s *VolcenginePolicyService) RefreshResourceState(data *schema.ResourceData, strings []string, duration time.Duration, id string) *resource.StateChangeConf { + return nil +} + +func (s *VolcenginePolicyService) WithResourceResponseHandlers(policy map[string]interface{}) []ve.ResourceResponseHandler { + return []ve.ResourceResponseHandler{} +} + +func (s *VolcenginePolicyService) CreateResource(data *schema.ResourceData, resource *schema.Resource) []ve.Callback { + createIamPolicyCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "CreateServiceControlPolicy", + ConvertMode: ve.RequestConvertAll, + 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(postUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + policyId, err := ve.ObtainSdkValue("Result.PolicyId", *resp) + if err != nil { + return err + } + d.SetId(policyId.(string)) + return nil + }, + // 必须顺序执行,否则并发失败 + LockId: func(d *schema.ResourceData) string { + return "lock-ServiceControlPolicy" + }, + }, + } + return []ve.Callback{createIamPolicyCallback} +} + +func (s *VolcenginePolicyService) ModifyResource(data *schema.ResourceData, resource *schema.Resource) []ve.Callback { + updatePolicyCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "UpdateServiceControlPolicy", + ConvertMode: ve.RequestConvertInConvert, + Convert: map[string]ve.RequestConvert{ + "policy_name": { + ForceGet: true, + }, + "description": { + ForceGet: true, + }, + "statement": { + ForceGet: true, + }, + }, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["PolicyID"] = d.Id() + 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(postUniversalInfo(call.Action), call.SdkParam) + }, + LockId: func(d *schema.ResourceData) string { + return "lock-ServiceControlPolicy" + }, + }, + } + return []ve.Callback{updatePolicyCallback} +} + +func (s *VolcenginePolicyService) RemoveResource(data *schema.ResourceData, r *schema.Resource) []ve.Callback { + deletePolicyCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "DeleteServiceControlPolicy", + ConvertMode: ve.RequestConvertIgnore, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["PolicyID"] = d.Id() + 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(postUniversalInfo(call.Action), call.SdkParam) + }, + LockId: func(d *schema.ResourceData) string { + return "lock-ServiceControlPolicy" + }, + }, + } + return []ve.Callback{deletePolicyCallback} +} + +func (s *VolcenginePolicyService) DatasourceResources(data *schema.ResourceData, resource *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{ + ResponseConverts: map[string]ve.ResponseConvert{ + "PolicyID": { + TargetField: "id", + }, + }, + NameField: "PolicyName", + IdField: "PolicyID", + CollectField: "policies", + } +} + +func (s *VolcenginePolicyService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "organization", + Version: "2022-01-01", + HttpMethod: ve.GET, + Action: actionName, + } +} + +func postUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "organization", + Version: "2022-01-01", + HttpMethod: ve.POST, + Action: actionName, + ContentType: ve.ApplicationJSON, + } +} diff --git a/volcengine/provider.go b/volcengine/provider.go index 2e43bf6d..eb3de1c2 100644 --- a/volcengine/provider.go +++ b/volcengine/provider.go @@ -1,6 +1,7 @@ package volcengine import ( + "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_service_control_policy" "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_service_control_policy_enabler" "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_unit" @@ -552,7 +553,8 @@ func Provider() terraform.ResourceProvider { "volcengine_rds_postgresql_instances": rds_postgresql_instance.DataSourceVolcengineRdsPostgresqlInstances(), // ================ Organization ================ - "volcengine_organization_units": organization_unit.DataSourceVolcengineOrganizationUnits(), + "volcengine_organization_units": organization_unit.DataSourceVolcengineOrganizationUnits(), + "volcengine_organization_service_control_policies": organization_service_control_policy.DataSourceVolcengineServiceControlPolicies(), }, ResourcesMap: map[string]*schema.Resource{ "volcengine_vpc": vpc.ResourceVolcengineVpc(), @@ -810,6 +812,7 @@ func Provider() terraform.ResourceProvider { // ================ Organization ================ "volcengine_organization_unit": organization_unit.ResourceVolcengineOrganizationUnit(), "volcengine_organization_service_control_policy_enabler": organization_service_control_policy_enabler.ResourceVolcengineOrganizationServiceControlPolicyEnabler(), + "volcengine_organization_service_control_policy": organization_service_control_policy.ResourceVolcengineServiceControlPolicy(), }, ConfigureFunc: ProviderConfigure, } From 57c202fb3e210caee1dc4dcbc5f1ea189d1b2745 Mon Sep 17 00:00:00 2001 From: zhangpeihua Date: Tue, 5 Dec 2023 15:26:17 +0800 Subject: [PATCH 06/13] feat: add delay time for enabler --- ...volcengine_organization_service_control_policy_enabler.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/volcengine/organization/organization_service_control_policy_enabler/service_volcengine_organization_service_control_policy_enabler.go b/volcengine/organization/organization_service_control_policy_enabler/service_volcengine_organization_service_control_policy_enabler.go index 0a9d1af4..9407117e 100644 --- a/volcengine/organization/organization_service_control_policy_enabler/service_volcengine_organization_service_control_policy_enabler.go +++ b/volcengine/organization/organization_service_control_policy_enabler/service_volcengine_organization_service_control_policy_enabler.go @@ -75,6 +75,7 @@ func (s *VolcengineOrganizationServiceControlPolicyEnablerService) CreateResourc }, AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { d.SetId("organization:service_control_policy_enable") + time.Sleep(3 * time.Second) return nil }, }, @@ -95,6 +96,10 @@ func (s *VolcengineOrganizationServiceControlPolicyEnablerService) RemoveResourc logger.Debug(logger.RespFormat, call.Action, call.SdkParam) return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + time.Sleep(3 * time.Second) + return nil + }, }, } return []ve.Callback{callback} From a096fb49a9ed22f47fee2f7aa71dc7637a50e411 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=93=B2=E9=93=AD?= Date: Wed, 6 Dec 2023 10:48:12 +0800 Subject: [PATCH 07/13] feat: organization add lock --- example/organizationUnit/main.tf | 2 +- ...volcengine_organization_service_control_policy.go | 8 +++++--- ...ne_organization_service_control_policy_enabler.go | 8 ++++++++ .../service_volcengine_organization_unit.go | 12 ++++++++++++ 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/example/organizationUnit/main.tf b/example/organizationUnit/main.tf index 844b8533..59ca8a8e 100644 --- a/example/organizationUnit/main.tf +++ b/example/organizationUnit/main.tf @@ -1,5 +1,5 @@ resource "volcengine_organization_unit" "foo" { - name = "tftest2" + name = "tftest57" parent_id = "7306629044253098034" description = "test" } \ No newline at end of file diff --git a/volcengine/organization/organization_service_control_policy/service_volcengine_organization_service_control_policy.go b/volcengine/organization/organization_service_control_policy/service_volcengine_organization_service_control_policy.go index 9227920f..c5f68b38 100644 --- a/volcengine/organization/organization_service_control_policy/service_volcengine_organization_service_control_policy.go +++ b/volcengine/organization/organization_service_control_policy/service_volcengine_organization_service_control_policy.go @@ -120,7 +120,7 @@ func (s *VolcenginePolicyService) CreateResource(data *schema.ResourceData, reso }, // 必须顺序执行,否则并发失败 LockId: func(d *schema.ResourceData) string { - return "lock-ServiceControlPolicy" + return "lock-Organization" }, }, } @@ -151,8 +151,9 @@ func (s *VolcenginePolicyService) ModifyResource(data *schema.ResourceData, reso logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) return s.Client.UniversalClient.DoCall(postUniversalInfo(call.Action), call.SdkParam) }, + // 必须顺序执行,否则并发失败 LockId: func(d *schema.ResourceData) string { - return "lock-ServiceControlPolicy" + return "lock-Organization" }, }, } @@ -172,8 +173,9 @@ func (s *VolcenginePolicyService) RemoveResource(data *schema.ResourceData, r *s logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) return s.Client.UniversalClient.DoCall(postUniversalInfo(call.Action), call.SdkParam) }, + // 必须顺序执行,否则并发失败 LockId: func(d *schema.ResourceData) string { - return "lock-ServiceControlPolicy" + return "lock-Organization" }, }, } diff --git a/volcengine/organization/organization_service_control_policy_enabler/service_volcengine_organization_service_control_policy_enabler.go b/volcengine/organization/organization_service_control_policy_enabler/service_volcengine_organization_service_control_policy_enabler.go index 9407117e..82530720 100644 --- a/volcengine/organization/organization_service_control_policy_enabler/service_volcengine_organization_service_control_policy_enabler.go +++ b/volcengine/organization/organization_service_control_policy_enabler/service_volcengine_organization_service_control_policy_enabler.go @@ -78,6 +78,10 @@ func (s *VolcengineOrganizationServiceControlPolicyEnablerService) CreateResourc time.Sleep(3 * time.Second) return nil }, + // 必须顺序执行,否则并发失败 + LockId: func(d *schema.ResourceData) string { + return "lock-Organization" + }, }, } return []ve.Callback{callback} @@ -100,6 +104,10 @@ func (s *VolcengineOrganizationServiceControlPolicyEnablerService) RemoveResourc time.Sleep(3 * time.Second) return nil }, + // 必须顺序执行,否则并发失败 + LockId: func(d *schema.ResourceData) string { + return "lock-Organization" + }, }, } return []ve.Callback{callback} diff --git a/volcengine/organization/organization_unit/service_volcengine_organization_unit.go b/volcengine/organization/organization_unit/service_volcengine_organization_unit.go index cd978722..f041aaa1 100644 --- a/volcengine/organization/organization_unit/service_volcengine_organization_unit.go +++ b/volcengine/organization/organization_unit/service_volcengine_organization_unit.go @@ -114,6 +114,10 @@ func (s *VolcengineOrganizationUnitService) CreateResource(resourceData *schema. d.SetId(id.(string)) return nil }, + // 必须顺序执行,否则并发失败 + LockId: func(d *schema.ResourceData) string { + return "lock-Organization" + }, }, } return []ve.Callback{callback} @@ -147,6 +151,10 @@ func (s *VolcengineOrganizationUnitService) ModifyResource(resourceData *schema. logger.Debug(logger.RespFormat, call.Action, resp, err) return resp, err }, + // 必须顺序执行,否则并发失败 + LockId: func(d *schema.ResourceData) string { + return "lock-Organization" + }, }, } return []ve.Callback{callback} @@ -167,6 +175,10 @@ func (s *VolcengineOrganizationUnitService) RemoveResource(resourceData *schema. AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { return ve.CheckResourceUtilRemoved(d, s.ReadResource, 5*time.Minute) }, + // 必须顺序执行,否则并发失败 + LockId: func(d *schema.ResourceData) string { + return "lock-Organization" + }, }, } return []ve.Callback{callback} From 9687e566650972dc2e4febb81126d9a4143668ff Mon Sep 17 00:00:00 2001 From: zhangpeihua Date: Mon, 11 Dec 2023 11:43:18 +0800 Subject: [PATCH 08/13] feat: support policy attach --- .../main.tf | 17 ++ ...ine_organization_service_control_policy.go | 8 + ...ation_service_control_policy_attachment.go | 92 +++++++++ ...ation_service_control_policy_attachment.go | 194 ++++++++++++++++++ volcengine/provider.go | 8 +- 5 files changed, 316 insertions(+), 3 deletions(-) create mode 100644 example/organizationServiceControlPolicyAttachment/main.tf create mode 100644 volcengine/organization/organization_service_control_policy_attachment/resource_volcengine_organization_service_control_policy_attachment.go create mode 100644 volcengine/organization/organization_service_control_policy_attachment/service_volcengine_organization_service_control_policy_attachment.go diff --git a/example/organizationServiceControlPolicyAttachment/main.tf b/example/organizationServiceControlPolicyAttachment/main.tf new file mode 100644 index 00000000..634d374d --- /dev/null +++ b/example/organizationServiceControlPolicyAttachment/main.tf @@ -0,0 +1,17 @@ +resource "volcengine_organization_service_control_policy" "foo" { + policy_name = "tfpolicy11" + description = "tftest1" + statement = "{\"Statement\":[{\"Effect\":\"Deny\",\"Action\":[\"ecs:RunInstances\"],\"Resource\":[\"*\"]}]}" +} + +resource "volcengine_organization_service_control_policy_attachment" "foo" { + policy_id = volcengine_organization_service_control_policy.foo.id + target_id = "21*********94" + target_type = "Account" +} + +resource "volcengine_organization_service_control_policy_attachment" "foo1" { + policy_id = volcengine_organization_service_control_policy.foo.id + target_id = "73*********9" + target_type = "OU" +} \ No newline at end of file diff --git a/volcengine/organization/organization_service_control_policy/service_volcengine_organization_service_control_policy.go b/volcengine/organization/organization_service_control_policy/service_volcengine_organization_service_control_policy.go index c5f68b38..d6f47216 100644 --- a/volcengine/organization/organization_service_control_policy/service_volcengine_organization_service_control_policy.go +++ b/volcengine/organization/organization_service_control_policy/service_volcengine_organization_service_control_policy.go @@ -116,6 +116,9 @@ func (s *VolcenginePolicyService) CreateResource(data *schema.ResourceData, reso return err } d.SetId(policyId.(string)) + + // 单独处理 + time.Sleep(2 * time.Second) return nil }, // 必须顺序执行,否则并发失败 @@ -151,6 +154,11 @@ func (s *VolcenginePolicyService) ModifyResource(data *schema.ResourceData, reso logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) return s.Client.UniversalClient.DoCall(postUniversalInfo(call.Action), call.SdkParam) }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + // 单独处理 + time.Sleep(2 * time.Second) + return nil + }, // 必须顺序执行,否则并发失败 LockId: func(d *schema.ResourceData) string { return "lock-Organization" diff --git a/volcengine/organization/organization_service_control_policy_attachment/resource_volcengine_organization_service_control_policy_attachment.go b/volcengine/organization/organization_service_control_policy_attachment/resource_volcengine_organization_service_control_policy_attachment.go new file mode 100644 index 00000000..906637ed --- /dev/null +++ b/volcengine/organization/organization_service_control_policy_attachment/resource_volcengine_organization_service_control_policy_attachment.go @@ -0,0 +1,92 @@ +package organization_service_control_policy_attachment + +import ( + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +Service Control policy attachment can be imported using the id, e.g. +``` +$ terraform import volcengine_organization_service_control_policy_attachment.default PolicyID:TargetID +``` + +*/ + +func ResourceVolcengineServiceControlPolicyAttachment() *schema.Resource { + return &schema.Resource{ + Create: resourceVolcengineServiceControlPolicyAttachmentCreate, + Read: resourceVolcengineServiceControlPolicyAttachmentRead, + Delete: resourceVolcengineServiceControlPolicyAttachmentDelete, + 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 is invalid") + } + if err := data.Set("policy_id", items[0]); err != nil { + return []*schema.ResourceData{data}, err + } + if err := data.Set("target_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{ + "policy_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The id of policy.", + }, + "target_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The id of target.", + }, + "target_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The type of target. Support Account or OU.", + }, + }, + } +} + +func resourceVolcengineServiceControlPolicyAttachmentCreate(d *schema.ResourceData, meta interface{}) error { + service := NewServiceControlPolicyAttachmentService(meta.(*ve.SdkClient)) + if err := ve.DefaultDispatcher().Create(service, d, ResourceVolcengineServiceControlPolicyAttachment()); err != nil { + return fmt.Errorf("error on creating service_control_policy_attachment %q, %w", d.Id(), err) + } + return resourceVolcengineServiceControlPolicyAttachmentRead(d, meta) +} + +func resourceVolcengineServiceControlPolicyAttachmentRead(d *schema.ResourceData, meta interface{}) error { + service := NewServiceControlPolicyAttachmentService(meta.(*ve.SdkClient)) + if err := ve.DefaultDispatcher().Read(service, d, ResourceVolcengineServiceControlPolicyAttachment()); err != nil { + return fmt.Errorf("error on reading service_control_policy_attachment %q, %w", d.Id(), err) + } + return nil +} + +func resourceVolcengineServiceControlPolicyAttachmentDelete(d *schema.ResourceData, meta interface{}) error { + service := NewServiceControlPolicyAttachmentService(meta.(*ve.SdkClient)) + if err := ve.DefaultDispatcher().Delete(service, d, ResourceVolcengineServiceControlPolicyAttachment()); err != nil { + return fmt.Errorf("error on deleting service_control_policy_attachment %q, %w", d.Id(), err) + } + return nil +} diff --git a/volcengine/organization/organization_service_control_policy_attachment/service_volcengine_organization_service_control_policy_attachment.go b/volcengine/organization/organization_service_control_policy_attachment/service_volcengine_organization_service_control_policy_attachment.go new file mode 100644 index 00000000..6e862db1 --- /dev/null +++ b/volcengine/organization/organization_service_control_policy_attachment/service_volcengine_organization_service_control_policy_attachment.go @@ -0,0 +1,194 @@ +package organization_service_control_policy_attachment + +import ( + "errors" + "fmt" + "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" + "strings" + "time" +) + +type VolcengineServiceControlPolicyAttachmentService struct { + Client *ve.SdkClient +} + +func NewServiceControlPolicyAttachmentService(c *ve.SdkClient) *VolcengineServiceControlPolicyAttachmentService { + return &VolcengineServiceControlPolicyAttachmentService{ + Client: c, + } +} + +func (s *VolcengineServiceControlPolicyAttachmentService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineServiceControlPolicyAttachmentService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + action := "ListTargetAttachmentsForServiceControlPolicy" + logger.Debug(logger.ReqFormat, action, m) + if m == nil { + resp, err = s.Client.UniversalClient.DoCall(postUniversalInfo(action), nil) + if err != nil { + return data, err + } + } else { + resp, err = s.Client.UniversalClient.DoCall(postUniversalInfo(action), &m) + if err != nil { + return data, err + } + } + + logger.Debug(logger.RespFormat, action, m, *resp) + + results, err = ve.ObtainSdkValue("Result", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New(" Result is not Slice") + } + return data, err +} + +func (s *VolcengineServiceControlPolicyAttachmentService) ReadResource(resourceData *schema.ResourceData, roleId string) (data map[string]interface{}, err error) { + var ( + results []interface{} + ok bool + ) + if roleId == "" { + roleId = s.ReadResourceId(resourceData.Id()) + } + ids := strings.Split(roleId, ":") + if len(ids) != 2 { + return data, fmt.Errorf("import id is invalid") + } + req := map[string]interface{}{ + "PolicyID": ids[0], + } + 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") + } else if ids[1] == data["TargetID"].(string) { + return data, err + } + } + return data, fmt.Errorf("service control policy attachment %s not exist ", roleId) +} + +func (s *VolcengineServiceControlPolicyAttachmentService) RefreshResourceState(data *schema.ResourceData, strings []string, duration time.Duration, id string) *resource.StateChangeConf { + return nil +} + +func (s *VolcengineServiceControlPolicyAttachmentService) WithResourceResponseHandlers(rolePolicyAttachment map[string]interface{}) []ve.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]ve.ResponseConvert, error) { + return rolePolicyAttachment, map[string]ve.ResponseConvert{ + "TargetID": { + TargetField: "target_id", + }, + "PolicyID": { + TargetField: "policy_id", + }, + }, nil + } + return []ve.ResourceResponseHandler{handler} +} + +func (s *VolcengineServiceControlPolicyAttachmentService) CreateResource(data *schema.ResourceData, resource *schema.Resource) []ve.Callback { + createPolicyAttachmentCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "AttachServiceControlPolicy", + ConvertMode: ve.RequestConvertAll, + Convert: map[string]ve.RequestConvert{ + "policy_id": { + TargetField: "PolicyID", + }, + "target_id": { + TargetField: "TargetID", + }, + "target_type": { + Convert: func(data *schema.ResourceData, old interface{}) interface{} { + ty := 0 + switch old.(string) { + case "OU": + ty = 1 + case "Account": + ty = 2 + } + return ty + }, + }, + }, + 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(postUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + d.SetId(fmt.Sprintf("%s:%s", d.Get("policy_id"), d.Get("target_id"))) + return nil + }, + LockId: func(d *schema.ResourceData) string { + return "lock-Organization" + }, + }, + } + return []ve.Callback{createPolicyAttachmentCallback} +} + +func (s *VolcengineServiceControlPolicyAttachmentService) ModifyResource(data *schema.ResourceData, resource *schema.Resource) []ve.Callback { + return []ve.Callback{} +} + +func (s *VolcengineServiceControlPolicyAttachmentService) RemoveResource(data *schema.ResourceData, r *schema.Resource) []ve.Callback { + deleteRoleCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "DetachServiceControlPolicy", + ConvertMode: ve.RequestConvertIgnore, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + ids := strings.Split(d.Id(), ":") + (*call.SdkParam)["PolicyID"] = ids[0] + (*call.SdkParam)["TargetID"] = ids[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(postUniversalInfo(call.Action), call.SdkParam) + }, + LockId: func(d *schema.ResourceData) string { + return "lock-Organization" + }, + }, + } + return []ve.Callback{deleteRoleCallback} +} + +func (s *VolcengineServiceControlPolicyAttachmentService) DatasourceResources(data *schema.ResourceData, resource *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{} +} + +func (s *VolcengineServiceControlPolicyAttachmentService) ReadResourceId(id string) string { + return id +} + +func postUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "organization", + Version: "2022-01-01", + HttpMethod: ve.POST, + ContentType: ve.ApplicationJSON, + Action: actionName, + } +} diff --git a/volcengine/provider.go b/volcengine/provider.go index eb3de1c2..1c355120 100644 --- a/volcengine/provider.go +++ b/volcengine/provider.go @@ -2,6 +2,7 @@ package volcengine import ( "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_service_control_policy" + "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_service_control_policy_attachment" "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_service_control_policy_enabler" "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_unit" @@ -810,9 +811,10 @@ func Provider() terraform.ResourceProvider { "volcengine_rds_postgresql_instance_readonly_node": rds_postgresql_instance_readonly_node.ResourceVolcengineRdsPostgresqlInstanceReadonlyNode(), // ================ Organization ================ - "volcengine_organization_unit": organization_unit.ResourceVolcengineOrganizationUnit(), - "volcengine_organization_service_control_policy_enabler": organization_service_control_policy_enabler.ResourceVolcengineOrganizationServiceControlPolicyEnabler(), - "volcengine_organization_service_control_policy": organization_service_control_policy.ResourceVolcengineServiceControlPolicy(), + "volcengine_organization_unit": organization_unit.ResourceVolcengineOrganizationUnit(), + "volcengine_organization_service_control_policy_enabler": organization_service_control_policy_enabler.ResourceVolcengineOrganizationServiceControlPolicyEnabler(), + "volcengine_organization_service_control_policy": organization_service_control_policy.ResourceVolcengineServiceControlPolicy(), + "volcengine_organization_service_control_policy_attachment": organization_service_control_policy_attachment.ResourceVolcengineServiceControlPolicyAttachment(), }, ConfigureFunc: ProviderConfigure, } From 253762dbbdbdb3b8322707b3622e286e43d27f5a Mon Sep 17 00:00:00 2001 From: "maoshuai.17" Date: Mon, 11 Dec 2023 16:15:17 +0800 Subject: [PATCH 09/13] feat: support organization account and add the AssumeRole feature to the provider --- common/common_volcengine_config.go | 76 +++- example/dataOrganizationAccounts/main.tf | 5 + example/organizationAccount/main.tf | 17 + go.mod | 1 + ...source_volcengine_organization_accounts.go | 161 +++++++ ...esource_volcengine_organization_account.go | 125 ++++++ ...service_volcengine_organization_account.go | 408 ++++++++++++++++++ volcengine/provider.go | 78 ++++ 8 files changed, 862 insertions(+), 9 deletions(-) create mode 100644 example/dataOrganizationAccounts/main.tf create mode 100644 example/organizationAccount/main.tf create mode 100644 volcengine/organization/organization_account/data_source_volcengine_organization_accounts.go create mode 100644 volcengine/organization/organization_account/resource_volcengine_organization_account.go create mode 100644 volcengine/organization/organization_account/service_volcengine_organization_account.go diff --git a/common/common_volcengine_config.go b/common/common_volcengine_config.go index 33869b7c..67089f78 100644 --- a/common/common_volcengine_config.go +++ b/common/common_volcengine_config.go @@ -6,6 +6,8 @@ import ( "net/http" "net/url" + "github.com/volcengine/volc-sdk-golang/base" + "github.com/volcengine/volc-sdk-golang/service/sts" "github.com/volcengine/volcengine-go-sdk/service/autoscaling" "github.com/volcengine/volcengine-go-sdk/service/clb" "github.com/volcengine/volcengine-go-sdk/service/ecs" @@ -23,15 +25,19 @@ import ( ) type Config struct { - AccessKey string - SecretKey string - SessionToken string - Region string - Endpoint string - DisableSSL bool - CustomerHeaders map[string]string - CustomerEndpoints map[string]string - ProxyUrl string + AccessKey string + SecretKey string + SessionToken string + Region string + Endpoint string + DisableSSL bool + CustomerHeaders map[string]string + CustomerEndpoints map[string]string + ProxyUrl string + AssumeRoleTrn string + AssumeRoleSessionName string + DurationSeconds int + AssumeRolePolicy string } func (c *Config) Client() (*SdkClient, error) { @@ -52,6 +58,14 @@ func (c *Config) Client() (*SdkClient, error) { }). WithEndpoint(volcengineutil.NewEndpoint().WithCustomerEndpoint(c.Endpoint).GetEndpoint()) + if c.AssumeRoleTrn != "" && c.AssumeRoleSessionName != "" { + cred, err := c.assumeRole() + if err != nil { + return nil, err + } + config.WithCredentials(cred) + } + if c.ProxyUrl != "" { u, _ := url.Parse(c.ProxyUrl) t := &http.Transport{ @@ -85,6 +99,50 @@ func (c *Config) Client() (*SdkClient, error) { return &client, nil } +func (c *Config) assumeRole() (*credentials.Credentials, error) { + ins := sts.NewInstance() + if c.Region != "" { + ins.SetRegion(c.Region) + } + if c.Endpoint != "" { + ins.SetHost(c.Endpoint) + } + + ins.Client.SetAccessKey(c.AccessKey) + ins.Client.SetSecretKey(c.SecretKey) + input := &sts.AssumeRoleRequest{ + RoleTrn: c.AssumeRoleTrn, + RoleSessionName: c.AssumeRoleSessionName, + DurationSeconds: c.DurationSeconds, + } + output, statusCode, err := ins.AssumeRole(input) + var ( + reqId string + errObj *base.ErrorObj + ) + if output != nil { + reqId = output.ResponseMetadata.RequestId + errObj = output.ResponseMetadata.Error + } + if err != nil { + return nil, fmt.Errorf("AssumeRole error, httpcode is %v and reqId is %s error is %s", statusCode, reqId, err.Error()) + } + if errObj != nil { + return nil, fmt.Errorf("AssumeRole error, code is %v and reqId is %s error is %s", errObj.Code, reqId, errObj.Message) + } + + if output.Result == nil { + return nil, fmt.Errorf("assume role failed, result is nil") + } + cred := credentials.NewCredentials(&credentials.StaticProvider{Value: credentials.Value{ + AccessKeyID: output.Result.Credentials.AccessKeyId, + SecretAccessKey: output.Result.Credentials.SecretAccessKey, + SessionToken: output.Result.Credentials.SessionToken, + }}) + + return cred, nil +} + func init() { InitLocks() //InitSyncLimit() diff --git a/example/dataOrganizationAccounts/main.tf b/example/dataOrganizationAccounts/main.tf new file mode 100644 index 00000000..e697234e --- /dev/null +++ b/example/dataOrganizationAccounts/main.tf @@ -0,0 +1,5 @@ +data "volcengine_organization_accounts" "foo" { + search = "210061****" + # org_unit_id = "730662904425309****" + # verification_id = "730671013833631****" +} \ No newline at end of file diff --git a/example/organizationAccount/main.tf b/example/organizationAccount/main.tf new file mode 100644 index 00000000..a61b0806 --- /dev/null +++ b/example/organizationAccount/main.tf @@ -0,0 +1,17 @@ +resource "volcengine_organization_unit" "foo" { + name = "acc-test-org-unit" + parent_id = "730671013833632****" + description = "acc-test" +} + +resource "volcengine_organization_account" "foo" { + account_name = "acc-test-account" + show_name = "acc-test-account" + description = "acc-test" + org_unit_id = volcengine_organization_unit.foo.id + + tags { + key = "k1" + value = "v1" + } +} \ No newline at end of file diff --git a/go.mod b/go.mod index b677b22a..ee6f3094 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/hashicorp/terraform-plugin-sdk v1.7.0 github.com/mitchellh/copystructure v1.0.0 github.com/stretchr/testify v1.7.0 + github.com/volcengine/volc-sdk-golang v1.0.23 github.com/volcengine/volcengine-go-sdk v1.0.75 golang.org/x/sync v0.0.0-20190423024810-112230192c58 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 diff --git a/volcengine/organization/organization_account/data_source_volcengine_organization_accounts.go b/volcengine/organization/organization_account/data_source_volcengine_organization_accounts.go new file mode 100644 index 00000000..4c839998 --- /dev/null +++ b/volcengine/organization/organization_account/data_source_volcengine_organization_accounts.go @@ -0,0 +1,161 @@ +package organization_account + +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 DataSourceVolcengineOrganizationAccounts() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcengineOrganizationAccountsRead, + Schema: map[string]*schema.Schema{ + "search": { + Type: schema.TypeString, + Optional: true, + Description: "The id or the show name of the account. This field supports fuzzy query.", + }, + "org_unit_id": { + Type: schema.TypeString, + Optional: true, + Description: "The id of the organization unit.", + }, + "verification_id": { + Type: schema.TypeString, + Optional: true, + Description: "The id of the verification.", + }, + "name_regex": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsValidRegExp, + Description: "A Name Regex of Resource.", + }, + "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.", + }, + "accounts": { + 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 account.", + }, + "account_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the account.", + }, + "account_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the account.", + }, + "show_name": { + Type: schema.TypeString, + Computed: true, + Description: "The show name of the account.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the account.", + }, + "owner": { + Type: schema.TypeString, + Computed: true, + Description: "The owner id of the account.", + }, + "org_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the organization.", + }, + "org_type": { + Type: schema.TypeInt, + Computed: true, + Description: "The type of the organization. `1` means business organization.", + }, + "org_unit_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the organization unit.", + }, + "org_unit_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the organization unit.", + }, + "org_verification_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the organization verification.", + }, + "iam_role": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the iam role.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "The created time of the account.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "The updated time of the account.", + }, + "deleted_time": { + Type: schema.TypeString, + Computed: true, + Description: "The deleted time of the account.", + }, + "delete_uk": { + Type: schema.TypeString, + Computed: true, + Description: "The delete uk of the account.", + }, + "join_type": { + Type: schema.TypeInt, + Computed: true, + Description: "The join type of the account. `0` means create, `1` means invitation.", + }, + "allow_exit": { + Type: schema.TypeInt, + Computed: true, + Description: "Whether to allow exit the organization. `0` means allowed, `1` means not allowed.", + }, + "allow_console": { + Type: schema.TypeInt, + Computed: true, + Description: "Whether to allow the account enable console. `0` means allowed, `1` means not allowed.", + }, + "is_owner": { + Type: schema.TypeInt, + Computed: true, + Description: "Whether the account is owner. `0` means not owner, `1` means owner.", + }, + "tags": ve.TagsSchemaComputed(), + }, + }, + }, + }, + } +} + +func dataSourceVolcengineOrganizationAccountsRead(d *schema.ResourceData, meta interface{}) error { + service := NewOrganizationAccountService(meta.(*ve.SdkClient)) + return service.Dispatcher.Data(service, d, DataSourceVolcengineOrganizationAccounts()) +} diff --git a/volcengine/organization/organization_account/resource_volcengine_organization_account.go b/volcengine/organization/organization_account/resource_volcengine_organization_account.go new file mode 100644 index 00000000..37b00074 --- /dev/null +++ b/volcengine/organization/organization_account/resource_volcengine_organization_account.go @@ -0,0 +1,125 @@ +package organization_account + +import ( + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +OrganizationAccount can be imported using the id, e.g. +``` +$ terraform import volcengine_organization_account.default resource_id +``` + +*/ + +func ResourceVolcengineOrganizationAccount() *schema.Resource { + resource := &schema.Resource{ + Create: resourceVolcengineOrganizationAccountCreate, + Read: resourceVolcengineOrganizationAccountRead, + Update: resourceVolcengineOrganizationAccountUpdate, + Delete: resourceVolcengineOrganizationAccountDelete, + 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{ + "account_name": { + Type: schema.TypeString, + Required: true, + Description: "The name of the account.", + }, + "show_name": { + Type: schema.TypeString, + Required: true, + Description: "The show name of the account.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The description of the account.", + }, + "org_unit_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The id of the organization unit. Default is root organization.", + }, + "tags": ve.TagsSchema(), + + // computed fields + "owner": { + Type: schema.TypeString, + Computed: true, + Description: "The owner id of the account.", + }, + "org_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the organization.", + }, + "org_unit_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the organization unit.", + }, + "org_verification_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the organization verification.", + }, + "iam_role": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the iam role.", + }, + }, + } + return resource +} + +func resourceVolcengineOrganizationAccountCreate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewOrganizationAccountService(meta.(*ve.SdkClient)) + err = service.Dispatcher.Create(service, d, ResourceVolcengineOrganizationAccount()) + if err != nil { + return fmt.Errorf("error on creating organization_account %q, %s", d.Id(), err) + } + return resourceVolcengineOrganizationAccountRead(d, meta) +} + +func resourceVolcengineOrganizationAccountRead(d *schema.ResourceData, meta interface{}) (err error) { + service := NewOrganizationAccountService(meta.(*ve.SdkClient)) + err = service.Dispatcher.Read(service, d, ResourceVolcengineOrganizationAccount()) + if err != nil { + return fmt.Errorf("error on reading organization_account %q, %s", d.Id(), err) + } + return err +} + +func resourceVolcengineOrganizationAccountUpdate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewOrganizationAccountService(meta.(*ve.SdkClient)) + err = service.Dispatcher.Update(service, d, ResourceVolcengineOrganizationAccount()) + if err != nil { + return fmt.Errorf("error on updating organization_account %q, %s", d.Id(), err) + } + return resourceVolcengineOrganizationAccountRead(d, meta) +} + +func resourceVolcengineOrganizationAccountDelete(d *schema.ResourceData, meta interface{}) (err error) { + service := NewOrganizationAccountService(meta.(*ve.SdkClient)) + err = service.Dispatcher.Delete(service, d, ResourceVolcengineOrganizationAccount()) + if err != nil { + return fmt.Errorf("error on deleting organization_account %q, %s", d.Id(), err) + } + return err +} diff --git a/volcengine/organization/organization_account/service_volcengine_organization_account.go b/volcengine/organization/organization_account/service_volcengine_organization_account.go new file mode 100644 index 00000000..f673868b --- /dev/null +++ b/volcengine/organization/organization_account/service_volcengine_organization_account.go @@ -0,0 +1,408 @@ +package organization_account + +import ( + "encoding/json" + "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 VolcengineOrganizationAccountService struct { + Client *ve.SdkClient + Dispatcher *ve.Dispatcher +} + +func NewOrganizationAccountService(c *ve.SdkClient) *VolcengineOrganizationAccountService { + return &VolcengineOrganizationAccountService{ + Client: c, + Dispatcher: &ve.Dispatcher{}, + } +} + +func (s *VolcengineOrganizationAccountService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineOrganizationAccountService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + m["IncludeTags"] = true + return ve.WithPageOffsetQuery(m, "Limit", "Offset", 100, 1, func(condition map[string]interface{}) ([]interface{}, error) { + action := "ListAccounts" + + bytes, _ := json.Marshal(condition) + logger.Debug(logger.ReqFormat, action, string(bytes)) + 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 + } + } + respBytes, _ := json.Marshal(resp) + logger.Debug(logger.RespFormat, action, condition, string(respBytes)) + + results, err = ve.ObtainSdkValue("Result.AccountList", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.AccountList is not Slice") + } + return data, err + }) +} + +func (s *VolcengineOrganizationAccountService) 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{}{ + "Search": id, + } + results, err = s.ReadResources(req) + if err != nil { + return data, err + } + for _, v := range results { + var instanceMap map[string]interface{} + if instanceMap, ok = v.(map[string]interface{}); !ok { + return data, errors.New("value is not map") + } + if id == instanceMap["AccountID"].(string) { + data = instanceMap + break + } + } + if len(data) == 0 { + return data, fmt.Errorf("organization_account %s not exist ", id) + } + return data, err +} + +func (s *VolcengineOrganizationAccountService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return &resource.StateChangeConf{} +} + +func (VolcengineOrganizationAccountService) WithResourceResponseHandlers(d map[string]interface{}) []ve.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]ve.ResponseConvert, error) { + return d, map[string]ve.ResponseConvert{ + "ID": { + TargetField: "id", + }, + "AccountID": { + TargetField: "account_id", + }, + "OrgID": { + TargetField: "org_id", + }, + "OrgUnitID": { + TargetField: "org_unit_id", + }, + "OrgVerificationID": { + TargetField: "org_verification_id", + }, + }, nil + } + return []ve.ResourceResponseHandler{handler} +} + +func (s *VolcengineOrganizationAccountService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "CreateAccount", + ConvertMode: ve.RequestConvertAll, + Convert: map[string]ve.RequestConvert{ + "tags": { + Ignore: true, + }, + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + resp, err := s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + logger.Debug(logger.RespFormat, call.Action, resp, err) + return resp, err + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + id, _ := ve.ObtainSdkValue("Result.AccountId", *resp) + d.SetId(id.(string)) + return nil + }, + // 必须顺序执行,否则并发失败 + LockId: func(d *schema.ResourceData) string { + return "lock-Organization" + }, + }, + } + callbacks = append(callbacks, callback) + + // 更新Tags + callbacks = s.setResourceTags(resourceData, callbacks) + + return callbacks +} + +func (s *VolcengineOrganizationAccountService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + + if resourceData.HasChanges("account_name", "show_name", "description") { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "UpdateAccount", + ConvertMode: ve.RequestConvertInConvert, + Convert: map[string]ve.RequestConvert{ + "account_name": { + TargetField: "AccountName", + ForceGet: true, + }, + "show_name": { + TargetField: "ShowName", + ForceGet: true, + }, + "description": { + TargetField: "Description", + ForceGet: true, + }, + }, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["AccountId"] = d.Id() + 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) + resp, err := s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + logger.Debug(logger.RespFormat, call.Action, resp, err) + return resp, err + }, + // 必须顺序执行,否则并发失败 + LockId: func(d *schema.ResourceData) string { + return "lock-Organization" + }, + }, + } + callbacks = append(callbacks, callback) + } + + if resourceData.HasChange("org_unit_id") { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "MoveAccount", + ConvertMode: ve.RequestConvertInConvert, + Convert: map[string]ve.RequestConvert{ + "org_unit_id": { + TargetField: "ToOrgUnitId", + ForceGet: true, + }, + }, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["AccountId"] = d.Id() + 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) + resp, err := s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + logger.Debug(logger.RespFormat, call.Action, resp, err) + return resp, err + }, + // 必须顺序执行,否则并发失败 + LockId: func(d *schema.ResourceData) string { + return "lock-Organization" + }, + }, + } + callbacks = append(callbacks, callback) + } + + // 更新Tags + callbacks = s.setResourceTags(resourceData, callbacks) + + return callbacks +} + +func (s *VolcengineOrganizationAccountService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "RemoveAccount", + ConvertMode: ve.RequestConvertIgnore, + SdkParam: &map[string]interface{}{ + "AccountId": 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(getUniversalInfo(call.Action), call.SdkParam) + }, + CallError: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall, baseErr error) error { + // 不允许移除的账号,直接返回接口报错 + if strings.Contains(baseErr.Error(), "Remove is not allow") { + return baseErr + } + + // 出现错误后重试 + 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 organization account on delete %q, %w", d.Id(), callErr)) + } + } + _, callErr = call.ExecuteCall(d, client, call) + if callErr == nil { + return nil + } + return resource.RetryableError(callErr) + }) + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + return ve.CheckResourceUtilRemoved(d, s.ReadResource, 5*time.Minute) + }, + // 必须顺序执行,否则并发失败 + LockId: func(d *schema.ResourceData) string { + return "lock-Organization" + }, + }, + } + return []ve.Callback{callback} +} + +func (s *VolcengineOrganizationAccountService) DatasourceResources(*schema.ResourceData, *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{ + NameField: "AccountName", + IdField: "AccountID", + CollectField: "accounts", + ResponseConverts: map[string]ve.ResponseConvert{ + "ID": { + TargetField: "id", + }, + "AccountID": { + TargetField: "account_id", + }, + "OrgID": { + TargetField: "org_id", + }, + "OrgUnitID": { + TargetField: "org_unit_id", + }, + "OrgVerificationID": { + TargetField: "org_verification_id", + }, + }, + } +} + +func (s *VolcengineOrganizationAccountService) ReadResourceId(id string) string { + return id +} + +func (s *VolcengineOrganizationAccountService) setResourceTags(resourceData *schema.ResourceData, callbacks []ve.Callback) []ve.Callback { + addedTags, removedTags, _, _ := ve.GetSetDifference("tags", resourceData, ve.TagsHash, false) + + removeCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "UntagResources", + ConvertMode: ve.RequestConvertIgnore, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + if removedTags != nil && len(removedTags.List()) > 0 { + (*call.SdkParam)["ResourceIds"] = []string{resourceData.Id()} + (*call.SdkParam)["ResourceType"] = "account" + (*call.SdkParam)["TagKeys"] = make([]interface{}, 0) + for _, v := range removedTags.List() { + tag, ok := v.(map[string]interface{}) + if !ok { + return false, fmt.Errorf("Tags is not map ") + } + (*call.SdkParam)["TagKeys"] = append((*call.SdkParam)["TagKeys"].([]interface{}), tag["key"].(string)) + } + return true, nil + } + return false, 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) + }, + // 必须顺序执行,否则并发失败 + LockId: func(d *schema.ResourceData) string { + return "lock-Organization" + }, + }, + } + callbacks = append(callbacks, removeCallback) + + addCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "TagResources", + ConvertMode: ve.RequestConvertIgnore, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + if addedTags != nil && len(addedTags.List()) > 0 { + (*call.SdkParam)["ResourceIds"] = []string{resourceData.Id()} + (*call.SdkParam)["ResourceType"] = "account" + (*call.SdkParam)["Tags"] = make(map[string]interface{}) + for _, v := range addedTags.List() { + tag, ok := v.(map[string]interface{}) + if !ok { + return false, fmt.Errorf("Tags is not map ") + } + (*call.SdkParam)["Tags"].(map[string]interface{})[tag["key"].(string)] = tag["value"].(string) + } + return true, nil + } + return false, 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) + }, + // 必须顺序执行,否则并发失败 + LockId: func(d *schema.ResourceData) string { + return "lock-Organization" + }, + }, + } + callbacks = append(callbacks, addCallback) + + return callbacks +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "organization", + Version: "2022-01-01", + HttpMethod: ve.GET, + ContentType: ve.Default, + Action: actionName, + } +} + +func getPostUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "organization", + Version: "2022-01-01", + HttpMethod: ve.POST, + ContentType: ve.ApplicationJSON, + Action: actionName, + } +} diff --git a/volcengine/provider.go b/volcengine/provider.go index 1c355120..244f68ff 100644 --- a/volcengine/provider.go +++ b/volcengine/provider.go @@ -1,6 +1,12 @@ package volcengine import ( + "fmt" + "os" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_account" "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_service_control_policy" "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_service_control_policy_attachment" "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_service_control_policy_enabler" @@ -306,6 +312,45 @@ func Provider() terraform.ResourceProvider { DefaultFunc: schema.EnvDefaultFunc("VOLCENGINE_PROXY_URL", nil), Description: "PROXY URL for Volcengine Provider", }, + "assume_role": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "The ASSUME ROLE block for Volcengine Provider. If provided, terraform will attempt to assume this role using the supplied credentials.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "assume_role_trn": { + Type: schema.TypeString, + Required: true, + DefaultFunc: schema.EnvDefaultFunc("VOLCENGINE_ASSUME_ROLE_TRN", nil), + Description: "The TRN of the role to assume.", + }, + "assume_role_session_name": { + Type: schema.TypeString, + Required: true, + DefaultFunc: schema.EnvDefaultFunc("VOLCENGINE_ASSUME_ROLE_SESSION_NAME", nil), + Description: "The session name to use when making the AssumeRole call.", + }, + "duration_seconds": { + Type: schema.TypeInt, + Required: true, + DefaultFunc: func() (interface{}, error) { + if v := os.Getenv("VOLCENGINE_ASSUME_ROLE_DURATION_SECONDS"); v != "" { + return strconv.Atoi(v) + } + return 3600, nil + }, + ValidateFunc: validation.IntBetween(900, 43200), + Description: "The duration of the session when making the AssumeRole call. Its value ranges from 900 to 43200(seconds), and default is 3600 seconds.", + }, + "policy": { + Type: schema.TypeString, + Optional: true, + Description: "A more restrictive policy when making the AssumeRole call.", + }, + }, + }, + }, }, DataSourcesMap: map[string]*schema.Resource{ "volcengine_vpcs": vpc.DataSourceVolcengineVpcs(), @@ -556,6 +601,7 @@ func Provider() terraform.ResourceProvider { // ================ Organization ================ "volcengine_organization_units": organization_unit.DataSourceVolcengineOrganizationUnits(), "volcengine_organization_service_control_policies": organization_service_control_policy.DataSourceVolcengineServiceControlPolicies(), + "volcengine_organization_accounts": organization_account.DataSourceVolcengineOrganizationAccounts(), }, ResourcesMap: map[string]*schema.Resource{ "volcengine_vpc": vpc.ResourceVolcengineVpc(), @@ -815,6 +861,7 @@ func Provider() terraform.ResourceProvider { "volcengine_organization_service_control_policy_enabler": organization_service_control_policy_enabler.ResourceVolcengineOrganizationServiceControlPolicyEnabler(), "volcengine_organization_service_control_policy": organization_service_control_policy.ResourceVolcengineServiceControlPolicy(), "volcengine_organization_service_control_policy_attachment": organization_service_control_policy_attachment.ResourceVolcengineServiceControlPolicyAttachment(), + "volcengine_organization_account": organization_account.ResourceVolcengineOrganizationAccount(), }, ConfigureFunc: ProviderConfigure, } @@ -855,6 +902,37 @@ func ProviderConfigure(d *schema.ResourceData) (interface{}, error) { } } + // get assume role + if v, ok := d.GetOk("assume_role"); ok { + assumeRoleList, ok := v.([]interface{}) + if !ok { + return nil, fmt.Errorf("the assume_role is not slice ") + } + if len(assumeRoleList) == 1 { + assumeRoleMap, ok := assumeRoleList[0].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("the value of the assume_role is not map ") + } + config.AssumeRoleTrn = assumeRoleMap["assume_role_trn"].(string) + config.AssumeRoleSessionName = assumeRoleMap["assume_role_session_name"].(string) + config.DurationSeconds = assumeRoleMap["duration_seconds"].(int) + config.AssumeRolePolicy = assumeRoleMap["policy"].(string) + } + } else { + config.AssumeRoleTrn = os.Getenv("VOLCENGINE_ASSUME_ROLE_TRN") + config.AssumeRoleSessionName = os.Getenv("VOLCENGINE_ASSUME_ROLE_SESSION_NAME") + duration := os.Getenv("VOLCENGINE_ASSUME_ROLE_DURATION_SECONDS") + if duration != "" { + durationSeconds, err := strconv.Atoi(duration) + if err != nil { + return nil, err + } + config.DurationSeconds = durationSeconds + } else { + config.DurationSeconds = 3600 + } + } + client, err := config.Client() return client, err } From 4909d7aa59afeee62f5be845f6698198aa0cf8cf Mon Sep 17 00:00:00 2001 From: "maoshuai.17" Date: Mon, 11 Dec 2023 17:32:24 +0800 Subject: [PATCH 10/13] feat: opt AssumeRole --- common/common_volcengine_config.go | 76 ++++-------------------------- volcengine/provider.go | 75 +++++++++++++++++++++++++---- 2 files changed, 76 insertions(+), 75 deletions(-) diff --git a/common/common_volcengine_config.go b/common/common_volcengine_config.go index 67089f78..33869b7c 100644 --- a/common/common_volcengine_config.go +++ b/common/common_volcengine_config.go @@ -6,8 +6,6 @@ import ( "net/http" "net/url" - "github.com/volcengine/volc-sdk-golang/base" - "github.com/volcengine/volc-sdk-golang/service/sts" "github.com/volcengine/volcengine-go-sdk/service/autoscaling" "github.com/volcengine/volcengine-go-sdk/service/clb" "github.com/volcengine/volcengine-go-sdk/service/ecs" @@ -25,19 +23,15 @@ import ( ) type Config struct { - AccessKey string - SecretKey string - SessionToken string - Region string - Endpoint string - DisableSSL bool - CustomerHeaders map[string]string - CustomerEndpoints map[string]string - ProxyUrl string - AssumeRoleTrn string - AssumeRoleSessionName string - DurationSeconds int - AssumeRolePolicy string + AccessKey string + SecretKey string + SessionToken string + Region string + Endpoint string + DisableSSL bool + CustomerHeaders map[string]string + CustomerEndpoints map[string]string + ProxyUrl string } func (c *Config) Client() (*SdkClient, error) { @@ -58,14 +52,6 @@ func (c *Config) Client() (*SdkClient, error) { }). WithEndpoint(volcengineutil.NewEndpoint().WithCustomerEndpoint(c.Endpoint).GetEndpoint()) - if c.AssumeRoleTrn != "" && c.AssumeRoleSessionName != "" { - cred, err := c.assumeRole() - if err != nil { - return nil, err - } - config.WithCredentials(cred) - } - if c.ProxyUrl != "" { u, _ := url.Parse(c.ProxyUrl) t := &http.Transport{ @@ -99,50 +85,6 @@ func (c *Config) Client() (*SdkClient, error) { return &client, nil } -func (c *Config) assumeRole() (*credentials.Credentials, error) { - ins := sts.NewInstance() - if c.Region != "" { - ins.SetRegion(c.Region) - } - if c.Endpoint != "" { - ins.SetHost(c.Endpoint) - } - - ins.Client.SetAccessKey(c.AccessKey) - ins.Client.SetSecretKey(c.SecretKey) - input := &sts.AssumeRoleRequest{ - RoleTrn: c.AssumeRoleTrn, - RoleSessionName: c.AssumeRoleSessionName, - DurationSeconds: c.DurationSeconds, - } - output, statusCode, err := ins.AssumeRole(input) - var ( - reqId string - errObj *base.ErrorObj - ) - if output != nil { - reqId = output.ResponseMetadata.RequestId - errObj = output.ResponseMetadata.Error - } - if err != nil { - return nil, fmt.Errorf("AssumeRole error, httpcode is %v and reqId is %s error is %s", statusCode, reqId, err.Error()) - } - if errObj != nil { - return nil, fmt.Errorf("AssumeRole error, code is %v and reqId is %s error is %s", errObj.Code, reqId, errObj.Message) - } - - if output.Result == nil { - return nil, fmt.Errorf("assume role failed, result is nil") - } - cred := credentials.NewCredentials(&credentials.StaticProvider{Value: credentials.Value{ - AccessKeyID: output.Result.Credentials.AccessKeyId, - SecretAccessKey: output.Result.Credentials.SecretAccessKey, - SessionToken: output.Result.Credentials.SessionToken, - }}) - - return cred, nil -} - func init() { InitLocks() //InitSyncLimit() diff --git a/volcengine/provider.go b/volcengine/provider.go index 244f68ff..4c5b3f24 100644 --- a/volcengine/provider.go +++ b/volcengine/provider.go @@ -11,6 +11,8 @@ import ( "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_service_control_policy_attachment" "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_service_control_policy_enabler" "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_unit" + "github.com/volcengine/volc-sdk-golang/base" + "github.com/volcengine/volc-sdk-golang/service/sts" "github.com/volcengine/terraform-provider-volcengine/volcengine/alb/alb" "github.com/volcengine/terraform-provider-volcengine/volcengine/alb/alb_acl" @@ -903,6 +905,13 @@ func ProviderConfigure(d *schema.ResourceData) (interface{}, error) { } // get assume role + var ( + arTrn string + arSessionName string + arPolicy string + arDurationSeconds int + ) + if v, ok := d.GetOk("assume_role"); ok { assumeRoleList, ok := v.([]interface{}) if !ok { @@ -913,30 +922,80 @@ func ProviderConfigure(d *schema.ResourceData) (interface{}, error) { if !ok { return nil, fmt.Errorf("the value of the assume_role is not map ") } - config.AssumeRoleTrn = assumeRoleMap["assume_role_trn"].(string) - config.AssumeRoleSessionName = assumeRoleMap["assume_role_session_name"].(string) - config.DurationSeconds = assumeRoleMap["duration_seconds"].(int) - config.AssumeRolePolicy = assumeRoleMap["policy"].(string) + arTrn = assumeRoleMap["assume_role_trn"].(string) + arSessionName = assumeRoleMap["assume_role_session_name"].(string) + arDurationSeconds = assumeRoleMap["duration_seconds"].(int) + arPolicy = assumeRoleMap["policy"].(string) } } else { - config.AssumeRoleTrn = os.Getenv("VOLCENGINE_ASSUME_ROLE_TRN") - config.AssumeRoleSessionName = os.Getenv("VOLCENGINE_ASSUME_ROLE_SESSION_NAME") + arTrn = os.Getenv("VOLCENGINE_ASSUME_ROLE_TRN") + arSessionName = os.Getenv("VOLCENGINE_ASSUME_ROLE_SESSION_NAME") duration := os.Getenv("VOLCENGINE_ASSUME_ROLE_DURATION_SECONDS") if duration != "" { durationSeconds, err := strconv.Atoi(duration) if err != nil { return nil, err } - config.DurationSeconds = durationSeconds + arDurationSeconds = durationSeconds } else { - config.DurationSeconds = 3600 + arDurationSeconds = 3600 + } + } + + if arTrn != "" && arSessionName != "" { + cred, err := assumeRole(config, arTrn, arSessionName, arPolicy, arDurationSeconds) + if err != nil { + return nil, err } + config.AccessKey = cred.AccessKeyId + config.SecretKey = cred.SecretAccessKey + config.SessionToken = cred.SessionToken } client, err := config.Client() return client, err } +func assumeRole(c ve.Config, arTrn, arSessionName, arPolicy string, arDurationSeconds int) (*sts.Credentials, error) { + ins := sts.NewInstance() + if c.Region != "" { + ins.SetRegion(c.Region) + } + if c.Endpoint != "" { + ins.SetHost(c.Endpoint) + } + + ins.Client.SetAccessKey(c.AccessKey) + ins.Client.SetSecretKey(c.SecretKey) + input := &sts.AssumeRoleRequest{ + RoleTrn: arTrn, + RoleSessionName: arSessionName, + DurationSeconds: arDurationSeconds, + Policy: arPolicy, + } + output, statusCode, err := ins.AssumeRole(input) + var ( + reqId string + errObj *base.ErrorObj + ) + if output != nil { + reqId = output.ResponseMetadata.RequestId + errObj = output.ResponseMetadata.Error + } + if err != nil { + return nil, fmt.Errorf("AssumeRole error, httpcode is %v and reqId is %s error is %s", statusCode, reqId, err.Error()) + } + if errObj != nil { + return nil, fmt.Errorf("AssumeRole error, code is %v and reqId is %s error is %s", errObj.Code, reqId, errObj.Message) + } + + if output.Result == nil || output.Result.Credentials == nil { + return nil, fmt.Errorf("assume role failed, result is nil") + } + + return output.Result.Credentials, nil +} + func defaultCustomerEndPoints() map[string]string { return map[string]string{ "veenedge": "veenedge.volcengineapi.com", From 809e1bc4d5473f0aa16dc34f3df051c639364c45 Mon Sep 17 00:00:00 2001 From: "maoshuai.17" Date: Tue, 23 Jan 2024 19:32:13 +0800 Subject: [PATCH 11/13] feat: support enable organization --- example/dataOrganizations/main.tf | 3 + example/organization/main.tf | 3 + example/organizationUnit/main.tf | 14 +- .../data_source_volcengine_organizations.go | 110 +++++++++ .../resource_volcengine_organization.go | 125 ++++++++++ .../service_volcengine_organization.go | 232 ++++++++++++++++++ volcengine/provider.go | 3 + 7 files changed, 487 insertions(+), 3 deletions(-) create mode 100644 example/dataOrganizations/main.tf create mode 100644 example/organization/main.tf create mode 100644 volcengine/organization/organization/data_source_volcengine_organizations.go create mode 100644 volcengine/organization/organization/resource_volcengine_organization.go create mode 100644 volcengine/organization/organization/service_volcengine_organization.go diff --git a/example/dataOrganizations/main.tf b/example/dataOrganizations/main.tf new file mode 100644 index 00000000..cc3582ac --- /dev/null +++ b/example/dataOrganizations/main.tf @@ -0,0 +1,3 @@ +data "volcengine_organizations" "foo" { + +} \ No newline at end of file diff --git a/example/organization/main.tf b/example/organization/main.tf new file mode 100644 index 00000000..09b7f53d --- /dev/null +++ b/example/organization/main.tf @@ -0,0 +1,3 @@ +resource "volcengine_organization" "foo" { + +} diff --git a/example/organizationUnit/main.tf b/example/organizationUnit/main.tf index 59ca8a8e..0df68be1 100644 --- a/example/organizationUnit/main.tf +++ b/example/organizationUnit/main.tf @@ -1,5 +1,13 @@ +resource "volcengine_organization" "foo" { + +} + +data "volcengine_organization_units" "foo" { + depends_on = [volcengine_organization.foo] +} + resource "volcengine_organization_unit" "foo" { - name = "tftest57" - parent_id = "7306629044253098034" - description = "test" + name = "tf-test-unit" + parent_id = [for unit in data.volcengine_organization_units.foo.units : unit.id if unit.parent_id == "0"][0] + description = "tf-test" } \ No newline at end of file diff --git a/volcengine/organization/organization/data_source_volcengine_organizations.go b/volcengine/organization/organization/data_source_volcengine_organizations.go new file mode 100644 index 00000000..96ca8912 --- /dev/null +++ b/volcengine/organization/organization/data_source_volcengine_organizations.go @@ -0,0 +1,110 @@ +package organization + +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 DataSourceVolcengineOrganizations() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcengineOrganizationsRead, + Schema: map[string]*schema.Schema{ + "name_regex": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsValidRegExp, + Description: "A Name Regex of Resource.", + }, + "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.", + }, + "organizations": { + 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 organization.", + }, + "owner": { + Type: schema.TypeString, + Computed: true, + Description: "The owner id of the organization.", + }, + "type": { + Type: schema.TypeInt, + Computed: true, + Description: "The type of the organization.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the organization.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the organization.", + }, + "status": { + Type: schema.TypeInt, + Computed: true, + Description: "The status of the organization.", + }, + "delete_uk": { + Type: schema.TypeString, + Computed: true, + Description: "The delete uk of the organization.", + }, + "account_id": { + Type: schema.TypeInt, + Computed: true, + Description: "The account id of the organization owner.", + }, + "account_name": { + Type: schema.TypeString, + Computed: true, + Description: "The account name of the organization owner.", + }, + "main_name": { + Type: schema.TypeString, + Computed: true, + Description: "The main name of the organization owner.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "The created time of the organization.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "The updated time of the organization.", + }, + "deleted_time": { + Type: schema.TypeString, + Computed: true, + Description: "The deleted time of the organization.", + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcengineOrganizationsRead(d *schema.ResourceData, meta interface{}) error { + service := NewOrganizationService(meta.(*ve.SdkClient)) + return service.Dispatcher.Data(service, d, DataSourceVolcengineOrganizations()) +} diff --git a/volcengine/organization/organization/resource_volcengine_organization.go b/volcengine/organization/organization/resource_volcengine_organization.go new file mode 100644 index 00000000..68810ecc --- /dev/null +++ b/volcengine/organization/organization/resource_volcengine_organization.go @@ -0,0 +1,125 @@ +package organization + +import ( + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +Organization can be imported using the id, e.g. +``` +$ terraform import volcengine_organization.default resource_id +``` + +*/ + +func ResourceVolcengineOrganization() *schema.Resource { + resource := &schema.Resource{ + Create: resourceVolcengineOrganizationCreate, + Read: resourceVolcengineOrganizationRead, + Delete: resourceVolcengineOrganizationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + // computed fields + "owner": { + Type: schema.TypeString, + Computed: true, + Description: "The owner id of the organization.", + }, + "type": { + Type: schema.TypeInt, + Computed: true, + Description: "The type of the organization.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the organization.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the organization.", + }, + "status": { + Type: schema.TypeInt, + Computed: true, + Description: "The status of the organization.", + }, + "delete_uk": { + Type: schema.TypeString, + Computed: true, + Description: "The delete uk of the organization.", + }, + "account_id": { + Type: schema.TypeInt, + Computed: true, + Description: "The account id of the organization owner.", + }, + "account_name": { + Type: schema.TypeString, + Computed: true, + Description: "The account name of the organization owner.", + }, + "main_name": { + Type: schema.TypeString, + Computed: true, + Description: "The main name of the organization owner.", + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "The created time of the organization.", + }, + "updated_time": { + Type: schema.TypeString, + Computed: true, + Description: "The updated time of the organization.", + }, + "deleted_time": { + Type: schema.TypeString, + Computed: true, + Description: "The deleted time of the organization.", + }, + }, + } + return resource +} + +func resourceVolcengineOrganizationCreate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewOrganizationService(meta.(*ve.SdkClient)) + err = service.Dispatcher.Create(service, d, ResourceVolcengineOrganization()) + if err != nil { + return fmt.Errorf("error on creating organization %q, %s", d.Id(), err) + } + return resourceVolcengineOrganizationRead(d, meta) +} + +func resourceVolcengineOrganizationRead(d *schema.ResourceData, meta interface{}) (err error) { + service := NewOrganizationService(meta.(*ve.SdkClient)) + err = service.Dispatcher.Read(service, d, ResourceVolcengineOrganization()) + if err != nil { + return fmt.Errorf("error on reading organization %q, %s", d.Id(), err) + } + return err +} + +func resourceVolcengineOrganizationDelete(d *schema.ResourceData, meta interface{}) (err error) { + service := NewOrganizationService(meta.(*ve.SdkClient)) + err = service.Dispatcher.Delete(service, d, ResourceVolcengineOrganization()) + if err != nil { + return fmt.Errorf("error on deleting organization %q, %s", d.Id(), err) + } + return err +} diff --git a/volcengine/organization/organization/service_volcengine_organization.go b/volcengine/organization/organization/service_volcengine_organization.go new file mode 100644 index 00000000..776bea68 --- /dev/null +++ b/volcengine/organization/organization/service_volcengine_organization.go @@ -0,0 +1,232 @@ +package organization + +import ( + "encoding/json" + "errors" + "fmt" + "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 VolcengineOrganizationService struct { + Client *ve.SdkClient + Dispatcher *ve.Dispatcher +} + +func NewOrganizationService(c *ve.SdkClient) *VolcengineOrganizationService { + return &VolcengineOrganizationService{ + Client: c, + Dispatcher: &ve.Dispatcher{}, + } +} + +func (s *VolcengineOrganizationService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineOrganizationService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + ) + return ve.WithPageNumberQuery(m, "PageSize", "PageNumber", 100, 1, func(condition map[string]interface{}) ([]interface{}, error) { + action := "DescribeOrganization" + + bytes, _ := json.Marshal(condition) + logger.Debug(logger.ReqFormat, action, string(bytes)) + 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 + } + } + respBytes, _ := json.Marshal(resp) + logger.Debug(logger.RespFormat, action, condition, string(respBytes)) + + organization, err := ve.ObtainSdkValue("Result.Organization", *resp) + if err != nil { + return data, err + } + owner, err := ve.ObtainSdkValue("Result.Owner", *resp) + if err != nil { + return data, err + } + if organization == nil || owner == nil { + return []interface{}{}, nil + } + organizationMap, ok := organization.(map[string]interface{}) + if !ok { + return data, fmt.Errorf("Result.Organization is not map") + } + ownerMap, ok := owner.(map[string]interface{}) + if !ok { + return data, fmt.Errorf("Result.Owner is not map") + } + for k, v := range ownerMap { + organizationMap[k] = v + } + data = []interface{}{ + organizationMap, + } + + return data, err + }) +} + +func (s *VolcengineOrganizationService) 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{}{} + 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("organization %s not exist ", id) + } + + if organizationId, exist := data["ID"]; exist { + if organizationId.(string) != id { + return data, fmt.Errorf("The id of the organization is mismatch: %v ", id) + } + } + + return data, err +} + +func (s *VolcengineOrganizationService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return &resource.StateChangeConf{} +} + +func (VolcengineOrganizationService) WithResourceResponseHandlers(d map[string]interface{}) []ve.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]ve.ResponseConvert, error) { + return d, map[string]ve.ResponseConvert{ + "ID": { + TargetField: "id", + }, + "AccountID": { + TargetField: "account_id", + }, + "DeleteUK": { + TargetField: "delete_uk", + }, + }, nil + } + return []ve.ResourceResponseHandler{handler} +} + +func (s *VolcengineOrganizationService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "CreateOrganization", + ConvertMode: ve.RequestConvertAll, + Convert: map[string]ve.RequestConvert{}, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + resp, err := s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + logger.Debug(logger.RespFormat, call.Action, resp, err) + return resp, err + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + id, _ := ve.ObtainSdkValue("Result.ID", *resp) + d.SetId(id.(string)) + return nil + }, + }, + } + return []ve.Callback{callback} +} + +func (s *VolcengineOrganizationService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + return []ve.Callback{} +} + +func (s *VolcengineOrganizationService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "DeleteOrganization", + ConvertMode: ve.RequestConvertIgnore, + ContentType: ve.ContentTypeJson, + SdkParam: &map[string]interface{}{ + "Id": 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(getUniversalInfo(call.Action), call.SdkParam) + }, + 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 organization on delete %q, %w", d.Id(), callErr)) + } + } + _, callErr = call.ExecuteCall(d, client, call) + if callErr == nil { + return nil + } + return resource.RetryableError(callErr) + }) + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + return ve.CheckResourceUtilRemoved(d, s.ReadResource, 5*time.Minute) + }, + }, + } + return []ve.Callback{callback} +} + +func (s *VolcengineOrganizationService) DatasourceResources(*schema.ResourceData, *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{ + NameField: "Name", + IdField: "ID", + CollectField: "organizations", + ResponseConverts: map[string]ve.ResponseConvert{ + "ID": { + TargetField: "id", + }, + "AccountID": { + TargetField: "account_id", + }, + "DeleteUK": { + TargetField: "delete_uk", + }, + }, + } +} + +func (s *VolcengineOrganizationService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "organization", + Version: "2022-01-01", + HttpMethod: ve.GET, + ContentType: ve.Default, + Action: actionName, + } +} diff --git a/volcengine/provider.go b/volcengine/provider.go index 4c5b3f24..79dab18d 100644 --- a/volcengine/provider.go +++ b/volcengine/provider.go @@ -6,6 +6,7 @@ import ( "strconv" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization" "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_account" "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_service_control_policy" "github.com/volcengine/terraform-provider-volcengine/volcengine/organization/organization_service_control_policy_attachment" @@ -604,6 +605,7 @@ func Provider() terraform.ResourceProvider { "volcengine_organization_units": organization_unit.DataSourceVolcengineOrganizationUnits(), "volcengine_organization_service_control_policies": organization_service_control_policy.DataSourceVolcengineServiceControlPolicies(), "volcengine_organization_accounts": organization_account.DataSourceVolcengineOrganizationAccounts(), + "volcengine_organizations": organization.DataSourceVolcengineOrganizations(), }, ResourcesMap: map[string]*schema.Resource{ "volcengine_vpc": vpc.ResourceVolcengineVpc(), @@ -864,6 +866,7 @@ func Provider() terraform.ResourceProvider { "volcengine_organization_service_control_policy": organization_service_control_policy.ResourceVolcengineServiceControlPolicy(), "volcengine_organization_service_control_policy_attachment": organization_service_control_policy_attachment.ResourceVolcengineServiceControlPolicyAttachment(), "volcengine_organization_account": organization_account.ResourceVolcengineOrganizationAccount(), + "volcengine_organization": organization.ResourceVolcengineOrganization(), }, ConfigureFunc: ProviderConfigure, } From 6806970d5f662cb2936952be0bad00d5241552c0 Mon Sep 17 00:00:00 2001 From: "maoshuai.17" Date: Thu, 22 Feb 2024 10:51:11 +0800 Subject: [PATCH 12/13] feat: opt vke kubernetes_version description --- volcengine/vke/cluster/resource_volcengine_vke_cluster.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/volcengine/vke/cluster/resource_volcengine_vke_cluster.go b/volcengine/vke/cluster/resource_volcengine_vke_cluster.go index 351d0503..48734387 100644 --- a/volcengine/vke/cluster/resource_volcengine_vke_cluster.go +++ b/volcengine/vke/cluster/resource_volcengine_vke_cluster.go @@ -68,7 +68,7 @@ func ResourceVolcengineVkeCluster() *schema.Resource { } return false }, - Description: "The version of Kubernetes specified when creating a VKE cluster (specified to patch version), if not specified, the latest Kubernetes version supported by VKE is used by default, which is a 3-segment version format starting with a lowercase v, that is, KubernetesVersion with IsLatestVersion=True in the return value of ListSupportedVersions.", + Description: "The version of Kubernetes specified when creating a VKE cluster (specified to patch version),with an example value of `v1.24`. If not specified, the latest Kubernetes version supported by VKE is used by default, which is a 3-segment version format starting with a lowercase v, that is, KubernetesVersion with IsLatestVersion=True in the return value of ListSupportedVersions.", }, "tags": ve.TagsSchema(), "cluster_config": { From e67e1cb90e7f251207d271879ddfc798cedd03aa Mon Sep 17 00:00:00 2001 From: "maoshuai.17" Date: Thu, 22 Feb 2024 11:05:18 +0800 Subject: [PATCH 13/13] feat: update docs and version --- docgen/main.go | 1 + ...e_organization_service_control_policies.go | 2 +- .../resource_volcengine_vke_cluster.go | 2 +- .../docs/d/iam_saml_providers.html.markdown | 33 +++++++++++ .../d/organization_accounts.html.markdown | 55 +++++++++++++++++ ...ion_service_control_policies.html.markdown | 36 +++++++++++ .../docs/d/organization_units.html.markdown | 37 ++++++++++++ website/docs/d/organizations.html.markdown | 40 +++++++++++++ .../docs/r/iam_saml_provider.html.markdown | 41 +++++++++++++ website/docs/r/organization.html.markdown | 43 ++++++++++++++ .../docs/r/organization_account.html.markdown | 59 +++++++++++++++++++ ...ation_service_control_policy.html.markdown | 43 ++++++++++++++ ...ce_control_policy_attachment.html.markdown | 48 +++++++++++++++ ...rvice_control_policy_enabler.html.markdown | 32 ++++++++++ .../docs/r/organization_unit.html.markdown | 47 +++++++++++++++ website/docs/r/vke_cluster.html.markdown | 2 +- website/volcengine.erb | 51 ++++++++++++++++ 17 files changed, 569 insertions(+), 3 deletions(-) create mode 100644 website/docs/d/iam_saml_providers.html.markdown create mode 100644 website/docs/d/organization_accounts.html.markdown create mode 100644 website/docs/d/organization_service_control_policies.html.markdown create mode 100644 website/docs/d/organization_units.html.markdown create mode 100644 website/docs/d/organizations.html.markdown create mode 100644 website/docs/r/iam_saml_provider.html.markdown create mode 100644 website/docs/r/organization.html.markdown create mode 100644 website/docs/r/organization_account.html.markdown create mode 100644 website/docs/r/organization_service_control_policy.html.markdown create mode 100644 website/docs/r/organization_service_control_policy_attachment.html.markdown create mode 100644 website/docs/r/organization_service_control_policy_enabler.html.markdown create mode 100644 website/docs/r/organization_unit.html.markdown diff --git a/docgen/main.go b/docgen/main.go index 5241b85b..d24a51b0 100644 --- a/docgen/main.go +++ b/docgen/main.go @@ -155,6 +155,7 @@ var resourceKeys = map[string]string{ "cloud_monitor": "CLOUD_MONITOR", "rds_mssql": "RDS_MSSQL", "rds_postgresql": "RDS_POSTGRESQL", + "organization": "ORGANIZATION", } type Products struct { diff --git a/volcengine/organization/organization_service_control_policy/data_source_volcengine_organization_service_control_policies.go b/volcengine/organization/organization_service_control_policy/data_source_volcengine_organization_service_control_policies.go index 0f999ba0..a63ca609 100644 --- a/volcengine/organization/organization_service_control_policy/data_source_volcengine_organization_service_control_policies.go +++ b/volcengine/organization/organization_service_control_policy/data_source_volcengine_organization_service_control_policies.go @@ -27,7 +27,7 @@ func DataSourceVolcengineServiceControlPolicies() *schema.Resource { "policy_type": { Type: schema.TypeString, Optional: true, - Description: "The type of policy. The value can be System or Custom", + Description: "The type of policy. The value can be System or Custom.", }, "policies": { Description: "The collection of Policy query.", diff --git a/volcengine/vke/cluster/resource_volcengine_vke_cluster.go b/volcengine/vke/cluster/resource_volcengine_vke_cluster.go index 48734387..7d32496c 100644 --- a/volcengine/vke/cluster/resource_volcengine_vke_cluster.go +++ b/volcengine/vke/cluster/resource_volcengine_vke_cluster.go @@ -68,7 +68,7 @@ func ResourceVolcengineVkeCluster() *schema.Resource { } return false }, - Description: "The version of Kubernetes specified when creating a VKE cluster (specified to patch version),with an example value of `v1.24`. If not specified, the latest Kubernetes version supported by VKE is used by default, which is a 3-segment version format starting with a lowercase v, that is, KubernetesVersion with IsLatestVersion=True in the return value of ListSupportedVersions.", + Description: "The version of Kubernetes specified when creating a VKE cluster (specified to patch version), with an example value of `v1.24`. If not specified, the latest Kubernetes version supported by VKE is used by default, which is a 3-segment version format starting with a lowercase v, that is, KubernetesVersion with IsLatestVersion=True in the return value of ListSupportedVersions.", }, "tags": ve.TagsSchema(), "cluster_config": { diff --git a/website/docs/d/iam_saml_providers.html.markdown b/website/docs/d/iam_saml_providers.html.markdown new file mode 100644 index 00000000..bd09e557 --- /dev/null +++ b/website/docs/d/iam_saml_providers.html.markdown @@ -0,0 +1,33 @@ +--- +subcategory: "IAM" +layout: "volcengine" +page_title: "Volcengine: volcengine_iam_saml_providers" +sidebar_current: "docs-volcengine-datasource-iam_saml_providers" +description: |- + Use this data source to query detailed information of iam saml providers +--- +# volcengine_iam_saml_providers +Use this data source to query detailed information of iam saml providers +## Example Usage +```hcl +data "volcengine_iam_saml_providers" "foo" { +} +``` +## 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: +* `providers` - The collection of query. + * `create_date` - Identity provider creation time, such as 20150123T123318Z. + * `description` - The description of the SAML provider. + * `encoded_saml_metadata_document` - Metadata document, encoded in Base64. + * `saml_provider_name` - The name of the SAML provider. + * `sso_type` - SSO types, 1. Role-based SSO, 2. User-based SSO. + * `status` - User SSO status, 1. Enabled, 2. Disable other console login methods after enabling, 3. Disabled, is a required field when creating user SSO. + * `trn` - The format for the resource name of an identity provider is trn:iam::${accountID}:saml-provider/{$SAMLProviderName}. + * `update_date` - Identity provider update time, such as: 20150123T123318Z. +* `total_count` - The total count of query. + + diff --git a/website/docs/d/organization_accounts.html.markdown b/website/docs/d/organization_accounts.html.markdown new file mode 100644 index 00000000..cede24f0 --- /dev/null +++ b/website/docs/d/organization_accounts.html.markdown @@ -0,0 +1,55 @@ +--- +subcategory: "ORGANIZATION" +layout: "volcengine" +page_title: "Volcengine: volcengine_organization_accounts" +sidebar_current: "docs-volcengine-datasource-organization_accounts" +description: |- + Use this data source to query detailed information of organization accounts +--- +# volcengine_organization_accounts +Use this data source to query detailed information of organization accounts +## Example Usage +```hcl +data "volcengine_organization_accounts" "foo" { + search = "210061****" + # org_unit_id = "730662904425309****" + # verification_id = "730671013833631****" +} +``` +## Argument Reference +The following arguments are supported: +* `name_regex` - (Optional) A Name Regex of Resource. +* `org_unit_id` - (Optional) The id of the organization unit. +* `output_file` - (Optional) File name where to save data source results. +* `search` - (Optional) The id or the show name of the account. This field supports fuzzy query. +* `verification_id` - (Optional) The id of the verification. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `accounts` - The collection of query. + * `account_id` - The id of the account. + * `account_name` - The name of the account. + * `allow_console` - Whether to allow the account enable console. `0` means allowed, `1` means not allowed. + * `allow_exit` - Whether to allow exit the organization. `0` means allowed, `1` means not allowed. + * `created_time` - The created time of the account. + * `delete_uk` - The delete uk of the account. + * `deleted_time` - The deleted time of the account. + * `description` - The description of the account. + * `iam_role` - The name of the iam role. + * `id` - The id of the account. + * `is_owner` - Whether the account is owner. `0` means not owner, `1` means owner. + * `join_type` - The join type of the account. `0` means create, `1` means invitation. + * `org_id` - The id of the organization. + * `org_type` - The type of the organization. `1` means business organization. + * `org_unit_id` - The id of the organization unit. + * `org_unit_name` - The name of the organization unit. + * `org_verification_id` - The id of the organization verification. + * `owner` - The owner id of the account. + * `show_name` - The show name of the account. + * `tags` - Tags. + * `key` - The Key of Tags. + * `value` - The Value of Tags. + * `updated_time` - The updated time of the account. +* `total_count` - The total count of query. + + diff --git a/website/docs/d/organization_service_control_policies.html.markdown b/website/docs/d/organization_service_control_policies.html.markdown new file mode 100644 index 00000000..36e9d6c8 --- /dev/null +++ b/website/docs/d/organization_service_control_policies.html.markdown @@ -0,0 +1,36 @@ +--- +subcategory: "ORGANIZATION" +layout: "volcengine" +page_title: "Volcengine: volcengine_organization_service_control_policies" +sidebar_current: "docs-volcengine-datasource-organization_service_control_policies" +description: |- + Use this data source to query detailed information of organization service control policies +--- +# volcengine_organization_service_control_policies +Use this data source to query detailed information of organization service control policies +## Example Usage +```hcl +data "volcengine_organization_service_control_policies" "foo" { + policy_type = "Custom" + query = "test" +} +``` +## Argument Reference +The following arguments are supported: +* `output_file` - (Optional) File name where to save data source results. +* `policy_type` - (Optional) The type of policy. The value can be System or Custom. +* `query` - (Optional) Query policies, support policy name or description. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `policies` - The collection of Policy query. + * `create_date` - The create time of the Policy. + * `description` - The description of the Policy. + * `id` - The ID of the Policy. + * `policy_name` - The name of the Policy. + * `policy_type` - The type of the Policy. + * `statement` - The statement of the Policy. + * `update_date` - The update time of the Policy. +* `total_count` - The total count of Policy query. + + diff --git a/website/docs/d/organization_units.html.markdown b/website/docs/d/organization_units.html.markdown new file mode 100644 index 00000000..6f605570 --- /dev/null +++ b/website/docs/d/organization_units.html.markdown @@ -0,0 +1,37 @@ +--- +subcategory: "ORGANIZATION" +layout: "volcengine" +page_title: "Volcengine: volcengine_organization_units" +sidebar_current: "docs-volcengine-datasource-organization_units" +description: |- + Use this data source to query detailed information of organization units +--- +# volcengine_organization_units +Use this data source to query detailed information of organization units +## Example Usage +```hcl +data "volcengine_organization_units" "foo" { +} +``` +## 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: +* `total_count` - The total count of query. +* `units` - The collection of query. + * `created_time` - The created time of the organization unit. + * `delete_uk` - Delete marker. + * `deleted_time` - The deleted time of the organization unit. + * `depth` - The depth of the organization unit. + * `description` - The description of the organization unit. + * `id` - The id of the organization unit. + * `name` - The name of the organization unit. + * `org_id` - The id of the organization. + * `org_type` - The organization type. + * `owner` - The owner of the organization unit. + * `parent_id` - Parent Unit ID. + * `updated_time` - The updated time of the organization unit. + + diff --git a/website/docs/d/organizations.html.markdown b/website/docs/d/organizations.html.markdown new file mode 100644 index 00000000..419bb9ea --- /dev/null +++ b/website/docs/d/organizations.html.markdown @@ -0,0 +1,40 @@ +--- +subcategory: "ORGANIZATION" +layout: "volcengine" +page_title: "Volcengine: volcengine_organizations" +sidebar_current: "docs-volcengine-datasource-organizations" +description: |- + Use this data source to query detailed information of organizations +--- +# volcengine_organizations +Use this data source to query detailed information of organizations +## Example Usage +```hcl +data "volcengine_organizations" "foo" { + +} +``` +## Argument Reference +The following arguments are supported: +* `name_regex` - (Optional) A Name Regex of Resource. +* `output_file` - (Optional) File name where to save data source results. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `organizations` - The collection of query. + * `account_id` - The account id of the organization owner. + * `account_name` - The account name of the organization owner. + * `created_time` - The created time of the organization. + * `delete_uk` - The delete uk of the organization. + * `deleted_time` - The deleted time of the organization. + * `description` - The description of the organization. + * `id` - The id of the organization. + * `main_name` - The main name of the organization owner. + * `name` - The name of the organization. + * `owner` - The owner id of the organization. + * `status` - The status of the organization. + * `type` - The type of the organization. + * `updated_time` - The updated time of the organization. +* `total_count` - The total count of query. + + diff --git a/website/docs/r/iam_saml_provider.html.markdown b/website/docs/r/iam_saml_provider.html.markdown new file mode 100644 index 00000000..0c87ec66 --- /dev/null +++ b/website/docs/r/iam_saml_provider.html.markdown @@ -0,0 +1,41 @@ +--- +subcategory: "IAM" +layout: "volcengine" +page_title: "Volcengine: volcengine_iam_saml_provider" +sidebar_current: "docs-volcengine-resource-iam_saml_provider" +description: |- + Provides a resource to manage iam saml provider +--- +# volcengine_iam_saml_provider +Provides a resource to manage iam saml provider +## Example Usage +```hcl +resource "volcengine_iam_saml_provider" "foo" { + encoded_saml_metadata_document = "your document" + saml_provider_name = "terraform" + sso_type = 2 + status = 1 +} +``` +## Argument Reference +The following arguments are supported: +* `encoded_saml_metadata_document` - (Required) Metadata document, encoded in Base64. +* `saml_provider_name` - (Required, ForceNew) The name of the SAML provider. +* `sso_type` - (Required) SSO types, 1. Role-based SSO, 2. User-based SSO. +* `description` - (Optional) The description of the SAML provider. +* `status` - (Optional) User SSO status, 1. Enabled, 2. Disable other console login methods after enabling, 3. Disabled, is a required field when creating user SSO. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. +* `create_date` - Identity provider creation time, such as 20150123T123318Z. +* `trn` - The format for the resource name of an identity provider is trn:iam::${accountID}:saml-provider/{$SAMLProviderName}. +* `update_date` - Identity provider update time, such as: 20150123T123318Z. + + +## Import +IamSamlProvider can be imported using the id, e.g. +``` +$ terraform import volcengine_iam_saml_provider.default SAMLProviderName +``` + diff --git a/website/docs/r/organization.html.markdown b/website/docs/r/organization.html.markdown new file mode 100644 index 00000000..4ae7bd4a --- /dev/null +++ b/website/docs/r/organization.html.markdown @@ -0,0 +1,43 @@ +--- +subcategory: "ORGANIZATION" +layout: "volcengine" +page_title: "Volcengine: volcengine_organization" +sidebar_current: "docs-volcengine-resource-organization" +description: |- + Provides a resource to manage organization +--- +# volcengine_organization +Provides a resource to manage organization +## Example Usage +```hcl +resource "volcengine_organization" "foo" { + +} +``` +## Argument Reference +The following arguments are supported: + + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. +* `account_id` - The account id of the organization owner. +* `account_name` - The account name of the organization owner. +* `created_time` - The created time of the organization. +* `delete_uk` - The delete uk of the organization. +* `deleted_time` - The deleted time of the organization. +* `description` - The description of the organization. +* `main_name` - The main name of the organization owner. +* `name` - The name of the organization. +* `owner` - The owner id of the organization. +* `status` - The status of the organization. +* `type` - The type of the organization. +* `updated_time` - The updated time of the organization. + + +## Import +Organization can be imported using the id, e.g. +``` +$ terraform import volcengine_organization.default resource_id +``` + diff --git a/website/docs/r/organization_account.html.markdown b/website/docs/r/organization_account.html.markdown new file mode 100644 index 00000000..2e38c1e6 --- /dev/null +++ b/website/docs/r/organization_account.html.markdown @@ -0,0 +1,59 @@ +--- +subcategory: "ORGANIZATION" +layout: "volcengine" +page_title: "Volcengine: volcengine_organization_account" +sidebar_current: "docs-volcengine-resource-organization_account" +description: |- + Provides a resource to manage organization account +--- +# volcengine_organization_account +Provides a resource to manage organization account +## Example Usage +```hcl +resource "volcengine_organization_unit" "foo" { + name = "acc-test-org-unit" + parent_id = "730671013833632****" + description = "acc-test" +} + +resource "volcengine_organization_account" "foo" { + account_name = "acc-test-account" + show_name = "acc-test-account" + description = "acc-test" + org_unit_id = volcengine_organization_unit.foo.id + + tags { + key = "k1" + value = "v1" + } +} +``` +## Argument Reference +The following arguments are supported: +* `account_name` - (Required) The name of the account. +* `show_name` - (Required) The show name of the account. +* `description` - (Optional) The description of the account. +* `org_unit_id` - (Optional) The id of the organization unit. Default is root organization. +* `tags` - (Optional) Tags. + +The `tags` object supports the following: + +* `key` - (Required) The Key of Tags. +* `value` - (Required) The Value of Tags. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. +* `iam_role` - The name of the iam role. +* `org_id` - The id of the organization. +* `org_unit_name` - The name of the organization unit. +* `org_verification_id` - The id of the organization verification. +* `owner` - The owner id of the account. + + +## Import +OrganizationAccount can be imported using the id, e.g. +``` +$ terraform import volcengine_organization_account.default resource_id +``` + diff --git a/website/docs/r/organization_service_control_policy.html.markdown b/website/docs/r/organization_service_control_policy.html.markdown new file mode 100644 index 00000000..b6f16e34 --- /dev/null +++ b/website/docs/r/organization_service_control_policy.html.markdown @@ -0,0 +1,43 @@ +--- +subcategory: "ORGANIZATION" +layout: "volcengine" +page_title: "Volcengine: volcengine_organization_service_control_policy" +sidebar_current: "docs-volcengine-resource-organization_service_control_policy" +description: |- + Provides a resource to manage organization service control policy +--- +# volcengine_organization_service_control_policy +Provides a resource to manage organization service control policy +## Example Usage +```hcl +resource "volcengine_organization_service_control_policy" "foo" { + policy_name = "tfpolicy11" + description = "tftest1" + statement = "{\"Statement\":[{\"Effect\":\"Deny\",\"Action\":[\"ecs:RunInstances\"],\"Resource\":[\"*\"]}]}" +} + +resource "volcengine_organization_service_control_policy" "foo2" { + policy_name = "tfpolicy21" + statement = "{\"Statement\":[{\"Effect\":\"Deny\",\"Action\":[\"ecs:DeleteInstance\"],\"Resource\":[\"*\"]}]}" +} +``` +## Argument Reference +The following arguments are supported: +* `policy_name` - (Required) The name of the Policy. +* `statement` - (Required) The statement of the Policy. +* `description` - (Optional) The description of the Policy. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. +* `create_date` - The create time of the Policy. +* `policy_type` - The type of the Policy. +* `update_date` - The update time of the Policy. + + +## Import +Service Control Policy can be imported using the id, e.g. +``` +$ terraform import volcengine_organization_service_control_policy.default 1000001 +``` + diff --git a/website/docs/r/organization_service_control_policy_attachment.html.markdown b/website/docs/r/organization_service_control_policy_attachment.html.markdown new file mode 100644 index 00000000..dfcb0288 --- /dev/null +++ b/website/docs/r/organization_service_control_policy_attachment.html.markdown @@ -0,0 +1,48 @@ +--- +subcategory: "ORGANIZATION" +layout: "volcengine" +page_title: "Volcengine: volcengine_organization_service_control_policy_attachment" +sidebar_current: "docs-volcengine-resource-organization_service_control_policy_attachment" +description: |- + Provides a resource to manage organization service control policy attachment +--- +# volcengine_organization_service_control_policy_attachment +Provides a resource to manage organization service control policy attachment +## Example Usage +```hcl +resource "volcengine_organization_service_control_policy" "foo" { + policy_name = "tfpolicy11" + description = "tftest1" + statement = "{\"Statement\":[{\"Effect\":\"Deny\",\"Action\":[\"ecs:RunInstances\"],\"Resource\":[\"*\"]}]}" +} + +resource "volcengine_organization_service_control_policy_attachment" "foo" { + policy_id = volcengine_organization_service_control_policy.foo.id + target_id = "21*********94" + target_type = "Account" +} + +resource "volcengine_organization_service_control_policy_attachment" "foo1" { + policy_id = volcengine_organization_service_control_policy.foo.id + target_id = "73*********9" + target_type = "OU" +} +``` +## Argument Reference +The following arguments are supported: +* `policy_id` - (Required, ForceNew) The id of policy. +* `target_id` - (Required, ForceNew) The id of target. +* `target_type` - (Required, ForceNew) The type of target. Support Account or OU. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. + + + +## Import +Service Control policy attachment can be imported using the id, e.g. +``` +$ terraform import volcengine_organization_service_control_policy_attachment.default PolicyID:TargetID +``` + diff --git a/website/docs/r/organization_service_control_policy_enabler.html.markdown b/website/docs/r/organization_service_control_policy_enabler.html.markdown new file mode 100644 index 00000000..73824214 --- /dev/null +++ b/website/docs/r/organization_service_control_policy_enabler.html.markdown @@ -0,0 +1,32 @@ +--- +subcategory: "ORGANIZATION" +layout: "volcengine" +page_title: "Volcengine: volcengine_organization_service_control_policy_enabler" +sidebar_current: "docs-volcengine-resource-organization_service_control_policy_enabler" +description: |- + Provides a resource to manage organization service control policy enabler +--- +# volcengine_organization_service_control_policy_enabler +Provides a resource to manage organization service control policy enabler +## Example Usage +```hcl +resource "volcengine_organization_service_control_policy_enabler" "foo" { + +} +``` +## Argument Reference +The following arguments are supported: + + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. + + + +## Import +ServiceControlPolicy enabler can be imported using the default_id (organization:service_control_policy_enable) , e.g. +``` +$ terraform import volcengine_organization_service_control_policy_enabler.default organization:service_control_policy_enable +``` + diff --git a/website/docs/r/organization_unit.html.markdown b/website/docs/r/organization_unit.html.markdown new file mode 100644 index 00000000..3461ad25 --- /dev/null +++ b/website/docs/r/organization_unit.html.markdown @@ -0,0 +1,47 @@ +--- +subcategory: "ORGANIZATION" +layout: "volcengine" +page_title: "Volcengine: volcengine_organization_unit" +sidebar_current: "docs-volcengine-resource-organization_unit" +description: |- + Provides a resource to manage organization unit +--- +# volcengine_organization_unit +Provides a resource to manage organization unit +## Example Usage +```hcl +resource "volcengine_organization" "foo" { + +} + +data "volcengine_organization_units" "foo" { + depends_on = [volcengine_organization.foo] +} + +resource "volcengine_organization_unit" "foo" { + name = "tf-test-unit" + parent_id = [for unit in data.volcengine_organization_units.foo.units : unit.id if unit.parent_id == "0"][0] + description = "tf-test" +} +``` +## Argument Reference +The following arguments are supported: +* `name` - (Required) Name of the organization unit. +* `parent_id` - (Required, ForceNew) Parent Organization Unit ID. +* `description` - (Optional) Description of the organization unit. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. +* `depth` - The depth of the organization unit. +* `org_id` - The id of the organization. +* `org_type` - The organization type. +* `owner` - The owner of the organization unit. + + +## Import +OrganizationUnit can be imported using the id, e.g. +``` +$ terraform import volcengine_organization_unit.default ID +``` + diff --git a/website/docs/r/vke_cluster.html.markdown b/website/docs/r/vke_cluster.html.markdown index fde3925b..b889a437 100644 --- a/website/docs/r/vke_cluster.html.markdown +++ b/website/docs/r/vke_cluster.html.markdown @@ -66,7 +66,7 @@ The following arguments are supported: * `client_token` - (Optional) ClientToken is a case-sensitive string of no more than 64 ASCII characters passed in by the caller. * `delete_protection_enabled` - (Optional) The delete protection of the cluster, the value is `true` or `false`. * `description` - (Optional) The description of the cluster. -* `kubernetes_version` - (Optional, ForceNew) The version of Kubernetes specified when creating a VKE cluster (specified to patch version), if not specified, the latest Kubernetes version supported by VKE is used by default, which is a 3-segment version format starting with a lowercase v, that is, KubernetesVersion with IsLatestVersion=True in the return value of ListSupportedVersions. +* `kubernetes_version` - (Optional, ForceNew) The version of Kubernetes specified when creating a VKE cluster (specified to patch version), with an example value of `v1.24`. If not specified, the latest Kubernetes version supported by VKE is used by default, which is a 3-segment version format starting with a lowercase v, that is, KubernetesVersion with IsLatestVersion=True in the return value of ListSupportedVersions. * `logging_config` - (Optional) Cluster log configuration information. * `tags` - (Optional) Tags. diff --git a/website/volcengine.erb b/website/volcengine.erb index 1fccb618..0575660b 100644 --- a/website/volcengine.erb +++ b/website/volcengine.erb @@ -670,6 +670,9 @@
  • iam_roles
  • +
  • + iam_saml_providers +
  • iam_users
  • @@ -699,6 +702,9 @@
  • iam_role_policy_attachment
  • +
  • + iam_saml_provider +
  • iam_user
  • @@ -859,6 +865,51 @@ +
  • + ORGANIZATION + +
  • PRIVATELINK