yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/openstack/network.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 openstack 16 17 import ( 18 "fmt" 19 "net/url" 20 "strings" 21 "time" 22 23 "github.com/pkg/errors" 24 25 "yunion.io/x/jsonutils" 26 "yunion.io/x/log" 27 "yunion.io/x/pkg/util/netutils" 28 29 api "yunion.io/x/cloudmux/pkg/apis/compute" 30 "yunion.io/x/cloudmux/pkg/cloudprovider" 31 "yunion.io/x/cloudmux/pkg/multicloud" 32 "yunion.io/x/onecloud/pkg/util/rbacutils" 33 ) 34 35 type AllocationPool struct { 36 Start string `json:"start"` 37 End string `json:"end"` 38 } 39 40 func (p AllocationPool) IsValid() bool { 41 for _, ip := range []string{p.Start, p.End} { 42 _, err := netutils.NewIPV4Addr(ip) 43 if err != nil { 44 return false 45 } 46 } 47 return true 48 } 49 50 func (p AllocationPool) Equals(s AllocationPool) bool { 51 return p.Start == s.Start && p.End == s.End 52 } 53 54 func (p AllocationPool) Contains(ip string) bool { 55 start, err := netutils.NewIPV4Addr(p.Start) 56 if err != nil { 57 return false 58 } 59 end, err := netutils.NewIPV4Addr(p.End) 60 if err != nil { 61 return false 62 } 63 addr, err := netutils.NewIPV4Addr(ip) 64 if err != nil { 65 return false 66 } 67 return netutils.NewIPV4AddrRange(start, end).Contains(addr) 68 } 69 70 type SNextLinks []SNextLink 71 72 func (links SNextLinks) GetNextMark() string { 73 for _, link := range links { 74 if link.Rel == "next" && len(link.Href) > 0 { 75 href, err := url.Parse(link.Href) 76 if err != nil { 77 log.Errorf("failed parse next link %s error: %v", link.Href, err) 78 continue 79 } 80 marker := href.Query().Get("marker") 81 if len(marker) > 0 { 82 return marker 83 } 84 } 85 } 86 return "" 87 } 88 89 type SNextLink struct { 90 Href string 91 Rel string 92 } 93 94 type SNetwork struct { 95 multicloud.SResourceBase 96 OpenStackTags 97 wire *SWire 98 99 Name string 100 EnableDhcp bool 101 NetworkId string 102 SegmentId string 103 ProjectId string 104 TenantId string 105 DnsNameservers []string 106 AllocationPools []AllocationPool 107 HostRoutes []string 108 IpVersion int 109 GatewayIP string 110 CIDR string 111 Id string 112 CreatedAt time.Time 113 Description string 114 Ipv6AddressMode string 115 Ipv6RaMode string 116 RevisionNumber int 117 ServiceTypes []string 118 SubnetpoolId string 119 Tags []string 120 UpdatedAt time.Time 121 } 122 123 func (network *SNetwork) GetId() string { 124 return network.Id 125 } 126 127 func (network *SNetwork) GetName() string { 128 if len(network.Name) > 0 { 129 return network.Name 130 } 131 return network.Id 132 } 133 134 func (network *SNetwork) GetGlobalId() string { 135 if len(network.AllocationPools) > 0 { 136 return fmt.Sprintf("%s|%s-%s", network.Id, network.AllocationPools[0].Start, network.AllocationPools[0].End) 137 } 138 return network.Id 139 } 140 141 func (network *SNetwork) IsEmulated() bool { 142 return false 143 } 144 145 func (network *SNetwork) GetStatus() string { 146 return api.NETWORK_STATUS_AVAILABLE 147 } 148 149 func (network *SNetwork) Delete() error { 150 nw, err := network.wire.vpc.region.GetNetwork(network.Id) 151 if err != nil { 152 return errors.Wrapf(err, "GetNetwork(%s)", network.Id) 153 } 154 if len(nw.AllocationPools) <= 1 || len(network.AllocationPools) == 0 { 155 return network.wire.vpc.region.DeleteNetwork(network.Id) 156 } 157 pools := []AllocationPool{} 158 for i := range nw.AllocationPools { 159 if nw.AllocationPools[i].Equals(network.AllocationPools[0]) { 160 continue 161 } 162 pools = append(pools, nw.AllocationPools[i]) 163 } 164 165 params := map[string]interface{}{ 166 "subnet": map[string]interface{}{ 167 "allocation_pools": pools, 168 }, 169 } 170 resource := fmt.Sprintf("/v2.0/subnets/%s", network.Id) 171 _, err = network.wire.vpc.region.vpcUpdate(resource, jsonutils.Marshal(params)) 172 return err 173 } 174 175 func (region *SRegion) DeleteNetwork(networkId string) error { 176 resource := fmt.Sprintf("/v2.0/subnets/%s", networkId) 177 _, err := region.vpcDelete(resource) 178 return err 179 } 180 181 func (network *SNetwork) GetIWire() cloudprovider.ICloudWire { 182 return network.wire 183 } 184 185 func (network *SNetwork) GetAllocTimeoutSeconds() int { 186 return 120 // 2 minutes 187 } 188 189 func (network *SNetwork) GetGateway() string { 190 return network.GatewayIP 191 } 192 193 func (network *SNetwork) GetIpStart() string { 194 if len(network.AllocationPools) >= 1 { 195 return network.AllocationPools[0].Start 196 } 197 return "" 198 } 199 200 func (network *SNetwork) GetIpEnd() string { 201 if len(network.AllocationPools) >= 1 { 202 return network.AllocationPools[0].End 203 } 204 return "" 205 } 206 207 func (network *SNetwork) GetIPRange() netutils.IPV4AddrRange { 208 start, _ := netutils.NewIPV4Addr(network.GetIpStart()) 209 end, _ := netutils.NewIPV4Addr(network.GetIpEnd()) 210 return netutils.NewIPV4AddrRange(start, end) 211 } 212 213 func (network *SNetwork) Contains(ipAddr string) bool { 214 for _, pool := range network.AllocationPools { 215 if pool.Contains(ipAddr) { 216 return true 217 } 218 } 219 return false 220 } 221 222 func (network *SNetwork) GetIpMask() int8 { 223 pref, _ := netutils.NewIPV4Prefix(network.CIDR) 224 return pref.MaskLen 225 } 226 227 func (network *SNetwork) GetIsPublic() bool { 228 return network.wire.vpc.Shared 229 } 230 231 func (network *SNetwork) GetPublicScope() rbacutils.TRbacScope { 232 if network.wire.vpc.Shared { 233 return rbacutils.ScopeSystem 234 } 235 return rbacutils.ScopeNone 236 } 237 238 func (network *SNetwork) GetServerType() string { 239 return api.NETWORK_TYPE_GUEST 240 } 241 242 func getNetworkId(networkId string) (AllocationPool, string) { 243 pool := AllocationPool{} 244 if !strings.Contains(networkId, "|") { 245 return pool, networkId 246 } 247 info := strings.Split(networkId, "|") 248 networkId = info[0] 249 ipInfo := strings.Split(info[1], "-") 250 pool.Start, pool.End = ipInfo[0], ipInfo[1] 251 return pool, networkId 252 } 253 254 func (region *SRegion) GetNetwork(networkId string) (*SNetwork, error) { 255 var pool AllocationPool 256 pool, networkId = getNetworkId(networkId) 257 resource := fmt.Sprintf("/v2.0/subnets/%s", networkId) 258 resp, err := region.vpcGet(resource) 259 if err != nil { 260 return nil, err 261 } 262 network := &SNetwork{} 263 err = resp.Unmarshal(network, "subnet") 264 if err != nil { 265 return nil, err 266 } 267 if len(pool.Start) == 0 && len(pool.End) == 0 { 268 return network, nil 269 } 270 for _, _pool := range network.AllocationPools { 271 if _pool.Equals(pool) { 272 network.AllocationPools = []AllocationPool{pool} 273 return network, nil 274 } 275 } 276 return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s", networkId) 277 } 278 279 func (region *SRegion) GetNetworks(vpcId string) ([]SNetwork, error) { 280 resource := "/v2.0/subnets" 281 networks := []SNetwork{} 282 query := url.Values{} 283 if len(vpcId) > 0 { 284 query.Set("network_id", vpcId) 285 } 286 for { 287 resp, err := region.vpcList(resource, query) 288 if err != nil { 289 return nil, errors.Wrap(err, "vpcList") 290 } 291 292 part := struct { 293 Subnets []SNetwork 294 SubnetsLinks SNextLinks 295 }{} 296 297 err = resp.Unmarshal(&part) 298 if err != nil { 299 return nil, errors.Wrap(err, "resp.Unmarshal") 300 } 301 302 networks = append(networks, part.Subnets...) 303 marker := part.SubnetsLinks.GetNextMark() 304 if len(marker) == 0 { 305 break 306 } 307 query.Set("marker", marker) 308 } 309 return networks, nil 310 } 311 312 func (network *SNetwork) Refresh() error { 313 _network, err := network.wire.vpc.region.GetNetwork(network.Id) 314 if err != nil { 315 return err 316 } 317 return jsonutils.Update(network, _network) 318 } 319 320 func (region *SRegion) CreateNetwork(vpcId string, projectId, name string, cidr string, desc string) (*SNetwork, error) { 321 params := map[string]map[string]interface{}{ 322 "subnet": { 323 "name": name, 324 "network_id": vpcId, 325 "cidr": cidr, 326 "description": desc, 327 "ip_version": 4, 328 }, 329 } 330 if len(projectId) > 0 { 331 params["subnet"]["project_id"] = projectId 332 } 333 resp, err := region.vpcPost("/v2.0/subnets", params) 334 if err != nil { 335 return nil, errors.Wrap(err, "vpcPost") 336 } 337 network := &SNetwork{} 338 err = resp.Unmarshal(network, "subnet") 339 if err != nil { 340 return nil, errors.Wrap(err, "resp.Unmarshal") 341 } 342 return network, nil 343 } 344 345 func (network *SNetwork) GetProjectId() string { 346 return network.TenantId 347 }