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 }