yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/ucloud/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 ucloud 16 17 import ( 18 "fmt" 19 "math/rand" 20 "strings" 21 "time" 22 23 "yunion.io/x/jsonutils" 24 "yunion.io/x/log" 25 "yunion.io/x/pkg/errors" 26 "yunion.io/x/pkg/util/secrules" 27 28 api "yunion.io/x/cloudmux/pkg/apis/compute" 29 "yunion.io/x/cloudmux/pkg/cloudprovider" 30 "yunion.io/x/cloudmux/pkg/multicloud" 31 ) 32 33 // https://docs.ucloud.cn/api/unet-api/describe_firewall 34 type SSecurityGroup struct { 35 multicloud.SSecurityGroup 36 UcloudTags 37 region *SRegion 38 vpc *SVPC // 安全组在UCLOUD实际上与VPC是没有直接关联的。这里的vpc字段只是为了统一,仅仅是标记是哪个VPC在操作该安全组。 39 40 CreateTime int64 `json:"CreateTime"` 41 FWID string `json:"FWId"` 42 GroupID string `json:"GroupId"` 43 Name string `json:"Name"` 44 Remark string `json:"Remark"` 45 ResourceCount int `json:"ResourceCount"` 46 Rule []Rule `json:"Rule"` 47 Tag string `json:"Tag"` 48 Type string `json:"Type"` 49 } 50 51 func (self *SSecurityGroup) GetProjectId() string { 52 return self.region.client.projectId 53 } 54 55 type Rule struct { 56 DstPort string `json:"DstPort"` 57 Priority string `json:"Priority"` 58 ProtocolType string `json:"ProtocolType"` 59 RuleAction string `json:"RuleAction"` 60 SrcIP string `json:"SrcIP"` 61 } 62 63 func (self *SSecurityGroup) GetId() string { 64 return self.FWID 65 } 66 67 func (self *SSecurityGroup) GetName() string { 68 if len(self.Name) == 0 { 69 return self.GetId() 70 } 71 72 return self.Name 73 } 74 75 func (self *SSecurityGroup) GetGlobalId() string { 76 return self.GetId() 77 } 78 79 func (self *SSecurityGroup) GetStatus() string { 80 return "" 81 } 82 83 func (self *SSecurityGroup) Refresh() error { 84 if new, err := self.region.GetSecurityGroupById(self.GetId()); err != nil { 85 return err 86 } else { 87 return jsonutils.Update(self, new) 88 } 89 } 90 91 func (self *SSecurityGroup) IsEmulated() bool { 92 return false 93 } 94 95 func (self *SSecurityGroup) GetDescription() string { 96 return self.Remark 97 } 98 99 func (self *SSecurityGroup) UcloudSecRuleToOnecloud(rule Rule) (cloudprovider.SecurityRule, error) { 100 secrule := cloudprovider.SecurityRule{} 101 switch rule.Priority { 102 case "HIGH": 103 secrule.Priority = 3 104 case "MEDIUM": 105 secrule.Priority = 2 106 case "LOW": 107 secrule.Priority = 1 108 default: 109 secrule.Priority = 1 110 } 111 112 switch rule.RuleAction { 113 case "ACCEPT": 114 secrule.Action = secrules.SecurityRuleAllow 115 case "DROP": 116 secrule.Action = secrules.SecurityRuleDeny 117 default: 118 secrule.Action = secrules.SecurityRuleDeny 119 } 120 121 secrule.ParseCIDR(rule.SrcIP) 122 secrule.Protocol = strings.ToLower(rule.ProtocolType) 123 secrule.Direction = secrules.SecurityRuleIngress 124 err := secrule.ParsePorts(rule.DstPort) 125 if err != nil { 126 return secrule, errors.Wrapf(err, "ParsePorts(%s)", rule.DstPort) 127 } 128 129 return secrule, nil 130 } 131 132 // https://docs.ucloud.cn/network/firewall/firewall 133 // 只有入方向规则 134 func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { 135 rules := make([]cloudprovider.SecurityRule, 0) 136 for _, r := range self.Rule { 137 rule, err := self.UcloudSecRuleToOnecloud(r) 138 if err != nil { 139 log.Errorf("failed to convert rule for group %s(%s) error: %v", self.Name, self.GroupID, err) 140 continue 141 } 142 rules = append(rules, rule) 143 } 144 145 return rules, nil 146 } 147 148 func (self *SSecurityGroup) GetVpcId() string { 149 // 无vpc关联的安全组统一返回normal 150 return api.NORMAL_VPC_ID 151 } 152 153 func (self *SRegion) GetSecurityGroupById(secGroupId string) (*SSecurityGroup, error) { 154 secgroups, err := self.GetSecurityGroups(secGroupId, "", "") 155 if err != nil { 156 return nil, err 157 } 158 159 if len(secgroups) == 1 { 160 return &secgroups[0], nil 161 } else if len(secgroups) == 0 { 162 return nil, cloudprovider.ErrNotFound 163 } else { 164 return nil, fmt.Errorf("GetSecurityGroupById %s %d found", secGroupId, len(secgroups)) 165 } 166 } 167 168 func randomString(prefix string, length int) string { 169 bytes := []byte("0123456789abcdefghijklmnopqrstuvwxyz") 170 result := []byte{} 171 r := rand.New(rand.NewSource(time.Now().UnixNano())) 172 for i := 0; i < length; i++ { 173 result = append(result, bytes[r.Intn(len(bytes))]) 174 } 175 return prefix + string(result) 176 } 177 178 func (self *SRegion) CreateDefaultSecurityGroup(name, description string) (string, error) { 179 // 减少安全组名称冲突 180 name = randomString(name, 4) 181 return self.CreateSecurityGroup(name, description, []string{"TCP|1-65535|0.0.0.0/0|ACCEPT|LOW", "UDP|1-65535|0.0.0.0/0|ACCEPT|LOW", "ICMP||0.0.0.0/0|ACCEPT|LOW"}) 182 } 183 184 // https://docs.ucloud.cn/api/unet-api/create_firewall 185 func (self *SRegion) CreateSecurityGroup(name, description string, rules []string) (string, error) { 186 params := NewUcloudParams() 187 params.Set("Name", name) 188 params.Set("Remark", description) 189 if len(rules) == 0 { 190 return "", fmt.Errorf("CreateSecurityGroup required at least one rule") 191 } 192 193 for i, rule := range rules { 194 params.Set(fmt.Sprintf("Rule.%d", i), rule) 195 } 196 197 type Firewall struct { 198 FWId string 199 } 200 201 firewall := Firewall{} 202 err := self.DoAction("CreateFirewall", params, &firewall) 203 if err != nil { 204 return "", err 205 } 206 207 return firewall.FWId, nil 208 } 209 210 // https://docs.ucloud.cn/api/unet-api/describe_firewall 211 func (self *SRegion) GetSecurityGroups(secGroupId string, resourceId string, name string) ([]SSecurityGroup, error) { 212 secgroups := make([]SSecurityGroup, 0) 213 214 params := NewUcloudParams() 215 if len(secGroupId) > 0 { 216 params.Set("FWId", secGroupId) 217 } 218 219 if len(resourceId) > 0 { 220 params.Set("ResourceId", resourceId) 221 params.Set("ResourceType", "uhost") // 默认只支持"uhost",云主机 222 } 223 err := self.DoListAll("DescribeFirewall", params, &secgroups) 224 if err != nil { 225 if strings.Contains(err.Error(), "not exist") { 226 return nil, cloudprovider.ErrNotFound 227 } 228 return nil, err 229 } 230 231 result := []SSecurityGroup{} 232 233 for i := range secgroups { 234 if len(name) == 0 || secgroups[i].Name == name { 235 secgroups[i].region = self 236 result = append(result, secgroups[i]) 237 } 238 } 239 240 return result, nil 241 } 242 243 func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { 244 if len(inAdds) == 0 && len(inDels) == 0 { 245 return nil 246 } 247 rules := append(common, inAdds...) 248 return self.region.syncSecgroupRules(self.FWID, rules) 249 } 250 251 func (self *SSecurityGroup) Delete() error { 252 return self.region.DeleteSecurityGroup(self.FWID) 253 }