yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aliyun/natgateway.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 aliyun 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/utils" 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 ) 31 32 type SBandwidthPackageIds struct { 33 BandwidthPackageId []string 34 } 35 36 type SForwardTableIds struct { 37 ForwardTableId []string 38 } 39 40 type SSnatTableIds struct { 41 SnatTableId []string 42 } 43 44 type NatGatewayPrivateInfo struct { 45 EniInstanceId string 46 IzNo string 47 MaxBandwidth int 48 PrivateIpAddress string 49 VswitchId string 50 } 51 52 type SNatGateway struct { 53 multicloud.SNatGatewayBase 54 AliyunTags 55 56 vpc *SVpc 57 58 BandwidthPackageIds SBandwidthPackageIds 59 BusinessStatus string 60 CreationTime time.Time 61 ExpiredTime time.Time 62 Description string 63 ForwardTableIds SForwardTableIds 64 SnatTableIds SSnatTableIds 65 InstanceChargeType TChargeType 66 Name string 67 NatGatewayId string 68 RegionId string 69 Spec string 70 Status string 71 VpcId string 72 NatGatewayPrivateInfo NatGatewayPrivateInfo 73 } 74 75 func (nat *SNatGateway) GetId() string { 76 return nat.NatGatewayId 77 } 78 79 func (nat *SNatGateway) GetGlobalId() string { 80 return nat.NatGatewayId 81 } 82 83 func (nat *SNatGateway) GetName() string { 84 if len(nat.Name) > 0 { 85 return nat.Name 86 } 87 return nat.NatGatewayId 88 } 89 90 func (nat *SNatGateway) GetStatus() string { 91 switch nat.Status { 92 case "Initiating": 93 return api.NAT_STATUS_ALLOCATE 94 case "Available": 95 return api.NAT_STAUTS_AVAILABLE 96 case "Pending": 97 return api.NAT_STATUS_DEPLOYING 98 default: 99 return api.NAT_STATUS_UNKNOWN 100 } 101 } 102 103 func (self *SNatGateway) GetINetworkId() string { 104 return self.NatGatewayPrivateInfo.VswitchId 105 } 106 107 func (self *SNatGateway) GetIpAddr() string { 108 return self.NatGatewayPrivateInfo.PrivateIpAddress 109 } 110 111 func (self *SNatGateway) GetBandwidthMb() int { 112 return self.NatGatewayPrivateInfo.MaxBandwidth 113 } 114 115 func (self *SNatGateway) Delete() error { 116 return self.vpc.region.DeleteNatGateway(self.NatGatewayId, false) 117 } 118 119 func (nat *SNatGateway) GetBillingType() string { 120 return convertChargeType(nat.InstanceChargeType) 121 } 122 123 func (nat *SNatGateway) GetNatSpec() string { 124 if len(nat.Spec) == 0 { 125 return api.ALIYUN_NAT_SKU_DEFAULT 126 } 127 return nat.Spec 128 } 129 130 func (self *SNatGateway) Refresh() error { 131 nat, total, err := self.vpc.region.GetNatGateways("", self.NatGatewayId, 0, 1) 132 if err != nil { 133 return errors.Wrapf(err, "GetNatGateways") 134 } 135 if total > 1 { 136 return errors.Wrapf(cloudprovider.ErrDuplicateId, "get %d natgateways by id %s", total, self.NatGatewayId) 137 } 138 if total == 0 { 139 return errors.Wrapf(cloudprovider.ErrNotFound, self.NatGatewayId) 140 } 141 return jsonutils.Update(self, nat[0]) 142 } 143 144 func (nat *SNatGateway) GetCreatedAt() time.Time { 145 return nat.CreationTime 146 } 147 148 func (nat *SNatGateway) GetExpiredAt() time.Time { 149 return nat.ExpiredTime 150 } 151 152 func (nat *SNatGateway) GetIEips() ([]cloudprovider.ICloudEIP, error) { 153 eips := []SEipAddress{} 154 for { 155 parts, total, err := nat.vpc.region.GetEips("", nat.NatGatewayId, "", len(eips), 50) 156 if err != nil { 157 return nil, err 158 } 159 eips = append(eips, parts...) 160 if len(eips) >= total { 161 break 162 } 163 } 164 ieips := []cloudprovider.ICloudEIP{} 165 for i := 0; i < len(eips); i++ { 166 eips[i].region = nat.vpc.region 167 ieips = append(ieips, &eips[i]) 168 } 169 return ieips, nil 170 } 171 172 func (nat *SNatGateway) GetINatDTable() ([]cloudprovider.ICloudNatDEntry, error) { 173 itables := []cloudprovider.ICloudNatDEntry{} 174 for _, dtableId := range nat.ForwardTableIds.ForwardTableId { 175 dtables, err := nat.vpc.region.GetAllDTables(dtableId) 176 if err != nil { 177 return nil, err 178 } 179 for i := 0; i < len(dtables); i++ { 180 dtables[i].nat = nat 181 itables = append(itables, &dtables[i]) 182 } 183 } 184 return itables, nil 185 } 186 187 func (nat *SNatGateway) GetINatSTable() ([]cloudprovider.ICloudNatSEntry, error) { 188 stables, err := nat.getSnatEntries() 189 if err != nil { 190 return nil, err 191 } 192 itables := []cloudprovider.ICloudNatSEntry{} 193 for i := 0; i < len(stables); i++ { 194 stables[i].nat = nat 195 itables = append(itables, &stables[i]) 196 } 197 return itables, nil 198 } 199 200 func (nat *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) { 201 dNATEntry, err := nat.vpc.region.GetForwardTableEntry(nat.ForwardTableIds.ForwardTableId[0], id) 202 if err != nil { 203 return nil, cloudprovider.ErrNotFound 204 } 205 dNATEntry.nat = nat 206 return &dNATEntry, nil 207 } 208 209 func (nat *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) { 210 sNATEntry, err := nat.vpc.region.GetSNATEntry(nat.SnatTableIds.SnatTableId[0], id) 211 if err != nil { 212 return nil, cloudprovider.ErrNotFound 213 } 214 sNATEntry.nat = nat 215 return &sNATEntry, nil 216 } 217 218 func (nat *SNatGateway) CreateINatDEntry(rule cloudprovider.SNatDRule) (cloudprovider.ICloudNatDEntry, error) { 219 entryID, err := nat.vpc.region.CreateForwardTableEntry(rule, nat.ForwardTableIds.ForwardTableId[0]) 220 if err != nil { 221 return nil, errors.Wrapf(err, `create dnat rule for nat gateway %q`, nat.GetId()) 222 } 223 return nat.GetINatDEntryByID(entryID) 224 } 225 226 func (nat *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) { 227 entryID, err := nat.vpc.region.CreateSNATTableEntry(rule, nat.SnatTableIds.SnatTableId[0]) 228 if err != nil { 229 return nil, errors.Wrapf(err, `create snat rule for nat gateway %q`, nat.GetId()) 230 } 231 return nat.GetINatSEntryByID(entryID) 232 } 233 234 func (self *SRegion) GetNatGateways(vpcId string, natGwId string, offset, limit int) ([]SNatGateway, int, error) { 235 if limit > 50 || limit <= 0 { 236 limit = 50 237 } 238 params := make(map[string]string) 239 params["RegionId"] = self.RegionId 240 params["PageSize"] = fmt.Sprintf("%d", limit) 241 params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) 242 if len(vpcId) > 0 { 243 params["VpcId"] = vpcId 244 } 245 if len(natGwId) > 0 { 246 params["NatGatewayId"] = natGwId 247 } 248 249 body, err := self.vpcRequest("DescribeNatGateways", params) 250 if err != nil { 251 return nil, 0, errors.Wrapf(err, "DescribeNatGateways") 252 } 253 254 if self.client.debug { 255 log.Debugf("%s", body.PrettyString()) 256 } 257 258 gateways := make([]SNatGateway, 0) 259 err = body.Unmarshal(&gateways, "NatGateways", "NatGateway") 260 if err != nil { 261 return nil, 0, errors.Wrapf(err, "body.Unmarshal") 262 } 263 total, _ := body.Int("TotalCount") 264 return gateways, int(total), nil 265 } 266 267 func (self *SVpc) CreateINatGateway(opts *cloudprovider.NatGatewayCreateOptions) (cloudprovider.ICloudNatGateway, error) { 268 nat, err := self.region.CreateNatGateway(opts) 269 if err != nil { 270 return nil, errors.Wrapf(err, "CreateNatGateway") 271 } 272 nat.vpc = self 273 return nat, nil 274 } 275 276 func (self *SRegion) CreateNatGateway(opts *cloudprovider.NatGatewayCreateOptions) (*SNatGateway, error) { 277 params := map[string]string{ 278 "RegionId": self.RegionId, 279 "VpcId": opts.VpcId, 280 "VSwitchId": opts.NetworkId, 281 "NatType": "Enhanced", 282 "Name": opts.Name, 283 "Description": opts.Desc, 284 "ClientToken": utils.GenRequestId(20), 285 "InstanceChargeType": "PostPaid", 286 "InternetChargeType": "PayBySpec", 287 } 288 if len(opts.NatSpec) == 0 || opts.NatSpec == api.ALIYUN_NAT_SKU_DEFAULT { 289 params["InternetChargeType"] = "PayByLcu" 290 } else { 291 params["Spec"] = opts.NatSpec 292 } 293 294 if opts.BillingCycle != nil { 295 params["InstanceChargeType"] = "PrePaid" 296 params["PricingCycle"] = "Month" 297 params["AutoPay"] = "false" 298 if opts.BillingCycle.GetYears() > 0 { 299 params["PricingCycle"] = "Year" 300 params["Duration"] = fmt.Sprintf("%d", opts.BillingCycle.GetYears()) 301 } else if opts.BillingCycle.GetMonths() > 0 { 302 params["PricingCycle"] = "Year" 303 params["Duration"] = fmt.Sprintf("%d", opts.BillingCycle.GetMonths()) 304 } 305 if opts.BillingCycle.AutoRenew { 306 params["AutoPay"] = "true" 307 } 308 } 309 resp, err := self.vpcRequest("CreateNatGateway", params) 310 if err != nil { 311 return nil, errors.Wrapf(err, "CreateNatGateway") 312 } 313 natId, err := resp.GetString("NatGatewayId") 314 if err != nil { 315 return nil, errors.Wrapf(err, "resp.Get(NatGatewayId)") 316 } 317 if len(natId) == 0 { 318 return nil, errors.Errorf("empty NatGatewayId after created") 319 } 320 321 var nat *SNatGateway = nil 322 err = cloudprovider.Wait(time.Second*5, time.Minute*15, func() (bool, error) { 323 nats, total, err := self.GetNatGateways("", natId, 0, 1) 324 if err != nil { 325 return false, errors.Wrapf(err, "GetNatGateways(%s)", natId) 326 } 327 if total > 1 { 328 return false, errors.Wrapf(cloudprovider.ErrDuplicateId, "get %d nats", total) 329 } 330 if total == 0 { 331 return false, errors.Wrapf(cloudprovider.ErrNotFound, "search %s after %s created", opts.Name, natId) 332 } 333 nat = &nats[0] 334 return true, nil 335 }) 336 if err != nil { 337 return nil, errors.Wrapf(err, "cloudprovider.Wait") 338 } 339 340 return nat, nil 341 } 342 343 func (self *SRegion) DeleteNatGateway(natId string, isForce bool) error { 344 params := map[string]string{ 345 "RegionId": self.RegionId, 346 "NatGatewayId": natId, 347 } 348 if isForce { 349 params["Force"] = "true" 350 } 351 _, err := self.vpcRequest("DeleteNatGateway", params) 352 return errors.Wrapf(err, "DeleteNatGateway") 353 } 354 355 func (self *SNatGateway) GetTags() (map[string]string, error) { 356 _, tags, err := self.vpc.region.ListSysAndUserTags(ALIYUN_SERVICE_VPC, "NATGATEWAY", self.NatGatewayId) 357 if err != nil { 358 return nil, errors.Wrapf(err, "ListTags") 359 } 360 tagMaps := map[string]string{} 361 for k, v := range tags { 362 tagMaps[strings.ToLower(k)] = v 363 } 364 return tagMaps, nil 365 } 366 367 func (self *SNatGateway) GetSysTags() map[string]string { 368 tags, _, err := self.vpc.region.ListSysAndUserTags(ALIYUN_SERVICE_VPC, "NATGATEWAY", self.NatGatewayId) 369 if err != nil { 370 return nil 371 } 372 tagMaps := map[string]string{} 373 for k, v := range tags { 374 tagMaps[strings.ToLower(k)] = v 375 } 376 return tagMaps 377 } 378 379 func (self *SNatGateway) SetTags(tags map[string]string, replace bool) error { 380 return self.vpc.region.SetResourceTags(ALIYUN_SERVICE_VPC, "NATGATEWAY", self.GetId(), tags, replace) 381 }