yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/huawei/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 huawei
    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  )
    40  
    41  type SecurityGroupRule struct {
    42  	Direction       string `json:"direction"`
    43  	Ethertype       string `json:"ethertype"`
    44  	ID              string `json:"id"`
    45  	Description     string `json:"description"`
    46  	SecurityGroupID string `json:"security_group_id"`
    47  	RemoteGroupID   string `json:"remote_group_id"`
    48  }
    49  
    50  type SecurityGroupRuleDetail struct {
    51  	Direction       string `json:"direction"`
    52  	Ethertype       string `json:"ethertype"`
    53  	ID              string `json:"id"`
    54  	Description     string `json:"description"`
    55  	PortRangeMax    int64  `json:"port_range_max"`
    56  	PortRangeMin    int64  `json:"port_range_min"`
    57  	Protocol        string `json:"protocol"`
    58  	RemoteGroupID   string `json:"remote_group_id"`
    59  	RemoteIPPrefix  string `json:"remote_ip_prefix"`
    60  	SecurityGroupID string `json:"security_group_id"`
    61  	TenantID        string `json:"tenant_id"`
    62  }
    63  
    64  // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090615.html
    65  type SSecurityGroup struct {
    66  	multicloud.SSecurityGroup
    67  	HuaweiTags
    68  	region *SRegion
    69  
    70  	ID                  string              `json:"id"`
    71  	Name                string              `json:"name"`
    72  	Description         string              `json:"description"`
    73  	VpcID               string              `json:"vpc_id"`
    74  	EnterpriseProjectID string              `json:"enterprise_project_id "`
    75  	SecurityGroupRules  []SecurityGroupRule `json:"security_group_rules"`
    76  }
    77  
    78  // 判断是否兼容云端安全组规则
    79  func compatibleSecurityGroupRule(r SecurityGroupRule) bool {
    80  	// 忽略了源地址是安全组的规则
    81  	if len(r.RemoteGroupID) > 0 {
    82  		return false
    83  	}
    84  
    85  	// 忽略IPV6
    86  	if r.Ethertype == "IPv6" {
    87  		return false
    88  	}
    89  
    90  	return true
    91  }
    92  
    93  func (self *SSecurityGroup) GetId() string {
    94  	return self.ID
    95  }
    96  
    97  func (self *SSecurityGroup) GetVpcId() string {
    98  	return api.NORMAL_VPC_ID
    99  }
   100  
   101  func (self *SSecurityGroup) GetName() string {
   102  	if len(self.Name) > 0 {
   103  		return self.Name
   104  	}
   105  	return self.ID
   106  }
   107  
   108  func (self *SSecurityGroup) GetGlobalId() string {
   109  	return self.ID
   110  }
   111  
   112  func (self *SSecurityGroup) GetStatus() string {
   113  	return ""
   114  }
   115  
   116  func (self *SSecurityGroup) Refresh() error {
   117  	if new, err := self.region.GetSecurityGroupDetails(self.GetId()); err != nil {
   118  		return err
   119  	} else {
   120  		return jsonutils.Update(self, new)
   121  	}
   122  }
   123  
   124  func (self *SSecurityGroup) IsEmulated() bool {
   125  	return false
   126  }
   127  
   128  func (self *SSecurityGroup) GetDescription() string {
   129  	if self.Description == self.VpcID {
   130  		return ""
   131  	}
   132  	return self.Description
   133  }
   134  
   135  // todo: 这里需要优化查询太多了
   136  func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) {
   137  	rules := make([]cloudprovider.SecurityRule, 0)
   138  	for _, r := range self.SecurityGroupRules {
   139  		if !compatibleSecurityGroupRule(r) {
   140  			continue
   141  		}
   142  
   143  		rule, err := self.GetSecurityRule(r.ID)
   144  		if err != nil {
   145  			return rules, err
   146  		}
   147  
   148  		rules = append(rules, rule)
   149  	}
   150  
   151  	return rules, nil
   152  }
   153  
   154  func (self *SSecurityGroup) GetSecurityRule(ruleId string) (cloudprovider.SecurityRule, error) {
   155  	remoteRule := SecurityGroupRuleDetail{}
   156  	err := DoGet(self.region.ecsClient.SecurityGroupRules.Get, ruleId, nil, &remoteRule)
   157  	if err != nil {
   158  		return cloudprovider.SecurityRule{}, err
   159  	}
   160  
   161  	var direction secrules.TSecurityRuleDirection
   162  	if remoteRule.Direction == "ingress" {
   163  		direction = secrules.SecurityRuleIngress
   164  	} else {
   165  		direction = secrules.SecurityRuleEgress
   166  	}
   167  
   168  	protocol := secrules.PROTO_ANY
   169  	if remoteRule.Protocol != "" {
   170  		protocol = remoteRule.Protocol
   171  	}
   172  
   173  	var portStart int
   174  	var portEnd int
   175  	if protocol == secrules.PROTO_ICMP {
   176  		portStart = -1
   177  		portEnd = -1
   178  	} else {
   179  		portStart = int(remoteRule.PortRangeMin)
   180  		portEnd = int(remoteRule.PortRangeMax)
   181  	}
   182  
   183  	ipNet := &net.IPNet{}
   184  	if len(remoteRule.RemoteIPPrefix) > 0 {
   185  		_, ipNet, err = net.ParseCIDR(remoteRule.RemoteIPPrefix)
   186  	} else {
   187  		_, ipNet, err = net.ParseCIDR("0.0.0.0/0")
   188  	}
   189  
   190  	if err != nil {
   191  		return cloudprovider.SecurityRule{}, err
   192  	}
   193  
   194  	rule := cloudprovider.SecurityRule{
   195  		ExternalId: ruleId,
   196  		SecurityRule: secrules.SecurityRule{
   197  			Priority:    1,
   198  			Action:      secrules.SecurityRuleAllow,
   199  			IPNet:       ipNet,
   200  			Protocol:    protocol,
   201  			Direction:   direction,
   202  			PortStart:   portStart,
   203  			PortEnd:     portEnd,
   204  			Ports:       nil,
   205  			Description: remoteRule.Description,
   206  		},
   207  	}
   208  
   209  	err = rule.ValidateRule()
   210  	return rule, err
   211  }
   212  
   213  func (self *SRegion) GetSecurityGroupDetails(secGroupId string) (*SSecurityGroup, error) {
   214  	securitygroup := SSecurityGroup{}
   215  	err := DoGet(self.ecsClient.SecurityGroups.Get, secGroupId, nil, &securitygroup)
   216  	if err != nil {
   217  		return nil, err
   218  	}
   219  
   220  	securitygroup.region = self
   221  	return &securitygroup, err
   222  }
   223  
   224  // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090617.html
   225  func (self *SRegion) GetSecurityGroups(vpcId string, name string) ([]SSecurityGroup, error) {
   226  	querys := map[string]string{}
   227  	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."}'
   228  		querys["vpc_id"] = vpcId
   229  	}
   230  
   231  	securitygroups := make([]SSecurityGroup, 0)
   232  	err := doListAllWithMarker(self.ecsClient.SecurityGroups.List, querys, &securitygroups)
   233  	if err != nil {
   234  		return nil, err
   235  	}
   236  
   237  	// security 中的vpc字段只是一个标识,实际可以跨vpc使用
   238  	for i := range securitygroups {
   239  		securitygroup := &securitygroups[i]
   240  		securitygroup.region = self
   241  	}
   242  
   243  	result := []SSecurityGroup{}
   244  	for _, secgroup := range securitygroups {
   245  		if len(name) == 0 || secgroup.Name == name {
   246  			result = append(result, secgroup)
   247  		}
   248  	}
   249  
   250  	return result, nil
   251  }
   252  
   253  func (self *SSecurityGroup) GetProjectId() string {
   254  	return ""
   255  }
   256  
   257  func (self *SSecurityGroup) Delete() error {
   258  	return self.region.DeleteSecurityGroup(self.ID)
   259  }
   260  
   261  func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error {
   262  	for _, r := range append(inDels, outDels...) {
   263  		err := self.region.delSecurityGroupRule(r.ExternalId)
   264  		if err != nil {
   265  			return errors.Wrapf(err, "delSecurityGroupRule(%s %s)", r.ExternalId, r.String())
   266  		}
   267  	}
   268  	for _, r := range append(inAdds, outAdds...) {
   269  		err := self.region.addSecurityGroupRules(self.ID, r)
   270  		if err != nil {
   271  			return errors.Wrapf(err, "addSecurityGroupRule(%d %s)", r.Priority, r.String())
   272  		}
   273  	}
   274  	return nil
   275  }