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 }