yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/hcso/wire.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 import ( 18 "fmt" 19 "strings" 20 "time" 21 22 "yunion.io/x/jsonutils" 23 "yunion.io/x/log" 24 "yunion.io/x/pkg/errors" 25 "yunion.io/x/pkg/util/netutils" 26 27 api "yunion.io/x/cloudmux/pkg/apis/compute" 28 "yunion.io/x/cloudmux/pkg/cloudprovider" 29 "yunion.io/x/cloudmux/pkg/multicloud" 30 "yunion.io/x/cloudmux/pkg/multicloud/huawei" 31 ) 32 33 // 华为云的子网有点特殊。子网在整个region可用。 34 type SWire struct { 35 multicloud.SResourceBase 36 huawei.HuaweiTags 37 region *SRegion 38 vpc *SVpc 39 40 inetworks []cloudprovider.ICloudNetwork 41 } 42 43 func (self *SWire) GetId() string { 44 return fmt.Sprintf("%s-%s", self.vpc.GetId(), self.region.GetId()) 45 } 46 47 func (self *SWire) GetName() string { 48 return self.GetId() 49 } 50 51 func (self *SWire) GetGlobalId() string { 52 return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.region.GetGlobalId()) 53 } 54 55 func (self *SWire) GetStatus() string { 56 return api.WIRE_STATUS_AVAILABLE 57 } 58 59 func (self *SWire) Refresh() error { 60 return nil 61 } 62 63 func (self *SWire) IsEmulated() bool { 64 return true 65 } 66 67 func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { 68 return self.vpc 69 } 70 71 func (self *SWire) GetIZone() cloudprovider.ICloudZone { 72 return nil 73 } 74 75 func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { 76 if self.inetworks == nil { 77 err := self.vpc.fetchNetworks() 78 if err != nil { 79 return nil, err 80 } 81 } 82 return self.inetworks, nil 83 } 84 85 func (self *SWire) GetBandwidth() int { 86 return 10000 87 } 88 89 func (self *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, error) { 90 networks, err := self.GetINetworks() 91 if err != nil { 92 return nil, err 93 } 94 for i := 0; i < len(networks); i += 1 { 95 if networks[i].GetGlobalId() == netid { 96 return networks[i], nil 97 } 98 } 99 return nil, cloudprovider.ErrNotFound 100 } 101 102 /* 103 华为云子网可用区,类似一个zone标签。即使指定了zone子网在整个region依然是可用。 104 通过华为web控制台创建子网需要指定可用区。这里是不指定的。 105 */ 106 func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { 107 networkId, err := self.region.createNetwork(self.vpc.GetId(), opts.Name, opts.Cidr, opts.Desc) 108 if err != nil { 109 log.Errorf("createNetwork error %s", err) 110 return nil, err 111 } 112 113 var network *SNetwork 114 err = cloudprovider.WaitCreated(5*time.Second, 60*time.Second, func() bool { 115 self.inetworks = nil 116 network = self.getNetworkById(networkId) 117 if network == nil { 118 return false 119 } else { 120 return true 121 } 122 }) 123 124 if err != nil { 125 log.Errorf("cannot find network after create????") 126 return nil, err 127 } 128 129 network.wire = self 130 return network, nil 131 } 132 133 func (self *SWire) addNetwork(network *SNetwork) { 134 if self.inetworks == nil { 135 self.inetworks = make([]cloudprovider.ICloudNetwork, 0) 136 } 137 find := false 138 for i := 0; i < len(self.inetworks); i += 1 { 139 if self.inetworks[i].GetId() == network.ID { 140 find = true 141 break 142 } 143 } 144 if !find { 145 self.inetworks = append(self.inetworks, network) 146 } 147 } 148 149 func (self *SWire) getNetworkById(networkId string) *SNetwork { 150 networks, err := self.GetINetworks() 151 if err != nil { 152 return nil 153 } 154 log.Debugf("search for networks %d", len(networks)) 155 for i := 0; i < len(networks); i += 1 { 156 log.Debugf("search %s", networks[i].GetName()) 157 network := networks[i] 158 if network.GetId() == networkId { 159 return network.(*SNetwork) 160 } 161 } 162 return nil 163 } 164 165 func getDefaultGateWay(cidr string) (string, error) { 166 pref, err := netutils.NewIPV4Prefix(cidr) 167 if err != nil { 168 return "", errors.Wrap(err, "getDefaultGateWay.NewIPV4Prefix") 169 } 170 startIp := pref.Address.NetAddr(pref.MaskLen) // 0 171 startIp = startIp.StepUp() // 1 172 return startIp.String(), nil 173 } 174 175 // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090590.html 176 // cidr 掩码长度不能大于28 177 func (self *SRegion) createNetwork(vpcId string, name string, cidr string, desc string) (string, error) { 178 gateway, err := getDefaultGateWay(cidr) 179 if err != nil { 180 return "", err 181 } 182 183 params := jsonutils.NewDict() 184 subnetObj := jsonutils.NewDict() 185 subnetObj.Add(jsonutils.NewString(name), "name") 186 subnetObj.Add(jsonutils.NewString(vpcId), "vpc_id") 187 subnetObj.Add(jsonutils.NewString(cidr), "cidr") 188 subnetObj.Add(jsonutils.NewString(gateway), "gateway_ip") 189 // hard code for hcso 190 // https://support.huaweicloud.com/dns_faq/dns_faq_002.html 191 // https://support.huaweicloud.com/api-dns/dns_api_69001.html 192 if self.client != nil && len(self.client.endpoints.DefaultSubnetDns) > 0 { 193 dns := strings.Split(self.client.endpoints.DefaultSubnetDns, ",") 194 if len(dns) > 0 && len(dns[0]) > 0 { 195 subnetObj.Add(jsonutils.NewString(dns[0]), "primary_dns") 196 } 197 198 if len(dns) > 1 && len(dns[1]) > 0 { 199 subnetObj.Add(jsonutils.NewString(dns[1]), "secondary_dns") 200 } 201 } 202 params.Add(subnetObj, "subnet") 203 204 subnet := SNetwork{} 205 err = DoCreate(self.ecsClient.Subnets.Create, params, &subnet) 206 return subnet.ID, err 207 }