yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/zstack/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 zstack 16 17 import ( 18 "fmt" 19 "net/url" 20 "strings" 21 22 "yunion.io/x/jsonutils" 23 "yunion.io/x/pkg/errors" 24 "yunion.io/x/pkg/util/secrules" 25 26 api "yunion.io/x/cloudmux/pkg/apis/compute" 27 "yunion.io/x/cloudmux/pkg/cloudprovider" 28 "yunion.io/x/cloudmux/pkg/multicloud" 29 ) 30 31 type SSecurityGroupRule struct { 32 ZStackBasic 33 SecurityGroupUUID string `json:"securityGroupUuid"` 34 Type string `json:"type"` 35 IPVersion int `json:"ipVersion"` 36 StartPort int `json:"startPort"` 37 EndPort int `json:"endPort"` 38 Protocol string `json:"protocol"` 39 State string `json:"state"` 40 AllowedCIDR string `json:"allowedCidr"` 41 RemoteSecurityGroupUUID string `json:"remoteSecurityGroupUuid"` 42 ZStackTime 43 } 44 45 type SSecurityGroup struct { 46 multicloud.SSecurityGroup 47 ZStackTags 48 region *SRegion 49 50 ZStackBasic 51 State string `json:"state"` 52 IPVersion int `json:"ipVersion"` 53 ZStackTime 54 InternalID int `json:"internalId"` 55 Rules []SSecurityGroupRule `json:"rules"` 56 AttachedL3NetworkUUIDs []string `json:"attachedL3NetworkUuids"` 57 } 58 59 func (region *SRegion) GetSecurityGroup(secgroupId string) (*SSecurityGroup, error) { 60 secgroup := &SSecurityGroup{region: region} 61 return secgroup, region.client.getResource("security-groups", secgroupId, secgroup) 62 } 63 64 func (region *SRegion) GetSecurityGroups(secgroupId string, instanceId string, name string) ([]SSecurityGroup, error) { 65 secgroups := []SSecurityGroup{} 66 params := url.Values{} 67 if len(secgroupId) > 0 { 68 params.Add("q", "uuid="+secgroupId) 69 } 70 if len(instanceId) > 0 { 71 params.Add("q", "vmNic.vmInstanceUuid="+instanceId) 72 } 73 if len(name) > 0 { 74 params.Add("q", "name="+name) 75 } 76 err := region.client.listAll("security-groups", params, &secgroups) 77 if err != nil { 78 return nil, err 79 } 80 for i := 0; i < len(secgroups); i++ { 81 secgroups[i].region = region 82 } 83 return secgroups, nil 84 } 85 86 func (self *SSecurityGroup) GetVpcId() string { 87 return api.NORMAL_VPC_ID 88 } 89 90 func (self *SSecurityGroup) GetId() string { 91 return self.UUID 92 } 93 94 func (self *SSecurityGroup) GetGlobalId() string { 95 return self.UUID 96 } 97 98 func (self *SSecurityGroup) GetDescription() string { 99 return self.Description 100 } 101 102 func (rule *SSecurityGroupRule) toRule() (cloudprovider.SecurityRule, error) { 103 r := cloudprovider.SecurityRule{ 104 ExternalId: rule.UUID, 105 SecurityRule: secrules.SecurityRule{ 106 Direction: secrules.DIR_IN, 107 Action: secrules.SecurityRuleAllow, 108 Priority: 1, 109 Protocol: secrules.PROTO_ANY, 110 PortStart: rule.StartPort, 111 PortEnd: rule.EndPort, 112 }, 113 } 114 r.ParseCIDR(rule.AllowedCIDR) 115 if rule.Type == "Egress" { 116 r.Direction = secrules.DIR_OUT 117 } 118 if rule.Protocol != "ALL" { 119 r.Protocol = strings.ToLower(rule.Protocol) 120 } 121 err := r.ValidateRule() 122 if err != nil { 123 return r, errors.Wrap(err, "invalid rule") 124 } 125 return r, nil 126 } 127 128 func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { 129 rules := []cloudprovider.SecurityRule{} 130 for i := 0; i < len(self.Rules); i++ { 131 if self.Rules[i].IPVersion == 4 { 132 rule, err := self.Rules[i].toRule() 133 if err != nil { 134 return nil, err 135 } 136 rules = append(rules, rule) 137 } 138 } 139 return rules, nil 140 } 141 142 func (self *SSecurityGroup) GetName() string { 143 return self.Name 144 } 145 146 func (self *SSecurityGroup) GetStatus() string { 147 return "" 148 } 149 150 func (self *SSecurityGroup) IsEmulated() bool { 151 return false 152 } 153 154 func (self *SSecurityGroup) Refresh() error { 155 new, err := self.region.GetSecurityGroup(self.UUID) 156 if err != nil { 157 return err 158 } 159 return jsonutils.Update(self, new) 160 } 161 162 func (self *SSecurityGroup) GetProjectId() string { 163 return "" 164 } 165 166 func (region *SRegion) AddSecurityGroupRule(secgroupId string, rules []cloudprovider.SecurityRule) error { 167 ruleParam := []map[string]interface{}{} 168 for _, rule := range rules { 169 Type := "Ingress" 170 if rule.Direction == secrules.DIR_OUT { 171 Type = "Egress" 172 } 173 protocol := "ALL" 174 if rule.Protocol != secrules.PROTO_ANY { 175 protocol = strings.ToUpper(rule.Protocol) 176 } 177 if rule.Protocol == secrules.PROTO_ICMP || rule.Protocol == secrules.PROTO_ANY { 178 rule.PortStart = -1 179 rule.PortEnd = -1 180 rule.Ports = []int{} 181 } 182 if len(rule.Ports) > 0 { 183 for _, port := range rule.Ports { 184 ruleParam = append(ruleParam, map[string]interface{}{ 185 "type": Type, 186 "startPort": port, 187 "endPort": port, 188 "protocol": protocol, 189 "allowedCidr": rule.IPNet.String(), 190 }) 191 } 192 } else { 193 if protocol != "ALL" { 194 // TCP UDP端口不能为-1 195 if (rule.Protocol == secrules.PROTO_TCP || rule.Protocol == secrules.PROTO_UDP) && 196 (rule.PortStart <= 0 && rule.PortEnd <= 0) { 197 rule.PortStart = 0 198 rule.PortEnd = 65535 199 } 200 ruleParam = append(ruleParam, map[string]interface{}{ 201 "type": Type, 202 "startPort": rule.PortStart, 203 "endPort": rule.PortEnd, 204 "protocol": protocol, 205 "allowedCidr": rule.IPNet.String(), 206 }) 207 } else { 208 ruleParam = append(ruleParam, map[string]interface{}{ 209 "type": Type, 210 "protocol": protocol, 211 "allowedCidr": rule.IPNet.String(), 212 }) 213 } 214 } 215 } 216 if len(ruleParam) > 0 { 217 params := map[string]interface{}{ 218 "params": map[string]interface{}{ 219 "rules": ruleParam, 220 }, 221 } 222 return region.client.create(fmt.Sprintf("security-groups/%s/rules", secgroupId), jsonutils.Marshal(params), nil) 223 } 224 return nil 225 } 226 227 func (region *SRegion) DeleteSecurityGroupRules(ruleIds []string) error { 228 if len(ruleIds) > 0 { 229 ids := []string{} 230 for _, ruleId := range ruleIds { 231 ids = append(ids, fmt.Sprintf("ruleUuids=%s", ruleId)) 232 } 233 resource := fmt.Sprintf("security-groups/rules?%s", strings.Join(ids, "&")) 234 return region.client.delete(resource, "", "") 235 } 236 return nil 237 } 238 239 func (region *SRegion) CreateSecurityGroup(name, desc string) (*SSecurityGroup, error) { 240 secgroup := &SSecurityGroup{region: region} 241 params := map[string]map[string]string{ 242 "params": { 243 "name": name, 244 "description": desc, 245 }, 246 } 247 return secgroup, region.client.create("security-groups", jsonutils.Marshal(params), secgroup) 248 } 249 250 func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { 251 deleteIds := []string{} 252 for _, r := range append(inDels, outDels...) { 253 deleteIds = append(deleteIds, r.ExternalId) 254 } 255 err := self.region.DeleteSecurityGroupRules(deleteIds) 256 if err != nil { 257 return errors.Wrapf(err, "DeleteSecurityGroupRules(%s)", deleteIds) 258 } 259 return self.region.AddSecurityGroupRule(self.UUID, append(inAdds, outAdds...)) 260 } 261 262 func (self *SSecurityGroup) Delete() error { 263 return self.region.client.delete("security-groups", self.UUID, "Permissive") 264 }