mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-05-23 21:11:02 +08:00
348 lines
8.0 KiB
Go
348 lines
8.0 KiB
Go
// Copyright 2019 Yunion
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package openstack
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"yunion.io/x/jsonutils"
|
|
"yunion.io/x/log"
|
|
"yunion.io/x/pkg/util/netutils"
|
|
|
|
api "yunion.io/x/onecloud/pkg/apis/compute"
|
|
"yunion.io/x/onecloud/pkg/cloudprovider"
|
|
"yunion.io/x/onecloud/pkg/multicloud"
|
|
"yunion.io/x/onecloud/pkg/util/rbacutils"
|
|
)
|
|
|
|
type AllocationPool struct {
|
|
Start string `json:"start"`
|
|
End string `json:"end"`
|
|
}
|
|
|
|
func (p AllocationPool) IsValid() bool {
|
|
for _, ip := range []string{p.Start, p.End} {
|
|
_, err := netutils.NewIPV4Addr(ip)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (p AllocationPool) Equals(s AllocationPool) bool {
|
|
return p.Start == s.Start && p.End == s.End
|
|
}
|
|
|
|
func (p AllocationPool) Contains(ip string) bool {
|
|
start, err := netutils.NewIPV4Addr(p.Start)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
end, err := netutils.NewIPV4Addr(p.End)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
addr, err := netutils.NewIPV4Addr(ip)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return netutils.NewIPV4AddrRange(start, end).Contains(addr)
|
|
}
|
|
|
|
type SNextLinks []SNextLink
|
|
|
|
func (links SNextLinks) GetNextMark() string {
|
|
for _, link := range links {
|
|
if link.Rel == "next" && len(link.Href) > 0 {
|
|
href, err := url.Parse(link.Href)
|
|
if err != nil {
|
|
log.Errorf("failed parse next link %s error: %v", link.Href, err)
|
|
continue
|
|
}
|
|
marker := href.Query().Get("marker")
|
|
if len(marker) > 0 {
|
|
return marker
|
|
}
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
type SNextLink struct {
|
|
Href string
|
|
Rel string
|
|
}
|
|
|
|
type SNetwork struct {
|
|
multicloud.SResourceBase
|
|
multicloud.OpenStackTags
|
|
wire *SWire
|
|
|
|
Name string
|
|
EnableDhcp bool
|
|
NetworkId string
|
|
SegmentId string
|
|
ProjectId string
|
|
TenantId string
|
|
DnsNameservers []string
|
|
AllocationPools []AllocationPool
|
|
HostRoutes []string
|
|
IpVersion int
|
|
GatewayIP string
|
|
CIDR string
|
|
Id string
|
|
CreatedAt time.Time
|
|
Description string
|
|
Ipv6AddressMode string
|
|
Ipv6RaMode string
|
|
RevisionNumber int
|
|
ServiceTypes []string
|
|
SubnetpoolId string
|
|
Tags []string
|
|
UpdatedAt time.Time
|
|
}
|
|
|
|
func (network *SNetwork) GetId() string {
|
|
return network.Id
|
|
}
|
|
|
|
func (network *SNetwork) GetName() string {
|
|
if len(network.Name) > 0 {
|
|
return network.Name
|
|
}
|
|
return network.Id
|
|
}
|
|
|
|
func (network *SNetwork) GetGlobalId() string {
|
|
if len(network.AllocationPools) > 0 {
|
|
return fmt.Sprintf("%s|%s-%s", network.Id, network.AllocationPools[0].Start, network.AllocationPools[0].End)
|
|
}
|
|
return network.Id
|
|
}
|
|
|
|
func (network *SNetwork) IsEmulated() bool {
|
|
return false
|
|
}
|
|
|
|
func (network *SNetwork) GetStatus() string {
|
|
return api.NETWORK_STATUS_AVAILABLE
|
|
}
|
|
|
|
func (network *SNetwork) Delete() error {
|
|
nw, err := network.wire.vpc.region.GetNetwork(network.Id)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "GetNetwork(%s)", network.Id)
|
|
}
|
|
if len(nw.AllocationPools) <= 1 || len(network.AllocationPools) == 0 {
|
|
return network.wire.vpc.region.DeleteNetwork(network.Id)
|
|
}
|
|
pools := []AllocationPool{}
|
|
for i := range nw.AllocationPools {
|
|
if nw.AllocationPools[i].Equals(network.AllocationPools[0]) {
|
|
continue
|
|
}
|
|
pools = append(pools, nw.AllocationPools[i])
|
|
}
|
|
|
|
params := map[string]interface{}{
|
|
"subnet": map[string]interface{}{
|
|
"allocation_pools": pools,
|
|
},
|
|
}
|
|
resource := fmt.Sprintf("/v2.0/subnets/%s", network.Id)
|
|
_, err = network.wire.vpc.region.vpcUpdate(resource, jsonutils.Marshal(params))
|
|
return err
|
|
}
|
|
|
|
func (region *SRegion) DeleteNetwork(networkId string) error {
|
|
resource := fmt.Sprintf("/v2.0/subnets/%s", networkId)
|
|
_, err := region.vpcDelete(resource)
|
|
return err
|
|
}
|
|
|
|
func (network *SNetwork) GetIWire() cloudprovider.ICloudWire {
|
|
return network.wire
|
|
}
|
|
|
|
func (network *SNetwork) GetAllocTimeoutSeconds() int {
|
|
return 120 // 2 minutes
|
|
}
|
|
|
|
func (network *SNetwork) GetGateway() string {
|
|
return network.GatewayIP
|
|
}
|
|
|
|
func (network *SNetwork) GetIpStart() string {
|
|
if len(network.AllocationPools) >= 1 {
|
|
return network.AllocationPools[0].Start
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (network *SNetwork) GetIpEnd() string {
|
|
if len(network.AllocationPools) >= 1 {
|
|
return network.AllocationPools[0].End
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (network *SNetwork) GetIPRange() netutils.IPV4AddrRange {
|
|
start, _ := netutils.NewIPV4Addr(network.GetIpStart())
|
|
end, _ := netutils.NewIPV4Addr(network.GetIpEnd())
|
|
return netutils.NewIPV4AddrRange(start, end)
|
|
}
|
|
|
|
func (network *SNetwork) Contains(ipAddr string) bool {
|
|
for _, pool := range network.AllocationPools {
|
|
if pool.Contains(ipAddr) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (network *SNetwork) GetIpMask() int8 {
|
|
pref, _ := netutils.NewIPV4Prefix(network.CIDR)
|
|
return pref.MaskLen
|
|
}
|
|
|
|
func (network *SNetwork) GetIsPublic() bool {
|
|
return network.wire.vpc.Shared
|
|
}
|
|
|
|
func (network *SNetwork) GetPublicScope() rbacutils.TRbacScope {
|
|
if network.wire.vpc.Shared {
|
|
return rbacutils.ScopeSystem
|
|
}
|
|
return rbacutils.ScopeNone
|
|
}
|
|
|
|
func (network *SNetwork) GetServerType() string {
|
|
return api.NETWORK_TYPE_GUEST
|
|
}
|
|
|
|
func getNetworkId(networkId string) (AllocationPool, string) {
|
|
pool := AllocationPool{}
|
|
if !strings.Contains(networkId, "|") {
|
|
return pool, networkId
|
|
}
|
|
info := strings.Split(networkId, "|")
|
|
networkId = info[0]
|
|
ipInfo := strings.Split(info[1], "-")
|
|
pool.Start, pool.End = ipInfo[0], ipInfo[1]
|
|
return pool, networkId
|
|
}
|
|
|
|
func (region *SRegion) GetNetwork(networkId string) (*SNetwork, error) {
|
|
var pool AllocationPool
|
|
pool, networkId = getNetworkId(networkId)
|
|
resource := fmt.Sprintf("/v2.0/subnets/%s", networkId)
|
|
resp, err := region.vpcGet(resource)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
network := &SNetwork{}
|
|
err = resp.Unmarshal(network, "subnet")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(pool.Start) == 0 && len(pool.End) == 0 {
|
|
return network, nil
|
|
}
|
|
for _, _pool := range network.AllocationPools {
|
|
if _pool.Equals(pool) {
|
|
network.AllocationPools = []AllocationPool{pool}
|
|
return network, nil
|
|
}
|
|
}
|
|
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s", networkId)
|
|
}
|
|
|
|
func (region *SRegion) GetNetworks(vpcId string) ([]SNetwork, error) {
|
|
resource := "/v2.0/subnets"
|
|
networks := []SNetwork{}
|
|
query := url.Values{}
|
|
if len(vpcId) > 0 {
|
|
query.Set("network_id", vpcId)
|
|
}
|
|
for {
|
|
resp, err := region.vpcList(resource, query)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "vpcList")
|
|
}
|
|
|
|
part := struct {
|
|
Subnets []SNetwork
|
|
SubnetsLinks SNextLinks
|
|
}{}
|
|
|
|
err = resp.Unmarshal(&part)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "resp.Unmarshal")
|
|
}
|
|
|
|
networks = append(networks, part.Subnets...)
|
|
marker := part.SubnetsLinks.GetNextMark()
|
|
if len(marker) == 0 {
|
|
break
|
|
}
|
|
query.Set("marker", marker)
|
|
}
|
|
return networks, nil
|
|
}
|
|
|
|
func (network *SNetwork) Refresh() error {
|
|
_network, err := network.wire.vpc.region.GetNetwork(network.Id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return jsonutils.Update(network, _network)
|
|
}
|
|
|
|
func (region *SRegion) CreateNetwork(vpcId string, projectId, name string, cidr string, desc string) (*SNetwork, error) {
|
|
params := map[string]map[string]interface{}{
|
|
"subnet": {
|
|
"name": name,
|
|
"network_id": vpcId,
|
|
"cidr": cidr,
|
|
"description": desc,
|
|
"ip_version": 4,
|
|
},
|
|
}
|
|
if len(projectId) > 0 {
|
|
params["subnet"]["project_id"] = projectId
|
|
}
|
|
resp, err := region.vpcPost("/v2.0/subnets", params)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "vpcPost")
|
|
}
|
|
network := &SNetwork{}
|
|
err = resp.Unmarshal(network, "subnet")
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "resp.Unmarshal")
|
|
}
|
|
return network, nil
|
|
}
|
|
|
|
func (network *SNetwork) GetProjectId() string {
|
|
return network.TenantId
|
|
}
|