alibabacloudstack/resource_apsarastack_security_group_rule.go (403 lines of code) (raw):

package alibabacloudstack import ( "fmt" "strconv" "strings" "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses" "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" "github.com/aliyun/terraform-provider-alibabacloudstack/alibabacloudstack/connectivity" "github.com/aliyun/terraform-provider-alibabacloudstack/alibabacloudstack/errmsgs" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func resourceAlibabacloudStackSecurityGroupRule() *schema.Resource { resource := &schema.Resource{ Schema: map[string]*schema.Schema{ "type": { Type: schema.TypeString, Required: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{"ingress", "egress"}, false), Description: "Type of rule, ingress (inbound) or egress (outbound).", }, "ip_protocol": { Type: schema.TypeString, Required: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{"tcp", "udp", "icmp", "gre", "all"}, false), }, "nic_type": { Type: schema.TypeString, Optional: true, ForceNew: true, Computed: true, ValidateFunc: validation.StringInSlice([]string{"internet", "intranet"}, false), }, "policy": { Type: schema.TypeString, Optional: true, ForceNew: true, Default: GroupRulePolicyAccept, ValidateFunc: validation.StringInSlice([]string{"accept", "drop"}, false), }, "port_range": { Type: schema.TypeString, Required: true, ForceNew: true, //Default: AllPortRange,//port_range has been set to Required in Alibabacloudstack and Default cannot be used with Required DiffSuppressFunc: ecsSecurityGroupRulePortRangeDiffSuppressFunc, }, "priority": { Type: schema.TypeInt, Optional: true, ForceNew: true, Default: 1, ValidateFunc: validation.IntBetween(1, 100), }, "security_group_id": { Type: schema.TypeString, Required: true, ForceNew: true, }, "cidr_ip": { Type: schema.TypeString, Optional: true, ForceNew: true, AtLeastOneOf: []string{"cidr_ip", "ipv6_cidr_ip", "source_security_group_id"}, }, "ipv6_cidr_ip": { Type: schema.TypeString, Optional: true, ForceNew: true, ConflictsWith: []string{"cidr_ip"}, }, "source_security_group_id": { Type: schema.TypeString, Optional: true, ForceNew: true, ConflictsWith: []string{"cidr_ip"}, }, "source_group_owner_account": { Type: schema.TypeString, Optional: true, ForceNew: true, }, "description": { Type: schema.TypeString, Optional: true, }, }, } setResourceFunc(resource, resourceAlibabacloudStackSecurityGroupRuleCreate, resourceAlibabacloudStackSecurityGroupRuleRead, resourceAlibabacloudStackSecurityGroupRuleUpdate, deleteSecurityGroupRule) return resource } func resourceAlibabacloudStackSecurityGroupRuleCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AlibabacloudStackClient) direction := d.Get("type").(string) sgId := d.Get("security_group_id").(string) ptl := d.Get("ip_protocol").(string) port := d.Get("port_range").(string) if port == "" { return errmsgs.WrapError(fmt.Errorf("'port_range': required field is not set or invalid.")) } nicType := d.Get("nic_type").(string) policy := d.Get("policy").(string) priority := d.Get("priority").(int) if _, ok := d.GetOk("cidr_ip"); !ok { if _, ok := d.GetOk("source_security_group_id"); !ok { return errmsgs.WrapError(fmt.Errorf("Either 'cidr_ip' or 'source_security_group_id' must be specified.")) } } request, err := buildAlibabacloudStackSGRuleRequest(d, meta) if err != nil { return errmsgs.WrapError(err) } var cidr_ip string if ip, ok := d.GetOk("cidr_ip"); ok { cidr_ip = ip.(string) } else { cidr_ip = d.Get("source_security_group_id").(string) } if direction == string(DirectionIngress) { request.ApiName = "AuthorizeSecurityGroup" raw, err := client.WithEcsClient(func(ecsClient *ecs.Client) (interface{}, error) { return ecsClient.ProcessCommonRequest(request) }) bresponse, ok := raw.(*responses.CommonResponse) if err != nil { errmsg := "" if ok { errmsg = errmsgs.GetBaseResponseErrorMessage(bresponse.BaseResponse) } return errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, "alibabacloudstack_security_group_rule", request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg) } } else { request.ApiName = "AuthorizeSecurityGroupEgress" raw, err := client.WithEcsClient(func(ecsClient *ecs.Client) (interface{}, error) { return ecsClient.ProcessCommonRequest(request) }) bresponse, ok := raw.(*responses.CommonResponse) if err != nil { errmsg := "" if ok { errmsg = errmsgs.GetBaseResponseErrorMessage(bresponse.BaseResponse) } return errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, "alibabacloudstack_security_group_rule", request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg) } } d.SetId(sgId + ":" + direction + ":" + ptl + ":" + port + ":" + nicType + ":" + cidr_ip + ":" + policy + ":" + strconv.Itoa(priority)) return nil } func resourceAlibabacloudStackSecurityGroupRuleRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AlibabacloudStackClient) ecsService := EcsService{client} parts := strings.Split(d.Id(), ":") policy := parseSecurityRuleId(d, meta, 6) strPriority := parseSecurityRuleId(d, meta, 7) var priority int if policy == "" || strPriority == "" { policy = d.Get("policy").(string) priority = d.Get("priority").(int) d.SetId(d.Id() + ":" + policy + ":" + strconv.Itoa(priority)) } else { prior, err := strconv.Atoi(strPriority) if err != nil { return errmsgs.WrapError(err) } priority = prior } sgId := parts[0] direction := parts[1] object, err := ecsService.DescribeSecurityGroupRule(d.Id()) if err != nil { if errmsgs.NotFoundError(err) { d.SetId("") //return nil } return errmsgs.WrapError(err) } d.Set("type", object.Direction) d.Set("ip_protocol", strings.ToLower(string(object.IpProtocol))) d.Set("nic_type", object.NicType) d.Set("policy", strings.ToLower(string(object.Policy))) d.Set("port_range", object.PortRange) d.Set("description", object.Description) if pri, err := strconv.Atoi(object.Priority); err != nil { return errmsgs.WrapError(err) } else { d.Set("priority", pri) } d.Set("security_group_id", sgId) //support source and desc by type if direction == string(DirectionIngress) { d.Set("cidr_ip", object.SourceCidrIp) d.Set("source_security_group_id", object.SourceGroupId) d.Set("source_group_owner_account", object.SourceGroupOwnerAccount) } else { d.Set("cidr_ip", object.DestCidrIp) d.Set("source_security_group_id", object.DestGroupId) d.Set("source_group_owner_account", object.DestGroupOwnerAccount) } return nil } func resourceAlibabacloudStackSecurityGroupRuleUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AlibabacloudStackClient) policy := parseSecurityRuleId(d, meta, 6) strPriority := parseSecurityRuleId(d, meta, 7) var priority int if policy == "" || strPriority == "" { policy = d.Get("policy").(string) priority = d.Get("priority").(int) d.SetId(d.Id() + ":" + policy + ":" + strconv.Itoa(priority)) } else { prior, err := strconv.Atoi(strPriority) if err != nil { return errmsgs.WrapError(err) } priority = prior } request, err := buildAlibabacloudStackSGRuleRequest(d, meta) if err != nil { return errmsgs.WrapError(err) } direction := d.Get("type").(string) if direction == string(DirectionIngress) { request.ApiName = "ModifySecurityGroupRule" raw, err := client.WithEcsClient(func(ecsClient *ecs.Client) (interface{}, error) { return ecsClient.ProcessCommonRequest(request) }) addDebug(request.GetActionName(), raw, request.Headers, request) bresponse, ok := raw.(*responses.CommonResponse) if err != nil { errmsg := "" if ok { errmsg = errmsgs.GetBaseResponseErrorMessage(bresponse.BaseResponse) } return errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, d.Id(), request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg) } } else { request.ApiName = "ModifySecurityGroupEgressRule" raw, err := client.WithEcsClient(func(ecsClient *ecs.Client) (interface{}, error) { return ecsClient.ProcessCommonRequest(request) }) addDebug(request.GetActionName(), raw, request.Headers, request) bresponse, ok := raw.(*responses.CommonResponse) if err != nil { errmsg := "" if ok { errmsg = errmsgs.GetBaseResponseErrorMessage(bresponse.BaseResponse) } return errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, d.Id(), request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg) } } return nil } func deleteSecurityGroupRule(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AlibabacloudStackClient) ruleType := d.Get("type").(string) request, err := buildAlibabacloudStackSGRuleRequest(d, meta) if err != nil { return errmsgs.WrapError(err) } if ruleType == string(DirectionIngress) { request.ApiName = "RevokeSecurityGroup" raw, err := client.WithEcsClient(func(ecsClient *ecs.Client) (interface{}, error) { return ecsClient.ProcessCommonRequest(request) }) bresponse, ok := raw.(*responses.CommonResponse) if err != nil { errmsg := "" if ok { errmsg = errmsgs.GetBaseResponseErrorMessage(bresponse.BaseResponse) } return errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, d.Id(), request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg) } } else { request.ApiName = "RevokeSecurityGroupEgress" raw, err := client.WithEcsClient(func(ecsClient *ecs.Client) (interface{}, error) { return ecsClient.ProcessCommonRequest(request) }) bresponse, ok := raw.(*responses.CommonResponse) if err != nil { errmsg := "" if ok { errmsg = errmsgs.GetBaseResponseErrorMessage(bresponse.BaseResponse) } return errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, d.Id(), request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg) } } return nil } func resourceAlibabacloudStackSecurityGroupRuleDelete(d *schema.ResourceData, meta interface{}) error { policy := parseSecurityRuleId(d, meta, 6) strPriority := parseSecurityRuleId(d, meta, 7) var priority int if policy == "" || strPriority == "" { policy = d.Get("policy").(string) priority = d.Get("priority").(int) d.SetId(d.Id() + ":" + policy + ":" + strconv.Itoa(priority)) } else { prior, err := strconv.Atoi(strPriority) if err != nil { return errmsgs.WrapError(err) } priority = prior } err := resource.Retry(5*time.Minute, func() *resource.RetryError { err := deleteSecurityGroupRule(d, meta) if err != nil { if errmsgs.NotFoundError(err) || errmsgs.IsExpectedErrors(err, []string{"InvalidSecurityGroupId.NotFound"}) { return nil } return resource.RetryableError(err) } return nil }) if err != nil { return errmsgs.WrapError(err) } return nil } func buildAlibabacloudStackSGRuleRequest(d *schema.ResourceData, meta interface{}) (*requests.CommonRequest, error) { client := meta.(*connectivity.AlibabacloudStackClient) ecsService := EcsService{client} // Get product code from the built request request := client.NewCommonRequest("GET", "Ecs", "2014-05-26", "", "") direction := d.Get("type").(string) port_range := d.Get("port_range").(string) request.QueryParams["PortRange"] = port_range if v, ok := d.GetOk("ip_protocol"); ok { request.QueryParams["IpProtocol"] = v.(string) if v.(string) == string(Tcp) || v.(string) == string(Udp) { if port_range == AllPortRange { return nil, fmt.Errorf("'tcp' and 'udp' can support port range: [1, 65535]. Please correct it and try again.") } } else if port_range != AllPortRange { return nil, fmt.Errorf("'icmp', 'gre' and 'all' only support port range '-1/-1'. Please correct it and try again.") } } if v, ok := d.GetOk("policy"); ok { request.QueryParams["Policy"] = v.(string) } if v, ok := d.GetOk("nic_type"); ok { request.QueryParams["NicType"] = v.(string) } if v, ok := d.GetOk("priority"); ok { request.QueryParams["Priority"] = strconv.Itoa(v.(int)) } if v, ok := d.GetOk("cidr_ip"); ok { if direction == string(DirectionIngress) { request.QueryParams["SourceCidrIp"] = v.(string) } else { request.QueryParams["DestCidrIp"] = v.(string) } } else if v, ok := d.GetOk("ipv6_cidr_ip"); ok { if direction == string(DirectionIngress) { request.QueryParams["Ipv6SourceGroupId"] = v.(string) } else { request.QueryParams["Ipv6DestCidrIp"] = v.(string) } } var targetGroupId string if v, ok := d.GetOk("source_security_group_id"); ok { targetGroupId = v.(string) if direction == string(DirectionIngress) { request.QueryParams["SourceGroupId"] = targetGroupId } else { request.QueryParams["DestGroupId"] = targetGroupId } } if v, ok := d.GetOk("source_group_owner_account"); ok { if direction == string(DirectionIngress) { request.QueryParams["SourceGroupOwnerAccount"] = v.(string) } else { request.QueryParams["DestGroupOwnerAccount"] = v.(string) } } sgId := d.Get("security_group_id").(string) group, err := ecsService.DescribeSecurityGroup(sgId) if err != nil { return nil, errmsgs.WrapError(err) } if v, ok := d.GetOk("nic_type"); ok { if group.VpcId != "" || targetGroupId != "" { if GroupRuleNicType(v.(string)) != GroupRuleIntranet { return nil, fmt.Errorf("When security group in the vpc or authorizing permission for source/destination security group, " + "the nic_type must be 'intranet'.") } } request.QueryParams["NicType"] = v.(string) } request.QueryParams["SecurityGroupId"] = sgId description := d.Get("description").(string) request.QueryParams["Description"] = description return request, nil } func parseSecurityRuleId(d *schema.ResourceData, meta interface{}, index int) (result string) { parts := strings.Split(d.Id(), ":") defer func() { if e := recover(); e != nil { fmt.Printf("Panicing %s\r\n", e) result = "" } }() return parts[index] }