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 }