diff --git a/common/common_volcengine_version.go b/common/common_volcengine_version.go index 008d7dea..8246002c 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.73" + TerraformProviderVersion = "0.0.74" ) diff --git a/docgen/main.go b/docgen/main.go index 94ee5003..d6c799ea 100644 --- a/docgen/main.go +++ b/docgen/main.go @@ -143,6 +143,7 @@ var resourceKeys = map[string]string{ "mongodb": "MONGODB", "bioos": "BIOOS", "rds_mysql": "RDS_MYSQL", + "privatelink": "PRIVATELINK", } type Products struct { diff --git a/example/dataPrivatelinkVpcEndpointConnections/main.tf b/example/dataPrivatelinkVpcEndpointConnections/main.tf new file mode 100644 index 00000000..f14d7b2d --- /dev/null +++ b/example/dataPrivatelinkVpcEndpointConnections/main.tf @@ -0,0 +1,4 @@ +data "volcengine_privatelink_vpc_endpoint_connections" "default" { + endpoint_id = "ep-3rel74u229dz45zsk2i6l69qa" + service_id = "epsvc-2byz5mykk9y4g2dx0efs4aqz3" +} \ No newline at end of file diff --git a/example/dataPrivatelinkVpcEndpointServicePermissions/main.tf b/example/dataPrivatelinkVpcEndpointServicePermissions/main.tf new file mode 100644 index 00000000..1961a8ae --- /dev/null +++ b/example/dataPrivatelinkVpcEndpointServicePermissions/main.tf @@ -0,0 +1,3 @@ +data "volcengine_privatelink_vpc_endpoint_service_permissions" "default" { + service_id = "epsvc-3rel73uf2ewao5zsk2j2l58ro" +} \ No newline at end of file diff --git a/example/dataPrivatelinkVpcEndpointServices/main.tf b/example/dataPrivatelinkVpcEndpointServices/main.tf new file mode 100644 index 00000000..16f8417f --- /dev/null +++ b/example/dataPrivatelinkVpcEndpointServices/main.tf @@ -0,0 +1,3 @@ +data "volcengine_privatelink_vpc_endpoint_services" "default" { + ids = ["epsvc-3rel73uf2ewao5zsk2j2l58ro", "epsvc-2d72mxjgq02yo58ozfe5tndeh"] +} \ No newline at end of file diff --git a/example/dataPrivatelinkVpcEndpointZones/main.tf b/example/dataPrivatelinkVpcEndpointZones/main.tf new file mode 100644 index 00000000..4f5137ac --- /dev/null +++ b/example/dataPrivatelinkVpcEndpointZones/main.tf @@ -0,0 +1,3 @@ +data "volcengine_privatelink_vpc_endpoint_zones" "default" { + endpoint_id = "ep-2byz5npiuu1hc2dx0efkv****" +} \ No newline at end of file diff --git a/example/dataPrivatelinkVpcEndpoints/main.tf b/example/dataPrivatelinkVpcEndpoints/main.tf new file mode 100644 index 00000000..0c38c5d4 --- /dev/null +++ b/example/dataPrivatelinkVpcEndpoints/main.tf @@ -0,0 +1,3 @@ +data "volcengine_privatelink_vpc_endpoints" "default" { + ids = ["ep-3rel74u229dz45zsk2i6l****"] +} \ No newline at end of file diff --git a/example/privateLinkVpcEndpointZone/main.tf b/example/privateLinkVpcEndpointZone/main.tf new file mode 100644 index 00000000..91f60842 --- /dev/null +++ b/example/privateLinkVpcEndpointZone/main.tf @@ -0,0 +1,5 @@ +resource "volcengine_privatelink_vpc_endpoint_zone" "foo" { + endpoint_id = "ep-2byz5nlkimc5c2dx0ef9g****" + subnet_id = "subnet-2bz47q19zhx4w2dx0eevn****" + private_ip_address = "172.16.0.251" +} \ No newline at end of file diff --git a/example/privatelinkSecurityGroup/main.tf b/example/privatelinkSecurityGroup/main.tf new file mode 100644 index 00000000..048ac613 --- /dev/null +++ b/example/privatelinkSecurityGroup/main.tf @@ -0,0 +1,4 @@ +resource "volcengine_privatelink_security_group" "foo" { + endpoint_id = "ep-2byz5npiuu1hc2dx0efkv7ehc" + security_group_id = "sg-2d6722jpp55og58ozfd1sqtdb" +} \ No newline at end of file diff --git a/example/privatelinkVpcEndpoint/main.tf b/example/privatelinkVpcEndpoint/main.tf new file mode 100644 index 00000000..a1cca26d --- /dev/null +++ b/example/privatelinkVpcEndpoint/main.tf @@ -0,0 +1,12 @@ +resource "volcengine_privatelink_vpc_endpoint" "endpoint" { + security_group_ids = ["sg-2d5z8cr53k45c58ozfdum****"] + service_id = "epsvc-2byz5nzgiansw2dx0eehh****" + endpoint_name = "tf-test-ep" + description = "tf-test" +} + +resource "volcengine_privatelink_vpc_endpoint_zone" "zone" { + endpoint_id = volcengine_privatelink_vpc_endpoint.endpoint.id + subnet_id = "subnet-2bz47q19zhx4w2dx0eevn****" + private_ip_address = "172.16.0.252" +} \ No newline at end of file diff --git a/example/privatelinkVpcEndpointConnection/main.tf b/example/privatelinkVpcEndpointConnection/main.tf new file mode 100644 index 00000000..d7eea57a --- /dev/null +++ b/example/privatelinkVpcEndpointConnection/main.tf @@ -0,0 +1,5 @@ +resource "volcengine_privatelink_vpc_endpoint_connection" "foo" { + endpoint_id = "ep-3rel74u229dz45zsk2i6l69qa" + service_id = "epsvc-2byz5mykk9y4g2dx0efs4aqz3" +} + diff --git a/example/privatelinkVpcEndpointService/main.tf b/example/privatelinkVpcEndpointService/main.tf new file mode 100644 index 00000000..b61b630b --- /dev/null +++ b/example/privatelinkVpcEndpointService/main.tf @@ -0,0 +1,8 @@ +resource "volcengine_privatelink_vpc_endpoint_service" "foo" { + resources { + resource_id = "clb-2bzxccdjo9uyo2dx0eg0orzla" + resource_type = "CLB" + } + description = "tftest" + auto_accept_enabled = true +} \ No newline at end of file diff --git a/example/privatelinkVpcEndpointServicePermission/main.tf b/example/privatelinkVpcEndpointServicePermission/main.tf new file mode 100644 index 00000000..05950359 --- /dev/null +++ b/example/privatelinkVpcEndpointServicePermission/main.tf @@ -0,0 +1,9 @@ +resource "volcengine_privatelink_vpc_endpoint_service_permission" "foo" { + service_id = "epsvc-3rel73uf2ewao5zsk2j2l58ro" + permit_account_id = "210000000" +} + +resource "volcengine_privatelink_vpc_endpoint_service_permission" "foo1" { + service_id = "epsvc-3rel73uf2ewao5zsk2j2l58ro" + permit_account_id = "210000001" +} \ No newline at end of file diff --git a/example/privatelinkVpcEndpointServiceResource/main.tf b/example/privatelinkVpcEndpointServiceResource/main.tf new file mode 100644 index 00000000..7b444ff1 --- /dev/null +++ b/example/privatelinkVpcEndpointServiceResource/main.tf @@ -0,0 +1,14 @@ +resource "volcengine_privatelink_vpc_endpoint_service_resource" "foo" { + service_id = "epsvc-3rel73uf2ewao5zsk2j2l58ro" + resource_id = "clb-3reii8qfbp7gg5zsk2hsrbe3c" +} + +resource "volcengine_privatelink_vpc_endpoint_service_resource" "foo1" { + service_id = "epsvc-3rel73uf2ewao5zsk2j2l58ro" + resource_id = "clb-2d6sfye98rzls58ozfducee1o" +} + +resource "volcengine_privatelink_vpc_endpoint_service_resource" "foo2" { + service_id = "epsvc-3rel73uf2ewao5zsk2j2l58ro" + resource_id = "clb-3refkvae02gow5zsk2ilaev5y" +} \ No newline at end of file diff --git a/volcengine/privatelink/security_group/resource_volcengine_privatelink_security_group.go b/volcengine/privatelink/security_group/resource_volcengine_privatelink_security_group.go new file mode 100644 index 00000000..a35c7663 --- /dev/null +++ b/volcengine/privatelink/security_group/resource_volcengine_privatelink_security_group.go @@ -0,0 +1,91 @@ +package security_group + +import ( + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +PrivateLink Security Group Service can be imported using the endpoint id and security group id, e.g. +``` +$ terraform import volcengine_privatelink_security_group.default ep-2fe630gurkl37k5gfuy33****:sg-xxxxx +``` + +*/ + +func ResourceVolcenginePrivatelinkSecurityGroupService() *schema.Resource { + resource := &schema.Resource{ + Create: resourceVolcenginePrivatelinkSecurityGroupCreate, + Read: resourceVolcenginePrivatelinkSecurityGroupRead, + Delete: resourceVolcenginePrivatelinkSecurityGroupDelete, + Importer: &schema.ResourceImporter{ + State: sgImporter, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "endpoint_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The id of the endpoint.", + }, + "security_group_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The id of the security group.", + }, + }, + } + return resource +} + +func resourceVolcenginePrivatelinkSecurityGroupCreate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewPrivateLinkSecurityGroupService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Create(service, d, ResourceVolcenginePrivatelinkSecurityGroupService()) + if err != nil { + return fmt.Errorf("error on creating private link security group service %q, %w", d.Id(), err) + } + return resourceVolcenginePrivatelinkSecurityGroupRead(d, meta) +} + +func resourceVolcenginePrivatelinkSecurityGroupRead(d *schema.ResourceData, meta interface{}) (err error) { + service := NewPrivateLinkSecurityGroupService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Read(service, d, ResourceVolcenginePrivatelinkSecurityGroupService()) + if err != nil { + return fmt.Errorf("error on reading private link security group service %q, %w", d.Id(), err) + } + return nil +} + +func resourceVolcenginePrivatelinkSecurityGroupDelete(d *schema.ResourceData, meta interface{}) (err error) { + service := NewPrivateLinkSecurityGroupService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Delete(service, d, ResourceVolcenginePrivatelinkSecurityGroupService()) + if err != nil { + return fmt.Errorf("error on deleting private link security group service %q, %w", d.Id(), err) + } + return nil +} + +var sgImporter = func(data *schema.ResourceData, i interface{}) ([]*schema.ResourceData, error) { + items := strings.Split(data.Id(), ":") + if len(items) != 2 { + return []*schema.ResourceData{data}, fmt.Errorf("import id must split with ':'") + } + if err := data.Set("endpoint_id", items[0]); err != nil { + return []*schema.ResourceData{data}, err + } + if err := data.Set("security_group_id", items[1]); err != nil { + return []*schema.ResourceData{data}, err + } + return []*schema.ResourceData{data}, nil +} diff --git a/volcengine/privatelink/security_group/service_volcengine_privatelink_security_group.go b/volcengine/privatelink/security_group/service_volcengine_privatelink_security_group.go new file mode 100644 index 00000000..67a497e8 --- /dev/null +++ b/volcengine/privatelink/security_group/service_volcengine_privatelink_security_group.go @@ -0,0 +1,170 @@ +package security_group + +import ( + "errors" + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" + "github.com/volcengine/terraform-provider-volcengine/volcengine/privatelink/vpc_endpoint" +) + +type VolcenginePrivateLinkSecurityGroupService struct { + Client *ve.SdkClient +} + +func (v *VolcenginePrivateLinkSecurityGroupService) GetClient() *ve.SdkClient { + return v.Client +} + +func (v *VolcenginePrivateLinkSecurityGroupService) ReadResources(condition map[string]interface{}) (data []interface{}, err error) { + return data, err +} + +func (v *VolcenginePrivateLinkSecurityGroupService) ReadResource(resourceData *schema.ResourceData, id string) (data map[string]interface{}, err error) { + if id == "" { + id = resourceData.Id() + } + ids := strings.Split(id, ":") + if len(ids) != 2 { + return data, errors.New("Invalid security group id ") + } + endpointId := ids[0] + securityGroupId := ids[1] + action := "DescribeVpcEndpointSecurityGroups" + req := map[string]interface{}{ + "EndpointId": endpointId, + } + resp, err := v.Client.UniversalClient.DoCall(getUniversalInfo(action), &req) + if err != nil { + return data, err + } + if resp == nil { + return data, fmt.Errorf("Security group %s not exists ", id) + } + securityGroupIds, err := ve.ObtainSdkValue("Result.SecurityGroupIds", *resp) + if err != nil { + return data, err + } + for _, s := range securityGroupIds.([]interface{}) { + if _, ok := s.(string); !ok { + return data, errors.New("security group id is not string") + } else { + if securityGroupId == s.(string) { + data = map[string]interface{}{ + "SecurityGroupId": securityGroupId, + "EndpointId": endpointId, + } + break + } + } + } + if len(data) == 0 { + return data, fmt.Errorf("Security group %s not exists ", id) + } + return data, nil +} + +func (v *VolcenginePrivateLinkSecurityGroupService) RefreshResourceState(data *schema.ResourceData, strings []string, duration time.Duration, s string) *resource.StateChangeConf { + return nil +} + +func (v *VolcenginePrivateLinkSecurityGroupService) 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 (v *VolcenginePrivateLinkSecurityGroupService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + endpointId := resourceData.Get("endpoint_id").(string) + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "AttachSecurityGroupToVpcEndpoint", + 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 v.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + id := fmt.Sprintf("%s:%s", endpointId, d.Get("security_group_id")) + d.SetId(id) + return nil + }, + ExtraRefresh: map[ve.ResourceService]*ve.StateRefresh{ + vpc_endpoint.NewVpcEndpointService(v.Client): { + Target: []string{"Available"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + ResourceId: endpointId, + }, + }, + LockId: func(d *schema.ResourceData) string { + return endpointId + }, + }, + } + return []ve.Callback{callback} +} + +func (v *VolcenginePrivateLinkSecurityGroupService) ModifyResource(data *schema.ResourceData, resource *schema.Resource) []ve.Callback { + return nil +} + +func (v *VolcenginePrivateLinkSecurityGroupService) RemoveResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "DetachSecurityGroupFromVpcEndpoint", + ConvertMode: ve.RequestConvertIgnore, + SdkParam: &map[string]interface{}{ + "EndpointId": resourceData.Get("endpoint_id"), + "SecurityGroupId": resourceData.Get("security_group_id"), + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return v.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, v.ReadResource, 5*time.Minute) + }, + ExtraRefresh: map[ve.ResourceService]*ve.StateRefresh{ + vpc_endpoint.NewVpcEndpointService(v.Client): { + Target: []string{"Available"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + ResourceId: resourceData.Get("endpoint_id").(string), + }, + }, + LockId: func(d *schema.ResourceData) string { + return resourceData.Get("endpoint_id").(string) + }, + }, + } + return []ve.Callback{callback} +} + +func (v *VolcenginePrivateLinkSecurityGroupService) DatasourceResources(data *schema.ResourceData, resource *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{} +} + +func (v *VolcenginePrivateLinkSecurityGroupService) ReadResourceId(id string) string { + return id +} + +func NewPrivateLinkSecurityGroupService(c *ve.SdkClient) *VolcenginePrivateLinkSecurityGroupService { + return &VolcenginePrivateLinkSecurityGroupService{ + Client: c, + } +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "privatelink", + Version: "2020-04-01", + HttpMethod: ve.GET, + Action: actionName, + ContentType: ve.Default, + } +} diff --git a/volcengine/privatelink/vpc_endpoint/data_source_volcengine_privatelink_vpc_endpoints.go b/volcengine/privatelink/vpc_endpoint/data_source_volcengine_privatelink_vpc_endpoints.go new file mode 100644 index 00000000..fc02150f --- /dev/null +++ b/volcengine/privatelink/vpc_endpoint/data_source_volcengine_privatelink_vpc_endpoints.go @@ -0,0 +1,150 @@ +package vpc_endpoint + +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 DataSourceVolcenginePrivatelinkVpcEndpoints() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcenginePrivatelinkVpcEndpointsRead, + Schema: map[string]*schema.Schema{ + "ids": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + Description: "The IDs of vpc endpoint.", + }, + "vpc_id": { + Type: schema.TypeString, + Optional: true, + Description: "The vpc id of vpc endpoint.", + }, + "endpoint_name": { + Type: schema.TypeString, + Optional: true, + Description: "The name of vpc endpoint.", + }, + "service_name": { + Type: schema.TypeString, + Optional: true, + Description: "The name of vpc endpoint service.", + }, + "status": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"Creating", "Pending", "Available", "Deleting", "Inactive"}, false), + Description: "The status of vpc endpoint. Valid values: `Creating`, `Pending`, `Available`, `Deleting`, `Inactive`.", + }, + "name_regex": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsValidRegExp, + Description: "A Name Regex of vpc endpoint.", + }, + "output_file": { + Type: schema.TypeString, + Optional: true, + Description: "File name where to save data source results.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Returns the total amount of the data list.", + }, + "vpc_endpoints": { + 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 vpc endpoint.", + }, + "endpoint_id": { + Type: schema.TypeString, + Computed: true, + Description: "The Id of vpc endpoint.", + }, + "endpoint_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of vpc endpoint.", + }, + "endpoint_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of vpc endpoint.", + }, + "endpoint_domain": { + Type: schema.TypeString, + Computed: true, + Description: "The domain of vpc endpoint.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of vpc endpoint.", + }, + "business_status": { + Type: schema.TypeString, + Computed: true, + Description: "Whether the vpc endpoint is locked.", + }, + "connection_status": { + Type: schema.TypeString, + Computed: true, + Description: "The connection status of vpc endpoint.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of vpc endpoint.", + }, + "service_id": { + Type: schema.TypeString, + Computed: true, + Description: "The Id of vpc endpoint service.", + }, + "service_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of vpc endpoint service.", + }, + "vpc_id": { + Type: schema.TypeString, + Computed: true, + Description: "The vpc id of vpc endpoint.", + }, + "creation_time": { + Type: schema.TypeString, + Computed: true, + Description: "The create time of vpc endpoint.", + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: "The update time of vpc endpoint.", + }, + "deleted_time": { + Type: schema.TypeString, + Computed: true, + Description: "The delete time of vpc endpoint.", + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcenginePrivatelinkVpcEndpointsRead(d *schema.ResourceData, meta interface{}) error { + service := NewVpcEndpointService(meta.(*ve.SdkClient)) + return ve.DefaultDispatcher().Data(service, d, DataSourceVolcenginePrivatelinkVpcEndpoints()) +} diff --git a/volcengine/privatelink/vpc_endpoint/resource_volcengine_privatelink_vpc_endpoint.go b/volcengine/privatelink/vpc_endpoint/resource_volcengine_privatelink_vpc_endpoint.go new file mode 100644 index 00000000..7f6d405b --- /dev/null +++ b/volcengine/privatelink/vpc_endpoint/resource_volcengine_privatelink_vpc_endpoint.go @@ -0,0 +1,156 @@ +package vpc_endpoint + +import ( + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +VpcEndpoint can be imported using the id, e.g. +``` +$ terraform import volcengine_privatelink_vpc_endpoint.default ep-3rel74u229dz45zsk2i6l**** +``` + +*/ + +func ResourceVolcenginePrivatelinkVpcEndpoint() *schema.Resource { + resource := &schema.Resource{ + Create: resourceVolcenginePrivateLinkVpcEndpointCreate, + Read: resourceVolcenginePrivateLinkVpcEndpointRead, + Update: resourceVolcenginePrivateLinkVpcEndpointUpdate, + Delete: resourceVolcenginePrivateLinkVpcEndpointDelete, + 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{ + "security_group_ids": { + Type: schema.TypeSet, + Required: true, + ForceNew: true, + Set: schema.HashString, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Description: "the security group ids of vpc endpoint.", + }, + "service_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The id of vpc endpoint service.", + }, + "service_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "The name of vpc endpoint service.", + }, + "endpoint_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name of vpc endpoint.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The description of vpc endpoint.", + }, + + "vpc_id": { + Type: schema.TypeString, + Computed: true, + Description: "The vpc id of vpc endpoint.", + }, + "endpoint_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of vpc endpoint.", + }, + "endpoint_domain": { + Type: schema.TypeString, + Computed: true, + Description: "The domain of vpc endpoint.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of vpc endpoint.", + }, + "business_status": { + Type: schema.TypeString, + Computed: true, + Description: "Whether the vpc endpoint is locked.", + }, + "connection_status": { + Type: schema.TypeString, + Computed: true, + Description: "The connection status of vpc endpoint.", + }, + "creation_time": { + Type: schema.TypeString, + Computed: true, + Description: "The create time of vpc endpoint.", + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: "The update time of vpc endpoint.", + }, + "deleted_time": { + Type: schema.TypeString, + Computed: true, + Description: "The delete time of vpc endpoint.", + }, + }, + } + return resource +} + +func resourceVolcenginePrivateLinkVpcEndpointCreate(d *schema.ResourceData, meta interface{}) (err error) { + vpcEndpointService := NewVpcEndpointService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Create(vpcEndpointService, d, ResourceVolcenginePrivatelinkVpcEndpoint()) + if err != nil { + return fmt.Errorf("error on creating vpc endpoint %q, %w", d.Id(), err) + } + return resourceVolcenginePrivateLinkVpcEndpointRead(d, meta) +} + +func resourceVolcenginePrivateLinkVpcEndpointRead(d *schema.ResourceData, meta interface{}) (err error) { + vpcEndpointService := NewVpcEndpointService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Read(vpcEndpointService, d, ResourceVolcenginePrivatelinkVpcEndpoint()) + if err != nil { + return fmt.Errorf("error on reading vpc endpoint %q, %w", d.Id(), err) + } + return err +} + +func resourceVolcenginePrivateLinkVpcEndpointUpdate(d *schema.ResourceData, meta interface{}) (err error) { + vpcEndpointService := NewVpcEndpointService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Update(vpcEndpointService, d, ResourceVolcenginePrivatelinkVpcEndpoint()) + if err != nil { + return fmt.Errorf("error on updating vpc endoint %q, %w", d.Id(), err) + } + return resourceVolcenginePrivateLinkVpcEndpointRead(d, meta) +} + +func resourceVolcenginePrivateLinkVpcEndpointDelete(d *schema.ResourceData, meta interface{}) (err error) { + vpcEndpointService := NewVpcEndpointService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Delete(vpcEndpointService, d, ResourceVolcenginePrivatelinkVpcEndpoint()) + if err != nil { + return fmt.Errorf("error on deleting vpc endpoint %q, %w", d.Id(), err) + } + return err +} diff --git a/volcengine/privatelink/vpc_endpoint/service_volcengine_privatelink_vpc_endpoint.go b/volcengine/privatelink/vpc_endpoint/service_volcengine_privatelink_vpc_endpoint.go new file mode 100644 index 00000000..274824f5 --- /dev/null +++ b/volcengine/privatelink/vpc_endpoint/service_volcengine_privatelink_vpc_endpoint.go @@ -0,0 +1,331 @@ +package vpc_endpoint + +import ( + "errors" + "fmt" + "time" + + "github.com/google/uuid" + "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 VolcengineVpcEndpointService struct { + Client *ve.SdkClient +} + +func NewVpcEndpointService(c *ve.SdkClient) *VolcengineVpcEndpointService { + return &VolcengineVpcEndpointService{ + Client: c, + } +} + +func (s *VolcengineVpcEndpointService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineVpcEndpointService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + return ve.WithPageNumberQuery(m, "PageSize", "PageNumber", 20, 1, func(condition map[string]interface{}) ([]interface{}, error) { + action := "DescribeVpcEndpoints" + logger.Debug(logger.ReqFormat, action, condition) + if condition == nil { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), nil) + if err != nil { + return data, err + } + } else { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &condition) + if err != nil { + return data, err + } + } + logger.Debug(logger.RespFormat, action, condition, *resp) + results, err = ve.ObtainSdkValue("Result.Endpoints", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.Endpoints is not Slice") + } + return data, err + }) +} + +func (s *VolcengineVpcEndpointService) 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{}{ + "EndpointIds.1": id, + } + results, err = s.ReadResources(req) + if err != nil { + return data, err + } + for _, v := range results { + if data, ok = v.(map[string]interface{}); !ok { + return data, errors.New("Value is not map ") + } + } + if len(data) == 0 { + return data, fmt.Errorf("Vpc endpoint service %s not exist ", id) + } + + // 查询 security_group + action := "DescribeVpcEndpointSecurityGroups" + condition := &map[string]interface{}{ + "EndpointId": id, + } + logger.Debug(logger.ReqFormat, action, condition) + resp, err := s.Client.UniversalClient.DoCall(getUniversalInfo(action), condition) + if err != nil { + return data, err + } + logger.Debug(logger.RespFormat, action, resp) + securityGroupIds, err := ve.ObtainSdkValue("Result.SecurityGroupIds", *resp) + if err != nil { + return data, err + } + if securityGroupIds == nil { + securityGroupIds = []interface{}{} + } + data["SecurityGroupIds"] = securityGroupIds + + return data, err +} + +func (s *VolcengineVpcEndpointService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return &resource.StateChangeConf{ + Pending: []string{}, + Delay: 1 * time.Second, + MinTimeout: 1 * time.Second, + Target: target, + Timeout: timeout, + Refresh: func() (result interface{}, state string, err error) { + var ( + data map[string]interface{} + status interface{} + ) + if err = resource.Retry(20*time.Minute, func() *resource.RetryError { + data, err = s.ReadResource(resourceData, id) + if err != nil { + if ve.ResourceNotFoundError(err) { + return resource.RetryableError(err) + } else { + return resource.NonRetryableError(err) + } + } + return nil + }); err != nil { + return nil, "", err + } + status, err = ve.ObtainSdkValue("Status", data) + if err != nil { + return nil, "", err + } + //注意 返回的第一个参数不能为空 否则会一直等下去 + return data, status.(string), err + }, + } +} + +func (s *VolcengineVpcEndpointService) WithResourceResponseHandlers(data map[string]interface{}) []ve.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]ve.ResponseConvert, error) { + return data, nil, nil + } + return []ve.ResourceResponseHandler{handler} +} + +func (s *VolcengineVpcEndpointService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "CreateVpcEndpoint", + ConvertMode: ve.RequestConvertAll, + Convert: map[string]ve.RequestConvert{ + "security_group_ids": { + TargetField: "SecurityGroupIds", + ConvertType: ve.ConvertWithN, + }, + }, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + // 通过安全组查询 vpc + securityGroupId := d.Get("security_group_ids").(*schema.Set).List()[0].(string) + action := "DescribeSecurityGroups" + req := map[string]interface{}{ + "SecurityGroupIds.1": securityGroupId, + } + resp, err := s.Client.VpcClient.DescribeSecurityGroupsCommon(&req) + if err != nil { + return false, err + } + logger.Debug(logger.RespFormat, action, req, *resp) + results, err := ve.ObtainSdkValue("Result.SecurityGroups", *resp) + if err != nil { + return false, err + } + if results == nil { + results = []interface{}{} + } + securityGroups, ok := results.([]interface{}) + if !ok { + return false, errors.New("Result.SecurityGroups is not Slice") + } + if len(securityGroups) == 0 { + return false, fmt.Errorf("securityGroup %s not exist", securityGroupId) + } + vpcId := securityGroups[0].(map[string]interface{})["VpcId"].(string) + + (*call.SdkParam)["VpcId"] = vpcId + (*call.SdkParam)["ClientToken"] = uuid.New().String() + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + 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.EndpointId", *resp) + d.SetId(id.(string)) + return nil + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Available"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + }, + LockId: func(d *schema.ResourceData) string { + return d.Get("service_id").(string) + }, + }, + } + return []ve.Callback{callback} + +} + +func (s *VolcengineVpcEndpointService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + + if resourceData.HasChange("endpoint_name") || resourceData.HasChange("description") { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "ModifyVpcEndpointAttributes", + ConvertMode: ve.RequestConvertInConvert, + Convert: map[string]ve.RequestConvert{ + "endpoint_name": { + TargetField: "EndpointName", + }, + "description": { + TargetField: "Description", + }, + }, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["EndpointId"] = 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, call.SdkParam, resp) + return resp, err + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Available"}, + Timeout: resourceData.Timeout(schema.TimeoutUpdate), + }, + }, + } + callbacks = append(callbacks, callback) + } + + return callbacks +} + +func (s *VolcengineVpcEndpointService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "DeleteVpcEndpoint", + ConvertMode: ve.RequestConvertIgnore, + SdkParam: &map[string]interface{}{ + "EndpointId": 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 vpc endpoint 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 d.Get("service_id").(string) + }, + }, + } + return []ve.Callback{callback} +} + +func (VolcengineVpcEndpointService) DatasourceResources(data *schema.ResourceData, resource *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{ + RequestConverts: map[string]ve.RequestConvert{ + "ids": { + TargetField: "EndpointIds", + ConvertType: ve.ConvertWithN, + }, + }, + NameField: "EndpointName", + IdField: "EndpointId", + CollectField: "vpc_endpoints", + ResponseConverts: map[string]ve.ResponseConvert{ + "EndpointId": { + TargetField: "id", + KeepDefault: true, + }, + }, + } +} + +func (s *VolcengineVpcEndpointService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "privatelink", + Version: "2020-04-01", + HttpMethod: ve.GET, + Action: actionName, + ContentType: ve.Default, + } +} diff --git a/volcengine/privatelink/vpc_endpoint_connection/data_source_volcengine_privatelink_vpc_endpoint_connections.go b/volcengine/privatelink/vpc_endpoint_connection/data_source_volcengine_privatelink_vpc_endpoint_connections.go new file mode 100644 index 00000000..cee11b83 --- /dev/null +++ b/volcengine/privatelink/vpc_endpoint_connection/data_source_volcengine_privatelink_vpc_endpoint_connections.go @@ -0,0 +1,132 @@ +package vpc_endpoint_connection + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +func DataSourceVolcenginePrivatelinkVpcEndpointConnections() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcenginePrivatelinkVpcEndpointConnectionsRead, + Schema: map[string]*schema.Schema{ + "service_id": { + Type: schema.TypeString, + Required: true, + Description: "The id of the vpc endpoint service.", + }, + "endpoint_id": { + Type: schema.TypeString, + Optional: true, + Description: "The id of the vpc endpoint.", + }, + "endpoint_owner_account_id": { + Type: schema.TypeString, + Optional: true, + Description: "The account id of the vpc endpoint.", + }, + "output_file": { + Type: schema.TypeString, + Optional: true, + Description: "File name where to save data source results.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Returns the total amount of the data list.", + }, + "connections": { + Description: "The list of query.", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the vpc endpoint service.", + }, + "endpoint_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the vpc endpoint.", + }, + "endpoint_owner_account_id": { + Type: schema.TypeString, + Computed: true, + Description: "The account id of the vpc endpoint.", + }, + "endpoint_vpc_id": { + Type: schema.TypeString, + Computed: true, + Description: "The vpc id of the vpc endpoint.", + }, + "connection_status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the connection.", + }, + "creation_time": { + Type: schema.TypeString, + Computed: true, + Description: "The create time of the connection.", + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: "The update time of the connection.", + }, + "zones": { + Type: schema.TypeList, + Computed: true, + Description: "The available zones.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "zone_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the zone.", + }, + "zone_domain": { + Type: schema.TypeString, + Computed: true, + Description: "The domain of the zone.", + }, + "zone_status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the zone.", + }, + "subnet_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the subnet.", + }, + "network_interface_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the network interface.", + }, + "network_interface_ip": { + Type: schema.TypeString, + Computed: true, + Description: "The ip address of the network interface.", + }, + "resource_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the resource.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcenginePrivatelinkVpcEndpointConnectionsRead(d *schema.ResourceData, meta interface{}) error { + service := NewVpcEndpointConnectionService(meta.(*ve.SdkClient)) + return ve.DefaultDispatcher().Data(service, d, DataSourceVolcenginePrivatelinkVpcEndpointConnections()) +} diff --git a/volcengine/privatelink/vpc_endpoint_connection/resource_volcengine_privatelink_vpc_endpoint_connection.go b/volcengine/privatelink/vpc_endpoint_connection/resource_volcengine_privatelink_vpc_endpoint_connection.go new file mode 100644 index 00000000..9490d8df --- /dev/null +++ b/volcengine/privatelink/vpc_endpoint_connection/resource_volcengine_privatelink_vpc_endpoint_connection.go @@ -0,0 +1,93 @@ +package vpc_endpoint_connection + +import ( + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +PrivateLink Vpc Endpoint Connection Service can be imported using the endpoint id and service id, e.g. +``` +$ terraform import volcengine_privatelink_vpc_endpoint_connection.default ep-3rel74u229dz45zsk2i6l69qa:epsvc-2byz5mykk9y4g2dx0efs4aqz3 +``` + +*/ + +func ResourceVolcenginePrivatelinkVpcEndpointConnectionService() *schema.Resource { + resource := &schema.Resource{ + Create: resourceVolcenginePrivatelinkVpcEndpointConnectionCreate, + Read: resourceVolcenginePrivatelinkVpcEndpointConnectionRead, + Delete: resourceVolcenginePrivatelinkVpcEndpointConnectionDelete, + Importer: &schema.ResourceImporter{ + State: vpcConnectionImporter, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "endpoint_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The id of the endpoint.", + }, + "service_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The id of the security group.", + }, + }, + } + dataSource := DataSourceVolcenginePrivatelinkVpcEndpointConnections().Schema["connections"].Elem.(*schema.Resource).Schema + ve.MergeDateSourceToResource(dataSource, &resource.Schema) + return resource +} + +func resourceVolcenginePrivatelinkVpcEndpointConnectionCreate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewVpcEndpointConnectionService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Create(service, d, ResourceVolcenginePrivatelinkVpcEndpointConnectionService()) + if err != nil { + return fmt.Errorf("error on creating private link VpcEndpointConnection service %q, %w", d.Id(), err) + } + return resourceVolcenginePrivatelinkVpcEndpointConnectionRead(d, meta) +} + +func resourceVolcenginePrivatelinkVpcEndpointConnectionRead(d *schema.ResourceData, meta interface{}) (err error) { + service := NewVpcEndpointConnectionService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Read(service, d, ResourceVolcenginePrivatelinkVpcEndpointConnectionService()) + if err != nil { + return fmt.Errorf("error on reading private link VpcEndpointConnection service %q, %w", d.Id(), err) + } + return nil +} + +func resourceVolcenginePrivatelinkVpcEndpointConnectionDelete(d *schema.ResourceData, meta interface{}) (err error) { + service := NewVpcEndpointConnectionService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Delete(service, d, ResourceVolcenginePrivatelinkVpcEndpointConnectionService()) + if err != nil { + return fmt.Errorf("error on deleting private link VpcEndpointConnection service %q, %w", d.Id(), err) + } + return nil +} + +var vpcConnectionImporter = func(data *schema.ResourceData, i interface{}) ([]*schema.ResourceData, error) { + items := strings.Split(data.Id(), ":") + if len(items) != 2 { + return []*schema.ResourceData{data}, fmt.Errorf("import id must split with ':'") + } + if err := data.Set("endpoint_id", items[0]); err != nil { + return []*schema.ResourceData{data}, err + } + if err := data.Set("service_id", items[1]); err != nil { + return []*schema.ResourceData{data}, err + } + return []*schema.ResourceData{data}, nil +} diff --git a/volcengine/privatelink/vpc_endpoint_connection/service_volcengine_privatelink_vpc_endpoint_connection.go b/volcengine/privatelink/vpc_endpoint_connection/service_volcengine_privatelink_vpc_endpoint_connection.go new file mode 100644 index 00000000..57a551c8 --- /dev/null +++ b/volcengine/privatelink/vpc_endpoint_connection/service_volcengine_privatelink_vpc_endpoint_connection.go @@ -0,0 +1,204 @@ +package vpc_endpoint_connection + +import ( + "errors" + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" +) + +type VolcenginePrivateLinkVpcEndpointConnection struct { + Client *ve.SdkClient +} + +func (v *VolcenginePrivateLinkVpcEndpointConnection) GetClient() *ve.SdkClient { + return v.Client +} + +func (v *VolcenginePrivateLinkVpcEndpointConnection) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + return ve.WithPageNumberQuery(m, "PageSize", "PageNumber", 20, 1, func(condition map[string]interface{}) ([]interface{}, error) { + action := "DescribeVpcEndpointConnections" + logger.Debug(logger.ReqFormat, action, condition) + if condition == nil { + resp, err = v.Client.UniversalClient.DoCall(getUniversalInfo(action), nil) + if err != nil { + return data, err + } + } else { + resp, err = v.Client.UniversalClient.DoCall(getUniversalInfo(action), &condition) + if err != nil { + return data, err + } + } + logger.Debug(logger.RespFormat, action, condition, *resp) + results, err = ve.ObtainSdkValue("Result.EndpointConnections", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.EndpointConnections is not Slice") + } + return data, err + }) +} + +func (v *VolcenginePrivateLinkVpcEndpointConnection) ReadResource(resourceData *schema.ResourceData, id string) (data map[string]interface{}, err error) { + var ( + results []interface{} + ok bool + ) + if id == "" { + id = v.ReadResourceId(resourceData.Id()) + } + ids := strings.Split(id, ":") + if len(ids) != 2 { + return nil, errors.New("vpc endpoint connection id err") + } + req := map[string]interface{}{ + "EndpointId": ids[0], + "ServiceId": ids[1], + } + results, err = v.ReadResources(req) + if err != nil { + return data, err + } + for _, r := range results { + if data, ok = r.(map[string]interface{}); !ok { + return data, errors.New("Value is not map ") + } + } + if len(data) == 0 { + return data, fmt.Errorf("vpc endpoint connection %s not exist", id) + } + return data, nil +} + +func (v *VolcenginePrivateLinkVpcEndpointConnection) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return &resource.StateChangeConf{ + Pending: []string{}, + Delay: 1 * time.Second, + MinTimeout: 1 * time.Second, + Target: target, + Timeout: timeout, + Refresh: func() (result interface{}, state string, err error) { + var ( + data map[string]interface{} + status interface{} + failStates []string + ) + failStates = append(failStates, "Error") + data, err = v.ReadResource(resourceData, id) + if err != nil { + return nil, "", err + } + status, err = ve.ObtainSdkValue("ConnectionStatus", data) + if err != nil { + return nil, "", err + } + for _, f := range failStates { + if f == status.(string) { + return nil, "", fmt.Errorf("Vpc endpoint connection status error, status: %s ", status.(string)) + } + } + //注意 返回的第一个参数不能为空 否则会一直等下去 + return data, status.(string), err + }, + } +} + +func (v *VolcenginePrivateLinkVpcEndpointConnection) WithResourceResponseHandlers(m map[string]interface{}) []ve.ResourceResponseHandler { + return nil +} + +func (v *VolcenginePrivateLinkVpcEndpointConnection) CreateResource(data *schema.ResourceData, resource *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "EnableVpcEndpointConnection", + 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 v.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + id := fmt.Sprintf("%s:%s", d.Get("endpoint_id"), d.Get("service_id")) + d.SetId(id) + return nil + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Connected"}, + Timeout: data.Timeout(schema.TimeoutCreate), + }, + }, + } + return []ve.Callback{callback} +} + +func (v *VolcenginePrivateLinkVpcEndpointConnection) ModifyResource(data *schema.ResourceData, resource *schema.Resource) []ve.Callback { + return nil +} + +func (v *VolcenginePrivateLinkVpcEndpointConnection) RemoveResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "DisableVpcEndpointConnection", + ConvertMode: ve.RequestConvertIgnore, + SdkParam: &map[string]interface{}{ + "EndpointId": resourceData.Get("endpoint_id"), + "ServiceId": resourceData.Get("service_id"), + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return v.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Rejected"}, + Timeout: resourceData.Timeout(schema.TimeoutDelete), + }, + }, + } + return []ve.Callback{callback} +} + +func (v *VolcenginePrivateLinkVpcEndpointConnection) DatasourceResources(data *schema.ResourceData, resource *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{ + CollectField: "connections", + ResponseConverts: map[string]ve.ResponseConvert{ + "NetworkInterfaceIP": { + TargetField: "network_interface_ip", + }, + }, + } +} + +func (v *VolcenginePrivateLinkVpcEndpointConnection) ReadResourceId(s string) string { + return s +} + +func NewVpcEndpointConnectionService(c *ve.SdkClient) *VolcenginePrivateLinkVpcEndpointConnection { + return &VolcenginePrivateLinkVpcEndpointConnection{ + Client: c, + } +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "privatelink", + Version: "2020-04-01", + HttpMethod: ve.GET, + Action: actionName, + ContentType: ve.Default, + } +} diff --git a/volcengine/privatelink/vpc_endpoint_service/data_source_volcengine_privatelink_vpc_endpoint_services.go b/volcengine/privatelink/vpc_endpoint_service/data_source_volcengine_privatelink_vpc_endpoint_services.go new file mode 100644 index 00000000..3147c42e --- /dev/null +++ b/volcengine/privatelink/vpc_endpoint_service/data_source_volcengine_privatelink_vpc_endpoint_services.go @@ -0,0 +1,146 @@ +package vpc_endpoint_service + +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 DataSourceVolcenginePrivatelinkVpcEndpointServices() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcenginePrivatelinkVpcEndpointServiceRead, + Schema: map[string]*schema.Schema{ + "ids": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + Description: "The IDs of vpc endpoint service.", + }, + "service_name": { + Type: schema.TypeString, + Optional: true, + Description: "The name of vpc endpoint service.", + }, + "name_regex": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsValidRegExp, + Description: "A Name Regex of vpc endpoint service.", + }, + "output_file": { + Type: schema.TypeString, + Optional: true, + Description: "File name where to save data source results.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Returns the total amount of the data list.", + }, + "services": { + 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 service.", + }, + "service_id": { + Type: schema.TypeString, + Computed: true, + Description: "The Id of service.", + }, + "service_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of service.", + }, + "service_domain": { + Type: schema.TypeString, + Computed: true, + Description: "The domain of service.", + }, + "service_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of service.", + }, + "service_resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type of service.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of service.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of service.", + }, + "creation_time": { + Type: schema.TypeString, + Computed: true, + Description: "The create time of service.", + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: "The update time of service.", + }, + "auto_accept_enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether auto accept node connect.", + }, + "zone_ids": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Description: "The IDs of zones.", + }, + "resources": { + Type: schema.TypeList, + Computed: true, + Description: "The resources info.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of resource.", + }, + "resource_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of resource.", + }, + "zone_id": { + Type: schema.TypeString, + Computed: true, + Description: "The zone id of resource.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcenginePrivatelinkVpcEndpointServiceRead(d *schema.ResourceData, meta interface{}) error { + service := NewService(meta.(*ve.SdkClient)) + return ve.DefaultDispatcher().Data(service, d, DataSourceVolcenginePrivatelinkVpcEndpointServices()) +} diff --git a/volcengine/privatelink/vpc_endpoint_service/resource_volcengine_privatelink_vpc_endpoint_service.go b/volcengine/privatelink/vpc_endpoint_service/resource_volcengine_privatelink_vpc_endpoint_service.go new file mode 100644 index 00000000..a403e000 --- /dev/null +++ b/volcengine/privatelink/vpc_endpoint_service/resource_volcengine_privatelink_vpc_endpoint_service.go @@ -0,0 +1,169 @@ +package vpc_endpoint_service + +import ( + "bytes" + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +VpcEndpointService can be imported using the id, e.g. +``` +$ terraform import volcengine_privatelink_vpc_endpoint_service.default epsvc-2fe630gurkl37k5gfuy33**** +``` + +*/ + +func ResourceVolcenginePrivatelinkVpcEndpointService() *schema.Resource { + resource := &schema.Resource{ + Create: resourceVolcenginePrivateLinkVpcEndpointServiceCreate, + Read: resourceVolcenginePrivateLinkVpcEndpointServiceRead, + Update: resourceVolcenginePrivateLinkVpcEndpointServiceUpdate, + Delete: resourceVolcenginePrivateLinkVpcEndpointServiceDelete, + 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{ + "auto_accept_enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Whether auto accept node connect.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The description of service.", + }, + // 创建 service 时候,必须传入一个 resource;在修改 resource 的时候,必须保留一个,不能全部删除 + "resources": { + Type: schema.TypeSet, + Required: true, + Description: "The resources info. When create vpc endpoint service, the resource must exist.", + Set: resourceHash, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "resource_type": { + Type: schema.TypeString, + Required: true, + Description: "The type of resource.", + }, + "resource_id": { + Type: schema.TypeString, + Required: true, + Description: "The id of resource.", + }, + }, + }, + }, + "service_id": { + Type: schema.TypeString, + Computed: true, + Description: "The Id of service.", + }, + "service_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of service.", + }, + "service_domain": { + Type: schema.TypeString, + Computed: true, + Description: "The domain of service.", + }, + "service_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of service.", + }, + "service_resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The resource type of service.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of service.", + }, + "creation_time": { + Type: schema.TypeString, + Computed: true, + Description: "The create time of service.", + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: "The update time of service.", + }, + "zone_ids": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Description: "The IDs of zones.", + }, + }, + } + return resource +} + +var resourceHash = func(v interface{}) int { + if v == nil { + return hashcode.String("") + } + m := v.(map[string]interface{}) + var ( + buf bytes.Buffer + ) + buf.WriteString(fmt.Sprintf("%v#%v", m["resource_type"], m["resource_id"])) + return hashcode.String(buf.String()) +} + +func resourceVolcenginePrivateLinkVpcEndpointServiceCreate(d *schema.ResourceData, meta interface{}) (err error) { + aclService := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Create(aclService, d, ResourceVolcenginePrivatelinkVpcEndpointService()) + if err != nil { + return fmt.Errorf("error on creating vpc endpoint service %q, %w", d.Id(), err) + } + return resourceVolcenginePrivateLinkVpcEndpointServiceRead(d, meta) +} + +func resourceVolcenginePrivateLinkVpcEndpointServiceRead(d *schema.ResourceData, meta interface{}) (err error) { + aclService := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Read(aclService, d, ResourceVolcenginePrivatelinkVpcEndpointService()) + if err != nil { + return fmt.Errorf("error on reading vpc endpoint service %q, %w", d.Id(), err) + } + return err +} + +func resourceVolcenginePrivateLinkVpcEndpointServiceUpdate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Update(service, d, ResourceVolcenginePrivatelinkVpcEndpointService()) + if err != nil { + return fmt.Errorf("error on updating vpc endoint service %q, %w", d.Id(), err) + } + return resourceVolcenginePrivateLinkVpcEndpointServiceRead(d, meta) +} + +func resourceVolcenginePrivateLinkVpcEndpointServiceDelete(d *schema.ResourceData, meta interface{}) (err error) { + service := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Delete(service, d, ResourceVolcenginePrivatelinkVpcEndpointService()) + if err != nil { + return fmt.Errorf("error on deleting vpc endpoint service%q, %w", d.Id(), err) + } + return err +} diff --git a/volcengine/privatelink/vpc_endpoint_service/service_volcengine_privatelink_vpc_endpoint_service.go b/volcengine/privatelink/vpc_endpoint_service/service_volcengine_privatelink_vpc_endpoint_service.go new file mode 100644 index 00000000..00469dee --- /dev/null +++ b/volcengine/privatelink/vpc_endpoint_service/service_volcengine_privatelink_vpc_endpoint_service.go @@ -0,0 +1,326 @@ +package vpc_endpoint_service + +import ( + "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 VolcengineService struct { + Client *ve.SdkClient +} + +func NewService(c *ve.SdkClient) *VolcengineService { + return &VolcengineService{ + Client: c, + } +} + +func (s *VolcengineService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + return ve.WithPageNumberQuery(m, "PageSize", "PageNumber", 20, 1, func(condition map[string]interface{}) ([]interface{}, error) { + action := "DescribeVpcEndpointServices" + logger.Debug(logger.ReqFormat, action, condition) + if condition == nil { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), nil) + if err != nil { + return data, err + } + } else { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &condition) + if err != nil { + return data, err + } + } + logger.Debug(logger.RespFormat, action, condition, *resp) + results, err = ve.ObtainSdkValue("Result.VpcEndpointServices", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.VpcEndpointServices is not Slice") + } + + for index, element := range data { + resources, err := s.describeResources(map[string]interface{}{ + "ServiceId": element.(map[string]interface{})["ServiceId"], + }) + if err != nil { + return nil, err + } + data[index].(map[string]interface{})["Resources"] = resources + } + return data, err + }) +} + +func (s *VolcengineService) describeResources(m map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + return ve.WithPageNumberQuery(m, "PageSize", "PageNumber", 20, 1, func(condition map[string]interface{}) ([]interface{}, error) { + action := "DescribeVpcEndpointServiceResources" + logger.Debug(logger.ReqFormat, action, condition) + if condition == nil { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), nil) + if err != nil { + return data, err + } + } else { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &condition) + if err != nil { + return data, err + } + } + logger.Debug(logger.RespFormat, action, resp) + results, err = ve.ObtainSdkValue("Result.Resources", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.Resources is not Slice") + } + return data, err + }) +} + +func (s *VolcengineService) 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{}{ + "ServiceIds.1": id, + } + results, err = s.ReadResources(req) + if err != nil { + return data, err + } + for _, v := range results { + if data, ok = v.(map[string]interface{}); !ok { + return data, errors.New("Value is not map ") + } + } + if len(data) == 0 { + return data, fmt.Errorf("Vpc endpoint service %s not exist ", id) + } + return data, err +} + +func (s *VolcengineService) WithResourceResponseHandlers(nodePool map[string]interface{}) []ve.ResourceResponseHandler { + return nil +} + +func (s *VolcengineService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return &resource.StateChangeConf{ + Pending: []string{}, + Delay: 1 * time.Second, + MinTimeout: 1 * time.Second, + Target: target, + Timeout: timeout, + Refresh: func() (result interface{}, state string, err error) { + var ( + data map[string]interface{} + status interface{} + failStates []string + ) + failStates = append(failStates, "Error") + data, err = s.ReadResource(resourceData, id) + if err != nil { + return nil, "", err + } + status, err = ve.ObtainSdkValue("Status", data) + if err != nil { + return nil, "", err + } + for _, v := range failStates { + if v == status.(string) { + return nil, "", fmt.Errorf("Vpc endpoint service status error, status: %s", status.(string)) + } + } + //注意 返回的第一个参数不能为空 否则会一直等下去 + return data, status.(string), err + }, + } +} + +func (s *VolcengineService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "CreateVpcEndpointService", + ConvertMode: ve.RequestConvertAll, + Convert: map[string]ve.RequestConvert{ + "resources": { + TargetField: "Resources", + ConvertType: ve.ConvertListN, + }, + }, + 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.ServiceId", *resp) + d.SetId(id.(string)) + return nil + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Available"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + }, + }, + } + return []ve.Callback{callback} + +} + +func (s *VolcengineService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + + if resourceData.HasChange("description") || resourceData.HasChange("auto_accept_enabled") { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "ModifyVpcEndpointServiceAttributes", + ConvertMode: ve.RequestConvertInConvert, + Convert: map[string]ve.RequestConvert{ + "auto_accept_enabled": { + TargetField: "AutoAcceptEnabled", + }, + "description": { + TargetField: "Description", + }, + }, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["ServiceId"] = 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, call.SdkParam, resp) + return resp, err + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Available"}, + Timeout: resourceData.Timeout(schema.TimeoutUpdate), + }, + }, + } + callbacks = append(callbacks, callback) + } + + if resourceData.HasChange("resources") { + add, remove, _, _ := ve.GetSetDifference("resources", resourceData, resourceHash, false) + for _, element := range add.List() { + callbacks = append(callbacks, s.resourceActionCallback(resourceData, "AttachResourceToVpcEndpointService", element)) + } + for _, element := range remove.List() { + callbacks = append(callbacks, s.resourceActionCallback(resourceData, "DetachResourceFromVpcEndpointService", element)) + } + } + return callbacks +} + +func (s *VolcengineService) resourceActionCallback(resourceData *schema.ResourceData, action string, element interface{}) ve.Callback { + return ve.Callback{ + Call: ve.SdkCall{ + Action: action, + ConvertMode: ve.RequestConvertIgnore, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["ServiceId"] = d.Id() + (*call.SdkParam)["ResourceId"] = element.(map[string]interface{})["resource_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, call.SdkParam, resp) + return resp, err + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Available"}, + Timeout: resourceData.Timeout(schema.TimeoutUpdate), + }, + }, + } +} + +func (s *VolcengineService) RemoveResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "DeleteVpcEndpointService", + ConvertMode: ve.RequestConvertIgnore, + SdkParam: &map[string]interface{}{ + "ServiceId": 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 (VolcengineService) DatasourceResources(data *schema.ResourceData, resource *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{ + RequestConverts: map[string]ve.RequestConvert{ + "ids": { + TargetField: "ServiceIds", + ConvertType: ve.ConvertWithN, + }, + }, + NameField: "ServiceName", + IdField: "ServiceId", + CollectField: "services", + ResponseConverts: map[string]ve.ResponseConvert{ + "ServiceId": { + TargetField: "id", + KeepDefault: true, + }, + }, + } +} + +func (s *VolcengineService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "privatelink", + Version: "2020-04-01", + HttpMethod: ve.GET, + Action: actionName, + ContentType: ve.Default, + } +} diff --git a/volcengine/privatelink/vpc_endpoint_service_permission/data_source_volcengine_privatelink_vpc_endpoint_service_permissions.go b/volcengine/privatelink/vpc_endpoint_service_permission/data_source_volcengine_privatelink_vpc_endpoint_service_permissions.go new file mode 100644 index 00000000..d7d09a91 --- /dev/null +++ b/volcengine/privatelink/vpc_endpoint_service_permission/data_source_volcengine_privatelink_vpc_endpoint_service_permissions.go @@ -0,0 +1,53 @@ +package vpc_endpoint_service_permission + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +func DataSourceVolcenginePrivatelinkVpcEndpointServicePermissions() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcenginePrivatelinkVpcEndpointServicePermissionRead, + Schema: map[string]*schema.Schema{ + "service_id": { + Type: schema.TypeString, + Required: true, + Description: "The Id of service.", + }, + "permit_account_id": { + Type: schema.TypeString, + Optional: true, + Description: "The Id of permit account.", + }, + "output_file": { + Type: schema.TypeString, + Optional: true, + Description: "File name where to save data source results.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Returns the total amount of the data list.", + }, + "permissions": { + Description: "The collection of query.", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "permit_account_id": { + Type: schema.TypeString, + Computed: true, + Description: "The permit account id.", + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcenginePrivatelinkVpcEndpointServicePermissionRead(d *schema.ResourceData, meta interface{}) error { + service := NewService(meta.(*ve.SdkClient)) + return ve.DefaultDispatcher().Data(service, d, DataSourceVolcenginePrivatelinkVpcEndpointServicePermissions()) +} diff --git a/volcengine/privatelink/vpc_endpoint_service_permission/resource_volcengine_privatelink_vpc_endpoint_service_permission.go b/volcengine/privatelink/vpc_endpoint_service_permission/resource_volcengine_privatelink_vpc_endpoint_service_permission.go new file mode 100644 index 00000000..e6be355a --- /dev/null +++ b/volcengine/privatelink/vpc_endpoint_service_permission/resource_volcengine_privatelink_vpc_endpoint_service_permission.go @@ -0,0 +1,89 @@ +package vpc_endpoint_service_permission + +import ( + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +VpcEndpointServicePermission can be imported using the serviceId:permitAccountId, e.g. +``` +$ terraform import volcengine_privatelink_vpc_endpoint_service_permission.default epsvc-2fe630gurkl37k5gfuy33****:2100000000 +``` + +*/ + +func ResourceVolcenginePrivatelinkVpcEndpointServicePermission() *schema.Resource { + resource := &schema.Resource{ + Create: resourceVolcenginePrivatelinkVpcEndpointServicePermissionCreate, + Read: resourceVolcenginePrivatelinkVpcEndpointServicePermissionRead, + Delete: resourceVolcenginePrivatelinkVpcEndpointServicePermissionDelete, + Importer: &schema.ResourceImporter{ + State: func(data *schema.ResourceData, i interface{}) ([]*schema.ResourceData, error) { + items := strings.Split(data.Id(), ":") + if len(items) != 2 { + return []*schema.ResourceData{data}, fmt.Errorf("import id must split with ':'") + } + if err := data.Set("service_id", items[0]); err != nil { + return []*schema.ResourceData{data}, err + } + if err := data.Set("permit_account_id", items[1]); err != nil { + return []*schema.ResourceData{data}, err + } + return []*schema.ResourceData{data}, nil + }, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "permit_account_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The id of account.", + }, + "service_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The id of service.", + }, + }, + } + return resource +} + +func resourceVolcenginePrivatelinkVpcEndpointServicePermissionCreate(d *schema.ResourceData, meta interface{}) (err error) { + aclService := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Create(aclService, d, ResourceVolcenginePrivatelinkVpcEndpointServicePermission()) + if err != nil { + return fmt.Errorf("error on creating vpc endpoint service permission %q, %w", d.Id(), err) + } + return resourceVolcenginePrivatelinkVpcEndpointServicePermissionRead(d, meta) +} + +func resourceVolcenginePrivatelinkVpcEndpointServicePermissionRead(d *schema.ResourceData, meta interface{}) (err error) { + aclService := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Read(aclService, d, ResourceVolcenginePrivatelinkVpcEndpointServicePermission()) + if err != nil { + return fmt.Errorf("error on reading vpc endpoint service permission %q, %w", d.Id(), err) + } + return err +} + +func resourceVolcenginePrivatelinkVpcEndpointServicePermissionDelete(d *schema.ResourceData, meta interface{}) (err error) { + service := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Delete(service, d, ResourceVolcenginePrivatelinkVpcEndpointServicePermission()) + if err != nil { + return fmt.Errorf("error on deleting vpc endpoint service permission %q, %w", d.Id(), err) + } + return err +} diff --git a/volcengine/privatelink/vpc_endpoint_service_permission/service_volcengine_privatelink_vpc_endpoint_service_permission.go b/volcengine/privatelink/vpc_endpoint_service_permission/service_volcengine_privatelink_vpc_endpoint_service_permission.go new file mode 100644 index 00000000..39d2f772 --- /dev/null +++ b/volcengine/privatelink/vpc_endpoint_service_permission/service_volcengine_privatelink_vpc_endpoint_service_permission.go @@ -0,0 +1,188 @@ +package vpc_endpoint_service_permission + +import ( + "errors" + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" + "github.com/volcengine/terraform-provider-volcengine/volcengine/privatelink/vpc_endpoint_service" +) + +type VolcengineService struct { + Client *ve.SdkClient +} + +func NewService(c *ve.SdkClient) *VolcengineService { + return &VolcengineService{ + Client: c, + } +} + +func (s *VolcengineService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + return ve.WithPageNumberQuery(m, "PageSize", "PageNumber", 20, 1, func(condition map[string]interface{}) ([]interface{}, error) { + action := "DescribeVpcEndpointServicePermissions" + logger.Debug(logger.ReqFormat, action, condition) + if condition == nil { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), nil) + if err != nil { + return data, err + } + } else { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &condition) + if err != nil { + return data, err + } + } + logger.Debug(logger.RespFormat, action, *resp) + results, err = ve.ObtainSdkValue("Result.Permissions", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.Permissions is not Slice") + } + + return data, err + }) + +} + +func (s *VolcengineService) ReadResource(resourceData *schema.ResourceData, id string) (data map[string]interface{}, err error) { + var ( + results []interface{} + ) + if id == "" { + id = s.ReadResourceId(resourceData.Id()) + } + + ids := strings.Split(id, ":") + serviceId := ids[0] + accountId := ids[1] + + results, err = s.ReadResources(map[string]interface{}{ + "ServiceId": serviceId, + "PermitAccountId": accountId, + }) + if err != nil { + return data, err + } + if len(results) == 0 { + return data, fmt.Errorf("Vpc endpoint service permission %s not exist ", id) + } + + return map[string]interface{}{ + "ServiceId": serviceId, + "PermitAccountId": accountId, + }, nil +} + +func (s *VolcengineService) WithResourceResponseHandlers(nodePool map[string]interface{}) []ve.ResourceResponseHandler { + return nil +} + +func (s *VolcengineService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return nil +} + +func (s *VolcengineService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "AddPermissionToVpcEndpointService", + 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) + resp, err := s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + logger.Debug(logger.RespFormat, call.Action, call.SdkParam, resp) + return resp, err + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + d.SetId(fmt.Sprint((*call.SdkParam)["ServiceId"], ":", (*call.SdkParam)["PermitAccountId"])) + return nil + }, + ExtraRefresh: map[ve.ResourceService]*ve.StateRefresh{ + vpc_endpoint_service.NewService(s.Client): { + Target: []string{"Available"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + ResourceId: resourceData.Get("service_id").(string), + }, + }, + LockId: func(d *schema.ResourceData) string { + return d.Get("service_id").(string) + }, + }, + } + return []ve.Callback{callback} +} + +func (s *VolcengineService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + return callbacks +} + +func (s *VolcengineService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + ids := strings.Split(s.ReadResourceId(resourceData.Id()), ":") + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "RemovePermissionFromVpcEndpointService", + ConvertMode: ve.RequestConvertIgnore, + SdkParam: &map[string]interface{}{ + "ServiceId": ids[0], + "PermitAccountId": ids[1], + }, + 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, call.SdkParam, resp) + return resp, err + }, + LockId: func(d *schema.ResourceData) string { + return d.Get("service_id").(string) + }, + ExtraRefresh: map[ve.ResourceService]*ve.StateRefresh{ + vpc_endpoint_service.NewService(s.Client): { + Target: []string{"Available"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + ResourceId: resourceData.Get("service_id").(string), + }, + }, + }, + } + return []ve.Callback{callback} +} + +func (VolcengineService) DatasourceResources(data *schema.ResourceData, resource *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{ + CollectField: "permissions", + } +} + +func (s *VolcengineService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "privatelink", + Version: "2020-04-01", + HttpMethod: ve.GET, + Action: actionName, + ContentType: ve.Default, + } +} diff --git a/volcengine/privatelink/vpc_endpoint_service_resource/resource_volcengine_privatelink_vpc_endpoint_service_resource.go b/volcengine/privatelink/vpc_endpoint_service_resource/resource_volcengine_privatelink_vpc_endpoint_service_resource.go new file mode 100644 index 00000000..a6c66203 --- /dev/null +++ b/volcengine/privatelink/vpc_endpoint_service_resource/resource_volcengine_privatelink_vpc_endpoint_service_resource.go @@ -0,0 +1,89 @@ +package vpc_endpoint_service_resource + +import ( + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +VpcEndpointServiceResource can be imported using the serviceId:resourceId, e.g. +``` +$ terraform import volcengine_privatelink_vpc_endpoint_service_resource.default epsvc-2fe630gurkl37k5gfuy33****:clb-bp1o94dp5i6ea**** +``` + +*/ + +func ResourceVolcenginePrivatelinkVpcEndpointServiceResource() *schema.Resource { + resource := &schema.Resource{ + Create: resourceVolcenginePrivatelinkVpcEndpointServiceResourceCreate, + Read: resourceVolcenginePrivatelinkVpcEndpointServiceResourceRead, + Delete: resourceVolcenginePrivatelinkVpcEndpointServiceResourceDelete, + Importer: &schema.ResourceImporter{ + State: func(data *schema.ResourceData, i interface{}) ([]*schema.ResourceData, error) { + items := strings.Split(data.Id(), ":") + if len(items) != 2 { + return []*schema.ResourceData{data}, fmt.Errorf("import id must split with ':'") + } + if err := data.Set("service_id", items[0]); err != nil { + return []*schema.ResourceData{data}, err + } + if err := data.Set("resource_id", items[1]); err != nil { + return []*schema.ResourceData{data}, err + } + return []*schema.ResourceData{data}, nil + }, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "resource_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The id of resource.", + }, + "service_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The id of service.", + }, + }, + } + return resource +} + +func resourceVolcenginePrivatelinkVpcEndpointServiceResourceCreate(d *schema.ResourceData, meta interface{}) (err error) { + aclService := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Create(aclService, d, ResourceVolcenginePrivatelinkVpcEndpointServiceResource()) + if err != nil { + return fmt.Errorf("error on creating vpc endpoint service resource %q, %w", d.Id(), err) + } + return resourceVolcenginePrivatelinkVpcEndpointServiceResourceRead(d, meta) +} + +func resourceVolcenginePrivatelinkVpcEndpointServiceResourceRead(d *schema.ResourceData, meta interface{}) (err error) { + aclService := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Read(aclService, d, ResourceVolcenginePrivatelinkVpcEndpointServiceResource()) + if err != nil { + return fmt.Errorf("error on reading vpc endpoint service resource %q, %w", d.Id(), err) + } + return err +} + +func resourceVolcenginePrivatelinkVpcEndpointServiceResourceDelete(d *schema.ResourceData, meta interface{}) (err error) { + service := NewService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Delete(service, d, ResourceVolcenginePrivatelinkVpcEndpointServiceResource()) + if err != nil { + return fmt.Errorf("error on deleting vpc endpoint service resource %q, %w", d.Id(), err) + } + return err +} diff --git a/volcengine/privatelink/vpc_endpoint_service_resource/service_volcengine_privatelink_vpc_endpoint_service_resource.go b/volcengine/privatelink/vpc_endpoint_service_resource/service_volcengine_privatelink_vpc_endpoint_service_resource.go new file mode 100644 index 00000000..c70ba8e3 --- /dev/null +++ b/volcengine/privatelink/vpc_endpoint_service_resource/service_volcengine_privatelink_vpc_endpoint_service_resource.go @@ -0,0 +1,192 @@ +package vpc_endpoint_service_resource + +import ( + "errors" + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" + "github.com/volcengine/terraform-provider-volcengine/volcengine/privatelink/vpc_endpoint_service" +) + +type VolcengineService struct { + Client *ve.SdkClient +} + +func NewService(c *ve.SdkClient) *VolcengineService { + return &VolcengineService{ + Client: c, + } +} + +func (s *VolcengineService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + return nil, err +} + +func (s *VolcengineService) describeResources(m map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + return ve.WithPageNumberQuery(m, "PageSize", "PageNumber", 20, 1, func(condition map[string]interface{}) ([]interface{}, error) { + action := "DescribeVpcEndpointServiceResources" + logger.Debug(logger.ReqFormat, action, condition) + if condition == nil { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), nil) + if err != nil { + return data, err + } + } else { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &condition) + if err != nil { + return data, err + } + } + logger.Debug(logger.RespFormat, action, *resp) + results, err = ve.ObtainSdkValue("Result.Resources", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.Resources is not Slice") + } + return data, err + }) +} + +func (s *VolcengineService) ReadResource(resourceData *schema.ResourceData, id string) (data map[string]interface{}, err error) { + var ( + results []interface{} + ) + if id == "" { + id = s.ReadResourceId(resourceData.Id()) + } + + ids := strings.Split(id, ":") + serviceId := ids[0] + resourceId := ids[1] + + results, err = s.describeResources(map[string]interface{}{ + "ServiceId": serviceId, + }) + if err != nil { + return data, err + } + if len(results) == 0 { + return data, fmt.Errorf("Vpc endpoint service resource %s not exist ", id) + } + + for _, ele := range results { + if ele.(map[string]interface{})["ResourceId"] == resourceId { + return map[string]interface{}{ + "ServiceId": serviceId, + "ResourceId": resourceId, + }, nil + } + } + return data, fmt.Errorf("resource does not associate target service. service_id: %s, resource_id: %s", serviceId, resourceId) +} + +func (s *VolcengineService) WithResourceResponseHandlers(nodePool map[string]interface{}) []ve.ResourceResponseHandler { + return nil +} + +func (s *VolcengineService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return nil +} + +func (s *VolcengineService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "AttachResourceToVpcEndpointService", + 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) + resp, err := s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + logger.Debug(logger.RespFormat, call.Action, call.SdkParam, resp) + return resp, err + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + d.SetId(fmt.Sprint((*call.SdkParam)["ServiceId"], ":", (*call.SdkParam)["ResourceId"])) + return nil + }, + ExtraRefresh: map[ve.ResourceService]*ve.StateRefresh{ + vpc_endpoint_service.NewService(s.Client): { + Target: []string{"Available"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + ResourceId: resourceData.Get("service_id").(string), + }, + }, + LockId: func(d *schema.ResourceData) string { + return d.Get("service_id").(string) + }, + }, + } + return []ve.Callback{callback} +} + +func (s *VolcengineService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + return callbacks +} + +func (s *VolcengineService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + ids := strings.Split(s.ReadResourceId(resourceData.Id()), ":") + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "DetachResourceFromVpcEndpointService", + ConvertMode: ve.RequestConvertIgnore, + SdkParam: &map[string]interface{}{ + "ServiceId": ids[0], + "ResourceId": ids[1], + }, + 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, call.SdkParam, resp) + return resp, err + }, + LockId: func(d *schema.ResourceData) string { + return d.Get("service_id").(string) + }, + ExtraRefresh: map[ve.ResourceService]*ve.StateRefresh{ + vpc_endpoint_service.NewService(s.Client): { + Target: []string{"Available"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + ResourceId: resourceData.Get("service_id").(string), + }, + }, + }, + } + return []ve.Callback{callback} +} + +func (VolcengineService) DatasourceResources(data *schema.ResourceData, resource *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{} +} + +func (s *VolcengineService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "privatelink", + Version: "2020-04-01", + HttpMethod: ve.GET, + Action: actionName, + ContentType: ve.Default, + } +} diff --git a/volcengine/privatelink/vpc_endpoint_zone/data_source_volcengine_privatelink_vpc_endpoint_zones.go b/volcengine/privatelink/vpc_endpoint_zone/data_source_volcengine_privatelink_vpc_endpoint_zones.go new file mode 100644 index 00000000..9343f876 --- /dev/null +++ b/volcengine/privatelink/vpc_endpoint_zone/data_source_volcengine_privatelink_vpc_endpoint_zones.go @@ -0,0 +1,83 @@ +package vpc_endpoint_zone + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +func DataSourceVolcenginePrivatelinkVpcEndpointZones() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcenginePrivatelinkVpcEndpointZonesRead, + Schema: map[string]*schema.Schema{ + "endpoint_id": { + Type: schema.TypeString, + Optional: true, + Description: "The endpoint id of query.", + }, + "output_file": { + Type: schema.TypeString, + Optional: true, + Description: "File name where to save data source results.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Returns the total amount of the data list.", + }, + "vpc_endpoint_zones": { + 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 vpc endpoint zone.", + }, + "zone_id": { + Type: schema.TypeString, + Computed: true, + Description: "The Id of vpc endpoint zone.", + }, + "zone_domain": { + Type: schema.TypeString, + Computed: true, + Description: "The domain of vpc endpoint zone.", + }, + "zone_status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of vpc endpoint zone.", + }, + "service_status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of vpc endpoint service.", + }, + "subnet_id": { + Type: schema.TypeString, + Computed: true, + Description: "The subnet id of vpc endpoint.", + }, + "network_interface_id": { + Type: schema.TypeString, + Computed: true, + Description: "The network interface id of vpc endpoint.", + }, + "network_interface_ip": { + Type: schema.TypeString, + Computed: true, + Description: "The network interface ip of vpc endpoint.", + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcenginePrivatelinkVpcEndpointZonesRead(d *schema.ResourceData, meta interface{}) error { + service := NewVpcEndpointZoneService(meta.(*ve.SdkClient)) + return ve.DefaultDispatcher().Data(service, d, DataSourceVolcenginePrivatelinkVpcEndpointZones()) +} diff --git a/volcengine/privatelink/vpc_endpoint_zone/resource_volcengine_privatelink_vpc_endpoint_zone.go b/volcengine/privatelink/vpc_endpoint_zone/resource_volcengine_privatelink_vpc_endpoint_zone.go new file mode 100644 index 00000000..4de75715 --- /dev/null +++ b/volcengine/privatelink/vpc_endpoint_zone/resource_volcengine_privatelink_vpc_endpoint_zone.go @@ -0,0 +1,118 @@ +package vpc_endpoint_zone + +import ( + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +VpcEndpointZone can be imported using the endpointId:subnetId, e.g. +``` +$ terraform import volcengine_privatelink_vpc_endpoint_zone.default ep-3rel75r081l345zsk2i59****:subnet-2bz47q19zhx4w2dx0eevn**** +``` + +*/ + +func ResourceVolcenginePrivatelinkVpcEndpointZone() *schema.Resource { + resource := &schema.Resource{ + Create: resourceVolcenginePrivateLinkVpcEndpointZoneCreate, + Read: resourceVolcenginePrivateLinkVpcEndpointZoneRead, + Delete: resourceVolcenginePrivateLinkVpcEndpointZoneDelete, + Importer: &schema.ResourceImporter{ + State: func(data *schema.ResourceData, i interface{}) ([]*schema.ResourceData, error) { + items := strings.Split(data.Id(), ":") + if len(items) != 2 { + return []*schema.ResourceData{data}, fmt.Errorf("import id must split with ':'") + } + if err := data.Set("endpoint_id", items[0]); err != nil { + return []*schema.ResourceData{data}, err + } + if err := data.Set("subnet_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{ + "endpoint_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The endpoint id of vpc endpoint zone.", + }, + "subnet_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The subnet id of vpc endpoint zone.", + }, + "private_ip_address": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "The private ip address of vpc endpoint zone.", + }, + + "zone_id": { + Type: schema.TypeString, + Computed: true, + Description: "The Id of vpc endpoint zone.", + }, + "zone_domain": { + Type: schema.TypeString, + Computed: true, + Description: "The domain of vpc endpoint zone.", + }, + "zone_status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of vpc endpoint zone.", + }, + "network_interface_id": { + Type: schema.TypeString, + Computed: true, + Description: "The network interface id of vpc endpoint.", + }, + }, + } + return resource +} + +func resourceVolcenginePrivateLinkVpcEndpointZoneCreate(d *schema.ResourceData, meta interface{}) (err error) { + vpcEndpointZoneService := NewVpcEndpointZoneService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Create(vpcEndpointZoneService, d, ResourceVolcenginePrivatelinkVpcEndpointZone()) + if err != nil { + return fmt.Errorf("error on creating vpc endpoint zone %q, %w", d.Id(), err) + } + return resourceVolcenginePrivateLinkVpcEndpointZoneRead(d, meta) +} + +func resourceVolcenginePrivateLinkVpcEndpointZoneRead(d *schema.ResourceData, meta interface{}) (err error) { + vpcEndpointZoneService := NewVpcEndpointZoneService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Read(vpcEndpointZoneService, d, ResourceVolcenginePrivatelinkVpcEndpointZone()) + if err != nil { + return fmt.Errorf("error on reading vpc endpoint zone %q, %w", d.Id(), err) + } + return err +} + +func resourceVolcenginePrivateLinkVpcEndpointZoneDelete(d *schema.ResourceData, meta interface{}) (err error) { + vpcEndpointZoneService := NewVpcEndpointZoneService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Delete(vpcEndpointZoneService, d, ResourceVolcenginePrivatelinkVpcEndpointZone()) + if err != nil { + return fmt.Errorf("error on deleting vpc endpoint zone %q, %w", d.Id(), err) + } + return err +} diff --git a/volcengine/privatelink/vpc_endpoint_zone/service_volcengine_privatelink_vpc_endpoint_zone.go b/volcengine/privatelink/vpc_endpoint_zone/service_volcengine_privatelink_vpc_endpoint_zone.go new file mode 100644 index 00000000..52b014ce --- /dev/null +++ b/volcengine/privatelink/vpc_endpoint_zone/service_volcengine_privatelink_vpc_endpoint_zone.go @@ -0,0 +1,266 @@ +package vpc_endpoint_zone + +import ( + "errors" + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" + "github.com/volcengine/terraform-provider-volcengine/volcengine/privatelink/vpc_endpoint" +) + +type VolcengineVpcEndpointZoneService struct { + Client *ve.SdkClient +} + +func NewVpcEndpointZoneService(c *ve.SdkClient) *VolcengineVpcEndpointZoneService { + return &VolcengineVpcEndpointZoneService{ + Client: c, + } +} + +func (s *VolcengineVpcEndpointZoneService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineVpcEndpointZoneService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + return ve.WithPageNumberQuery(m, "PageSize", "PageNumber", 10, 1, func(condition map[string]interface{}) ([]interface{}, error) { + action := "DescribeVpcEndpointZones" + logger.Debug(logger.ReqFormat, action, condition) + if condition == nil { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), nil) + if err != nil { + return data, err + } + } else { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &condition) + if err != nil { + return data, err + } + } + logger.Debug(logger.RespFormat, action, condition, *resp) + results, err = ve.ObtainSdkValue("Result.EndpointZones", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.EndpointZones is not Slice") + } + return data, err + }) +} + +func (s *VolcengineVpcEndpointZoneService) ReadResource(resourceData *schema.ResourceData, id string) (data map[string]interface{}, err error) { + var ( + results []interface{} + ok bool + ) + if id == "" { + id = s.ReadResourceId(resourceData.Id()) + } + ids := strings.Split(id, ":") + if len(ids) != 2 { + return data, errors.New("Invalid vpc endpoint zone id ") + } + endpointId := ids[0] + subnetId := ids[1] + req := map[string]interface{}{ + "EndpointId": endpointId, + } + results, err = s.ReadResources(req) + if err != nil { + return data, err + } + for _, v := range results { + zoneMap := make(map[string]interface{}) + if zoneMap, ok = v.(map[string]interface{}); !ok { + return data, errors.New("Value is not map ") + } + if subnetId == zoneMap["SubnetId"].(string) { + data = zoneMap + data["PrivateIpAddress"] = data["NetworkInterfaceIP"] + data["EndpointId"] = endpointId + break + } + } + if len(data) == 0 { + return data, fmt.Errorf("Vpc endpoint zone %s not exist ", id) + } + + return data, err +} + +func (s *VolcengineVpcEndpointZoneService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return nil +} + +func (s *VolcengineVpcEndpointZoneService) WithResourceResponseHandlers(data map[string]interface{}) []ve.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]ve.ResponseConvert, error) { + return data, nil, nil + } + return []ve.ResourceResponseHandler{handler} +} + +func (s *VolcengineVpcEndpointZoneService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + endpointId := resourceData.Get("endpoint_id").(string) + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "AddZoneToVpcEndpoint", + ConvertMode: ve.RequestConvertAll, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + // 查询子网所属的 zone_id + zoneId, err := s.getZoneIdBySubnet(d.Get("subnet_id").(string)) + if err != nil { + return false, err + } + if zoneId == "" { + return false, fmt.Errorf(" Failed to obtain zone from subnet id: %v", d.Get("subnet_id")) + } + (*call.SdkParam)["ZoneId"] = zoneId + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + 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 := fmt.Sprintf("%s:%s", endpointId, d.Get("subnet_id")) + d.SetId(id) + return nil + }, + ExtraRefresh: map[ve.ResourceService]*ve.StateRefresh{ + vpc_endpoint.NewVpcEndpointService(s.Client): { + Target: []string{"Available"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + ResourceId: endpointId, + }, + }, + LockId: func(d *schema.ResourceData) string { + return endpointId + }, + }, + } + return []ve.Callback{callback} + +} + +func (s *VolcengineVpcEndpointZoneService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + return []ve.Callback{} +} + +func (s *VolcengineVpcEndpointZoneService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "RemoveZoneFromVpcEndpoint", + ConvertMode: ve.RequestConvertIgnore, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + ids := strings.Split(d.Id(), ":") + if len(ids) != 2 { + return false, errors.New("Invalid vpc endpoint zone id ") + } + endpointId := ids[0] + subnetId := ids[1] + + // 查询子网所属的 zone_id + zoneId, err := s.getZoneIdBySubnet(subnetId) + if err != nil { + return false, err + } + if zoneId == "" { + return false, fmt.Errorf(" Failed to obtain zone from subnet id: %v", d.Get("subnet_id")) + } + + (*call.SdkParam)["EndpointId"] = endpointId + (*call.SdkParam)["ZoneId"] = zoneId + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + ExtraRefresh: map[ve.ResourceService]*ve.StateRefresh{ + vpc_endpoint.NewVpcEndpointService(s.Client): { + Target: []string{"Available"}, + Timeout: resourceData.Timeout(schema.TimeoutDelete), + ResourceId: resourceData.Get("endpoint_id").(string), + }, + }, + LockId: func(d *schema.ResourceData) string { + return d.Get("endpoint_id").(string) + }, + }, + } + return []ve.Callback{callback} +} + +func (VolcengineVpcEndpointZoneService) DatasourceResources(data *schema.ResourceData, resource *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{ + IdField: "ZoneId", + CollectField: "vpc_endpoint_zones", + ResponseConverts: map[string]ve.ResponseConvert{ + "ZoneId": { + TargetField: "id", + KeepDefault: true, + }, + "NetworkInterfaceIP": { + TargetField: "network_interface_ip", + }, + }, + } +} + +func (s *VolcengineVpcEndpointZoneService) ReadResourceId(id string) string { + return id +} + +func (s *VolcengineVpcEndpointZoneService) getZoneIdBySubnet(subnetId string) (zoneId string, err error) { + action := "DescribeSubnets" + req := map[string]interface{}{ + "SubnetIds.1": subnetId, + } + resp, err := s.Client.VpcClient.DescribeSubnetsCommon(&req) + if err != nil { + return "", err + } + logger.Debug(logger.RespFormat, action, req, *resp) + results, err := ve.ObtainSdkValue("Result.Subnets", *resp) + if err != nil { + return "", err + } + if results == nil { + results = []interface{}{} + } + subnets, ok := results.([]interface{}) + if !ok { + return "", errors.New("Result.Subnets is not Slice") + } + if len(subnets) == 0 { + return "", fmt.Errorf("subnet %s not exist", subnetId) + } + zoneId = subnets[0].(map[string]interface{})["ZoneId"].(string) + return zoneId, nil +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "privatelink", + Version: "2020-04-01", + HttpMethod: ve.GET, + Action: actionName, + ContentType: ve.Default, + } +} diff --git a/volcengine/provider.go b/volcengine/provider.go index d611522c..607533f7 100644 --- a/volcengine/provider.go +++ b/volcengine/provider.go @@ -6,6 +6,14 @@ import ( "github.com/volcengine/terraform-provider-volcengine/volcengine/mongodb/ssl_state" "github.com/volcengine/terraform-provider-volcengine/volcengine/tos/bucket_policy" + plSecurityGroup "github.com/volcengine/terraform-provider-volcengine/volcengine/privatelink/security_group" + "github.com/volcengine/terraform-provider-volcengine/volcengine/privatelink/vpc_endpoint" + "github.com/volcengine/terraform-provider-volcengine/volcengine/privatelink/vpc_endpoint_connection" + "github.com/volcengine/terraform-provider-volcengine/volcengine/privatelink/vpc_endpoint_service" + "github.com/volcengine/terraform-provider-volcengine/volcengine/privatelink/vpc_endpoint_service_permission" + "github.com/volcengine/terraform-provider-volcengine/volcengine/privatelink/vpc_endpoint_service_resource" + "github.com/volcengine/terraform-provider-volcengine/volcengine/privatelink/vpc_endpoint_zone" + "github.com/volcengine/terraform-provider-volcengine/volcengine/mongodb/spec" "github.com/volcengine/terraform-provider-volcengine/volcengine/rds_mysql/rds_mysql_account" @@ -312,6 +320,13 @@ func Provider() terraform.ResourceProvider { "volcengine_bioos_clusters": bioosCluster.DataSourceVolcengineBioosClusters(), "volcengine_bioos_workspaces": workspace.DataSourceVolcengineBioosWorkspaces(), + // ================ PrivateLink ================== + "volcengine_privatelink_vpc_endpoints": vpc_endpoint.DataSourceVolcenginePrivatelinkVpcEndpoints(), + "volcengine_privatelink_vpc_endpoint_services": vpc_endpoint_service.DataSourceVolcenginePrivatelinkVpcEndpointServices(), + "volcengine_privatelink_vpc_endpoint_service_permissions": vpc_endpoint_service_permission.DataSourceVolcenginePrivatelinkVpcEndpointServicePermissions(), + "volcengine_privatelink_vpc_endpoint_connections": vpc_endpoint_connection.DataSourceVolcenginePrivatelinkVpcEndpointConnections(), + "volcengine_privatelink_vpc_endpoint_zones": vpc_endpoint_zone.DataSourceVolcenginePrivatelinkVpcEndpointZones(), + // ================ RDS V2 ============== "volcengine_rds_instances_v2": rds_instance_v2.DataSourceVolcengineRdsInstances(), @@ -453,6 +468,15 @@ func Provider() terraform.ResourceProvider { "volcengine_bioos_workspace": workspace.ResourceVolcengineBioosWorkspace(), "volcengine_bioos_cluster_bind": cluster_bind.ResourceVolcengineBioosClusterBind(), + // ================ PrivateLink ================== + "volcengine_privatelink_vpc_endpoint": vpc_endpoint.ResourceVolcenginePrivatelinkVpcEndpoint(), + "volcengine_privatelink_vpc_endpoint_service": vpc_endpoint_service.ResourceVolcenginePrivatelinkVpcEndpointService(), + "volcengine_privatelink_vpc_endpoint_service_resource": vpc_endpoint_service_resource.ResourceVolcenginePrivatelinkVpcEndpointServiceResource(), + "volcengine_privatelink_vpc_endpoint_service_permission": vpc_endpoint_service_permission.ResourceVolcenginePrivatelinkVpcEndpointServicePermission(), + "volcengine_privatelink_security_group": plSecurityGroup.ResourceVolcenginePrivatelinkSecurityGroupService(), + "volcengine_privatelink_vpc_endpoint_connection": vpc_endpoint_connection.ResourceVolcenginePrivatelinkVpcEndpointConnectionService(), + "volcengine_privatelink_vpc_endpoint_zone": vpc_endpoint_zone.ResourceVolcenginePrivatelinkVpcEndpointZone(), + // ================ RDS V2 ============== "volcengine_rds_instance_v2": rds_instance_v2.ResourceVolcengineRdsInstance(), diff --git a/volcengine/vke/cluster/resource_volcengine_vke_cluster.go b/volcengine/vke/cluster/resource_volcengine_vke_cluster.go index 47f5aa7f..1fdbd3d9 100644 --- a/volcengine/vke/cluster/resource_volcengine_vke_cluster.go +++ b/volcengine/vke/cluster/resource_volcengine_vke_cluster.go @@ -262,7 +262,7 @@ func ResourceVolcengineVkeCluster() *schema.Resource { Type: schema.TypeSet, Optional: true, Set: logSetupsHash, - Description: "Cluster logging options. This structure can only be modified and added, and cannot be deleted.", + Description: "Cluster logging options. This structure can only be modified and added, and cannot be deleted. When encountering a `cannot be deleted` error, please query the log setups of the current cluster and fill in the current `tf` file.", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "log_type": { diff --git a/website/docs/d/privatelink_vpc_endpoint_connections.html.markdown b/website/docs/d/privatelink_vpc_endpoint_connections.html.markdown new file mode 100644 index 00000000..1925958e --- /dev/null +++ b/website/docs/d/privatelink_vpc_endpoint_connections.html.markdown @@ -0,0 +1,45 @@ +--- +subcategory: "PRIVATELINK" +layout: "volcengine" +page_title: "Volcengine: volcengine_privatelink_vpc_endpoint_connections" +sidebar_current: "docs-volcengine-datasource-privatelink_vpc_endpoint_connections" +description: |- + Use this data source to query detailed information of privatelink vpc endpoint connections +--- +# volcengine_privatelink_vpc_endpoint_connections +Use this data source to query detailed information of privatelink vpc endpoint connections +## Example Usage +```hcl +data "volcengine_privatelink_vpc_endpoint_connections" "default" { + endpoint_id = "ep-3rel74u229dz45zsk2i6l69qa" + service_id = "epsvc-2byz5mykk9y4g2dx0efs4aqz3" +} +``` +## Argument Reference +The following arguments are supported: +* `service_id` - (Required) The id of the vpc endpoint service. +* `endpoint_id` - (Optional) The id of the vpc endpoint. +* `endpoint_owner_account_id` - (Optional) The account id of the vpc endpoint. +* `output_file` - (Optional) File name where to save data source results. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `connections` - The list of query. + * `connection_status` - The status of the connection. + * `creation_time` - The create time of the connection. + * `endpoint_id` - The id of the vpc endpoint. + * `endpoint_owner_account_id` - The account id of the vpc endpoint. + * `endpoint_vpc_id` - The vpc id of the vpc endpoint. + * `service_id` - The id of the vpc endpoint service. + * `update_time` - The update time of the connection. + * `zones` - The available zones. + * `network_interface_id` - The id of the network interface. + * `network_interface_ip` - The ip address of the network interface. + * `resource_id` - The id of the resource. + * `subnet_id` - The id of the subnet. + * `zone_domain` - The domain of the zone. + * `zone_id` - The id of the zone. + * `zone_status` - The status of the zone. +* `total_count` - Returns the total amount of the data list. + + diff --git a/website/docs/d/privatelink_vpc_endpoint_service_permissions.html.markdown b/website/docs/d/privatelink_vpc_endpoint_service_permissions.html.markdown new file mode 100644 index 00000000..f945ba8b --- /dev/null +++ b/website/docs/d/privatelink_vpc_endpoint_service_permissions.html.markdown @@ -0,0 +1,29 @@ +--- +subcategory: "PRIVATELINK" +layout: "volcengine" +page_title: "Volcengine: volcengine_privatelink_vpc_endpoint_service_permissions" +sidebar_current: "docs-volcengine-datasource-privatelink_vpc_endpoint_service_permissions" +description: |- + Use this data source to query detailed information of privatelink vpc endpoint service permissions +--- +# volcengine_privatelink_vpc_endpoint_service_permissions +Use this data source to query detailed information of privatelink vpc endpoint service permissions +## Example Usage +```hcl +data "volcengine_privatelink_vpc_endpoint_service_permissions" "default" { + service_id = "epsvc-3rel73uf2ewao5zsk2j2l58ro" +} +``` +## Argument Reference +The following arguments are supported: +* `service_id` - (Required) The Id of service. +* `output_file` - (Optional) File name where to save data source results. +* `permit_account_id` - (Optional) The Id of permit account. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `permissions` - The collection of query. + * `permit_account_id` - The permit account id. +* `total_count` - Returns the total amount of the data list. + + diff --git a/website/docs/d/privatelink_vpc_endpoint_services.html.markdown b/website/docs/d/privatelink_vpc_endpoint_services.html.markdown new file mode 100644 index 00000000..540c345e --- /dev/null +++ b/website/docs/d/privatelink_vpc_endpoint_services.html.markdown @@ -0,0 +1,45 @@ +--- +subcategory: "PRIVATELINK" +layout: "volcengine" +page_title: "Volcengine: volcengine_privatelink_vpc_endpoint_services" +sidebar_current: "docs-volcengine-datasource-privatelink_vpc_endpoint_services" +description: |- + Use this data source to query detailed information of privatelink vpc endpoint services +--- +# volcengine_privatelink_vpc_endpoint_services +Use this data source to query detailed information of privatelink vpc endpoint services +## Example Usage +```hcl +data "volcengine_privatelink_vpc_endpoint_services" "default" { + ids = ["epsvc-3rel73uf2ewao5zsk2j2l58ro", "epsvc-2d72mxjgq02yo58ozfe5tndeh"] +} +``` +## Argument Reference +The following arguments are supported: +* `ids` - (Optional) The IDs of vpc endpoint service. +* `name_regex` - (Optional) A Name Regex of vpc endpoint service. +* `output_file` - (Optional) File name where to save data source results. +* `service_name` - (Optional) The name of vpc endpoint service. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `services` - The collection of query. + * `auto_accept_enabled` - Whether auto accept node connect. + * `creation_time` - The create time of service. + * `description` - The description of service. + * `id` - The Id of service. + * `resources` - The resources info. + * `resource_id` - The id of resource. + * `resource_type` - The type of resource. + * `zone_id` - The zone id of resource. + * `service_domain` - The domain of service. + * `service_id` - The Id of service. + * `service_name` - The name of service. + * `service_resource_type` - The resource type of service. + * `service_type` - The type of service. + * `status` - The status of service. + * `update_time` - The update time of service. + * `zone_ids` - The IDs of zones. +* `total_count` - Returns the total amount of the data list. + + diff --git a/website/docs/d/privatelink_vpc_endpoint_zones.html.markdown b/website/docs/d/privatelink_vpc_endpoint_zones.html.markdown new file mode 100644 index 00000000..fc820597 --- /dev/null +++ b/website/docs/d/privatelink_vpc_endpoint_zones.html.markdown @@ -0,0 +1,35 @@ +--- +subcategory: "PRIVATELINK" +layout: "volcengine" +page_title: "Volcengine: volcengine_privatelink_vpc_endpoint_zones" +sidebar_current: "docs-volcengine-datasource-privatelink_vpc_endpoint_zones" +description: |- + Use this data source to query detailed information of privatelink vpc endpoint zones +--- +# volcengine_privatelink_vpc_endpoint_zones +Use this data source to query detailed information of privatelink vpc endpoint zones +## Example Usage +```hcl +data "volcengine_privatelink_vpc_endpoint_zones" "default" { + endpoint_id = "ep-2byz5npiuu1hc2dx0efkv****" +} +``` +## Argument Reference +The following arguments are supported: +* `endpoint_id` - (Optional) The endpoint id of query. +* `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` - Returns the total amount of the data list. +* `vpc_endpoint_zones` - The collection of query. + * `id` - The Id of vpc endpoint zone. + * `network_interface_id` - The network interface id of vpc endpoint. + * `network_interface_ip` - The network interface ip of vpc endpoint. + * `service_status` - The status of vpc endpoint service. + * `subnet_id` - The subnet id of vpc endpoint. + * `zone_domain` - The domain of vpc endpoint zone. + * `zone_id` - The Id of vpc endpoint zone. + * `zone_status` - The status of vpc endpoint zone. + + diff --git a/website/docs/d/privatelink_vpc_endpoints.html.markdown b/website/docs/d/privatelink_vpc_endpoints.html.markdown new file mode 100644 index 00000000..d85baf59 --- /dev/null +++ b/website/docs/d/privatelink_vpc_endpoints.html.markdown @@ -0,0 +1,47 @@ +--- +subcategory: "PRIVATELINK" +layout: "volcengine" +page_title: "Volcengine: volcengine_privatelink_vpc_endpoints" +sidebar_current: "docs-volcengine-datasource-privatelink_vpc_endpoints" +description: |- + Use this data source to query detailed information of privatelink vpc endpoints +--- +# volcengine_privatelink_vpc_endpoints +Use this data source to query detailed information of privatelink vpc endpoints +## Example Usage +```hcl +data "volcengine_privatelink_vpc_endpoints" "default" { + ids = ["ep-3rel74u229dz45zsk2i6l****"] +} +``` +## Argument Reference +The following arguments are supported: +* `endpoint_name` - (Optional) The name of vpc endpoint. +* `ids` - (Optional) The IDs of vpc endpoint. +* `name_regex` - (Optional) A Name Regex of vpc endpoint. +* `output_file` - (Optional) File name where to save data source results. +* `service_name` - (Optional) The name of vpc endpoint service. +* `status` - (Optional) The status of vpc endpoint. Valid values: `Creating`, `Pending`, `Available`, `Deleting`, `Inactive`. +* `vpc_id` - (Optional) The vpc id of vpc endpoint. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `total_count` - Returns the total amount of the data list. +* `vpc_endpoints` - The collection of query. + * `business_status` - Whether the vpc endpoint is locked. + * `connection_status` - The connection status of vpc endpoint. + * `creation_time` - The create time of vpc endpoint. + * `deleted_time` - The delete time of vpc endpoint. + * `description` - The description of vpc endpoint. + * `endpoint_domain` - The domain of vpc endpoint. + * `endpoint_id` - The Id of vpc endpoint. + * `endpoint_name` - The name of vpc endpoint. + * `endpoint_type` - The type of vpc endpoint. + * `id` - The Id of vpc endpoint. + * `service_id` - The Id of vpc endpoint service. + * `service_name` - The name of vpc endpoint service. + * `status` - The status of vpc endpoint. + * `update_time` - The update time of vpc endpoint. + * `vpc_id` - The vpc id of vpc endpoint. + + diff --git a/website/docs/r/privatelink_security_group.html.markdown b/website/docs/r/privatelink_security_group.html.markdown new file mode 100644 index 00000000..8e61906b --- /dev/null +++ b/website/docs/r/privatelink_security_group.html.markdown @@ -0,0 +1,34 @@ +--- +subcategory: "PRIVATELINK" +layout: "volcengine" +page_title: "Volcengine: volcengine_privatelink_security_group" +sidebar_current: "docs-volcengine-resource-privatelink_security_group" +description: |- + Provides a resource to manage privatelink security group +--- +# volcengine_privatelink_security_group +Provides a resource to manage privatelink security group +## Example Usage +```hcl +resource "volcengine_privatelink_security_group" "foo" { + endpoint_id = "ep-2byz5npiuu1hc2dx0efkv7ehc" + security_group_id = "sg-2d6722jpp55og58ozfd1sqtdb" +} +``` +## Argument Reference +The following arguments are supported: +* `endpoint_id` - (Required, ForceNew) The id of the endpoint. +* `security_group_id` - (Required, ForceNew) The id of the security group. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. + + + +## Import +PrivateLink Security Group Service can be imported using the endpoint id and security group id, e.g. +``` +$ terraform import volcengine_privatelink_security_group.default ep-2fe630gurkl37k5gfuy33****:sg-xxxxx +``` + diff --git a/website/docs/r/privatelink_vpc_endpoint.html.markdown b/website/docs/r/privatelink_vpc_endpoint.html.markdown new file mode 100644 index 00000000..fb7c3787 --- /dev/null +++ b/website/docs/r/privatelink_vpc_endpoint.html.markdown @@ -0,0 +1,53 @@ +--- +subcategory: "PRIVATELINK" +layout: "volcengine" +page_title: "Volcengine: volcengine_privatelink_vpc_endpoint" +sidebar_current: "docs-volcengine-resource-privatelink_vpc_endpoint" +description: |- + Provides a resource to manage privatelink vpc endpoint +--- +# volcengine_privatelink_vpc_endpoint +Provides a resource to manage privatelink vpc endpoint +## Example Usage +```hcl +resource "volcengine_privatelink_vpc_endpoint" "endpoint" { + security_group_ids = ["sg-2d5z8cr53k45c58ozfdum****"] + service_id = "epsvc-2byz5nzgiansw2dx0eehh****" + endpoint_name = "tf-test-ep" + description = "tf-test" +} + +resource "volcengine_privatelink_vpc_endpoint_zone" "zone" { + endpoint_id = volcengine_privatelink_vpc_endpoint.endpoint.id + subnet_id = "subnet-2bz47q19zhx4w2dx0eevn****" + private_ip_address = "172.16.0.252" +} +``` +## Argument Reference +The following arguments are supported: +* `security_group_ids` - (Required, ForceNew) the security group ids of vpc endpoint. +* `service_id` - (Required, ForceNew) The id of vpc endpoint service. +* `description` - (Optional) The description of vpc endpoint. +* `endpoint_name` - (Optional) The name of vpc endpoint. +* `service_name` - (Optional, ForceNew) The name of vpc endpoint service. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. +* `business_status` - Whether the vpc endpoint is locked. +* `connection_status` - The connection status of vpc endpoint. +* `creation_time` - The create time of vpc endpoint. +* `deleted_time` - The delete time of vpc endpoint. +* `endpoint_domain` - The domain of vpc endpoint. +* `endpoint_type` - The type of vpc endpoint. +* `status` - The status of vpc endpoint. +* `update_time` - The update time of vpc endpoint. +* `vpc_id` - The vpc id of vpc endpoint. + + +## Import +VpcEndpoint can be imported using the id, e.g. +``` +$ terraform import volcengine_privatelink_vpc_endpoint.default ep-3rel74u229dz45zsk2i6l**** +``` + diff --git a/website/docs/r/privatelink_vpc_endpoint_connection.html.markdown b/website/docs/r/privatelink_vpc_endpoint_connection.html.markdown new file mode 100644 index 00000000..7bafba1b --- /dev/null +++ b/website/docs/r/privatelink_vpc_endpoint_connection.html.markdown @@ -0,0 +1,46 @@ +--- +subcategory: "PRIVATELINK" +layout: "volcengine" +page_title: "Volcengine: volcengine_privatelink_vpc_endpoint_connection" +sidebar_current: "docs-volcengine-resource-privatelink_vpc_endpoint_connection" +description: |- + Provides a resource to manage privatelink vpc endpoint connection +--- +# volcengine_privatelink_vpc_endpoint_connection +Provides a resource to manage privatelink vpc endpoint connection +## Example Usage +```hcl +resource "volcengine_privatelink_vpc_endpoint_connection" "foo" { + endpoint_id = "ep-3rel74u229dz45zsk2i6l69qa" + service_id = "epsvc-2byz5mykk9y4g2dx0efs4aqz3" +} +``` +## Argument Reference +The following arguments are supported: +* `endpoint_id` - (Required, ForceNew) The id of the endpoint. +* `service_id` - (Required, ForceNew) The id of the security group. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. +* `connection_status` - The status of the connection. +* `creation_time` - The create time of the connection. +* `endpoint_owner_account_id` - The account id of the vpc endpoint. +* `endpoint_vpc_id` - The vpc id of the vpc endpoint. +* `update_time` - The update time of the connection. +* `zones` - The available zones. + * `network_interface_id` - The id of the network interface. + * `network_interface_ip` - The ip address of the network interface. + * `resource_id` - The id of the resource. + * `subnet_id` - The id of the subnet. + * `zone_domain` - The domain of the zone. + * `zone_id` - The id of the zone. + * `zone_status` - The status of the zone. + + +## Import +PrivateLink Vpc Endpoint Connection Service can be imported using the endpoint id and service id, e.g. +``` +$ terraform import volcengine_privatelink_vpc_endpoint_connection.default ep-3rel74u229dz45zsk2i6l69qa:epsvc-2byz5mykk9y4g2dx0efs4aqz3 +``` + diff --git a/website/docs/r/privatelink_vpc_endpoint_service.html.markdown b/website/docs/r/privatelink_vpc_endpoint_service.html.markdown new file mode 100644 index 00000000..c8712c40 --- /dev/null +++ b/website/docs/r/privatelink_vpc_endpoint_service.html.markdown @@ -0,0 +1,52 @@ +--- +subcategory: "PRIVATELINK" +layout: "volcengine" +page_title: "Volcengine: volcengine_privatelink_vpc_endpoint_service" +sidebar_current: "docs-volcengine-resource-privatelink_vpc_endpoint_service" +description: |- + Provides a resource to manage privatelink vpc endpoint service +--- +# volcengine_privatelink_vpc_endpoint_service +Provides a resource to manage privatelink vpc endpoint service +## Example Usage +```hcl +resource "volcengine_privatelink_vpc_endpoint_service" "foo" { + resources { + resource_id = "clb-2bzxccdjo9uyo2dx0eg0orzla" + resource_type = "CLB" + } + description = "tftest" + auto_accept_enabled = true +} +``` +## Argument Reference +The following arguments are supported: +* `resources` - (Required) The resources info. When create vpc endpoint service, the resource must exist. +* `auto_accept_enabled` - (Optional) Whether auto accept node connect. +* `description` - (Optional) The description of service. + +The `resources` object supports the following: + +* `resource_id` - (Required) The id of resource. +* `resource_type` - (Required) The type of resource. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. +* `creation_time` - The create time of service. +* `service_domain` - The domain of service. +* `service_id` - The Id of service. +* `service_name` - The name of service. +* `service_resource_type` - The resource type of service. +* `service_type` - The type of service. +* `status` - The status of service. +* `update_time` - The update time of service. +* `zone_ids` - The IDs of zones. + + +## Import +VpcEndpointService can be imported using the id, e.g. +``` +$ terraform import volcengine_privatelink_vpc_endpoint_service.default epsvc-2fe630gurkl37k5gfuy33**** +``` + diff --git a/website/docs/r/privatelink_vpc_endpoint_service_permission.html.markdown b/website/docs/r/privatelink_vpc_endpoint_service_permission.html.markdown new file mode 100644 index 00000000..a8070542 --- /dev/null +++ b/website/docs/r/privatelink_vpc_endpoint_service_permission.html.markdown @@ -0,0 +1,39 @@ +--- +subcategory: "PRIVATELINK" +layout: "volcengine" +page_title: "Volcengine: volcengine_privatelink_vpc_endpoint_service_permission" +sidebar_current: "docs-volcengine-resource-privatelink_vpc_endpoint_service_permission" +description: |- + Provides a resource to manage privatelink vpc endpoint service permission +--- +# volcengine_privatelink_vpc_endpoint_service_permission +Provides a resource to manage privatelink vpc endpoint service permission +## Example Usage +```hcl +resource "volcengine_privatelink_vpc_endpoint_service_permission" "foo" { + service_id = "epsvc-3rel73uf2ewao5zsk2j2l58ro" + permit_account_id = "210000000" +} + +resource "volcengine_privatelink_vpc_endpoint_service_permission" "foo1" { + service_id = "epsvc-3rel73uf2ewao5zsk2j2l58ro" + permit_account_id = "210000001" +} +``` +## Argument Reference +The following arguments are supported: +* `permit_account_id` - (Required, ForceNew) The id of account. +* `service_id` - (Required, ForceNew) The id of service. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. + + + +## Import +VpcEndpointServicePermission can be imported using the serviceId:permitAccountId, e.g. +``` +$ terraform import volcengine_privatelink_vpc_endpoint_service_permission.default epsvc-2fe630gurkl37k5gfuy33****:2100000000 +``` + diff --git a/website/docs/r/privatelink_vpc_endpoint_service_resource.html.markdown b/website/docs/r/privatelink_vpc_endpoint_service_resource.html.markdown new file mode 100644 index 00000000..955b5be1 --- /dev/null +++ b/website/docs/r/privatelink_vpc_endpoint_service_resource.html.markdown @@ -0,0 +1,44 @@ +--- +subcategory: "PRIVATELINK" +layout: "volcengine" +page_title: "Volcengine: volcengine_privatelink_vpc_endpoint_service_resource" +sidebar_current: "docs-volcengine-resource-privatelink_vpc_endpoint_service_resource" +description: |- + Provides a resource to manage privatelink vpc endpoint service resource +--- +# volcengine_privatelink_vpc_endpoint_service_resource +Provides a resource to manage privatelink vpc endpoint service resource +## Example Usage +```hcl +resource "volcengine_privatelink_vpc_endpoint_service_resource" "foo" { + service_id = "epsvc-3rel73uf2ewao5zsk2j2l58ro" + resource_id = "clb-3reii8qfbp7gg5zsk2hsrbe3c" +} + +resource "volcengine_privatelink_vpc_endpoint_service_resource" "foo1" { + service_id = "epsvc-3rel73uf2ewao5zsk2j2l58ro" + resource_id = "clb-2d6sfye98rzls58ozfducee1o" +} + +resource "volcengine_privatelink_vpc_endpoint_service_resource" "foo2" { + service_id = "epsvc-3rel73uf2ewao5zsk2j2l58ro" + resource_id = "clb-3refkvae02gow5zsk2ilaev5y" +} +``` +## Argument Reference +The following arguments are supported: +* `resource_id` - (Required, ForceNew) The id of resource. +* `service_id` - (Required, ForceNew) The id of service. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. + + + +## Import +VpcEndpointServiceResource can be imported using the serviceId:resourceId, e.g. +``` +$ terraform import volcengine_privatelink_vpc_endpoint_service_resource.default epsvc-2fe630gurkl37k5gfuy33****:clb-bp1o94dp5i6ea**** +``` + diff --git a/website/docs/r/privatelink_vpc_endpoint_zone.html.markdown b/website/docs/r/privatelink_vpc_endpoint_zone.html.markdown new file mode 100644 index 00000000..021e5f43 --- /dev/null +++ b/website/docs/r/privatelink_vpc_endpoint_zone.html.markdown @@ -0,0 +1,39 @@ +--- +subcategory: "PRIVATELINK" +layout: "volcengine" +page_title: "Volcengine: volcengine_privatelink_vpc_endpoint_zone" +sidebar_current: "docs-volcengine-resource-privatelink_vpc_endpoint_zone" +description: |- + Provides a resource to manage privatelink vpc endpoint zone +--- +# volcengine_privatelink_vpc_endpoint_zone +Provides a resource to manage privatelink vpc endpoint zone +## Example Usage +```hcl +resource "volcengine_privatelink_vpc_endpoint_zone" "foo" { + endpoint_id = "ep-2byz5nlkimc5c2dx0ef9g****" + subnet_id = "subnet-2bz47q19zhx4w2dx0eevn****" + private_ip_address = "172.16.0.251" +} +``` +## Argument Reference +The following arguments are supported: +* `endpoint_id` - (Required, ForceNew) The endpoint id of vpc endpoint zone. +* `subnet_id` - (Required, ForceNew) The subnet id of vpc endpoint zone. +* `private_ip_address` - (Optional, ForceNew) The private ip address of vpc endpoint zone. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. +* `network_interface_id` - The network interface id of vpc endpoint. +* `zone_domain` - The domain of vpc endpoint zone. +* `zone_id` - The Id of vpc endpoint zone. +* `zone_status` - The status of vpc endpoint zone. + + +## Import +VpcEndpointZone can be imported using the endpointId:subnetId, e.g. +``` +$ terraform import volcengine_privatelink_vpc_endpoint_zone.default ep-3rel75r081l345zsk2i59****:subnet-2bz47q19zhx4w2dx0eevn**** +``` + diff --git a/website/docs/r/vke_cluster.html.markdown b/website/docs/r/vke_cluster.html.markdown index f9db8b12..a8f39d63 100644 --- a/website/docs/r/vke_cluster.html.markdown +++ b/website/docs/r/vke_cluster.html.markdown @@ -90,7 +90,7 @@ The `log_setups` object supports the following: The `logging_config` object supports the following: * `log_project_id` - (Optional) The TLS log item ID of the collection target. -* `log_setups` - (Optional) Cluster logging options. This structure can only be modified and added, and cannot be deleted. +* `log_setups` - (Optional) Cluster logging options. This structure can only be modified and added, and cannot be deleted. When encountering a `cannot be deleted` error, please query the log setups of the current cluster and fill in the current `tf` file. The `pods_config` object supports the following: diff --git a/website/volcengine.erb b/website/volcengine.erb index 488b7235..a68a36da 100644 --- a/website/volcengine.erb +++ b/website/volcengine.erb @@ -523,6 +523,57 @@ +
  • + PRIVATELINK + +
  • RDS_MYSQL