yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/ctyun/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 ctyun
    16  
    17  import (
    18  	"fmt"
    19  	"net"
    20  
    21  	"yunion.io/x/jsonutils"
    22  	"yunion.io/x/pkg/errors"
    23  	"yunion.io/x/pkg/util/secrules"
    24  
    25  	apis "yunion.io/x/cloudmux/pkg/apis/compute"
    26  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    27  	"yunion.io/x/cloudmux/pkg/multicloud"
    28  )
    29  
    30  type SSecurityGroup struct {
    31  	multicloud.SSecurityGroup
    32  	CtyunTags
    33  	region *SRegion
    34  
    35  	ResSecurityGroupID string `json:"resSecurityGroupId"`
    36  	Name               string `json:"name"`
    37  	AccountID          string `json:"accountId"`
    38  	UserID             string `json:"userId"`
    39  	RegionID           string `json:"regionId"`
    40  	ZoneID             string `json:"zoneId"`
    41  	VpcID              string `json:"vpcId"`
    42  	CreateDate         int64  `json:"createDate"`
    43  	Status             int64  `json:"status"`
    44  }
    45  
    46  func (self *SRegion) delSecurityGroupRule(secGrpRuleId string) error {
    47  	return self.DeleteSecurityGroupRule(secGrpRuleId)
    48  }
    49  
    50  func (self *SRegion) AddSecurityGroupRules(secGrpId string, rule cloudprovider.SecurityRule) error {
    51  	direction := ""
    52  	if rule.Direction == secrules.SecurityRuleIngress {
    53  		direction = "ingress"
    54  	} else {
    55  		direction = "egress"
    56  	}
    57  
    58  	protocal := rule.Protocol
    59  	if rule.Protocol == secrules.PROTO_ANY {
    60  		protocal = ""
    61  	}
    62  
    63  	// imcp协议默认为any
    64  	if rule.Protocol == secrules.PROTO_ICMP {
    65  		return self.addSecurityGroupRule(secGrpId, direction, "-1", "-1", protocal, rule.IPNet.String())
    66  	}
    67  
    68  	if len(rule.Ports) > 0 {
    69  		for _, port := range rule.Ports {
    70  			portStr := fmt.Sprintf("%d", port)
    71  			err := self.addSecurityGroupRule(secGrpId, direction, portStr, portStr, protocal, rule.IPNet.String())
    72  			if err != nil {
    73  				return err
    74  			}
    75  		}
    76  	} else {
    77  		portStart := fmt.Sprintf("%d", rule.PortStart)
    78  		portEnd := fmt.Sprintf("%d", rule.PortEnd)
    79  		err := self.addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocal, rule.IPNet.String())
    80  		if err != nil {
    81  			return err
    82  		}
    83  	}
    84  
    85  	return nil
    86  }
    87  
    88  func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error {
    89  	for _, r := range append(inDels, outDels...) {
    90  		err := self.region.delSecurityGroupRule(r.ExternalId)
    91  		if err != nil {
    92  			return errors.Wrapf(err, "delSecurityGroupRule(%s)", r.ExternalId)
    93  		}
    94  	}
    95  	for _, r := range append(inAdds, outAdds...) {
    96  		err := self.region.AddSecurityGroupRules(self.ResSecurityGroupID, r)
    97  		if err != nil {
    98  			return errors.Wrapf(err, "addSecurityGroupRule(%d %s)", r.Priority, r.String())
    99  		}
   100  	}
   101  	return nil
   102  }
   103  
   104  func (self *SSecurityGroup) Delete() error {
   105  	return self.region.DeleteSecurityGroup(self.GetId())
   106  }
   107  
   108  func (self *SSecurityGroup) GetId() string {
   109  	return self.ResSecurityGroupID
   110  }
   111  
   112  func (self *SSecurityGroup) GetName() string {
   113  	if len(self.Name) > 0 {
   114  		return self.Name
   115  	}
   116  	return self.ResSecurityGroupID
   117  }
   118  
   119  func (self *SSecurityGroup) GetGlobalId() string {
   120  	return self.GetId()
   121  }
   122  
   123  func (self *SSecurityGroup) GetStatus() string {
   124  	return ""
   125  }
   126  
   127  func (self *SSecurityGroup) Refresh() error {
   128  	if new, err := self.region.GetSecurityGroupDetails(self.GetId()); err != nil {
   129  		return err
   130  	} else {
   131  		return jsonutils.Update(self, new)
   132  	}
   133  }
   134  
   135  func (self *SSecurityGroup) IsEmulated() bool {
   136  	return false
   137  }
   138  
   139  func (self *SSecurityGroup) GetDescription() string {
   140  	return ""
   141  }
   142  
   143  // 判断是否兼容云端安全组规则
   144  func compatibleSecurityGroupRule(r SSecurityGroupRule) bool {
   145  	// 忽略了源地址是安全组的规则
   146  	if len(r.RemoteGroupId) > 0 {
   147  		return false
   148  	}
   149  
   150  	// 忽略IPV6
   151  	if r.Ethertype == "IPv6" {
   152  		return false
   153  	}
   154  
   155  	return true
   156  }
   157  
   158  func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) {
   159  	_rules, err := self.region.GetSecurityGroupRules(self.GetId())
   160  	if err != nil {
   161  		return nil, errors.Wrap(err, "SSecurityGroup.GetRules.GetSecurityGroupRules")
   162  	}
   163  
   164  	rules := make([]cloudprovider.SecurityRule, 0)
   165  	for _, r := range _rules {
   166  		if !compatibleSecurityGroupRule(r) {
   167  			continue
   168  		}
   169  
   170  		rule, err := self.GetSecurityRule(r)
   171  		if err != nil {
   172  			return rules, err
   173  		}
   174  
   175  		rules = append(rules, rule)
   176  	}
   177  
   178  	return rules, nil
   179  }
   180  
   181  func (self *SSecurityGroup) GetSecurityRule(remoteRule SSecurityGroupRule) (cloudprovider.SecurityRule, error) {
   182  	var err error
   183  	var direction secrules.TSecurityRuleDirection
   184  	if remoteRule.Direction == "ingress" {
   185  		direction = secrules.SecurityRuleIngress
   186  	} else {
   187  		direction = secrules.SecurityRuleEgress
   188  	}
   189  
   190  	protocol := secrules.PROTO_ANY
   191  	if remoteRule.Protocol != "" {
   192  		protocol = remoteRule.Protocol
   193  	}
   194  
   195  	var portStart int
   196  	var portEnd int
   197  	if protocol == secrules.PROTO_ICMP {
   198  		portStart = -1
   199  		portEnd = -1
   200  	} else {
   201  		portStart = int(remoteRule.PortRangeMin)
   202  		portEnd = int(remoteRule.PortRangeMax)
   203  	}
   204  
   205  	ipNet := &net.IPNet{}
   206  	if len(remoteRule.RemoteIPPrefix) > 0 {
   207  		_, ipNet, err = net.ParseCIDR(remoteRule.RemoteIPPrefix)
   208  	} else {
   209  		_, ipNet, err = net.ParseCIDR("0.0.0.0/0")
   210  	}
   211  
   212  	if err != nil {
   213  		return cloudprovider.SecurityRule{}, err
   214  	}
   215  
   216  	rule := cloudprovider.SecurityRule{
   217  		ExternalId: remoteRule.ID,
   218  		SecurityRule: secrules.SecurityRule{
   219  			Priority:    1,
   220  			Action:      secrules.SecurityRuleAllow,
   221  			IPNet:       ipNet,
   222  			Protocol:    protocol,
   223  			Direction:   direction,
   224  			PortStart:   portStart,
   225  			PortEnd:     portEnd,
   226  			Ports:       nil,
   227  			Description: remoteRule.Description,
   228  		},
   229  	}
   230  
   231  	err = rule.ValidateRule()
   232  	return rule, err
   233  }
   234  
   235  func (self *SSecurityGroup) GetVpcId() string {
   236  	return apis.NORMAL_VPC_ID
   237  }
   238  
   239  func (self *SRegion) GetSecurityGroupDetails(groupId string) (*SSecurityGroup, error) {
   240  	params := map[string]string{
   241  		"regionId":        self.GetId(),
   242  		"securityGroupId": groupId,
   243  	}
   244  
   245  	resp, err := self.client.DoGet("/apiproxy/v3/querySecurityGroupDetail", params)
   246  	if err != nil {
   247  		return nil, errors.Wrap(err, "SRegion.GetSecurityGroupDetails")
   248  	}
   249  
   250  	ret := &SSecurityGroup{}
   251  	err = resp.Unmarshal(&ret, "returnObj")
   252  	if err != nil {
   253  		return nil, errors.Wrap(err, "SRegion.GetSecurityGroupDetails.Unmarshal")
   254  	}
   255  
   256  	ret.region = self
   257  	return ret, nil
   258  }
   259  
   260  func (self *SRegion) GetSecurityGroups(vpcId string) ([]SSecurityGroup, error) {
   261  	params := map[string]string{
   262  		"regionId": self.GetId(),
   263  	}
   264  
   265  	if len(vpcId) > 0 {
   266  		params["vpcId"] = vpcId
   267  	}
   268  
   269  	resp, err := self.client.DoGet("/apiproxy/v3/getSecurityGroups", params)
   270  	if err != nil {
   271  		return nil, errors.Wrap(err, "SRegion.GetSecurityGroups")
   272  	}
   273  
   274  	ret := make([]SSecurityGroup, 0)
   275  	err = resp.Unmarshal(&ret, "returnObj")
   276  	if err != nil {
   277  		return nil, errors.Wrap(err, "SRegion.GetSecurityGroups.Unmarshal")
   278  	}
   279  
   280  	for i := range ret {
   281  		ret[i].region = self
   282  	}
   283  
   284  	return ret, nil
   285  }
   286  
   287  func (self *SRegion) CreateSecurityGroup(vpcId, name string) (*SSecurityGroup, error) {
   288  	params := map[string]jsonutils.JSONObject{
   289  		"regionId": jsonutils.NewString(self.GetId()),
   290  		"name":     jsonutils.NewString(name),
   291  	}
   292  
   293  	if len(vpcId) > 0 && vpcId != apis.NORMAL_VPC_ID {
   294  		params["vpcId"] = jsonutils.NewString(vpcId)
   295  	}
   296  
   297  	resp, err := self.client.DoPost("/apiproxy/v3/createSecurityGroup", params)
   298  	if err != nil {
   299  		return nil, errors.Wrap(err, "SRegion.CreateSecurityGroup.DoPost")
   300  	}
   301  
   302  	secgroupId, err := resp.GetString("returnObj", "id")
   303  	if err != nil {
   304  		return nil, errors.Wrap(err, "SRegion.CreateSecurityGroup.GetSecgroupId")
   305  	}
   306  
   307  	secgroup, err := self.GetSecurityGroupDetails(secgroupId)
   308  	if err != nil {
   309  		return nil, errors.Wrap(err, "SRegion.CreateSecurityGroup.GetISecurityGroupById")
   310  	}
   311  
   312  	secgroup.region = self
   313  	return secgroup, nil
   314  }
   315  
   316  func (self *SRegion) DeleteSecurityGroupRule(securityGroupRuleId string) error {
   317  	params := map[string]jsonutils.JSONObject{
   318  		"regionId":            jsonutils.NewString(self.GetId()),
   319  		"securityGroupRuleId": jsonutils.NewString(securityGroupRuleId),
   320  	}
   321  
   322  	_, err := self.client.DoPost("/apiproxy/v3/deleteSecurityGroupRule", params)
   323  	if err != nil {
   324  		return errors.Wrap(err, "SRegion.DeleteSecurityGroupRule.DoPost")
   325  	}
   326  
   327  	return err
   328  }
   329  
   330  func (self *SRegion) addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocol, ipNet string) error {
   331  	secgroupObj := jsonutils.NewDict()
   332  	secgroupObj.Add(jsonutils.NewString(self.GetId()), "regionId")
   333  	secgroupObj.Add(jsonutils.NewString(secGrpId), "securityGroupId")
   334  	secgroupObj.Add(jsonutils.NewString(direction), "direction")
   335  	secgroupObj.Add(jsonutils.NewString(ipNet), "remoteIpPrefix")
   336  	secgroupObj.Add(jsonutils.NewString("IPv4"), "ethertype")
   337  	// 端口为空或者1-65535
   338  	if len(portStart) > 0 && portStart != "0" && portStart != "-1" {
   339  		secgroupObj.Add(jsonutils.NewString(portStart), "portRangeMin")
   340  	}
   341  	if len(portEnd) > 0 && portEnd != "0" && portEnd != "-1" {
   342  		secgroupObj.Add(jsonutils.NewString(portEnd), "portRangeMax")
   343  	}
   344  	if len(protocol) > 0 {
   345  		secgroupObj.Add(jsonutils.NewString(protocol), "protocol")
   346  	}
   347  
   348  	params := map[string]jsonutils.JSONObject{
   349  		"jsonStr": secgroupObj,
   350  	}
   351  
   352  	resp, err := self.client.DoPost("/apiproxy/v3/createSecurityGroupRule", params)
   353  	if err != nil {
   354  		return errors.Wrap(err, "SRegion.DoPost")
   355  	}
   356  
   357  	rule := SSecurityGroupRule{}
   358  	err = resp.Unmarshal(&rule, "returnObj")
   359  	if err != nil {
   360  		return errors.Wrap(err, "SRegion.Unmarshal")
   361  	}
   362  
   363  	return nil
   364  }