yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/hcso/securitygroup.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package hcso
    16  
    17  /*
    18  https://support.huaweicloud.com/usermanual-vpc/zh-cn_topic_0073379079.html
    19  安全组的限制
    20  默认情况下,一个用户可以创建100个安全组。
    21  默认情况下,一个安全组最多只允许拥有50条安全组规则。
    22  默认情况下,一个弹性云服务器或辅助网卡最多只能被添加到5个安全组中。
    23  在创建私网弹性负载均衡时,需要选择弹性负载均衡所在的安全组。请勿删除默认规则或者确保满足以下规则:
    24  出方向:允许发往同一个安全组的报文可以通过,或者允许对端负载均衡器报文通过。
    25  入方向:允许来自同一个安全组的报文可以通过,或者允许对端负载均衡器报文通过。
    26  */
    27  
    28  import (
    29  	"net"
    30  
    31  	"yunion.io/x/jsonutils"
    32  	"yunion.io/x/pkg/errors"
    33  	"yunion.io/x/pkg/util/secrules"
    34  	"yunion.io/x/pkg/utils"
    35  
    36  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    37  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    38  	"yunion.io/x/cloudmux/pkg/multicloud"
    39  	"yunion.io/x/cloudmux/pkg/multicloud/huawei"
    40  )
    41  
    42  type SecurityGroupRule struct {
    43  	Direction       string `json:"direction"`
    44  	Ethertype       string `json:"ethertype"`
    45  	ID              string `json:"id"`
    46  	Description     string `json:"description"`
    47  	SecurityGroupID string `json:"security_group_id"`
    48  	RemoteGroupID   string `json:"remote_group_id"`
    49  }
    50  
    51  type SecurityGroupRuleDetail struct {
    52  	Direction       string `json:"direction"`
    53  	Ethertype       string `json:"ethertype"`
    54  	ID              string `json:"id"`
    55  	Description     string `json:"description"`
    56  	PortRangeMax    int64  `json:"port_range_max"`
    57  	PortRangeMin    int64  `json:"port_range_min"`
    58  	Protocol        string `json:"protocol"`
    59  	RemoteGroupID   string `json:"remote_group_id"`
    60  	RemoteIPPrefix  string `json:"remote_ip_prefix"`
    61  	SecurityGroupID string `json:"security_group_id"`
    62  	TenantID        string `json:"tenant_id"`
    63  }
    64  
    65  // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090615.html
    66  type SSecurityGroup struct {
    67  	multicloud.SSecurityGroup
    68  	huawei.HuaweiTags
    69  	region *SRegion
    70  
    71  	ID                  string              `json:"id"`
    72  	Name                string              `json:"name"`
    73  	Description         string              `json:"description"`
    74  	VpcID               string              `json:"vpc_id"`
    75  	EnterpriseProjectID string              `json:"enterprise_project_id "`
    76  	SecurityGroupRules  []SecurityGroupRule `json:"security_group_rules"`
    77  }
    78  
    79  // 判断是否兼容云端安全组规则
    80  func compatibleSecurityGroupRule(r SecurityGroupRule) bool {
    81  	// 忽略了源地址是安全组的规则
    82  	if len(r.RemoteGroupID) > 0 {
    83  		return false
    84  	}
    85  
    86  	// 忽略IPV6
    87  	if r.Ethertype == "IPv6" {
    88  		return false
    89  	}
    90  
    91  	return true
    92  }
    93  
    94  func (self *SSecurityGroup) GetId() string {
    95  	return self.ID
    96  }
    97  
    98  func (self *SSecurityGroup) GetVpcId() string {
    99  	return api.NORMAL_VPC_ID
   100  }
   101  
   102  func (self *SSecurityGroup) GetName() string {
   103  	if len(self.Name) > 0 {
   104  		return self.Name
   105  	}
   106  	return self.ID
   107  }
   108  
   109  func (self *SSecurityGroup) GetGlobalId() string {
   110  	return self.ID
   111  }
   112  
   113  func (self *SSecurityGroup) GetStatus() string {
   114  	return ""
   115  }
   116  
   117  func (self *SSecurityGroup) Refresh() error {
   118  	if new, err := self.region.GetSecurityGroupDetails(self.GetId()); err != nil {
   119  		return err
   120  	} else {
   121  		return jsonutils.Update(self, new)
   122  	}
   123  }
   124  
   125  func (self *SSecurityGroup) IsEmulated() bool {
   126  	return false
   127  }
   128  
   129  func (self *SSecurityGroup) GetDescription() string {
   130  	if self.Description == self.VpcID {
   131  		return ""
   132  	}
   133  	return self.Description
   134  }
   135  
   136  // todo: 这里需要优化查询太多了
   137  func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) {
   138  	rules := make([]cloudprovider.SecurityRule, 0)
   139  	for _, r := range self.SecurityGroupRules {
   140  		if !compatibleSecurityGroupRule(r) {
   141  			continue
   142  		}
   143  
   144  		rule, err := self.GetSecurityRule(r.ID)
   145  		if err != nil {
   146  			return rules, err
   147  		}
   148  
   149  		rules = append(rules, rule)
   150  	}
   151  
   152  	return rules, nil
   153  }
   154  
   155  func (self *SSecurityGroup) GetSecurityRule(ruleId string) (cloudprovider.SecurityRule, error) {
   156  	remoteRule := SecurityGroupRuleDetail{}
   157  	err := DoGet(self.region.ecsClient.SecurityGroupRules.Get, ruleId, nil, &remoteRule)
   158  	if err != nil {
   159  		return cloudprovider.SecurityRule{}, err
   160  	}
   161  
   162  	var direction secrules.TSecurityRuleDirection
   163  	if remoteRule.Direction == "ingress" {
   164  		direction = secrules.SecurityRuleIngress
   165  	} else {
   166  		direction = secrules.SecurityRuleEgress
   167  	}
   168  
   169  	protocol := secrules.PROTO_ANY
   170  	if remoteRule.Protocol != "" {
   171  		protocol = remoteRule.Protocol
   172  	}
   173  
   174  	var portStart int
   175  	var portEnd int
   176  	if protocol == secrules.PROTO_ICMP {
   177  		portStart = -1
   178  		portEnd = -1
   179  	} else {
   180  		portStart = int(remoteRule.PortRangeMin)
   181  		portEnd = int(remoteRule.PortRangeMax)
   182  	}
   183  
   184  	ipNet := &net.IPNet{}
   185  	if len(remoteRule.RemoteIPPrefix) > 0 {
   186  		_, ipNet, err = net.ParseCIDR(remoteRule.RemoteIPPrefix)
   187  	} else {
   188  		_, ipNet, err = net.ParseCIDR("0.0.0.0/0")
   189  	}
   190  
   191  	if err != nil {
   192  		return cloudprovider.SecurityRule{}, err
   193  	}
   194  
   195  	rule := cloudprovider.SecurityRule{
   196  		ExternalId: ruleId,
   197  		SecurityRule: secrules.SecurityRule{
   198  			Priority:    1,
   199  			Action:      secrules.SecurityRuleAllow,
   200  			IPNet:       ipNet,
   201  			Protocol:    protocol,
   202  			Direction:   direction,
   203  			PortStart:   portStart,
   204  			PortEnd:     portEnd,
   205  			Ports:       nil,
   206  			Description: remoteRule.Description,
   207  		},
   208  	}
   209  
   210  	err = rule.ValidateRule()
   211  	return rule, err
   212  }
   213  
   214  func (self *SRegion) GetSecurityGroupDetails(secGroupId string) (*SSecurityGroup, error) {
   215  	securitygroup := SSecurityGroup{}
   216  	err := DoGet(self.ecsClient.SecurityGroups.Get, secGroupId, nil, &securitygroup)
   217  	if err != nil {
   218  		return nil, err
   219  	}
   220  
   221  	securitygroup.region = self
   222  	return &securitygroup, err
   223  }
   224  
   225  // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090617.html
   226  func (self *SRegion) GetSecurityGroups(vpcId string, name string) ([]SSecurityGroup, error) {
   227  	querys := map[string]string{}
   228  	if len(vpcId) > 0 && !utils.IsInStringArray(vpcId, []string{"default", api.NORMAL_VPC_ID}) { // vpc_id = default or normal 时报错 '{"code":"VPC.0601","message":"Query security groups error vpcId is invalid."}'
   229  		querys["vpc_id"] = vpcId
   230  	}
   231  
   232  	securitygroups := make([]SSecurityGroup, 0)
   233  	err := doListAllWithMarker(self.ecsClient.SecurityGroups.List, querys, &securitygroups)
   234  	if err != nil {
   235  		return nil, err
   236  	}
   237  
   238  	// security 中的vpc字段只是一个标识,实际可以跨vpc使用
   239  	for i := range securitygroups {
   240  		securitygroup := &securitygroups[i]
   241  		securitygroup.region = self
   242  	}
   243  
   244  	result := []SSecurityGroup{}
   245  	for _, secgroup := range securitygroups {
   246  		if len(name) == 0 || secgroup.Name == name {
   247  			result = append(result, secgroup)
   248  		}
   249  	}
   250  
   251  	return result, nil
   252  }
   253  
   254  func (self *SSecurityGroup) GetProjectId() string {
   255  	return ""
   256  }
   257  
   258  func (self *SSecurityGroup) Delete() error {
   259  	return self.region.DeleteSecurityGroup(self.ID)
   260  }
   261  
   262  func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error {
   263  	for _, r := range append(inDels, outDels...) {
   264  		err := self.region.delSecurityGroupRule(r.ExternalId)
   265  		if err != nil {
   266  			return errors.Wrapf(err, "delSecurityGroupRule(%s %s)", r.ExternalId, r.String())
   267  		}
   268  	}
   269  	for _, r := range append(inAdds, outAdds...) {
   270  		err := self.region.addSecurityGroupRules(self.ID, r)
   271  		if err != nil {
   272  			return errors.Wrapf(err, "addSecurityGroupRule(%d %s)", r.Priority, r.String())
   273  		}
   274  	}
   275  	return nil
   276  }