feat(region): nat op support

This commit is contained in:
Qu Xuan
2021-02-22 15:30:04 +08:00
parent d3f06ef1e9
commit 22937c4afb
70 changed files with 2338 additions and 723 deletions

View File

@@ -15,265 +15,24 @@
package compute
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/compute"
)
func init() {
type ElasticipListOptions struct {
Region string `help:"List eips in cloudregion"`
Usable *bool `help:"List all zones that is usable"`
UsableEipForAssociateType string `help:"With associate id filter which eip can associate"`
UsableEipForAssociateId string `help:"With associate type filter which eip can associate"`
options.BaseListOptions
}
R(&ElasticipListOptions{}, "eip-list", "List elastic IPs", func(s *mcclient.ClientSession, opts *ElasticipListOptions) error {
params, err := options.ListStructToParams(opts)
if err != nil {
return err
}
results, err := modules.Elasticips.List(s, params)
if err != nil {
return err
}
printList(results, modules.Elasticips.GetColumns(s))
return nil
})
type EipCreateOptions struct {
NAME string `help:"name of the EIP"`
Manager string `help:"cloud provider"`
Region string `help:"cloud region in which EIP is allocated"`
Bandwidth int `help:"Bandwidth in Mbps"`
IpAddr string `help:"IP address of the EIP" json:"ip_addr"`
Network string `help:"Network of the EIP"`
BgpType string `help:"BgpType of the EIP" positional:"false"`
ChargeType string `help:"bandwidth charge type" choices:"traffic|bandwidth"`
}
R(&EipCreateOptions{}, "eip-create", "Create an EIP", func(s *mcclient.ClientSession, args *EipCreateOptions) error {
params := jsonutils.NewDict()
params.Add(jsonutils.NewString(args.NAME), "name")
if args.Region != "" {
params.Add(jsonutils.NewString(args.Region), "region")
}
if args.Manager != "" {
params.Add(jsonutils.NewString(args.Manager), "manager")
}
if args.Bandwidth != 0 {
params.Add(jsonutils.NewInt(int64(args.Bandwidth)), "bandwidth")
}
if len(args.ChargeType) > 0 {
params.Add(jsonutils.NewString(args.ChargeType), "charge_type")
}
if len(args.Network) > 0 {
params.Add(jsonutils.NewString(args.Network), "network")
}
if len(args.BgpType) > 0 {
params.Add(jsonutils.NewString(args.BgpType), "bgp_type")
}
if len(args.IpAddr) > 0 {
params.Add(jsonutils.NewString(args.IpAddr), "ip_addr")
}
result, err := modules.Elasticips.Create(s, params)
if err != nil {
return err
}
printObject(result)
return nil
})
type EipDeleteOptions struct {
ID string `help:"ID or name of EIP"`
}
R(&EipDeleteOptions{}, "eip-delete", "Delete an EIP", func(s *mcclient.ClientSession, args *EipDeleteOptions) error {
result, err := modules.Elasticips.Delete(s, args.ID, nil)
if err != nil {
return err
}
printObject(result)
return nil
})
type EipUpdateOptions struct {
ID string `help:"ID or name of EIP"`
Name string `help:"New name of EIP"`
Desc string `help:"New description of EIP"`
EnableAutoDellocate bool `help:"enable automatically dellocate when dissociate from instance"`
DisableAutoDellocate bool `help:"disable automatically dellocate when dissociate from instance"`
}
R(&EipUpdateOptions{}, "eip-update", "Update EIP properties", func(s *mcclient.ClientSession, args *EipUpdateOptions) error {
params := jsonutils.NewDict()
if len(args.Name) > 0 {
params.Add(jsonutils.NewString(args.Name), "name")
}
if len(args.Desc) > 0 {
params.Add(jsonutils.NewString(args.Desc), "description")
}
if args.EnableAutoDellocate {
params.Add(jsonutils.JSONTrue, "auto_dellocate")
} else if args.DisableAutoDellocate {
params.Add(jsonutils.JSONFalse, "auto_dellocate")
}
result, err := modules.Elasticips.Update(s, args.ID, params)
if err != nil {
return err
}
printObject(result)
return nil
})
type EipAssociateOptions struct {
ID string `help:"ID or name of EIP"`
INSTANCEID string `help:"ID of instance the eip associated with"`
InstanceType string `default:"server" help:"Instance type that the eip associated with, default is server" choices:"server"`
}
R(&EipAssociateOptions{}, "eip-associate", "Associate an EIP to an instance", func(s *mcclient.ClientSession, args *EipAssociateOptions) error {
params := jsonutils.NewDict()
params.Add(jsonutils.NewString(args.InstanceType), "instance_type")
params.Add(jsonutils.NewString(args.INSTANCEID), "instance_id")
result, err := modules.Elasticips.PerformAction(s, args.ID, "associate", params)
if err != nil {
return err
}
printObject(result)
return nil
})
type EipDissociateOptions struct {
ID string `help:"ID or name of EIP"`
AutoDelete bool `help:"automatically delete the dissociate EIP" json:"auto_delete,omitfalse"`
}
R(&EipDissociateOptions{}, "eip-dissociate", "Dissociate an EIP from an instance", func(s *mcclient.ClientSession, args *EipDissociateOptions) error {
params, err := options.StructToParams(args)
if err != nil {
return err
}
result, err := modules.Elasticips.PerformAction(s, args.ID, "dissociate", params)
if err != nil {
return err
}
printObject(result)
return nil
})
type EipSingleOptions struct {
ID string `help:"ID or name of EIP"`
}
R(&EipSingleOptions{}, "eip-sync", "Synchronize status of an EIP", func(s *mcclient.ClientSession, args *EipSingleOptions) error {
result, err := modules.Elasticips.PerformAction(s, args.ID, "sync", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&EipSingleOptions{}, "eip-syncstatus", "Synchronize status of an EIP", func(s *mcclient.ClientSession, args *EipSingleOptions) error {
result, err := modules.Elasticips.PerformAction(s, args.ID, "syncstatus", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
type ServerCreateEipOptions struct {
ID string `help:"server ID or name"`
BW int `help:"EIP bandwidth in Mbps"`
BgpType string `help:"desired BGP type"`
ChargeType string `help:"bandwidth charge type" choices:"traffic|bandwidth"`
}
R(&ServerCreateEipOptions{}, "server-create-eip", "allocate an EIP and associate EIP to server", func(s *mcclient.ClientSession, args *ServerCreateEipOptions) error {
params := jsonutils.NewDict()
params.Add(jsonutils.NewInt(int64(args.BW)), "bandwidth")
if args.BgpType != "" {
params.Add(jsonutils.NewString(args.BgpType), "bgp_type")
}
if len(args.ChargeType) > 0 {
params.Add(jsonutils.NewString(args.ChargeType), "charge_type")
}
result, err := modules.Servers.PerformAction(s, args.ID, "create-eip", params)
if err != nil {
return err
}
printObject(result)
return nil
})
type EipShowOptions struct {
ID string `help:"ID or name of EIP"`
}
R(&EipShowOptions{}, "eip-show", "show details of an EIP", func(s *mcclient.ClientSession, args *EipShowOptions) error {
result, err := modules.Elasticips.Get(s, args.ID, nil)
if err != nil {
return err
}
printObject(result)
return nil
})
type EipChangeBandwidthOptions struct {
ID string `help:"ID or name of the EIP"`
BW int `help:"new bandwidth of EIP"`
}
R(&EipChangeBandwidthOptions{}, "eip-change-bandwidth", "Change maximal bandwidth of EIP", func(s *mcclient.ClientSession, args *EipChangeBandwidthOptions) error {
params := jsonutils.NewDict()
params.Add(jsonutils.NewInt(int64(args.BW)), "bandwidth")
result, err := modules.Elasticips.PerformAction(s, args.ID, "change-bandwidth", params)
if err != nil {
return err
}
printObject(result)
return nil
})
type EipPurgeOptions struct {
ID string `help:"ID or name of EIP"`
}
R(&EipPurgeOptions{}, "eip-purge", "Purge EIP db records", func(s *mcclient.ClientSession, args *EipPurgeOptions) error {
result, err := modules.Elasticips.PerformAction(s, args.ID, "purge", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
type EipChangeOwnerOptions struct {
ID string `help:"EIP to change owner"`
PROJECT string `help:"Project ID or change"`
RawId bool `help:"User raw ID, instead of name"`
}
R(&EipChangeOwnerOptions{}, "eip-change-owner", "Change owner porject of a eip", func(s *mcclient.ClientSession, opts *EipChangeOwnerOptions) error {
params := jsonutils.NewDict()
if opts.RawId {
projid, err := modules.Projects.GetId(s, opts.PROJECT, nil)
if err != nil {
return err
}
params.Add(jsonutils.NewString(projid), "tenant")
params.Add(jsonutils.JSONTrue, "raw_id")
} else {
params.Add(jsonutils.NewString(opts.PROJECT), "tenant")
}
srv, err := modules.Elasticips.PerformAction(s, opts.ID, "change-owner", params)
if err != nil {
return err
}
printObject(srv)
return nil
})
cmd := shell.NewResourceCmd(&modules.Elasticips).WithKeyword("eip")
cmd.List(&compute.ElasticipListOptions{})
cmd.Create(&compute.EipCreateOptions{})
cmd.Delete(&options.BaseIdOptions{})
cmd.Update(&compute.EipUpdateOptions{})
cmd.Show(&options.BaseShowOptions{})
cmd.Perform("purge", &options.BaseIdOptions{})
cmd.Perform("associate", &compute.EipAssociateOptions{})
cmd.Perform("dissociate", &compute.EipDissociateOptions{})
cmd.Perform("sync", &options.BaseIdOptions{})
cmd.Perform("syncstatus", &options.BaseIdOptions{})
cmd.Perform("change-bandwidth", &options.BaseIdOptions{})
cmd.Perform("change-owner", &compute.EipChangeOwnerOptions{})
}

View File

@@ -0,0 +1,29 @@
// 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 compute
import (
"yunion.io/x/onecloud/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/compute"
)
func init() {
cmd := shell.NewResourceCmd(&modules.NatSkus).WithKeyword("nat-sku")
cmd.List(&compute.NatSkuListOption{})
cmd.Show(&compute.NatSkuIdOption{})
cmd.PerformClass("sync-skus", &options.SkuSyncOptions{})
}

View File

@@ -20,11 +20,12 @@ import (
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/compute"
)
func init() {
R(&options.NatDTableListOptions{}, "dnat-list", "List DNAT entries", func(s *mcclient.ClientSession, opts *options.NatDTableListOptions) error {
R(&compute.NatDTableListOptions{}, "dnat-list", "List DNAT entries", func(s *mcclient.ClientSession, opts *compute.NatDTableListOptions) error {
params, err := options.ListStructToParams(opts)
if err != nil {
return err
@@ -36,7 +37,7 @@ func init() {
printList(result, modules.NatDTable.GetColumns(s))
return nil
})
R(&options.NatDDeleteShowOptions{}, "dnat-delete", "Delete a DNAT", func(s *mcclient.ClientSession, args *options.NatDDeleteShowOptions) error {
R(&compute.NatDDeleteShowOptions{}, "dnat-delete", "Delete a DNAT", func(s *mcclient.ClientSession, args *compute.NatDDeleteShowOptions) error {
results, err := modules.NatDTable.Delete(s, args.ID, nil)
if err != nil {
return err
@@ -44,7 +45,7 @@ func init() {
printObject(results)
return nil
})
R(&options.NatDDeleteShowOptions{}, "dnat-show", "Show a DNAT", func(s *mcclient.ClientSession, args *options.NatDDeleteShowOptions) error {
R(&compute.NatDDeleteShowOptions{}, "dnat-show", "Show a DNAT", func(s *mcclient.ClientSession, args *compute.NatDDeleteShowOptions) error {
results, err := modules.NatDTable.Get(s, args.ID, nil)
if err != nil {
return err
@@ -53,7 +54,7 @@ func init() {
return nil
})
R(&options.NatDCreateOptions{}, "dnat-create", "Create a DNAT", func(s *mcclient.ClientSession, args *options.NatDCreateOptions) error {
R(&compute.NatDCreateOptions{}, "dnat-create", "Create a DNAT", func(s *mcclient.ClientSession, args *compute.NatDCreateOptions) error {
params := jsonutils.NewDict()
params.Add(jsonutils.NewString(args.NAME), "name")
params.Add(jsonutils.NewString(args.NATGATEWAYID), "natgateway_id")

View File

@@ -15,67 +15,18 @@
package compute
import (
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/cmd/climc/shell"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/compute"
)
func init() {
cmd := shell.NewResourceCmd(&modules.NatGateways).WithKeyword("nat")
R(&options.NatGatewayListOptions{}, "natgateway-list", "List NAT gateways", func(s *mcclient.ClientSession, opts *options.NatGatewayListOptions) error {
params, err := options.ListStructToParams(opts)
if err != nil {
return err
}
result, err := modules.NatGateways.List(s, params)
if err != nil {
return err
}
printList(result, modules.NatGateways.GetColumns(s))
return nil
})
R(&options.NatGatewayIdOptions{}, "natgateway-show", "Show a NAT gateway", func(s *mcclient.ClientSession, args *options.NatGatewayIdOptions) error {
results, err := modules.NatGateways.Get(s, args.ID, nil)
if err != nil {
return err
}
printObject(results)
return nil
})
R(&options.NatGatewayIdOptions{}, "natgateway-syncstatus", "Sync NAT gateway status", func(s *mcclient.ClientSession, args *options.NatGatewayIdOptions) error {
result, err := modules.NatGateways.PerformAction(s, args.ID, "syncstatus", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
type NatGatewayListEipOptions struct {
ID string `help:"ID"`
}
R(&NatGatewayListEipOptions{}, "natgateway-dnat-resources", "list resources in dnats of natgateway",
func(s *mcclient.ClientSession, opts *NatGatewayListEipOptions) error {
ret, err := modules.NatGateways.PerformAction(s, opts.ID, "dnat-resources", nil)
if err != nil {
return err
}
printObject(ret)
return nil
})
R(&NatGatewayListEipOptions{}, "natgateway-snat-resources", "list resources in snats of natgateway",
func(s *mcclient.ClientSession, opts *NatGatewayListEipOptions) error {
ret, err := modules.NatGateways.PerformAction(s, opts.ID, "snat-resources", nil)
if err != nil {
return err
}
printObject(ret)
return nil
})
cmd.List(&compute.NatGatewayListOptions{})
cmd.Create(&api.NatgatewayCreateInput{})
cmd.Show(&compute.NatGatewayIdOptions{})
cmd.Delete(&compute.NatGatewayDeleteOption{})
cmd.Perform("syncstauts", &compute.NatGatewayIdOptions{})
}

View File

@@ -20,11 +20,12 @@ import (
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/compute"
)
func init() {
R(&options.NatSTableListOptions{}, "snat-list", "List SNAT entries", func(s *mcclient.ClientSession, opts *options.NatSTableListOptions) error {
R(&compute.NatSTableListOptions{}, "snat-list", "List SNAT entries", func(s *mcclient.ClientSession, opts *compute.NatSTableListOptions) error {
params, err := options.ListStructToParams(opts)
if err != nil {
return err
@@ -36,7 +37,7 @@ func init() {
printList(result, modules.NatSTable.GetColumns(s))
return nil
})
R(&options.NatSDeleteShowOptions{}, "snat-delete", "Delete a SNAT", func(s *mcclient.ClientSession, args *options.NatSDeleteShowOptions) error {
R(&compute.NatSDeleteShowOptions{}, "snat-delete", "Delete a SNAT", func(s *mcclient.ClientSession, args *compute.NatSDeleteShowOptions) error {
results, err := modules.NatSTable.Delete(s, args.ID, nil)
if err != nil {
return err
@@ -45,7 +46,7 @@ func init() {
return nil
})
R(&options.NatSDeleteShowOptions{}, "snat-show", "Show a SNAT", func(s *mcclient.ClientSession, args *options.NatSDeleteShowOptions) error {
R(&compute.NatSDeleteShowOptions{}, "snat-show", "Show a SNAT", func(s *mcclient.ClientSession, args *compute.NatSDeleteShowOptions) error {
results, err := modules.NatSTable.Get(s, args.ID, nil)
if err != nil {
return err
@@ -54,7 +55,7 @@ func init() {
return nil
})
R(&options.NatSCreateOptions{}, "snat-create", "Create a SNAT", func(s *mcclient.ClientSession, args *options.NatSCreateOptions) error {
R(&compute.NatSCreateOptions{}, "snat-create", "Create a SNAT", func(s *mcclient.ClientSession, args *compute.NatSCreateOptions) error {
params := jsonutils.NewDict()
params.Add(jsonutils.NewString(args.NAME), "name")
params.Add(jsonutils.NewString(args.NATGATEWAYID), "natgateway_id")

View File

@@ -84,6 +84,7 @@ func init() {
cmd.Perform("set-auto-renew", new(options.ServerSetAutoRenew))
cmd.Perform("save-template", new(options.ServerSaveImageOptions))
cmd.Perform("remote-update", new(options.ServerRemoteUpdateOptions))
cmd.Perform("create-eip", &options.ServerCreateEipOptions{})
cmd.Get("vnc", new(options.ServerIdOptions))
cmd.Get("desc", new(options.ServerIdOptions))

View File

@@ -87,3 +87,18 @@ type ElasticipDetails struct {
type ElasticipSyncstatusInput struct {
}
type ElasticipAssociateInput struct {
// 待绑定实例Id
InstanceId string `json:"instance_id"`
// swagger:ignore
InstanceExternalId string `json:"instance_external_id"`
// swagger:ignore
Instance string `json:"instance" yunion-deprecated-by:"instance_id"`
// 实例类型
// enmu: server, natgateway
// default: server
InstanceType string `json:"instance_type"`
}

View File

@@ -42,6 +42,11 @@ const (
EIP_CHARGE_TYPE_BY_TRAFFIC = "traffic"
EIP_CHARGE_TYPE_BY_BANDWIDTH = "bandwidth"
INSTANCE_ASSOCIATE_EIP = "associate_eip"
INSTANCE_ASSOCIATE_EIP_FAILED = "associate_eip_failed"
INSTANCE_DISSOCIATE_EIP = "dissociate_eip"
INSTANCE_DISSOCIATE_EIP_FAILED = "dissociate_eip_failed"
)
var (

View File

@@ -109,10 +109,10 @@ const (
VM_RESTORE_STATE = "restore_state"
VM_RESTORE_FAILED = "restore_failed"
VM_ASSOCIATE_EIP = "associate_eip"
VM_ASSOCIATE_EIP_FAILED = "associate_eip_failed"
VM_DISSOCIATE_EIP = "dissociate_eip"
VM_DISSOCIATE_EIP_FAILED = "dissociate_eip_failed"
VM_ASSOCIATE_EIP = INSTANCE_ASSOCIATE_EIP
VM_ASSOCIATE_EIP_FAILED = INSTANCE_ASSOCIATE_EIP_FAILED
VM_DISSOCIATE_EIP = INSTANCE_DISSOCIATE_EIP
VM_DISSOCIATE_EIP_FAILED = INSTANCE_DISSOCIATE_EIP_FAILED
// 公网IP转换Eip中(EIP转换中)
VM_START_EIP_CONVERT = "start_eip_convert"

View File

@@ -0,0 +1,40 @@
// 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 compute
import "yunion.io/x/onecloud/pkg/apis"
const (
NAT_SKU_AVAILABLE = "available"
NAT_SKU_SOLDOUT = "soldout"
ALIYUN_NAT_SKU_DEFAULT = "Default"
)
type NatSkuListInput struct {
apis.EnabledStatusStandaloneResourceListInput
apis.ExternalizedResourceBaseListInput
RegionalFilterListInput
PostpaidStatus string `json:"postpaid_stauts"`
PrepaidStatus string `json:"prepaid_status"`
}
type NatSkuDetails struct {
apis.EnabledStatusStandaloneResourceDetails
CloudregionResourceInfo
}

View File

@@ -15,18 +15,26 @@
package compute
import (
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/apis"
)
const (
NAT_STAUTS_AVAILABLE = "available" //可用
NAT_STATUS_ALLOCATE = "allocate" //创建中
NAT_STATUS_DEPLOYING = "deploying" //配置中
NAT_STATUS_UNKNOWN = "unknown" //未知状态
NAT_STATUS_FAILED = "failed" //创建失败
NAT_STATUS_DELETED = "deleted" //删除
NAT_STATUS_DELETING = "deleting" //删除中
NAT_STATUS_DELETE_FAILED = "delete_failed" //删除失败
NAT_STAUTS_AVAILABLE = "available" // 可用
NAT_STATUS_ALLOCATE = "allocate" // 创建中
NAT_STATUS_DEPLOYING = "deploying" // 配置中
NAT_STATUS_UNKNOWN = "unknown" // 未知状态
NAT_STATUS_CREATE_FAILED = "create_failed" // 创建失败
NAT_STATUS_DELETED = "deleted" // 删除
NAT_STATUS_DELETING = "deleting" // 删除中
NAT_STATUS_DELETE_FAILED = "delete_failed" // 删除失败
NAT_STATUS_SET_AUTO_RENEW = "set_auto_renew" // 设置自动续费中
NAT_STATUS_SET_AUTO_RENEW_FAILED = "set_auto_renew_failed" // 设置自动续费失败
NAT_STATUS_RENEWING = "renewing" // 续费中
NAT_STATUS_RENEW_FAILED = "renew_failed" // 续费失败
NAT_SPEC_SMALL = "small" //小型
NAT_SPEC_MIDDLE = "middle" //中型
@@ -41,17 +49,15 @@ const (
type NatGetewayListInput struct {
apis.StatusInfrasResourceBaseListInput
apis.ExternalizedResourceBaseListInput
apis.DeletePreventableResourceBaseListInput
VpcFilterListInput
RegionalFilterListInput
ManagedResourceListInput
}
type NatEntryListInput struct {
apis.StatusInfrasResourceBaseListInput
apis.ExternalizedResourceBaseListInput
NatGatewayFilterListInput
ManagedResourceListInput
}
type NatDEntryListInput struct {
@@ -111,3 +117,49 @@ type NatEntryDetails struct {
type NatGatewaySyncstatusInput struct {
}
type NatgatewayCreateInput struct {
apis.StatusInfrasResourceBaseCreateInput
// 包年包月时间周期
Duration string `json:"duration"`
// 是否自动续费(仅包年包月时生效)
// default: false
AutoRenew bool `json:"auto_renew"`
// 到期释放时间,仅后付费支持
ExpiredAt time.Time `json:"expired_at"`
// 计费方式
// enum: postpaid, prepaid
BillingType string `json:"billing_type"`
// swagger:ignore
BillingCycle string `json:"billing_cycle"`
NetworkId string `json:"network_id"`
// swagger:ignore
VpcId string `json:"vpc_id"`
// 绑定已有弹性公网IP要求EIP必须和Vpc在同一区域
Eip string `json:"eip"`
// 绑定新建弹性公网IP
EipBw int `json:"eip_bw,omitzero"`
// 弹性公网IP计费类型
// enum: bandwidth, traffic
// default: traffic
EipChargeType string `json:"eip_charge_type,omitempty"`
EipBgpType string `json:"eip_bgp_type"`
EipAutoDellocate bool `json:"eip_auto_dellocate"`
}
func (opts *NatgatewayCreateInput) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(opts), nil
}
type NatgatewayDeleteInput struct {
Force bool `json:"force"`
}

View File

@@ -14,6 +14,8 @@
package apis
import "time"
type DomainizedResourceInput struct {
// 指定项目归属域名称或ID
// required: false
@@ -350,3 +352,17 @@ type DistinctFieldInput struct {
Field []string
ExtraField []string
}
type PostpaidExpireInput struct {
Duration string `json:"duration"`
ExpireTime time.Time `json:"expireType"`
}
type AutoRenewInput struct {
// 是否自动续费
AutoRenew bool `json:"auto_renew"`
}
type RenewInput struct {
Duration string `json:"duration"`
}

View File

@@ -54,6 +54,7 @@ const (
CLOUD_CAPABILITY_PUBLIC_IP = "public_ip"
CLOUD_CAPABILITY_INTERVPCNETWORK = "intervpcnetwork"
CLOUD_CAPABILITY_SAML_AUTH = "saml_auth" // 是否支持SAML 2.0
CLOUD_CAPABILITY_NAT = "nat" // NAT网关
)
const (

View File

@@ -14,6 +14,8 @@
package cloudprovider
import "yunion.io/x/onecloud/pkg/util/billing"
// These two structures are designed for modifying snat table and dnat table.
// There is a so strange point that they have both field of ExternalIP and ExternalIPID.
// The reason is that you must pass ExternalIPID to modify in Huawei Cloud for now.
@@ -38,3 +40,13 @@ type SNatDRule struct {
ExternalIPID string
ExternalPort int
}
type NatGatewayCreateOptions struct {
Name string
VpcId string
NetworkId string
Desc string
NatSpec string
BillingCycle *billing.SBillingCycle
}

View File

@@ -56,6 +56,7 @@ type IBillingResource interface {
GetCreatedAt() time.Time
GetExpiredAt() time.Time
SetAutoRenew(autoRenew bool) error
Renew(bc billing.SBillingCycle) error
IsAutoRenew() bool
}
@@ -328,8 +329,6 @@ type ICloudVM interface {
CreateDisk(ctx context.Context, sizeMb int, uuid string, driver string) error
Renew(bc billing.SBillingCycle) error
MigrateVM(hostid string) error
LiveMigrateVM(hostid string) error
@@ -524,6 +523,7 @@ type ICloudVpc interface {
GetIWireById(wireId string) (ICloudWire, error)
GetINatGateways() ([]ICloudNatGateway, error)
CreateINatGateway(opts *NatGatewayCreateOptions) (ICloudNatGateway, error)
GetICloudVpcPeeringConnections() ([]ICloudVpcPeeringConnection, error)
GetICloudAccepterVpcPeeringConnections() ([]ICloudVpcPeeringConnection, error)
@@ -790,6 +790,8 @@ type ICloudNatGateway interface {
// Read the description of these two structures before using.
CreateINatDEntry(rule SNatDRule) (ICloudNatDEntry, error)
CreateINatSEntry(rule SNatSRule) (ICloudNatSEntry, error)
Delete() error
}
// ICloudNatDEntry describe a DNat rule which transfer externalIp:externalPort to
@@ -874,7 +876,6 @@ type ICloudDBInstance interface {
GetIDBInstanceBackups() ([]ICloudDBInstanceBackup, error)
ChangeConfig(ctx context.Context, config *SManagedDBInstanceChangeConfig) error
Renew(bc billing.SBillingCycle) error
OpenPublicConnection() error
ClosePublicConnection() error
@@ -995,7 +996,6 @@ type ICloudElasticcache interface {
UpdateAuthMode(noPasswordAccess bool, password string) error
UpdateInstanceParameters(config jsonutils.JSONObject) error
UpdateBackupPolicy(config SCloudElasticCacheBackupPolicyUpdateInput) error
Renew(bc billing.SBillingCycle) error
UpdateSecurityGroups(secgroupIds []string) error
}

View File

@@ -18,16 +18,13 @@ import (
"context"
"fmt"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/httperrors"
@@ -237,58 +234,3 @@ func (self *SAwsGuestDriver) GetGuestInitialStateAfterRebuild() string {
func (self *SAwsGuestDriver) IsSupportedBillingCycle(bc billing.SBillingCycle) bool {
return false
}
func (self *SAwsGuestDriver) RequestAssociateEip(ctx context.Context, userCred mcclient.TokenCredential, server *models.SGuest, eip *models.SElasticip, task taskman.ITask) error {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
if server.Status != api.VM_ASSOCIATE_EIP {
server.SetStatus(userCred, api.VM_ASSOCIATE_EIP, "associate eip")
}
extEip, err := eip.GetIEip()
if err != nil {
return nil, fmt.Errorf("SAwsGuestDriver.RequestAssociateEip fail to find iEIP for eip %s", err)
}
conf := &cloudprovider.AssociateConfig{
InstanceId: server.ExternalId,
Bandwidth: eip.Bandwidth,
AssociateType: api.EIP_ASSOCIATE_TYPE_SERVER,
}
err = extEip.Associate(conf)
if err != nil {
return nil, fmt.Errorf("SAwsGuestDriver.RequestAssociateEip fail to remote associate EIP %s", err)
}
err = cloudprovider.WaitStatus(extEip, api.EIP_STATUS_READY, 3*time.Second, 60*time.Second)
if err != nil {
return nil, errors.Wrap(err, "SAwsGuestDriver.RequestAssociateEip.WaitStatus")
}
err = eip.AssociateVM(ctx, userCred, server)
if err != nil {
return nil, fmt.Errorf("SAwsGuestDriver.RequestAssociateEip fail to local associate EIP %s", err)
}
eip.SetStatus(userCred, api.EIP_STATUS_READY, "associate")
// 如果aws已经绑定了EIP则要把多余的公有IP删除
if extEip.GetMode() == api.EIP_MODE_STANDALONE_EIP {
publicIP, err := server.GetPublicIp()
if err != nil {
return nil, errors.Wrap(err, "AwsGuestDriver.GetPublicIp")
}
if publicIP != nil {
err = db.DeleteModel(ctx, userCred, publicIP)
if err != nil {
return nil, errors.Wrap(err, "AwsGuestDriver.DeletePublicIp")
}
}
}
return nil, nil
})
return nil
}

View File

@@ -294,10 +294,6 @@ func (self *SBaseGuestDriver) IsSupportPublicIp() bool {
return false
}
func (self *SBaseGuestDriver) RequestAssociateEip(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, eip *models.SElasticip, task taskman.ITask) error {
return fmt.Errorf("SBaseGuestDriver: Not Implement RequestAssociateEip")
}
func (self *SBaseGuestDriver) NeedStopForChangeSpec(guest *models.SGuest, cpuChanged, memChanged bool) bool {
return false
}

View File

@@ -531,10 +531,6 @@ func (self *SESXiGuestDriver) IsSupportEip() bool {
return false
}
func (self *SESXiGuestDriver) RequestAssociateEip(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, eip *models.SElasticip, task taskman.ITask) error {
return fmt.Errorf("ESXiGuestDriver not support associate eip")
}
func (self *SESXiGuestDriver) IsSupportCdrom(guest *models.SGuest) (bool, error) {
return false, nil
}

View File

@@ -372,7 +372,7 @@ func (self *SKVMGuestDriver) RequestAssociateEip(ctx context.Context, userCred m
guestnic.Ifname, guestnic.GuestId, guestnic.NetworkId)
}
if err := eip.AssociateVM(ctx, userCred, guest); err != nil {
if err := eip.AssociateInstance(ctx, userCred, api.EIP_ASSOCIATE_TYPE_SERVER, guest); err != nil {
return errors.Wrapf(err, "associate eip %s(%s) to vm %s(%s)", eip.Name, eip.Id, guest.Name, guest.Id)
}
if err := eip.SetStatus(userCred, api.EIP_STATUS_READY, api.EIP_STATUS_ASSOCIATE); err != nil {

View File

@@ -1103,45 +1103,6 @@ func (self *SManagedVirtualizedGuestDriver) IsSupportEip() bool {
return true
}
func (self *SManagedVirtualizedGuestDriver) RequestAssociateEip(ctx context.Context, userCred mcclient.TokenCredential, server *models.SGuest, eip *models.SElasticip, task taskman.ITask) error {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
if server.Status != api.VM_ASSOCIATE_EIP {
server.SetStatus(userCred, api.VM_ASSOCIATE_EIP, "associate eip")
}
extEip, err := eip.GetIEip()
if err != nil {
return nil, fmt.Errorf("ManagedVirtualizedGuestDriver.RequestAssociateEip fail to find iEIP for eip %s", err)
}
conf := &cloudprovider.AssociateConfig{
InstanceId: server.ExternalId,
Bandwidth: eip.Bandwidth,
AssociateType: api.EIP_ASSOCIATE_TYPE_SERVER,
}
err = extEip.Associate(conf)
if err != nil {
return nil, fmt.Errorf("ManagedVirtualizedGuestDriver.RequestAssociateEip fail to remote associate EIP %s", err)
}
err = cloudprovider.WaitStatus(extEip, api.EIP_STATUS_READY, 3*time.Second, 60*time.Second)
if err != nil {
return nil, errors.Wrap(err, "ManagedVirtualizedGuestDriver.RequestAssociateEip.WaitStatus")
}
err = eip.AssociateVM(ctx, userCred, server)
if err != nil {
return nil, fmt.Errorf("ManagedVirtualizedGuestDriver.RequestAssociateEip fail to local associate EIP %s", err)
}
eip.SetStatus(userCred, api.EIP_STATUS_READY, api.EIP_STATUS_ASSOCIATE)
return nil, nil
})
return nil
}
func (self *SManagedVirtualizedGuestDriver) chooseHostStorage(
drv models.IGuestDriver,
host *models.SHost,

View File

@@ -21,6 +21,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis"
api "yunion.io/x/onecloud/pkg/apis/billing"
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/httperrors"
@@ -175,23 +176,21 @@ func ListExpiredPostpaidResources(
return q
}
func ParseBillingCycleInput(billingBase *SBillingResourceBase, data jsonutils.JSONObject) (*billing.SBillingCycle, error) {
func ParseBillingCycleInput(billingBase *SBillingResourceBase, input apis.PostpaidExpireInput) (*billing.SBillingCycle, error) {
var (
bc billing.SBillingCycle
err error
durationStr string
)
durationStr, _ = data.GetString("duration")
if len(durationStr) == 0 {
expireTime, err := data.GetTime("expire_time")
if err != nil {
if len(input.Duration) == 0 {
if input.ExpireTime.IsZero() {
return nil, httperrors.NewInputParameterError("missing duration/expire_time")
}
timeC := billingBase.ExpiredAt
if timeC.IsZero() {
timeC = time.Now()
}
dur := expireTime.Sub(timeC)
dur := input.ExpireTime.Sub(timeC)
if dur <= 0 {
return nil, httperrors.NewInputParameterError("expire time is before current expire at")
}

View File

@@ -51,6 +51,8 @@ type SCapabilities struct {
// 支持SAML 2.0
SamlAuthBrands []string `json:",allowempty"`
DisabledSamlAuthBrands []string `json:",allowempty"`
NatBrands []string `json:",allowempty"`
DisabledNatBrands []string `json:",allowempty"`
PublicIpBrands []string `json:",allowempty"`
NetworkManageBrands []string `json:",allowempty"`
DisabledNetworkManageBrands []string `json:",allowempty"`
@@ -286,6 +288,7 @@ func getBrands(region *SCloudregion, zone *SZone, domainId string, capa *SCapabi
capa.PublicIpBrands, _ = CloudaccountManager.getBrandsOfCapability(region, zone, domainId, tristate.True, cloudprovider.CLOUD_CAPABILITY_PUBLIC_IP)
capa.LoadbalancerEngineBrands, _ = CloudaccountManager.getBrandsOfCapability(region, zone, domainId, tristate.True, cloudprovider.CLOUD_CAPABILITY_LOADBALANCER)
capa.SamlAuthBrands, _ = CloudaccountManager.getBrandsOfCapability(region, zone, domainId, tristate.True, cloudprovider.CLOUD_CAPABILITY_SAML_AUTH)
capa.NatBrands, _ = CloudaccountManager.getBrandsOfCapability(region, zone, domainId, tristate.True, cloudprovider.CLOUD_CAPABILITY_NAT)
if utils.IsInStringArray(api.HYPERVISOR_KVM, capa.Hypervisors) || utils.IsInStringArray(api.HYPERVISOR_BAREMETAL, capa.Hypervisors) {
capa.Brands = append(capa.Brands, api.ONECLOUD_BRAND_ONECLOUD)
@@ -305,6 +308,7 @@ func getBrands(region *SCloudregion, zone *SZone, domainId string, capa *SCapabi
capa.DisabledObjectStorageBrands, _ = CloudaccountManager.getBrandsOfCapability(region, zone, domainId, tristate.False, cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE)
capa.DisabledCloudIdBrands, _ = CloudaccountManager.getBrandsOfCapability(region, zone, domainId, tristate.False, cloudprovider.CLOUD_CAPABILITY_CLOUDID)
capa.DisabledSamlAuthBrands, _ = CloudaccountManager.getBrandsOfCapability(region, zone, domainId, tristate.False, cloudprovider.CLOUD_CAPABILITY_SAML_AUTH)
capa.DisabledNatBrands, _ = CloudaccountManager.getBrandsOfCapability(region, zone, domainId, tristate.False, cloudprovider.CLOUD_CAPABILITY_NAT)
return
}

View File

@@ -1978,12 +1978,12 @@ func (self *SDBInstance) AllowPerformPostpaidExpire(ctx context.Context, userCre
return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "postpaid-expire")
}
func (self *SDBInstance) PerformPostpaidExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
func (self *SDBInstance) PerformPostpaidExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PostpaidExpireInput) (jsonutils.JSONObject, error) {
if self.BillingType != billing_api.BILLING_TYPE_POSTPAID {
return nil, httperrors.NewBadRequestError("dbinstance billing type is %s", self.BillingType)
}
bc, err := ParseBillingCycleInput(&self.SBillingResourceBase, data)
bc, err := ParseBillingCycleInput(&self.SBillingResourceBase, input)
if err != nil {
return nil, err
}

View File

@@ -1851,12 +1851,12 @@ func (self *SElasticcache) AllowPerformPostpaidExpire(ctx context.Context, userC
return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "postpaid-expire")
}
func (self *SElasticcache) PerformPostpaidExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
func (self *SElasticcache) PerformPostpaidExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PostpaidExpireInput) (jsonutils.JSONObject, error) {
if self.BillingType != billing_api.BILLING_TYPE_POSTPAID {
return nil, httperrors.NewBadRequestError("elasticcache billing type is %s", self.BillingType)
}
bc, err := ParseBillingCycleInput(&self.SBillingResourceBase, data)
bc, err := ParseBillingCycleInput(&self.SBillingResourceBase, input)
if err != nil {
return nil, err
}

View File

@@ -1,13 +1,16 @@
package models
import "yunion.io/x/onecloud/pkg/httperrors"
import (
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/httperrors"
)
type IGetVpc interface {
GetName() string
type IEipAssociateInstance interface {
db.IStatusStandaloneModel
GetVpc() (*SVpc, error)
}
func ValidateAssociateEip(obj IGetVpc) error {
func ValidateAssociateEip(obj IEipAssociateInstance) error {
vpc, err := obj.GetVpc()
if err != nil {
return httperrors.NewGeneralError(err)

View File

@@ -248,8 +248,12 @@ func (manager *SElasticipManager) QueryDistinctExtraField(q *sqlchemy.SQuery, fi
return q, httperrors.ErrNotFound
}
func (self *SElasticip) GetRegion() *SCloudregion {
return CloudregionManager.FetchRegionById(self.CloudregionId)
func (self *SElasticip) GetRegion() (*SCloudregion, error) {
region, err := CloudregionManager.FetchById(self.CloudregionId)
if err != nil {
return nil, errors.Wrapf(err, "CloudregionManager.FetchById")
}
return region.(*SCloudregion), nil
}
func (self *SElasticip) GetNetwork() (*SNetwork, error) {
@@ -423,22 +427,11 @@ func (self *SElasticip) SyncInstanceWithCloudEip(ctx context.Context, userCred m
return q
})
if err != nil {
log.Errorf("fail to find vm by external ID %s", vmExtId)
return err
}
switch newRes := extRes.(type) {
case *SGuest:
err = self.AssociateVM(ctx, userCred, newRes)
case *SLoadbalancer:
err = self.AssociateLoadbalancer(ctx, userCred, newRes)
case *SNatGateway:
err = self.AssociateNatGateway(ctx, userCred, newRes)
default:
return errors.Error("unsupported association type")
return errors.Wrapf(err, "db.FetchByExternalIdAndManagerId %s %s", ext.GetAssociationType(), vmExtId)
}
err = self.AssociateInstance(ctx, userCred, ext.GetAssociationType(), extRes.(db.IStatusStandaloneModel))
if err != nil {
log.Errorf("fail to associate with new vm %s", err)
return err
return errors.Wrapf(err, "AssociateInstance")
}
}
@@ -720,29 +713,32 @@ func (self *SElasticip) AssociateLoadbalancer(ctx context.Context, userCred mccl
return nil
}
func (self *SElasticip) AssociateVM(ctx context.Context, userCred mcclient.TokenCredential, vm *SGuest) error {
if vm.PendingDeleted || vm.Deleted {
return fmt.Errorf("vm is deleted")
}
if len(self.AssociateType) > 0 && len(self.AssociateId) > 0 {
if self.AssociateType == api.EIP_ASSOCIATE_TYPE_SERVER && self.AssociateId == vm.Id {
return nil
} else {
return fmt.Errorf("EIP has been associated!!")
func (self *SElasticip) AssociateInstance(ctx context.Context, userCred mcclient.TokenCredential, insType string, ins db.IStatusStandaloneModel) error {
switch insType {
case api.EIP_ASSOCIATE_TYPE_SERVER:
vm := ins.(*SGuest)
if vm.PendingDeleted || vm.Deleted {
return fmt.Errorf("vm is deleted")
}
}
if len(self.AssociateType) > 0 && len(self.AssociateId) > 0 {
if self.AssociateType == insType && self.AssociateId == ins.GetId() {
return nil
}
return fmt.Errorf("EIP has been associated!!")
}
_, err := db.Update(self, func() error {
self.AssociateType = api.EIP_ASSOCIATE_TYPE_SERVER
self.AssociateId = vm.Id
self.AssociateType = insType
self.AssociateId = ins.GetId()
return nil
})
if err != nil {
return err
return errors.Wrapf(err, "db.Update")
}
db.OpsLog.LogAttachEvent(ctx, vm, self, userCred, self.GetShortDesc(ctx))
db.OpsLog.LogEvent(self, db.ACT_EIP_ATTACH, vm.GetShortDesc(ctx), userCred)
db.OpsLog.LogEvent(vm, db.ACT_EIP_ATTACH, self.GetShortDesc(ctx), userCred)
db.OpsLog.LogAttachEvent(ctx, ins, self, userCred, self.GetShortDesc(ctx))
db.OpsLog.LogEvent(self, db.ACT_EIP_ATTACH, ins.GetShortDesc(ctx), userCred)
db.OpsLog.LogEvent(ins, db.ACT_EIP_ATTACH, self.GetShortDesc(ctx), userCred)
return nil
}
@@ -852,9 +848,9 @@ func (manager *SElasticipManager) ValidateCreateData(ctx context.Context, userCr
}
func (eip *SElasticip) GetQuotaKeys() (quotas.IQuotaKeys, error) {
region := eip.GetRegion()
region, err := eip.GetRegion()
if region == nil {
return nil, errors.Wrap(httperrors.ErrInvalidStatus, "no valid region")
return nil, errors.Wrapf(err, "eip.GetRegion")
}
return fetchRegionalQuotaKeys(
rbacutils.ScopeProject,
@@ -885,12 +881,10 @@ func (self *SElasticip) PostCreate(ctx context.Context, userCred mcclient.TokenC
func (self *SElasticip) startEipAllocateTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
task, err := taskman.TaskManager.NewTask(ctx, "EipAllocateTask", self, userCred, params, parentTaskId, "", nil)
if err != nil {
log.Errorf("newtask EipAllocateTask fail %s", err)
return err
return errors.Wrapf(err, "NewTask")
}
self.SetStatus(userCred, api.EIP_STATUS_ALLOCATE, "start allocate")
task.ScheduleRun(nil)
return nil
return task.ScheduleRun(nil)
}
func (self *SElasticip) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
@@ -928,131 +922,122 @@ func (self *SElasticip) AllowPerformAssociate(ctx context.Context, userCred mccl
return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "associate")
}
func (self *SElasticip) PerformAssociate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
func (self *SElasticip) PerformAssociate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ElasticipAssociateInput) (api.ElasticipAssociateInput, error) {
if self.IsAssociated() {
return nil, httperrors.NewConflictError("eip has been associated with instance")
return input, httperrors.NewConflictError("eip has been associated with instance")
}
if self.Status != api.EIP_STATUS_READY {
return nil, httperrors.NewInvalidStatusError("eip cannot associate in status %s", self.Status)
return input, httperrors.NewInvalidStatusError("eip cannot associate in status %s", self.Status)
}
if self.Mode == api.EIP_MODE_INSTANCE_PUBLICIP {
return nil, httperrors.NewUnsupportOperationError("fixed eip cannot be associated")
return input, httperrors.NewUnsupportOperationError("fixed eip cannot be associated")
}
instanceId := jsonutils.GetAnyString(data, []string{"instance", "instance_id"})
if len(instanceId) == 0 {
return nil, httperrors.NewMissingParameterError("instance_id")
if len(input.InstanceId) == 0 {
return input, httperrors.NewMissingParameterError("instance_id")
}
instanceType := jsonutils.GetAnyString(data, []string{"instance_type"})
if len(instanceType) == 0 {
instanceType = api.EIP_ASSOCIATE_TYPE_SERVER
if len(input.InstanceType) == 0 {
input.InstanceType = api.EIP_ASSOCIATE_TYPE_SERVER
}
if instanceType != api.EIP_ASSOCIATE_TYPE_SERVER {
return nil, httperrors.NewInputParameterError("Unsupported %s", instanceType)
if !utils.IsInStringArray(input.InstanceType, api.EIP_ASSOCIATE_VALID_TYPES) {
return input, httperrors.NewUnsupportOperationError("Unsupported instance type %s", input.InstanceType)
}
vmObj, err := GuestManager.FetchByIdOrName(userCred, instanceId)
if err != nil {
if err == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError("server %s not found", instanceId)
} else {
return nil, httperrors.NewGeneralError(err)
}
}
server := vmObj.(*SGuest)
lockman.LockObject(ctx, server)
defer lockman.ReleaseObject(ctx, server)
if server.PendingDeleted {
return nil, httperrors.NewInvalidStatusError("cannot associate pending delete server")
}
// IMPORTANT: this serves as a guard against a guest to have multiple
// associated elastic_ips
seip, _ := server.GetEipOrPublicIp()
if seip != nil {
return nil, httperrors.NewInvalidStatusError("instance is already associated with eip")
}
if ok, _ := utils.InStringArray(server.Status, []string{api.VM_READY, api.VM_RUNNING}); !ok {
return nil, httperrors.NewInvalidStatusError("cannot associate server in status %s", server.Status)
}
err = ValidateAssociateEip(server)
if err != nil {
return nil, err
}
if len(self.NetworkId) > 0 {
gns, err := server.GetNetworks("")
switch input.InstanceType {
case api.EIP_ASSOCIATE_TYPE_SERVER:
vmObj, err := GuestManager.FetchByIdOrName(userCred, input.InstanceId)
if err != nil {
return nil, httperrors.NewGeneralError(errors.Wrap(err, "GetNetworks"))
if errors.Cause(err) == sql.ErrNoRows {
return input, httperrors.NewResourceNotFoundError("server %s not found", input.InstanceId)
}
return input, httperrors.NewGeneralError(err)
}
for _, gn := range gns {
if gn.NetworkId == self.NetworkId {
return nil, httperrors.NewInputParameterError("cannot associate eip with same network")
server := vmObj.(*SGuest)
lockman.LockObject(ctx, server)
defer lockman.ReleaseObject(ctx, server)
if server.PendingDeleted {
return input, httperrors.NewInvalidStatusError("cannot associate pending delete server")
}
// IMPORTANT: this serves as a guard against a guest to have multiple
// associated elastic_ips
seip, _ := server.GetEipOrPublicIp()
if seip != nil {
return input, httperrors.NewInvalidStatusError("instance is already associated with eip")
}
if ok, _ := utils.InStringArray(server.Status, []string{api.VM_READY, api.VM_RUNNING}); !ok {
return input, httperrors.NewInvalidStatusError("cannot associate server in status %s", server.Status)
}
err = ValidateAssociateEip(server)
if err != nil {
return input, err
}
if len(self.NetworkId) > 0 {
gns, err := server.GetNetworks("")
if err != nil {
return input, httperrors.NewGeneralError(errors.Wrap(err, "GetNetworks"))
}
for _, gn := range gns {
if gn.NetworkId == self.NetworkId {
return input, httperrors.NewInputParameterError("cannot associate eip with same network")
}
}
}
}
serverRegion := server.getRegion()
if serverRegion == nil {
return nil, httperrors.NewInputParameterError("server region is not found???")
}
eipRegion := self.GetRegion()
if eipRegion == nil {
return nil, httperrors.NewInputParameterError("eip region is not found???")
}
if serverRegion.Id != eipRegion.Id {
return nil, httperrors.NewInputParameterError("eip and server are not in the same region")
}
eipZone := self.GetZone()
if eipZone != nil {
serverZone := server.getZone()
if serverZone.Id != eipZone.Id {
return nil, httperrors.NewInputParameterError("eip and server are not in the same zone")
serverRegion := server.getRegion()
if serverRegion == nil {
return input, httperrors.NewInputParameterError("server region is not found???")
}
eipRegion, err := self.GetRegion()
if err != nil {
return input, httperrors.NewGeneralError(errors.Wrapf(err, "GetRegion"))
}
if serverRegion.Id != eipRegion.Id {
return input, httperrors.NewInputParameterError("eip and server are not in the same region")
}
eipZone := self.GetZone()
if eipZone != nil {
serverZone := server.getZone()
if serverZone.Id != eipZone.Id {
return input, httperrors.NewInputParameterError("eip and server are not in the same zone")
}
}
srvHost := server.GetHost()
if srvHost == nil {
return input, httperrors.NewInputParameterError("server host is not found???")
}
if srvHost.ManagerId != self.ManagerId {
return input, httperrors.NewInputParameterError("server and eip are not managed by the same provider")
}
input.InstanceExternalId = server.ExternalId
case api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY:
}
srvHost := server.GetHost()
if srvHost == nil {
return nil, httperrors.NewInputParameterError("server host is not found???")
}
if srvHost.ManagerId != self.ManagerId {
return nil, httperrors.NewInputParameterError("server and eip are not managed by the same provider")
}
err = self.StartEipAssociateInstanceTask(ctx, userCred, server, "")
return nil, err
return input, self.StartEipAssociateInstanceTask(ctx, userCred, input, "")
}
func (self *SElasticip) StartEipAssociateInstanceTask(ctx context.Context, userCred mcclient.TokenCredential, server *SGuest, parentTaskId string) error {
params := jsonutils.NewDict()
params.Add(jsonutils.NewString(server.ExternalId), "instance_external_id")
params.Add(jsonutils.NewString(server.Id), "instance_id")
params.Add(jsonutils.NewString(api.EIP_ASSOCIATE_TYPE_SERVER), "instance_type")
func (self *SElasticip) StartEipAssociateInstanceTask(ctx context.Context, userCred mcclient.TokenCredential, input api.ElasticipAssociateInput, parentTaskId string) error {
params := jsonutils.Marshal(input).(*jsonutils.JSONDict)
return self.StartEipAssociateTask(ctx, userCred, params, parentTaskId)
}
func (self *SElasticip) StartEipAssociateTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
task, err := taskman.TaskManager.NewTask(ctx, "EipAssociateTask", self, userCred, params, parentTaskId, "", nil)
if err != nil {
log.Errorf("create EipAssociateTask task fail %s", err)
return err
return errors.Wrapf(err, "NewTask")
}
self.SetStatus(userCred, api.EIP_STATUS_ASSOCIATE, "start to associate")
task.ScheduleRun(nil)
return nil
return task.ScheduleRun(nil)
}
func (self *SElasticip) AllowPerformDissociate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
@@ -1138,9 +1123,9 @@ func (self *SElasticip) GetIRegion() (cloudprovider.ICloudRegion, error) {
return nil, errors.Wrap(err, "GetDriver")
}
region := self.GetRegion()
if region == nil {
return nil, fmt.Errorf("fail to find region for eip")
region, err := self.GetRegion()
if err != nil {
return nil, errors.Wrapf(err, "self.GetRegion")
}
return provider.GetIRegionById(region.GetExternalId())
@@ -1232,6 +1217,7 @@ type NewEipForVMOnHostArgs struct {
Guest *SGuest
Host *SHost
Natgateway *SNatGateway
PendingUsage quotas.IQuota
}
@@ -1243,12 +1229,21 @@ func (manager *SElasticipManager) NewEipForVMOnHost(ctx context.Context, userCre
autoDellocate = args.AutoDellocate
vm = args.Guest
host = args.Host
nat = args.Natgateway
pendingUsage = args.PendingUsage
region *SCloudregion = nil
)
var (
region = host.GetRegion()
regionDriver = region.GetDriver()
)
if host != nil {
region = host.GetRegion()
} else if nat != nil {
region = nat.GetRegion()
} else {
return nil, fmt.Errorf("invalid host or nat")
}
regionDriver := region.GetDriver()
if chargeType == "" {
chargeType = regionDriver.GetEipDefaultChargeType()
@@ -1266,14 +1261,31 @@ func (manager *SElasticipManager) NewEipForVMOnHost(ctx context.Context, userCre
eip.Bandwidth = bw
eip.ChargeType = chargeType
eip.AutoDellocate = tristate.NewFromBool(autoDellocate)
eip.DomainId = vm.DomainId
eip.ProjectId = vm.ProjectId
if vm != nil {
eip.DomainId = vm.DomainId
eip.ProjectId = vm.ProjectId
} else {
eip.DomainId = userCred.GetProjectDomainId()
eip.ProjectId = userCred.GetProjectId()
}
eip.ProjectSrc = string(apis.OWNER_SOURCE_LOCAL)
eip.ManagerId = host.ManagerId
if host != nil {
eip.ManagerId = host.ManagerId
} else if nat != nil {
vpc, err := nat.GetVpc()
if err != nil {
return nil, errors.Wrapf(err, "nat.GetVpc")
}
eip.ManagerId = vpc.ManagerId
}
eip.CloudregionId = region.Id
eip.Name = fmt.Sprintf("eip-for-%s", vm.GetName())
if vm != nil {
eip.Name = fmt.Sprintf("eip-for-%s", vm.GetName())
} else if nat != nil {
eip.Name = fmt.Sprintf("eip-for-%s", nat.GetName())
}
if host.ManagerId == "" {
if host != nil && host.ManagerId == "" { // kvm
hostq := HostManager.Query().SubQuery()
wireq := WireManager.Query().SubQuery()
@@ -1316,17 +1328,30 @@ func (manager *SElasticipManager) NewEipForVMOnHost(ctx context.Context, userCre
err = manager.TableSpec().Insert(ctx, eip)
if err != nil {
log.Errorf("create EIP record fail %s", err)
return nil, err
return nil, errors.Wrapf(err, "TableSpec().Insert")
}
db.OpsLog.LogEvent(eip, db.ACT_CREATE, eip.GetShortDesc(ctx), userCred)
var ownerId mcclient.IIdentityProvider = nil
if vm != nil {
ownerId = vm.GetOwnerId()
} else if nat != nil {
ownerId = nat.GetOwnerId()
}
var provider *SCloudprovider = nil
if host != nil {
provider = host.GetCloudprovider()
} else if nat != nil {
provider = nat.GetCloudprovider()
}
eipPendingUsage := &SRegionQuota{Eip: 1}
keys := fetchRegionalQuotaKeys(
rbacutils.ScopeProject,
vm.GetOwnerId(),
ownerId,
region,
host.GetCloudprovider(),
provider,
)
eipPendingUsage.SetKeys(keys)
quotas.CancelPendingUsage(ctx, userCred, pendingUsage, eipPendingUsage, true)
@@ -1334,19 +1359,15 @@ func (manager *SElasticipManager) NewEipForVMOnHost(ctx context.Context, userCre
return eip, nil
}
func (eip *SElasticip) AllocateAndAssociateVM(ctx context.Context, userCred mcclient.TokenCredential, vm *SGuest, parentTaskId string) error {
err := ValidateAssociateEip(vm)
func (eip *SElasticip) AllocateAndAssociateInstance(ctx context.Context, userCred mcclient.TokenCredential, ins IEipAssociateInstance, input api.ElasticipAssociateInput, parentTaskId string) error {
err := ValidateAssociateEip(ins)
if err != nil {
return err
}
params := jsonutils.NewDict()
params.Add(jsonutils.NewString(vm.ExternalId), "instance_external_id")
params.Add(jsonutils.NewString(vm.Id), "instance_id")
params.Add(jsonutils.NewString(api.EIP_ASSOCIATE_TYPE_SERVER), "instance_type")
vm.SetStatus(userCred, api.VM_ASSOCIATE_EIP, "allocate and associate EIP")
params := jsonutils.Marshal(input).(*jsonutils.JSONDict)
db.StatusBaseSetStatus(ins, userCred, api.INSTANCE_ASSOCIATE_EIP, "allocate and associate EIP")
return eip.startEipAllocateTask(ctx, userCred, params, parentTaskId)
}
@@ -1498,7 +1519,7 @@ func (self *SElasticip) DoPendingDelete(ctx context.Context, userCred mcclient.T
}
func (self *SElasticip) getCloudProviderInfo() SCloudProviderInfo {
region := self.GetRegion()
region, _ := self.GetRegion()
provider := self.GetCloudprovider()
return MakeCloudProviderInfo(region, nil, provider)
}

View File

@@ -2972,7 +2972,10 @@ func (self *SGuest) PerformAssociateEip(ctx context.Context, userCred mcclient.T
}
eip = eipObj.(*SElasticip)
eipRegion := eip.GetRegion()
eipRegion, err := eip.GetRegion()
if err != nil {
return nil, httperrors.NewGeneralError(errors.Wrapf(err, "eip.GetRegion"))
}
instRegion := self.getRegion()
if eip.Mode == api.EIP_MODE_INSTANCE_PUBLICIP {
@@ -3017,7 +3020,7 @@ func (self *SGuest) PerformAssociateEip(ctx context.Context, userCred mcclient.T
return nil, httperrors.NewInputParameterError("cannot associate eip and instance in different provider")
}
self.SetStatus(userCred, api.VM_ASSOCIATE_EIP, "associate eip")
self.SetStatus(userCred, api.INSTANCE_ASSOCIATE_EIP, "associate eip")
params := jsonutils.NewDict()
params.Add(jsonutils.NewString(self.ExternalId), "instance_external_id")
@@ -3048,7 +3051,7 @@ func (self *SGuest) PerformDissociateEip(ctx context.Context, userCred mcclient.
return nil, errors.Wrap(err, "eip is not accessible")
}
self.SetStatus(userCred, api.VM_DISSOCIATE_EIP, "associate eip")
self.SetStatus(userCred, api.INSTANCE_DISSOCIATE_EIP, "associate eip")
autoDelete := (input.AudoDelete != nil && *input.AudoDelete)
@@ -3126,7 +3129,13 @@ func (self *SGuest) PerformCreateEip(ctx context.Context, userCred mcclient.Toke
return nil, httperrors.NewGeneralError(err)
}
err = eip.AllocateAndAssociateVM(ctx, userCred, self, "")
opts := api.ElasticipAssociateInput{
InstanceId: self.Id,
InstanceExternalId: self.ExternalId,
InstanceType: api.EIP_ASSOCIATE_TYPE_SERVER,
}
err = eip.AllocateAndAssociateInstance(ctx, userCred, self, opts, "")
if err != nil {
return nil, httperrors.NewGeneralError(err)
}
@@ -3694,7 +3703,7 @@ func (self *SGuest) AllowPerformPostpaidExpire(ctx context.Context, userCred mcc
return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "postpaid-expire")
}
func (self *SGuest) PerformPostpaidExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
func (self *SGuest) PerformPostpaidExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PostpaidExpireInput) (jsonutils.JSONObject, error) {
if self.BillingType != billing_api.BILLING_TYPE_POSTPAID {
return nil, httperrors.NewBadRequestError("guest billing type is %s", self.BillingType)
}
@@ -3703,7 +3712,7 @@ func (self *SGuest) PerformPostpaidExpire(ctx context.Context, userCred mcclient
return nil, httperrors.NewBadRequestError("guest %s unsupport postpaid expire", self.Hypervisor)
}
bc, err := ParseBillingCycleInput(&self.SBillingResourceBase, data)
bc, err := ParseBillingCycleInput(&self.SBillingResourceBase, input)
if err != nil {
return nil, err
}

View File

@@ -178,7 +178,6 @@ type IGuestDriver interface {
IsSupportEip() bool
IsSupportPublicIp() bool
ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error
RequestAssociateEip(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, eip *SElasticip, task taskman.ITask) error
NeedStopForChangeSpec(guest *SGuest, cpuChanged, memChanged bool) bool

View File

@@ -354,7 +354,10 @@ func (manager *SGuestManager) ListItemFilter(
} else {
hostQ = hostQ.IsNullOrEmpty("manager_id")
}
region := eip.GetRegion()
region, err := eip.GetRegion()
if err != nil {
return nil, httperrors.NewGeneralError(errors.Wrapf(err, "eip.GetRegion"))
}
regionTable := CloudregionManager.Query().SubQuery()
sq := hostQ.Join(regionTable, sqlchemy.Equals(zoneTable.Field("cloudregion_id"), regionTable.Field("id"))).
Filter(sqlchemy.Equals(regionTable.Field("id"), region.GetId())).SubQuery()
@@ -1638,7 +1641,10 @@ func (manager *SGuestManager) validateEip(userCred mcclient.TokenCredential, inp
}
input.PreferManager = eipCloudprovider.Id
eipRegion := eip.GetRegion()
eipRegion, err := eip.GetRegion()
if err != nil {
return httperrors.NewGeneralError(errors.Wrapf(err, "eip.GetRegion"))
}
// preferRegionId, _ := data.GetString("prefer_region_id")
if len(preferRegionId) > 0 && preferRegionId != eipRegion.Id {
return httperrors.NewConflictError("cannot assoicate with eip %s: different region", eipStr)
@@ -4879,7 +4885,7 @@ func (self *SGuest) SyncVMEip(ctx context.Context, userCred mcclient.TokenCreden
log.Errorf("getEipByExtEip error %v", err)
result.AddError(err)
} else {
err = neip.AssociateVM(ctx, userCred, self)
err = neip.AssociateInstance(ctx, userCred, api.EIP_ASSOCIATE_TYPE_SERVER, self)
if err != nil {
log.Errorf("AssociateVM error %v", err)
result.AddError(err)
@@ -4909,7 +4915,7 @@ func (self *SGuest) SyncVMEip(ctx context.Context, userCred mcclient.TokenCreden
if err != nil {
result.AddError(err)
} else {
err = neip.AssociateVM(ctx, userCred, self)
err = neip.AssociateInstance(ctx, userCred, api.EIP_ASSOCIATE_TYPE_SERVER, self)
if err != nil {
result.AddError(err)
} else {

View File

@@ -0,0 +1,331 @@
// 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 models
import (
"context"
"database/sql"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/compare"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SNatSkuManager struct {
db.SEnabledStatusStandaloneResourceBaseManager
db.SExternalizedResourceBaseManager
SCloudregionResourceBaseManager
}
var NatSkuManager *SNatSkuManager
func init() {
NatSkuManager = &SNatSkuManager{
SEnabledStatusStandaloneResourceBaseManager: db.NewEnabledStatusStandaloneResourceBaseManager(
SNatSku{},
"nat_skus_tbl",
"nat_sku",
"nat_skus",
),
}
NatSkuManager.NameRequireAscii = false
NatSkuManager.SetVirtualObject(NatSkuManager)
}
type SNatSku struct {
db.SEnabledStatusStandaloneResourceBase
db.SExternalizedResourceBase
SCloudregionResourceBase
PrepaidStatus string `width:"32" charset:"utf8" nullable:"false" list:"user" create:"admin_optional" update:"admin" default:"available"` // 预付费资源状态 available|soldout
PostpaidStatus string `width:"32" charset:"utf8" nullable:"false" list:"user" create:"admin_optional" update:"admin" default:"available"` // 按需付费资源状态 available|soldout
Cps int `nullable:"false" list:"user" create:"optional" update:"admin"`
Conns int `nullable:"false" list:"user" create:"optional" update:"admin"`
Pps int `nullable:"false" list:"user" create:"optional" update:"admin"`
Throughput int `nullable:"false" list:"user" create:"optional" update:"admin"`
Provider string `width:"32" charset:"ascii" nullable:"false" list:"user" create:"admin_required" update:"admin"`
ZoneIds string `charset:"utf8" nullable:"true" list:"user" update:"admin" create:"admin_optional" json:"zone_ids"`
}
func (manager *SNatSkuManager) ListItemFilter(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.NatSkuListInput,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
if err != nil {
return nil, errors.Wrapf(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemFilter")
}
q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
if err != nil {
return nil, errors.Wrapf(err, "SExternalizedResourceBaseManager.ListItemFilter")
}
q, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput)
if err != nil {
return nil, errors.Wrapf(err, "SCloudregionResourceBaseManager.ListItemFilter")
}
if len(query.PostpaidStatus) > 0 {
q = q.Equals("postpaid_status", query.PostpaidStatus)
}
if len(query.PrepaidStatus) > 0 {
q = q.Equals("prepaid_status", query.PrepaidStatus)
}
return q, nil
}
func (manager *SNatSkuManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []api.NatSkuDetails {
rows := make([]api.NatSkuDetails, len(objs))
stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
regRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = api.NatSkuDetails{
EnabledStatusStandaloneResourceDetails: stdRows[i],
CloudregionResourceInfo: regRows[i],
}
}
return rows
}
func (manager *SNatSkuManager) ListItemExportKeys(ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
keys stringutils2.SSortedStrings,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SEnabledStatusStandaloneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemExportKeys")
}
q, err = manager.SCloudregionResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemExportKeys")
}
return q, nil
}
func (manager *SNatSkuManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
return q, httperrors.ErrNotFound
}
func (manager *SNatSkuManager) OrderByExtraFields(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.NatSkuListInput,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields")
}
q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput)
if err != nil {
return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
func (self *SCloudregion) GetNatSkus() ([]SNatSku, error) {
skus := []SNatSku{}
q := NatSkuManager.Query().Equals("cloudregion_id", self.Id)
err := db.FetchModelObjects(NatSkuManager, q, &skus)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return skus, nil
}
func (self SNatSku) GetGlobalId() string {
return self.ExternalId
}
func (self *SCloudregion) SyncNatSkus(ctx context.Context, userCred mcclient.TokenCredential, meta *SSkuResourcesMeta) compare.SyncResult {
lockman.LockRawObject(ctx, self.Id, "nat-sku")
defer lockman.ReleaseRawObject(ctx, self.Id, "nat-sku")
syncResult := compare.SyncResult{}
iskus, err := meta.GetNatSkusByRegionExternalId(self.ExternalId)
if err != nil {
syncResult.Error(err)
return syncResult
}
dbSkus, err := self.GetNatSkus()
if err != nil {
syncResult.Error(err)
return syncResult
}
removed := make([]SNatSku, 0)
commondb := make([]SNatSku, 0)
commonext := make([]SNatSku, 0)
added := make([]SNatSku, 0)
err = compare.CompareSets(dbSkus, iskus, &removed, &commondb, &commonext, &added)
if err != nil {
syncResult.Error(err)
return syncResult
}
for i := 0; i < len(removed); i += 1 {
err = removed[i].Delete(ctx, userCred)
if err != nil {
syncResult.DeleteError(err)
continue
}
syncResult.Delete()
}
for i := 0; i < len(commondb); i += 1 {
err = commondb[i].syncWithCloudSku(ctx, userCred, commonext[i])
if err != nil {
syncResult.UpdateError(err)
continue
}
syncResult.Update()
}
for i := 0; i < len(added); i += 1 {
err = self.newFromCloudNatSku(ctx, userCred, added[i])
if err != nil {
syncResult.AddError(err)
} else {
syncResult.Add()
}
}
return syncResult
}
func (self *SNatSku) syncWithCloudSku(ctx context.Context, userCred mcclient.TokenCredential, sku SNatSku) error {
_, err := db.Update(self, func() error {
jsonutils.Update(self, sku)
self.Status = api.NAT_SKU_AVAILABLE
return nil
})
return err
}
func (self *SCloudregion) newFromCloudNatSku(ctx context.Context, userCred mcclient.TokenCredential, isku SNatSku) error {
sku := &isku
sku.SetModelManager(NatSkuManager, sku)
sku.Id = "" //避免使用yunion meta的id,导致出现duplicate entry问题
sku.Status = api.NAT_SKU_AVAILABLE
sku.CloudregionId = self.Id
return NatSkuManager.TableSpec().Insert(ctx, sku)
}
func SyncNatSkus(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
err := SyncRegionNatSkus(ctx, userCred, "", isStart)
if err != nil {
log.Errorf("SyncRegionNatSkus error: %v", err)
}
}
func SyncRegionNatSkus(ctx context.Context, userCred mcclient.TokenCredential, regionId string, isStart bool) error {
if isStart {
q := NatSkuManager.Query()
if len(regionId) > 0 {
q = q.Equals("cloudregion_id", regionId)
}
cnt, err := q.Limit(1).CountWithError()
if err != nil && err != sql.ErrNoRows {
return errors.Wrapf(err, "SyncRegionNatSkus.QueryNatSku")
}
if cnt > 0 {
log.Debugf("SyncRegionNatSkus synced skus, skip...")
return nil
}
}
q := CloudregionManager.Query()
q = q.In("provider", CloudproviderManager.GetPublicProviderProvidersQuery())
if len(regionId) > 0 {
q = q.Equals("id", regionId)
}
regions := []SCloudregion{}
err := db.FetchModelObjects(CloudregionManager, q, &regions)
if err != nil {
return errors.Wrapf(err, "db.FetchModelObjects")
}
meta, err := FetchSkuResourcesMeta()
if err != nil {
return errors.Wrapf(err, "FetchSkuResourcesMeta")
}
for i := range regions {
if !regions[i].GetDriver().IsSupportedNatGateway() {
log.Infof("region %s(%s) not support nat, skip sync", regions[i].Name, regions[i].Id)
continue
}
result := regions[i].SyncNatSkus(ctx, userCred, meta)
msg := result.Result()
notes := fmt.Sprintf("SyncNatSkus for region %s result: %s", regions[i].Name, msg)
log.Infof(notes)
}
return nil
}
func (manager *SNatSkuManager) AllowSyncSkus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return db.IsAdminAllowPerform(userCred, manager, "sync-skus")
}
func (manager *SNatSkuManager) PerformSyncSkus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.SkuSyncInput) (jsonutils.JSONObject, error) {
return PerformActionSyncSkus(ctx, userCred, manager.Keyword(), input)
}
func (manager *SNatSkuManager) AllowGetPropertySyncTasks(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return db.IsAdminAllowGetSpec(userCred, manager, "sync-tasks")
}
func (manager *SNatSkuManager) GetPropertySyncTasks(ctx context.Context, userCred mcclient.TokenCredential, query api.SkuTaskQueryInput) (jsonutils.JSONObject, error) {
return GetPropertySkusSyncTasks(ctx, userCred, query)
}

View File

@@ -60,12 +60,12 @@ func (self *SNatgatewayResourceBase) GetNatgateway() (*SNatGateway, error) {
return obj.(*SNatGateway), nil
}
func (self *SNatgatewayResourceBase) GetVpc() *SVpc {
nat, _ := self.GetNatgateway()
if nat != nil {
return nat.GetVpc()
func (self *SNatgatewayResourceBase) GetVpc() (*SVpc, error) {
nat, err := self.GetNatgateway()
if err != nil {
return nil, errors.Wrapf(err, "self.GetNatgateway")
}
return nil
return nat.GetVpc()
}
func (self *SNatgatewayResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) api.NatGatewayResourceInfo {

View File

@@ -25,15 +25,22 @@ import (
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/compare"
"yunion.io/x/pkg/util/reflectutils"
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis"
billing_api "yunion.io/x/onecloud/pkg/apis/billing"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/billing"
"yunion.io/x/onecloud/pkg/util/logclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
@@ -41,7 +48,8 @@ type SNatGatewayManager struct {
db.SStatusInfrasResourceBaseManager
db.SExternalizedResourceBaseManager
SVpcResourceBaseManager
// SManagedResourceBaseManager
SDeletePreventableResourceBaseManager
}
var NatGatewayManager *SNatGatewayManager
@@ -61,10 +69,11 @@ func init() {
type SNatGateway struct {
db.SStatusInfrasResourceBase
db.SExternalizedResourceBase
// SManagedResourceBase
SBillingResourceBase
SVpcResourceBase
SDeletePreventableResourceBase
NatSpec string `list:"user" create:"optional"` // NAT规格
}
@@ -85,6 +94,10 @@ func (man *SNatGatewayManager) ListItemFilter(
if err != nil {
return nil, errors.Wrap(err, "SStatusInfrasResourceBaseManager.ListItemFilter")
}
q, err = man.SDeletePreventableResourceBaseManager.ListItemFilter(ctx, q, userCred, query.DeletePreventableResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SDeletePreventableResourceBaseManager.ListItemFilter")
}
q, err = man.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
@@ -128,8 +141,91 @@ func (man *SNatGatewayManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field
return q, httperrors.ErrNotFound
}
func (man *SNatGatewayManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
return nil, httperrors.NewNotImplementedError("Not Implemented")
func (man *SNatGatewayManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.NatgatewayCreateInput) (api.NatgatewayCreateInput, error) {
if len(input.NetworkId) == 0 {
return input, httperrors.NewMissingParameterError("network_id")
}
_network, err := validators.ValidateModel(userCred, NetworkManager, &input.NetworkId)
if err != nil {
return input, err
}
network := _network.(*SNetwork)
vpc := network.GetVpc()
if vpc == nil {
return input, httperrors.NewGeneralError(errors.Errorf("failed to get network %s %s vpc", network.Name, network.Id))
}
input.VpcId = vpc.Id
region, err := vpc.GetRegion()
if err != nil {
return input, httperrors.NewGeneralError(errors.Wrapf(err, "vpc.GetRegion"))
}
if len(input.Duration) > 0 {
billingCycle, err := billing.ParseBillingCycle(input.Duration)
if err != nil {
return input, httperrors.NewInputParameterError("invalid duration %s", input.Duration)
}
if !utils.IsInStringArray(input.BillingType, []string{billing_api.BILLING_TYPE_PREPAID, billing_api.BILLING_TYPE_POSTPAID}) {
input.BillingType = billing_api.BILLING_TYPE_PREPAID
}
if input.BillingType == billing_api.BILLING_TYPE_PREPAID {
if !region.GetDriver().IsSupportedBillingCycle(billingCycle, man.KeywordPlural()) {
return input, httperrors.NewInputParameterError("unsupported duration %s", input.Duration)
}
}
tm := time.Time{}
input.BillingCycle = billingCycle.String()
input.ExpiredAt = billingCycle.EndAt(tm)
}
if len(input.Eip) > 0 || input.EipBw > 0 {
if len(input.Eip) > 0 {
_eip, err := validators.ValidateModel(userCred, ElasticipManager, &input.Eip)
if err != nil {
return input, err
}
eip := _eip.(*SElasticip)
if eip.Status != api.EIP_STATUS_READY {
return input, httperrors.NewInvalidStatusError("eip %s status invalid %s", input.Eip, eip.Status)
}
if eip.IsAssociated() {
return input, httperrors.NewResourceBusyError("eip %s has been associated", input.Eip)
}
if eip.CloudregionId != vpc.CloudregionId {
return input, httperrors.NewDuplicateResourceError("elastic ip %s and vpc %s not in same region", eip.Name, vpc.Name)
}
provider := eip.GetCloudprovider()
if provider != nil && provider.Id != vpc.ManagerId {
return input, httperrors.NewConflictError("cannot assoicate with eip %s: different cloudprovider", eip.Id)
}
} else {
// create new
}
}
driver := region.GetDriver()
return driver.ValidateCreateNatGateway(ctx, userCred, input)
}
func (self *SNatGateway) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
self.SInfrasResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
err := self.StartNatGatewayCreateTask(ctx, userCred, data.(*jsonutils.JSONDict))
if err != nil {
self.SetStatus(userCred, api.NAT_STATUS_CREATE_FAILED, err.Error())
return
}
self.SetStatus(userCred, api.NAT_STATUS_ALLOCATE, "start allocate")
}
func (self *SNatGateway) StartNatGatewayCreateTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict) error {
task, err := taskman.TaskManager.NewTask(ctx, "NatGatewayCreateTask", self, userCred, params, "", "", nil)
if err != nil {
return errors.Wrapf(err, "NewTask")
}
return task.ScheduleRun(nil)
}
func (self *SNatGateway) AllowPerformSnatResources(ctx context.Context, userCred mcclient.TokenCredential,
@@ -137,6 +233,7 @@ func (self *SNatGateway) AllowPerformSnatResources(ctx context.Context, userCred
return true
}
func (self *SNatGateway) PerformSnatResources(ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
@@ -348,6 +445,8 @@ func (self *SNatGateway) syncRemoveCloudNatGateway(ctx context.Context, userCred
lockman.LockObject(ctx, self)
defer lockman.ReleaseObject(ctx, self)
self.DeletePreventionOff(self, userCred)
err := self.ValidateDeleteCondition(ctx)
if err != nil { // cannot delete
return self.SetStatus(userCred, api.NAT_STATUS_UNKNOWN, "sync to delete")
@@ -355,6 +454,13 @@ func (self *SNatGateway) syncRemoveCloudNatGateway(ctx context.Context, userCred
return self.purge(ctx, userCred)
}
func (self *SNatGateway) ValidateDeleteCondition(ctx context.Context) error {
if self.DisableDelete.IsTrue() {
return httperrors.NewInvalidStatusError("Nat is locked, cannot delete")
}
return self.SStatusInfrasResourceBase.ValidateDeleteCondition(ctx)
}
func (self *SNatGateway) SyncWithCloudNatGateway(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, extNat cloudprovider.ICloudNatGateway) error {
diff, err := db.UpdateWithLock(ctx, self, func() error {
self.Status = extNat.GetStatus()
@@ -385,11 +491,6 @@ func (manager *SNatGatewayManager) newFromCloudNatGateway(ctx context.Context, u
nat := SNatGateway{}
nat.SetModelManager(manager, &nat)
/*region, err := vpc.GetRegion()
if err != nil {
return nil, errors.Wrap(err, "vpc.GetRegion")
}*/
newName, err := db.GenerateName(manager, ownerId, extNat.GetName())
if err != nil {
return nil, errors.Wrap(err, "db.GenerateName")
@@ -402,8 +503,6 @@ func (manager *SNatGatewayManager) newFromCloudNatGateway(ctx context.Context, u
nat.CreatedAt = extNat.GetCreatedAt()
}
nat.ExternalId = extNat.GetGlobalId()
// nat.CloudregionId = region.Id
// nat.ManagerId = provider.Id
nat.IsEmulated = extNat.IsEmulated()
factory, _ := provider.GetProviderFactory()
@@ -428,11 +527,53 @@ func (manager *SNatGatewayManager) newFromCloudNatGateway(ctx context.Context, u
return &nat, nil
}
// 删除NAT
func (self *SNatGateway) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query api.ServerDeleteInput, input api.NatgatewayDeleteInput) error {
if !input.Force {
eips, err := self.GetEips()
if err != nil {
return errors.Wrapf(err, "self.GetEips")
}
if len(eips) > 0 {
return httperrors.NewNotEmptyError("natgateway has bind %d eips", len(eips))
}
dnat, err := self.GetDTable()
if err != nil {
return errors.Wrapf(err, "GetDTable()")
}
if len(dnat) > 0 {
return httperrors.NewNotEmptyError("natgateway has %d stable", len(dnat))
}
snat, err := self.GetSTable()
if err != nil {
return errors.Wrapf(err, "GetSTable")
}
if len(snat) > 0 {
return httperrors.NewNotEmptyError("natgateway has %d dtable", len(snat))
}
}
err := self.StartNatGatewayDeleteTask(ctx, userCred, nil)
if err != nil {
return err
}
self.SetStatus(userCred, api.NAT_STATUS_DELETING, jsonutils.Marshal(input).String())
return nil
}
func (self *SNatGateway) StartNatGatewayDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict) error {
task, err := taskman.TaskManager.NewTask(ctx, "NatGatewayDeleteTask", self, userCred, params, "", "", nil)
if err != nil {
return errors.Wrapf(err, "NewTask")
}
return task.ScheduleRun(nil)
}
func (self *SNatGateway) GetEips() ([]SElasticip, error) {
q := ElasticipManager.Query().Equals("associate_id", self.Id)
eips := []SElasticip{}
if err := db.FetchModelObjects(ElasticipManager, q, &eips); err != nil {
return nil, err
err := db.FetchModelObjects(ElasticipManager, q, &eips)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return eips, nil
}
@@ -458,10 +599,10 @@ func (self *SNatGateway) SyncNatGatewayEips(ctx context.Context, userCred mcclie
for i := 0; i < len(removed); i += 1 {
err := removed[i].Dissociate(ctx, userCred)
if err != nil {
result.AddError(err)
} else {
result.Delete()
result.DeleteError(err)
continue
}
result.Delete()
}
for i := 0; i < len(added); i += 1 {
@@ -480,9 +621,9 @@ func (self *SNatGateway) SyncNatGatewayEips(ctx context.Context, userCred mcclie
err = neip.AssociateNatGateway(ctx, userCred, self)
if err != nil {
result.AddError(err)
} else {
result.Add()
continue
}
result.Add()
}
return result
@@ -503,15 +644,26 @@ func (self *SNatGateway) PerformSyncstatus(ctx context.Context, userCred mcclien
return nil, httperrors.NewBadRequestError("Nat gateway has %d task active, can't sync status", count)
}
return nil, StartResourceSyncStatusTask(ctx, userCred, self, "NatGatewaySyncstatusTask", "")
return nil, self.StartSyncstatus(ctx, userCred, "")
}
func (self *SNatGateway) StartSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
return StartResourceSyncStatusTask(ctx, userCred, self, "NatGatewaySyncstatusTask", parentTaskId)
}
func (self *SNatGateway) GetVpc() (*SVpc, error) {
vpc, err := VpcManager.FetchById(self.VpcId)
if err != nil {
return nil, errors.Wrapf(err, "Fetch vpc by ID %s failed", self.VpcId)
}
return vpc.(*SVpc), nil
}
func (self *SNatGateway) GetINatGateway() (cloudprovider.ICloudNatGateway, error) {
model, err := VpcManager.FetchById(self.VpcId)
vpc, err := self.GetVpc()
if err != nil {
return nil, errors.Wrap(err, "Fetch vpc by ID failed")
return nil, errors.Wrap(err, "GetVpc")
}
vpc := model.(*SVpc)
cloudVpc, err := vpc.GetIVpc()
if err != nil {
return nil, errors.Wrap(err, "Fetch IVpc failed")
@@ -525,7 +677,11 @@ func (self *SNatGateway) GetINatGateway() (cloudprovider.ICloudNatGateway, error
return cloudNatGateways[i], nil
}
}
return nil, errors.Error("CloudNatGateway Not Found")
return nil, errors.Wrapf(cloudprovider.ErrNotFound, self.ExternalId)
}
func (self *SNatGateway) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
return nil
}
func (self *SNatGateway) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
@@ -549,7 +705,7 @@ func (self *SNatGateway) RealDelete(ctx context.Context, userCred mcclient.Token
return errors.Wrapf(err, "delete snat %s failed", snats[i].GetId())
}
}
return self.Delete(ctx, userCred)
return self.SInfrasResourceBase.Delete(ctx, userCred)
}
func (nm *SNatGatewayManager) NatNameToReal(name string, natgatewayId string) string {
@@ -588,7 +744,6 @@ type SNatEntry struct {
db.SExternalizedResourceBase
SNatgatewayResourceBase `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"`
// NatgatewayId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"`
}
func (manager *SNatEntryManager) GetContextManagers() [][]db.IModelManager {
@@ -694,6 +849,144 @@ func (manager *SNatEntryManager) FetchCustomizeColumns(
return rows
}
func (self *SNatGateway) AllowPerformPostpaidExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "postpaid-expire")
}
func (self *SNatGateway) PerformPostpaidExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PostpaidExpireInput) (jsonutils.JSONObject, error) {
if self.BillingType != billing_api.BILLING_TYPE_POSTPAID {
return nil, httperrors.NewBadRequestError("nat gateway billing type is %s", self.BillingType)
}
bc, err := ParseBillingCycleInput(&self.SBillingResourceBase, input)
if err != nil {
return nil, err
}
err = self.SaveRenewInfo(ctx, userCred, bc, nil, billing_api.BILLING_TYPE_POSTPAID)
return nil, err
}
func (self *SNatGateway) SaveRenewInfo(
ctx context.Context, userCred mcclient.TokenCredential,
bc *billing.SBillingCycle, expireAt *time.Time, billingType string,
) error {
_, err := db.Update(self, func() error {
if billingType == "" {
billingType = billing_api.BILLING_TYPE_PREPAID
}
if self.BillingType == "" {
self.BillingType = billingType
}
if expireAt != nil && !expireAt.IsZero() {
self.ExpiredAt = *expireAt
} else {
self.BillingCycle = bc.String()
self.ExpiredAt = bc.EndAt(self.ExpiredAt)
}
return nil
})
if err != nil {
return errors.Wrapf(err, "db.Update")
}
db.OpsLog.LogEvent(self, db.ACT_RENEW, self.GetShortDesc(ctx), userCred)
return nil
}
func (self *SNatGateway) AllowPerformRenew(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "renew")
}
func (self *SNatGateway) PerformRenew(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.RenewInput) (jsonutils.JSONObject, error) {
if !utils.IsInStringArray(self.Status, []string{api.NAT_STAUTS_AVAILABLE}) {
return nil, httperrors.NewInvalidStatusError("Cannot do renew nat gateway in status %s required status %s", self.Status, api.NAT_SKU_AVAILABLE)
}
if len(input.Duration) == 0 {
return nil, httperrors.NewMissingParameterError("duration")
}
bc, err := billing.ParseBillingCycle(input.Duration)
if err != nil {
return nil, httperrors.NewInputParameterError("invalid duration %s: %s", input.Duration, err)
}
if !self.GetRegion().GetDriver().IsSupportedBillingCycle(bc, NatGatewayManager.KeywordPlural()) {
return nil, httperrors.NewInputParameterError("unsupported duration %s", input.Duration)
}
return nil, self.StartRenewTask(ctx, userCred, input.Duration, "")
}
func (self *SNatGateway) StartRenewTask(ctx context.Context, userCred mcclient.TokenCredential, duration string, parentTaskId string) error {
data := jsonutils.NewDict()
data.Set("duration", jsonutils.NewString(duration))
task, err := taskman.TaskManager.NewTask(ctx, "NatGatewayRenewTask", self, userCred, data, parentTaskId, "", nil)
if err != nil {
return errors.Wrap(err, "NewTask")
}
self.SetStatus(userCred, api.NAT_STATUS_RENEWING, "")
return task.ScheduleRun(nil)
}
func (self *SNatGateway) AllowPerformSetAutoRenew(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return db.IsAdminAllowPerform(userCred, self, "set-auto-renew")
}
func (self *SNatGateway) SetAutoRenew(autoRenew bool) error {
_, err := db.Update(self, func() error {
self.AutoRenew = autoRenew
return nil
})
return err
}
// 设置自动续费
// 要求NAT状态为available
// 要求NAT计费类型为包年包月(预付费)
func (self *SNatGateway) PerformSetAutoRenew(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.AutoRenewInput) (jsonutils.JSONObject, error) {
if !utils.IsInStringArray(self.Status, []string{api.NAT_STAUTS_AVAILABLE}) {
return nil, httperrors.NewUnsupportOperationError("The nat gateway status need be %s, current is %s", api.NAT_STAUTS_AVAILABLE, self.Status)
}
if self.BillingType != billing_api.BILLING_TYPE_PREPAID {
return nil, httperrors.NewUnsupportOperationError("Only %s nat gateway support this operation", billing_api.BILLING_TYPE_PREPAID)
}
if self.AutoRenew == input.AutoRenew {
return nil, nil
}
region := self.GetRegion()
if region == nil {
return nil, httperrors.NewGeneralError(fmt.Errorf("filed to get nat %s region", self.Name))
}
driver := region.GetDriver()
if !driver.IsSupportedNatAutoRenew() {
err := self.SetAutoRenew(input.AutoRenew)
if err != nil {
return nil, httperrors.NewGeneralError(err)
}
logclient.AddSimpleActionLog(self, logclient.ACT_SET_AUTO_RENEW, input, userCred, true)
return nil, nil
}
return nil, self.StartSetAutoRenewTask(ctx, userCred, input.AutoRenew, "")
}
func (self *SNatGateway) StartSetAutoRenewTask(ctx context.Context, userCred mcclient.TokenCredential, autoRenew bool, parentTaskId string) error {
data := jsonutils.NewDict()
data.Set("auto_renew", jsonutils.NewBool(autoRenew))
task, err := taskman.TaskManager.NewTask(ctx, "NatGatewaySetAutoRenewTask", self, userCred, data, parentTaskId, "", nil)
if err != nil {
return errors.Wrap(err, "NewTask")
}
self.SetStatus(userCred, api.NAT_STATUS_SET_AUTO_RENEW, "")
return task.ScheduleRun(nil)
}
func (self *SNatEntry) GetINatGateway() (cloudprovider.ICloudNatGateway, error) {
model, err := NatGatewayManager.FetchById(self.NatgatewayId)
if err != nil {
@@ -731,3 +1024,40 @@ func (self *SNatEntry) ValidateUpdateData(ctx context.Context, userCred mcclient
}
return nil, nil
}
func (manager *SNatGatewayManager) getExpiredPostpaids() ([]SNatGateway, error) {
q := ListExpiredPostpaidResources(manager.Query(), options.Options.ExpiredPrepaidMaxCleanBatchSize)
nats := make([]SNatGateway, 0)
err := db.FetchModelObjects(manager, q, &nats)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return nats, nil
}
func (self *SNatGateway) doExternalSync(ctx context.Context, userCred mcclient.TokenCredential) error {
iNat, err := self.GetINatGateway()
if err != nil {
return errors.Wrapf(err, "GetINatGateway")
}
return self.SyncWithCloudNatGateway(ctx, userCred, self.GetCloudprovider(), iNat)
}
func (manager *SNatGatewayManager) DeleteExpiredPostpaids(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
nats, err := manager.getExpiredPostpaids()
if err != nil {
log.Errorf("Nats getExpiredPostpaids error: %v", err)
return
}
for i := 0; i < len(nats); i += 1 {
if len(nats[i].ExternalId) > 0 {
err := nats[i].doExternalSync(ctx, userCred)
if err == nil && nats[i].IsValidPostPaid() {
continue
}
}
nats[i].DeletePreventionOff(&nats[i], userCred)
nats[i].StartNatGatewayDeleteTask(ctx, userCred, nil)
}
}

View File

@@ -177,9 +177,9 @@ func (man *SNatSEntryManager) ValidateCreateData(ctx context.Context, userCred m
}
natgateway := model.(*SNatGateway)
// get vpc
vpc := natgateway.GetVpc()
if vpc == nil {
return nil, errors.Wrap(httperrors.ErrBadRequest, "invalid natgateway vpc")
vpc, err := natgateway.GetVpc()
if err != nil {
return nil, errors.Wrapf(err, "GetVpc")
}
vpcIPV4Range, err := newIPv4RangeFromCIDR(vpc.CidrBlock)

View File

@@ -1228,12 +1228,14 @@ func (nat *SNatGateway) purge(ctx context.Context, userCred mcclient.TokenCreden
return err
}
nat.DeletePreventionOff(nat, userCred)
err = nat.ValidateDeleteCondition(ctx)
if err != nil {
return err
}
return nat.Delete(ctx, userCred)
return nat.RealDelete(ctx, userCred)
}
func (manager *SNatGatewayManager) purgeAll(ctx context.Context, userCred mcclient.TokenCredential, providerId string) error {

View File

@@ -180,6 +180,16 @@ type IDBInstanceDriver interface {
RequestRemoteUpdateDBInstance(ctx context.Context, userCred mcclient.TokenCredential, instance *SDBInstance, replaceTags bool, task taskman.ITask) error
RequestSyncRdsSecurityGroups(ctx context.Context, userCred mcclient.TokenCredential, rds *SDBInstance, task taskman.ITask) error
INatGatewayDriver
IElasticIpDriver
}
type INatGatewayDriver interface {
IsSupportedNatGateway() bool
IsSupportedNatAutoRenew() bool
ValidateCreateNatGateway(ctx context.Context, userCred mcclient.TokenCredential, input api.NatgatewayCreateInput) (api.NatgatewayCreateInput, error)
}
type IElasticcacheDriver interface {
@@ -236,6 +246,10 @@ type IElasticcacheBackup interface {
RequestElasticcacheBackupRestoreInstance(ctx context.Context, userCred mcclient.TokenCredential, ea *SElasticcacheBackup, task taskman.ITask) error
}
type IElasticIpDriver interface {
RequestAssociatEip(ctx context.Context, userCred mcclient.TokenCredential, eip *SElasticip, input api.ElasticipAssociateInput, obj db.IStatusStandaloneModel, task taskman.ITask) error
}
var regionDrivers map[string]IRegionDriver
func init() {

View File

@@ -19,7 +19,7 @@ import (
)
func PerformActionSyncSkus(ctx context.Context, userCred mcclient.TokenCredential, resourceKey string, input apis.SkuSyncInput) (jsonutils.JSONObject, error) {
if !utils.IsInStringArray(resourceKey, []string{ServerSkuManager.Keyword(), ElasticcacheSkuManager.Keyword(), DBInstanceSkuManager.Keyword()}) {
if !utils.IsInStringArray(resourceKey, []string{ServerSkuManager.Keyword(), ElasticcacheSkuManager.Keyword(), DBInstanceSkuManager.Keyword(), NatSkuManager.Keyword()}) {
return nil, httperrors.NewUnsupportOperationError("resource %s is not support sync skus", resourceKey)
}

View File

@@ -47,6 +47,7 @@ type SSkuResourcesMeta struct {
ServerBase string `json:"server_base"`
ElasticCacheBase string `json:"elastic_cache_base"`
ImageBase string `json:"image_base"`
NatBase string `json:"nat_base"`
}
func (self *SSkuResourcesMeta) getZoneIdBySuffix(zoneMaps map[string]string, suffix string) string {
@@ -123,6 +124,43 @@ func (self *SSkuResourcesMeta) GetDBInstanceSkusByRegionExternalId(regionExterna
return result, nil
}
func (self *SSkuResourcesMeta) GetNatSkusByRegionExternalId(regionExternalId string) ([]SNatSku, error) {
regionId, zoneMaps, err := self.GetRegionIdAndZoneMaps(regionExternalId)
if err != nil {
return nil, errors.Wrap(err, "GetRegionIdAndZoneMaps")
}
result := []SNatSku{}
objs, err := self.getObjsByRegion(self.NatBase, regionExternalId)
if err != nil {
return nil, errors.Wrapf(err, "getSkusByRegion")
}
for _, obj := range objs {
sku := SNatSku{}
sku.SetModelManager(NatSkuManager, &sku)
err = obj.Unmarshal(&sku)
if err != nil {
return nil, errors.Wrapf(err, "obj.Unmarshal")
}
if len(sku.ZoneIds) > 0 {
zoneIds := []string{}
for _, zoneExtId := range strings.Split(sku.ZoneIds, ",") {
zoneId := self.getZoneIdBySuffix(zoneMaps, zoneExtId) // Huawei rds sku zone1 maybe is cn-north-4f
if len(zoneId) == 0 {
log.Warningf("invalid nat sku %s(%s) %s zone: %s", sku.Name, sku.Id, sku.CloudregionId, zoneExtId)
continue
}
zoneIds = append(zoneIds, zoneId)
}
sku.ZoneIds = strings.Join(zoneIds, ",")
}
sku.Id = ""
sku.CloudregionId = regionId
result = append(result, sku)
}
return result, nil
}
func (self *SSkuResourcesMeta) getCloudregion(regionExternalId string) (*SCloudregion, error) {
region, err := db.FetchByExternalId(CloudregionManager, regionExternalId)
if err != nil {

View File

@@ -1091,7 +1091,7 @@ func (self *SAliyunRegionDriver) ValidateCreateDBInstanceData(ctx context.Contex
func (self *SAliyunRegionDriver) IsSupportedBillingCycle(bc billing.SBillingCycle, resource string) bool {
switch resource {
case models.DBInstanceManager.KeywordPlural(), models.ElasticcacheManager.KeywordPlural():
case models.DBInstanceManager.KeywordPlural(), models.ElasticcacheManager.KeywordPlural(), models.NatGatewayManager.KeywordPlural():
years := bc.GetYears()
months := bc.GetMonths()
if (years >= 1 && years <= 3) || (months >= 1 && months <= 9) {
@@ -1582,3 +1582,11 @@ func (self *SAliyunRegionDriver) ValidateCreateVpcData(ctx context.Context, user
return input, nil
}
func (self *SAliyunRegionDriver) ValidateCreateNatGateway(ctx context.Context, userCred mcclient.TokenCredential, input api.NatgatewayCreateInput) (api.NatgatewayCreateInput, error) {
return input, nil
}
func (self *SAliyunRegionDriver) IsSupportedNatGateway() bool {
return true
}

View File

@@ -1503,3 +1503,59 @@ func (self *SAwsRegionDriver) RequestDeleteVpc(ctx context.Context, userCred mcc
})
return nil
}
func (self *SAwsRegionDriver) RequestAssociateEip(ctx context.Context, userCred mcclient.TokenCredential, eip *models.SElasticip, input api.ElasticipAssociateInput, obj db.IStatusStandaloneModel, task taskman.ITask) error {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
iEip, err := eip.GetIEip()
if err != nil {
return nil, errors.Wrapf(err, "eip.GetIEip")
}
conf := &cloudprovider.AssociateConfig{
InstanceId: input.InstanceExternalId,
Bandwidth: eip.Bandwidth,
AssociateType: api.EIP_ASSOCIATE_TYPE_SERVER,
}
err = iEip.Associate(conf)
if err != nil {
return nil, errors.Wrapf(err, "iEip.Associate")
}
err = cloudprovider.WaitStatus(iEip, api.EIP_STATUS_READY, 3*time.Second, 60*time.Second)
if err != nil {
return nil, errors.Wrap(err, "cloudprovider.WaitStatus")
}
if obj.GetStatus() != api.INSTANCE_ASSOCIATE_EIP {
db.StatusBaseSetStatus(obj, userCred, api.INSTANCE_ASSOCIATE_EIP, "associate eip")
}
err = eip.AssociateInstance(ctx, userCred, input.InstanceType, obj)
if err != nil {
return nil, errors.Wrapf(err, "eip.AssociateVM")
}
if input.InstanceType == api.EIP_ASSOCIATE_TYPE_SERVER {
// 如果aws已经绑定了EIP则要把多余的公有IP删除
if iEip.GetMode() == api.EIP_MODE_STANDALONE_EIP {
server := obj.(*models.SGuest)
publicIP, err := server.GetPublicIp()
if err != nil {
return nil, errors.Wrap(err, "AwsGuestDriver.GetPublicIp")
}
if publicIP != nil {
err = db.DeleteModel(ctx, userCred, publicIP)
if err != nil {
return nil, errors.Wrap(err, "AwsGuestDriver.DeletePublicIp")
}
}
}
}
eip.SetStatus(userCred, api.EIP_STATUS_READY, "associate")
return nil, nil
})
return nil
}

View File

@@ -24,6 +24,7 @@ import (
"yunion.io/x/pkg/util/secrules"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
@@ -432,3 +433,19 @@ func (self *SBaseRegionDriver) RequestElasticcacheSetAutoRenew(ctx context.Conte
func (self *SBaseRegionDriver) RequestSyncRdsSecurityGroups(ctx context.Context, userCred mcclient.TokenCredential, rds *models.SDBInstance, task taskman.ITask) error {
return errors.Wrapf(cloudprovider.ErrNotImplemented, "RequestSyncRdsSecurityGroups")
}
func (self *SBaseRegionDriver) IsSupportedNatGateway() bool {
return false
}
func (self *SBaseRegionDriver) ValidateCreateNatGateway(ctx context.Context, userCred mcclient.TokenCredential, input api.NatgatewayCreateInput) (api.NatgatewayCreateInput, error) {
return input, httperrors.NewNotImplementedError("ValidateCreateNatGateway")
}
func (self *SBaseRegionDriver) IsSupportedNatAutoRenew() bool {
return true
}
func (self *SBaseRegionDriver) RequestAssociatEip(ctx context.Context, userCred mcclient.TokenCredential, eip *models.SElasticip, input api.ElasticipAssociateInput, obj db.IStatusStandaloneModel, task taskman.ITask) error {
return httperrors.NewNotImplementedError("RequestAssociatEip")
}

View File

@@ -2676,3 +2676,7 @@ func (self *SHuaWeiRegionDriver) ValidateCreateVpcData(ctx context.Context, user
}
return input, nil
}
func (self *SHuaWeiRegionDriver) IsSupportedNatGateway() bool {
return true
}

View File

@@ -25,6 +25,7 @@ import (
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
@@ -1405,3 +1406,60 @@ func (self *SKVMRegionDriver) IsSupportedElasticcacheSecgroup() bool {
func (self *SKVMRegionDriver) GetMaxElasticcacheSecurityGroupCount() int {
return 0
}
func (self *SKVMRegionDriver) RequestAssociatEip(ctx context.Context, userCred mcclient.TokenCredential, eip *models.SElasticip, input api.ElasticipAssociateInput, obj db.IStatusStandaloneModel, task taskman.ITask) error {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
if input.InstanceType != api.EIP_ASSOCIATE_TYPE_SERVER {
return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "instance type %s", input.InstanceType)
}
guest := obj.(*models.SGuest)
if guest.GetHypervisor() != api.HYPERVISOR_KVM {
return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "not support associate eip for hypervisor %s", guest.GetHypervisor())
}
lockman.LockObject(ctx, guest)
defer lockman.ReleaseObject(ctx, guest)
var guestnics []models.SGuestnetwork
{
netq := models.NetworkManager.Query().SubQuery()
wirq := models.WireManager.Query().SubQuery()
vpcq := models.VpcManager.Query().SubQuery()
gneq := models.GuestnetworkManager.Query()
q := gneq.Equals("guest_id", guest.Id).
IsNullOrEmpty("eip_id")
q = q.Join(netq, sqlchemy.Equals(netq.Field("id"), gneq.Field("network_id")))
q = q.Join(wirq, sqlchemy.Equals(wirq.Field("id"), netq.Field("wire_id")))
q = q.Join(vpcq, sqlchemy.Equals(vpcq.Field("id"), wirq.Field("vpc_id")))
q = q.Filter(sqlchemy.NotEquals(vpcq.Field("id"), api.DEFAULT_VPC_ID))
if err := db.FetchModelObjects(models.GuestnetworkManager, q, &guestnics); err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
if len(guestnics) == 0 {
return nil, errors.Errorf("guest has no nics to associate eip")
}
}
guestnic := &guestnics[0]
lockman.LockObject(ctx, guestnic)
defer lockman.ReleaseObject(ctx, guestnic)
if _, err := db.Update(guestnic, func() error {
guestnic.EipId = eip.Id
return nil
}); err != nil {
return nil, errors.Wrapf(err, "set associated eip for guestnic %s (guest:%s, network:%s)",
guestnic.Ifname, guestnic.GuestId, guestnic.NetworkId)
}
if err := eip.AssociateInstance(ctx, userCred, api.EIP_ASSOCIATE_TYPE_SERVER, guest); err != nil {
return nil, errors.Wrapf(err, "associate eip %s(%s) to vm %s(%s)", eip.Name, eip.Id, guest.Name, guest.Id)
}
if err := eip.SetStatus(userCred, api.EIP_STATUS_READY, api.EIP_STATUS_ASSOCIATE); err != nil {
return nil, errors.Wrapf(err, "set eip status to %s", api.EIP_STATUS_ALLOCATE)
}
return nil, nil
})
return nil
}

View File

@@ -3157,3 +3157,41 @@ func (self *SManagedVirtualizationRegionDriver) RequestSyncRdsSecurityGroups(ctx
})
return nil
}
func (self *SManagedVirtualizationRegionDriver) RequestAssociatEip(ctx context.Context, userCred mcclient.TokenCredential, eip *models.SElasticip, input api.ElasticipAssociateInput, obj db.IStatusStandaloneModel, task taskman.ITask) error {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
iEip, err := eip.GetIEip()
if err != nil {
return nil, errors.Wrapf(err, "eip.GetIEip")
}
conf := &cloudprovider.AssociateConfig{
InstanceId: input.InstanceExternalId,
Bandwidth: eip.Bandwidth,
AssociateType: input.InstanceType,
}
err = iEip.Associate(conf)
if err != nil {
return nil, errors.Wrapf(err, "extEip.Associate")
}
err = cloudprovider.WaitStatus(iEip, api.EIP_STATUS_READY, 3*time.Second, 60*time.Second)
if err != nil {
return nil, errors.Wrap(err, "cloudprovider.WaitStatus")
}
if obj.GetStatus() != api.INSTANCE_ASSOCIATE_EIP {
db.StatusBaseSetStatus(obj, userCred, api.INSTANCE_ASSOCIATE_EIP, "associate eip")
}
err = eip.AssociateInstance(ctx, userCred, input.InstanceType, obj)
if err != nil {
return nil, errors.Wrapf(err, "eip.AssociateVM")
}
eip.SetStatus(userCred, api.EIP_STATUS_READY, api.EIP_STATUS_ASSOCIATE)
return nil, nil
})
return nil
}

View File

@@ -203,6 +203,8 @@ func InitHandlers(app *appsrv.Application) {
models.VpcPeeringConnectionManager,
models.InterVpcNetworkManager,
models.NatSkuManager,
} {
db.RegisterModelManager(manager)
handler := db.NewModelHandler(manager)

View File

@@ -129,6 +129,7 @@ func StartService() {
cron.AddJobAtIntervals("CleanExpiredPostpaidElasticCaches", time.Duration(opts.PrepaidExpireCheckSeconds)*time.Second, models.ElasticcacheManager.DeleteExpiredPostpaids)
cron.AddJobAtIntervals("CleanExpiredPostpaidDBInstances", time.Duration(opts.PrepaidExpireCheckSeconds)*time.Second, models.DBInstanceManager.DeleteExpiredPostpaids)
cron.AddJobAtIntervals("CleanExpiredPostpaidServers", time.Duration(opts.PrepaidExpireCheckSeconds)*time.Second, models.GuestManager.DeleteExpiredPostpaidServers)
cron.AddJobAtIntervals("CleanExpiredPostpaidNatGateways", time.Duration(opts.PrepaidExpireCheckSeconds)*time.Second, models.NatGatewayManager.DeleteExpiredPostpaids)
cron.AddJobAtIntervals("StartHostPingDetectionTask", time.Duration(opts.HostOfflineDetectionInterval)*time.Second, models.HostManager.PingDetectionTask)
cron.AddJobAtIntervalsWithStartRun("CalculateQuotaUsages", time.Duration(opts.CalculateQuotaUsageIntervalSeconds)*time.Second, models.QuotaManager.CalculateQuotaUsages, true)
@@ -151,6 +152,7 @@ func StartService() {
cron.AddJobEveryFewHour("SnapshotsCleanup", 1, 35, 0, models.SnapshotManager.CleanupSnapshots, false)
cron.AddJobEveryFewDays("SyncSkus", opts.SyncSkusDay, opts.SyncSkusHour, 0, 0, models.SyncServerSkus, true)
cron.AddJobEveryFewDays("SyncDBInstanceSkus", opts.SyncSkusDay, opts.SyncSkusHour, 0, 0, models.SyncDBInstanceSkus, true)
cron.AddJobEveryFewDays("SyncNatSkus", opts.SyncSkusDay, opts.SyncSkusHour, 0, 0, models.SyncNatSkus, false)
cron.AddJobEveryFewDays("SyncElasticCacheSkus", opts.SyncSkusDay, opts.SyncSkusHour, 0, 0, models.SyncElasticCacheSkus, true)
cron.AddJobEveryFewDays("StorageSnapshotsRecycle", 1, 2, 0, 0, models.StorageManager.StorageSnapshotsRecycle, false)

View File

@@ -102,6 +102,9 @@ func (self *CloudAccountSyncSkusTask) OnInit(ctx context.Context, obj db.IStanda
syncFunc = models.ElasticcacheSkuManager.SyncElasticcacheSkus
case models.DBInstanceSkuManager.Keyword():
syncFunc = models.DBInstanceSkuManager.SyncDBInstanceSkus
case models.NatSkuManager.Keyword():
result := region.SyncNatSkus(ctx, self.GetUserCred(), meta)
log.Infof("Sync %s %s skus for region %s result: %s", region.Provider, res, region.Name, result.Result())
}
if syncFunc != nil {

View File

@@ -46,6 +46,9 @@ func (self *CloudRegionSyncSkusTask) OnInit(ctx context.Context, obj db.IStandal
syncFunc = models.ElasticcacheSkuManager.SyncElasticcacheSkus
case models.DBInstanceSkuManager.Keyword():
syncFunc = models.DBInstanceSkuManager.SyncDBInstanceSkus
case models.NatSkuManager.Keyword():
result := region.SyncNatSkus(ctx, self.GetUserCred(), meta)
log.Infof("Sync %s %s skus for region %s result: %s", region.Provider, res, region.Name, result.Result())
}
if syncFunc != nil {

View File

@@ -58,7 +58,7 @@ func (self *EipAllocateTask) setGuestAllocateEipFailed(eip *models.SElasticip, r
return
}
guest := instance.(*models.SGuest)
guest.SetStatus(self.UserCred, api.VM_ASSOCIATE_EIP_FAILED, reason.String())
guest.SetStatus(self.UserCred, api.INSTANCE_ASSOCIATE_EIP_FAILED, reason.String())
}
}

View File

@@ -19,6 +19,7 @@ import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
@@ -35,58 +36,98 @@ func init() {
taskman.RegisterTask(EipAssociateTask{})
}
func (self *EipAssociateTask) TaskFail(ctx context.Context, eip *models.SElasticip, msg jsonutils.JSONObject, vm *models.SGuest) {
eip.SetStatus(self.UserCred, api.EIP_STATUS_READY, msg.String())
self.SetStageFailed(ctx, msg)
if vm != nil {
vm.SetStatus(self.UserCred, api.VM_ASSOCIATE_EIP_FAILED, msg.String())
db.OpsLog.LogEvent(vm, db.ACT_EIP_ATTACH, msg, self.GetUserCred())
logclient.AddActionLogWithStartable(self, vm, logclient.ACT_EIP_ASSOCIATE, msg, self.UserCred, false)
func (self *EipAssociateTask) taskFail(ctx context.Context, eip *models.SElasticip, obj db.IStatusStandaloneModel, err error) {
eip.SetStatus(self.UserCred, api.EIP_STATUS_READY, err.Error())
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
if obj != nil {
db.StatusBaseSetStatus(obj, self.GetUserCred(), api.INSTANCE_ASSOCIATE_EIP_FAILED, err.Error())
db.OpsLog.LogEvent(obj, db.ACT_EIP_ATTACH, err, self.GetUserCred())
logclient.AddActionLogWithStartable(self, obj, logclient.ACT_EIP_ASSOCIATE, err, self.UserCred, false)
}
logclient.AddActionLogWithStartable(self, eip, logclient.ACT_VM_ASSOCIATE, err, self.UserCred, false)
}
func (self *EipAssociateTask) GetAssociateInput() (api.ElasticipAssociateInput, error) {
input := api.ElasticipAssociateInput{}
err := self.Params.Unmarshal(&input)
if err != nil {
return input, errors.Wrapf(err, "self.Params.Unmarshal")
}
return input, nil
}
func (self *EipAssociateTask) GetAssociateObj() (db.IStatusStandaloneModel, api.ElasticipAssociateInput, error) {
input, err := self.GetAssociateInput()
if err != nil {
return nil, input, errors.Wrapf(err, "GetAssociateInput")
}
switch input.InstanceType {
case api.EIP_ASSOCIATE_TYPE_SERVER:
vmObj, err := models.GuestManager.FetchById(input.InstanceId)
if err != nil {
return nil, input, errors.Wrapf(err, "GuestManager.FetchById(%s)", input.InstanceId)
}
return vmObj.(*models.SGuest), input, nil
case api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY:
natObj, err := models.NatGatewayManager.FetchById(input.InstanceId)
if err != nil {
return nil, input, errors.Wrapf(err, "NatGatewayManager.FetchById(%s)", input.InstanceId)
}
return natObj.(*models.SNatGateway), input, nil
default:
return nil, input, fmt.Errorf("invalid instance type %s", input.InstanceType)
}
logclient.AddActionLogWithStartable(self, eip, logclient.ACT_VM_ASSOCIATE, msg, self.UserCred, false)
}
func (self *EipAssociateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
eip := obj.(*models.SElasticip)
instanceId, _ := self.Params.GetString("instance_id")
server := models.GuestManager.FetchGuestById(instanceId)
if server == nil {
msg := fmt.Sprintf("fail to find server for instanceId %s", instanceId)
self.TaskFail(ctx, eip, jsonutils.NewString(msg), nil)
region, err := eip.GetRegion()
if err != nil {
self.taskFail(ctx, eip, nil, errors.Wrapf(err, "eip.GetRegion"))
return
}
driver := server.GetDriver()
if driver == nil {
msg := fmt.Sprintf("fail to find guest driver for instanceId %s", instanceId)
self.TaskFail(ctx, eip, jsonutils.NewString(msg), nil)
ins, input, err := self.GetAssociateObj()
if err != nil {
self.taskFail(ctx, eip, nil, errors.Wrapf(err, "self.GetAssociateObj"))
return
}
db.StatusBaseSetStatus(ins, self.GetUserCred(), api.INSTANCE_ASSOCIATE_EIP, "associate eip")
self.SetStage("OnAssociateEipComplete", nil)
if err := driver.RequestAssociateEip(ctx, self.UserCred, server, eip, self); err != nil {
self.TaskFail(ctx, eip, jsonutils.NewString(err.Error()), server)
err = region.GetDriver().RequestAssociatEip(ctx, self.UserCred, eip, input, ins, self)
if err != nil {
self.taskFail(ctx, eip, ins, errors.Wrapf(err, "RequestAssociatEip"))
return
}
}
func (self *EipAssociateTask) OnAssociateEipComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
eip := obj.(*models.SElasticip)
instanceId, _ := self.Params.GetString("instance_id")
server := models.GuestManager.FetchGuestById(instanceId)
server.StartSyncstatus(ctx, self.UserCred, "")
logclient.AddActionLogWithStartable(self, server, logclient.ACT_EIP_ASSOCIATE, nil, self.UserCred, true)
logclient.AddActionLogWithStartable(self, eip, logclient.ACT_VM_ASSOCIATE, nil, self.UserCred, true)
ins, input, err := self.GetAssociateObj()
if err == nil {
switch input.InstanceType {
case api.EIP_ASSOCIATE_TYPE_SERVER:
server := ins.(*models.SGuest)
server.StartSyncstatus(ctx, self.UserCred, "")
logclient.AddActionLogWithStartable(self, eip, logclient.ACT_VM_ASSOCIATE, nil, self.UserCred, true)
case api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY:
nat := ins.(*models.SNatGateway)
nat.StartSyncstatus(ctx, self.UserCred, "")
logclient.AddActionLogWithStartable(self, eip, logclient.ACT_NATGATEWAY_ASSOCIATE, nil, self.UserCred, true)
}
logclient.AddActionLogWithStartable(self, ins, logclient.ACT_EIP_ASSOCIATE, nil, self.UserCred, true)
}
self.SetStageComplete(ctx, nil)
}
func (self *EipAssociateTask) OnAssociateEipCompleteFailed(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
eip := obj.(*models.SElasticip)
instanceId, _ := self.Params.GetString("instance_id")
server := models.GuestManager.FetchGuestById(instanceId)
self.TaskFail(ctx, eip, data, server)
return
ins, _, _ := self.GetAssociateObj()
self.taskFail(ctx, eip, ins, errors.Errorf(data.String()))
}

View File

@@ -21,6 +21,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
@@ -129,17 +130,24 @@ func (self *GuestCreateTask) OnDeployGuestDescComplete(ctx context.Context, obj
eip := eipObj.(*models.SElasticip)
input := api.ElasticipAssociateInput{
InstanceId: guest.Id,
InstanceExternalId: guest.ExternalId,
InstanceType: api.EIP_ASSOCIATE_TYPE_SERVER,
}
eipBw, _ := self.Params.Int("eip_bw")
if eipBw > 0 {
// newly allocated eip, need allocation and associate
err = eip.AllocateAndAssociateVM(ctx, self.UserCred, guest, self.GetId())
err = eip.AllocateAndAssociateInstance(ctx, self.UserCred, guest, input, self.GetId())
err = errors.Wrapf(err, "eip.AllocateAndAssociateInstance")
} else {
// existing eip, association only
err = eip.StartEipAssociateInstanceTask(ctx, self.UserCred, guest, self.GetId())
err = eip.StartEipAssociateInstanceTask(ctx, self.UserCred, input, self.GetId())
err = errors.Wrapf(err, "eip.StartEipAssociateInstanceTask")
}
if err != nil {
msg := fmt.Sprintf("fail to asscociate eip %s %s", eipId, err)
self.OnDeployEipCompleteFailed(ctx, obj, jsonutils.NewString(msg))
self.OnDeployEipCompleteFailed(ctx, obj, jsonutils.NewString(err.Error()))
return
}
@@ -198,10 +206,10 @@ func (self *GuestCreateTask) OnDeployEipComplete(ctx context.Context, obj db.ISt
func (self *GuestCreateTask) OnDeployEipCompleteFailed(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
guest := obj.(*models.SGuest)
guest.SetStatus(self.UserCred, api.VM_ASSOCIATE_EIP_FAILED, "deploy_failed")
guest.SetStatus(self.UserCred, api.INSTANCE_ASSOCIATE_EIP_FAILED, "deploy_failed")
db.OpsLog.LogEvent(guest, db.ACT_EIP_ATTACH, data, self.UserCred)
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_EIP_ASSOCIATE, data, self.UserCred, false)
notifyclient.NotifySystemErrorWithCtx(ctx, guest.Id, guest.Name, api.VM_ASSOCIATE_EIP_FAILED, data.String())
notifyclient.NotifySystemErrorWithCtx(ctx, guest.Id, guest.Name, api.INSTANCE_ASSOCIATE_EIP_FAILED, data.String())
self.SetStageFailed(ctx, data)
}

View File

@@ -0,0 +1,195 @@
// 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 tasks
import (
"context"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
billing_api "yunion.io/x/onecloud/pkg/apis/billing"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/billing"
"yunion.io/x/onecloud/pkg/util/logclient"
)
type NatGatewayCreateTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(NatGatewayCreateTask{})
}
func (self *NatGatewayCreateTask) taskFailed(ctx context.Context, nat *models.SNatGateway, err error) {
nat.SetStatus(self.UserCred, api.NAT_STATUS_CREATE_FAILED, err.Error())
logclient.AddActionLogWithStartable(self, nat, logclient.ACT_ALLOCATE, err, self.UserCred, false)
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *NatGatewayCreateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
nat := obj.(*models.SNatGateway)
opts := cloudprovider.NatGatewayCreateOptions{
Name: nat.Name,
Desc: nat.Description,
NatSpec: nat.NatSpec,
}
vpc, err := nat.GetVpc()
if err != nil {
self.taskFailed(ctx, nat, errors.Wrapf(err, "nat.GetVpc"))
return
}
opts.VpcId = vpc.ExternalId
networkId, _ := self.GetParams().GetString("network_id")
if len(networkId) > 0 {
_network, err := models.NetworkManager.FetchById(networkId)
if err != nil {
self.taskFailed(ctx, nat, errors.Wrapf(err, "NetworkManager.FetchById(%s)", networkId))
return
}
network := _network.(*models.SNetwork)
opts.NetworkId = network.ExternalId
}
if nat.BillingType == billing_api.BILLING_TYPE_PREPAID {
bc, err := billing.ParseBillingCycle(nat.BillingCycle)
if err != nil {
self.taskFailed(ctx, nat, errors.Wrapf(err, "ParseBillingCycle(%s)", nat.BillingCycle))
return
}
bc.AutoRenew = nat.AutoRenew
opts.BillingCycle = &bc
}
self.SetStage("OnCreateNatGatewayCreateComplete", nil)
taskman.LocalTaskRun(self, func() (jsonutils.JSONObject, error) {
iVpc, err := vpc.GetIVpc()
if err != nil {
return nil, errors.Wrapf(err, "vpc.GetIVpc")
}
iNat, err := iVpc.CreateINatGateway(&opts)
if err != nil {
return nil, errors.Wrapf(err, "iVpc.CreateINatGateway")
}
err = db.SetExternalId(nat, self.GetUserCred(), iNat.GetGlobalId())
if err != nil {
return nil, errors.Wrapf(err, "db.SetExternalId")
}
err = cloudprovider.WaitStatus(iNat, api.NAT_STAUTS_AVAILABLE, time.Second*5, time.Minute*10)
if err != nil {
return nil, errors.Wrapf(err, "cloudprovider.WaitStatus")
}
nat.SyncWithCloudNatGateway(ctx, self.GetUserCred(), nat.GetCloudprovider(), iNat)
return nil, nil
})
}
func (self *NatGatewayCreateTask) OnCreateNatGatewayCreateComplete(ctx context.Context, nat *models.SNatGateway, body jsonutils.JSONObject) {
input := api.NatgatewayCreateInput{}
self.GetParams().Unmarshal(&input)
if len(input.Eip) > 0 || input.EipBw > 0 {
self.SetStage("OnDeployEipComplete", nil)
var eip *models.SElasticip = nil
var err error
if len(input.Eip) > 0 {
eipObj, err := models.ElasticipManager.FetchById(input.Eip)
if err != nil {
self.OnDeployEipCompleteFailed(ctx, nat, jsonutils.NewString(errors.Wrapf(err, "ElasticipManager.FetchById(%s)", input.Eip).Error()))
return
}
eip = eipObj.(*models.SElasticip)
} else {
pendingRegionUsage := models.SRegionQuota{}
self.GetPendingUsage(&pendingRegionUsage, 1)
self.SetPendingUsage(&pendingRegionUsage, 1)
eip, err = models.ElasticipManager.NewEipForVMOnHost(ctx, self.UserCred, &models.NewEipForVMOnHostArgs{
Bandwidth: input.EipBw,
BgpType: input.EipBgpType,
ChargeType: input.EipChargeType,
AutoDellocate: input.EipAutoDellocate,
Natgateway: nat,
PendingUsage: &pendingRegionUsage,
})
self.SetPendingUsage(&pendingRegionUsage, 1)
if err != nil {
self.OnDeployEipCompleteFailed(ctx, nat, jsonutils.NewString(errors.Wrapf(err, "ElasticipManager.NewEipForVMOnHost").Error()))
return
}
}
opts := api.ElasticipAssociateInput{
InstanceId: nat.Id,
InstanceExternalId: nat.ExternalId,
InstanceType: api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY,
}
if input.EipBw > 0 {
// newly allocated eip, need allocation and associate
err = eip.AllocateAndAssociateInstance(ctx, self.UserCred, nat, opts, self.GetId())
err = errors.Wrap(err, "AllocateAndAssociateVM")
} else {
err = eip.StartEipAssociateInstanceTask(ctx, self.UserCred, opts, self.GetId())
err = errors.Wrap(err, "StartEipAssociateInstanceTask")
}
if err != nil {
self.OnDeployEipCompleteFailed(ctx, nat, jsonutils.NewString(err.Error()))
return
}
return
}
self.OnDeployEipComplete(ctx, nat, nil)
}
func (self *NatGatewayCreateTask) OnCreateNatGatewayCreateCompleteFailed(ctx context.Context, nat *models.SNatGateway, body jsonutils.JSONObject) {
self.taskFailed(ctx, nat, errors.Errorf(body.String()))
}
func (self *NatGatewayCreateTask) OnDeployEipCompleteFailed(ctx context.Context, nat *models.SNatGateway, data jsonutils.JSONObject) {
nat.SetStatus(self.UserCred, api.INSTANCE_ASSOCIATE_EIP_FAILED, data.String())
db.OpsLog.LogEvent(nat, db.ACT_EIP_ATTACH, data, self.UserCred)
logclient.AddActionLogWithStartable(self, nat, logclient.ACT_EIP_ASSOCIATE, data, self.UserCred, false)
notifyclient.NotifySystemErrorWithCtx(ctx, nat.Id, nat.Name, api.INSTANCE_ASSOCIATE_EIP_FAILED, data.String())
self.SetStageFailed(ctx, data)
}
func (self *NatGatewayCreateTask) OnDeployEipComplete(ctx context.Context, nat *models.SNatGateway, data jsonutils.JSONObject) {
self.SetStage("OnSyncstatusComplete", nil)
nat.StartSyncstatus(ctx, self.GetUserCred(), self.GetTaskId())
}
func (self *NatGatewayCreateTask) OnSyncstatusComplete(ctx context.Context, nat *models.SNatGateway, data jsonutils.JSONObject) {
self.SetStageComplete(ctx, nil)
}
func (self *NatGatewayCreateTask) OnSyncstatusCompleteFailed(ctx context.Context, nat *models.SNatGateway, data jsonutils.JSONObject) {
self.SetStageFailed(ctx, data)
}

View File

@@ -0,0 +1,121 @@
// 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 tasks
import (
"context"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
)
type NatGatewayDeleteTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(NatGatewayDeleteTask{})
}
func (self *NatGatewayDeleteTask) taskFailed(ctx context.Context, nat *models.SNatGateway, err error) {
nat.SetStatus(self.UserCred, api.NAT_STATUS_DELETE_FAILED, err.Error())
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *NatGatewayDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
nat := obj.(*models.SNatGateway)
self.SetStage("OnEipDissociateComplete", nil)
self.OnEipDissociateComplete(ctx, nat, nil)
}
func (self *NatGatewayDeleteTask) OnEipDissociateComplete(ctx context.Context, nat *models.SNatGateway, data jsonutils.JSONObject) {
eips, err := nat.GetEips()
if err != nil {
self.taskFailed(ctx, nat, errors.Wrapf(err, "nat.GetEips"))
return
}
if len(eips) > 0 {
eips[0].StartEipDissociateTask(ctx, self.GetUserCred(), false, self.GetTaskId())
return
}
self.doDeleteNatGateway(ctx, nat)
}
func (self *NatGatewayDeleteTask) OnEipDissociateCompleteFailed(ctx context.Context, nat *models.SNatGateway, data jsonutils.JSONObject) {
self.SetStageFailed(ctx, nil)
}
func (self *NatGatewayDeleteTask) doDeleteNatGateway(ctx context.Context, nat *models.SNatGateway) {
iNat, err := nat.GetINatGateway()
if err != nil {
if errors.Cause(err) == cloudprovider.ErrNotFound {
self.taskComplete(ctx, nat)
return
}
self.taskFailed(ctx, nat, errors.Wrapf(err, "nat.GetINatGateway"))
return
}
dnat, err := iNat.GetINatDTable()
if err != nil {
self.taskFailed(ctx, nat, errors.Wrapf(err, "iNat.GetINatDTable"))
return
}
for i := range dnat {
err = dnat[i].Delete()
if err != nil {
self.taskFailed(ctx, nat, errors.Wrapf(err, "delete d entry %v", dnat[i]))
return
}
}
snat, err := iNat.GetINatSTable()
if err != nil {
self.taskFailed(ctx, nat, errors.Wrapf(err, "GetINatSTable"))
return
}
for i := range snat {
err = snat[i].Delete()
if err != nil {
self.taskFailed(ctx, nat, errors.Wrapf(err, "delete s entry %v", snat[i]))
}
}
err = iNat.Delete()
if err != nil {
self.taskFailed(ctx, nat, errors.Wrapf(err, "iNat.Delete"))
return
}
err = cloudprovider.WaitDeleted(iNat, time.Second*5, time.Minute*3)
if err != nil {
self.taskFailed(ctx, nat, errors.Wrapf(err, "cloudprovider.WaitDeleted"))
return
}
self.taskComplete(ctx, nat)
}
func (self *NatGatewayDeleteTask) taskComplete(ctx context.Context, nat *models.SNatGateway) {
nat.RealDelete(ctx, self.GetUserCred())
self.SetStageComplete(ctx, nil)
}

View File

@@ -0,0 +1,100 @@
// 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 tasks
import (
"context"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/billing"
"yunion.io/x/onecloud/pkg/util/logclient"
)
type NatGatewayRenewTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(NatGatewayRenewTask{})
}
func (self *NatGatewayRenewTask) taskFailed(ctx context.Context, nat *models.SNatGateway, err error) {
db.OpsLog.LogEvent(nat, db.ACT_REW_FAIL, err, self.UserCred)
logclient.AddActionLogWithStartable(self, nat, logclient.ACT_RENEW, err, self.UserCred, false)
nat.SetStatus(self.GetUserCred(), api.NAT_STATUS_RENEW_FAILED, err.Error())
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *NatGatewayRenewTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
nat := obj.(*models.SNatGateway)
duration, _ := self.GetParams().GetString("duration")
bc, err := billing.ParseBillingCycle(duration)
if err != nil {
self.taskFailed(ctx, nat, errors.Wrapf(err, "ParseBillingCycle(%s)", duration))
return
}
iNat, err := nat.GetINatGateway()
if err != nil {
self.taskFailed(ctx, nat, errors.Wrapf(err, "GetINatGateway"))
return
}
oldExpired := iNat.GetExpiredAt()
err = iNat.Renew(bc)
if err != nil {
self.taskFailed(ctx, nat, errors.Wrapf(err, "iNat.Renew"))
return
}
err = cloudprovider.WaitCreated(15*time.Second, 5*time.Minute, func() bool {
err := iNat.Refresh()
if err != nil {
log.Errorf("failed refresh nat %s error: %v", nat.Name, err)
}
newExipred := iNat.GetExpiredAt()
if newExipred.After(oldExpired) {
return true
}
return false
})
if err != nil {
self.taskFailed(ctx, nat, errors.Wrapf(err, "wait expired time refresh"))
return
}
logclient.AddActionLogWithStartable(self, nat, logclient.ACT_RENEW, map[string]string{"duration": duration}, self.UserCred, true)
self.SetStage("OnSyncstatusComplete", nil)
nat.StartSyncstatus(ctx, self.GetUserCred(), self.GetTaskId())
}
func (self *NatGatewayRenewTask) OnSyncstatusComplete(ctx context.Context, nat *models.SNatGateway, data jsonutils.JSONObject) {
self.SetStageComplete(ctx, nil)
}
func (self *NatGatewayRenewTask) OnSyncstatusCompleteFailed(ctx context.Context, nat *models.SNatGateway, reason jsonutils.JSONObject) {
self.SetStageFailed(ctx, reason)
}

View File

@@ -0,0 +1,68 @@
// 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 tasks
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/logclient"
)
type NatGatewaySetAutoRenewTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(NatGatewaySetAutoRenewTask{})
}
func (self *NatGatewaySetAutoRenewTask) taskFailed(ctx context.Context, nat *models.SNatGateway, err error) {
db.OpsLog.LogEvent(nat, db.ACT_SET_AUTO_RENEW_FAIL, err, self.GetUserCred())
logclient.AddActionLogWithStartable(self, nat, logclient.ACT_SET_AUTO_RENEW, err, self.GetUserCred(), false)
nat.SetStatus(self.GetUserCred(), api.NAT_STATUS_SET_AUTO_RENEW_FAILED, err.Error())
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *NatGatewaySetAutoRenewTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
nat := obj.(*models.SNatGateway)
autoRenew := jsonutils.QueryBoolean(self.GetParams(), "auto_renew", false)
iNat, err := nat.GetINatGateway()
if err != nil {
self.taskFailed(ctx, nat, errors.Wrapf(err, "GetINatGateway"))
return
}
err = iNat.SetAutoRenew(autoRenew)
if err != nil {
self.taskFailed(ctx, nat, errors.Wrapf(err, "iNat.SetAutoRenew"))
return
}
self.SetStage("OnNatGatewaySyncComplete", nil)
nat.StartSyncstatus(ctx, self.GetUserCred(), self.GetTaskId())
}
func (self *NatGatewaySetAutoRenewTask) OnNatGatewaySyncComplete(ctx context.Context, nat *models.SNatGateway, data jsonutils.JSONObject) {
self.SetStageComplete(ctx, nil)
}
func (self *NatGatewaySetAutoRenewTask) OnNatGatewaySyncCompleteFailed(ctx context.Context, nat *models.SNatGateway, data jsonutils.JSONObject) {
self.SetStageFailed(ctx, data)
}

View File

@@ -39,7 +39,7 @@ func init() {
}
func (self *SNatDEntryCreateTask) TaskFailed(ctx context.Context, dnatEntry models.INatHelper, reason jsonutils.JSONObject) {
dnatEntry.SetStatus(self.UserCred, api.NAT_STATUS_FAILED, reason.String())
dnatEntry.SetStatus(self.UserCred, api.NAT_STATUS_CREATE_FAILED, reason.String())
db.OpsLog.LogEvent(dnatEntry, db.ACT_ALLOCATE_FAIL, reason.String(), self.UserCred)
natgateway, err := dnatEntry.GetNatgateway()
if err == nil {

View File

@@ -39,7 +39,7 @@ func init() {
}
func (self *SNatSEntryCreateTask) TaskFailed(ctx context.Context, snatEntry models.INatHelper, reason jsonutils.JSONObject) {
snatEntry.SetStatus(self.UserCred, api.NAT_STATUS_FAILED, reason.String())
snatEntry.SetStatus(self.UserCred, api.NAT_STATUS_CREATE_FAILED, reason.String())
db.OpsLog.LogEvent(snatEntry, db.ACT_ALLOCATE_FAIL, reason, self.UserCred)
natgateway, err := snatEntry.GetNatgateway()
if err == nil {

View File

@@ -0,0 +1,33 @@
// 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 modules
import "yunion.io/x/onecloud/pkg/mcclient/modulebase"
type NatSkusManager struct {
modulebase.ResourceManager
}
var (
NatSkus NatSkusManager
)
func init() {
NatSkus = NatSkusManager{NewComputeManager("nat_sku", "nat_skus",
[]string{},
[]string{})}
registerCompute(&NatSkus)
}

View File

@@ -840,7 +840,7 @@ func (opts *CloudaccountShareModeOptions) Params() (jsonutils.JSONObject, error)
type CloudaccountSyncSkusOptions struct {
SCloudAccountIdOptions
RESOURCE string `help:"Resource of skus" choices:"serversku|elasticcachesku|dbinstance_sku"`
RESOURCE string `help:"Resource of skus" choices:"serversku|elasticcachesku|dbinstance_sku|nat_sku"`
Force bool `help:"Force sync no matter what"`
Provider string `help:"provider to sync"`
Region string `help:"region to sync"`

View File

@@ -0,0 +1,111 @@
// 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 compute
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type ElasticipListOptions struct {
Region string `help:"List eips in cloudregion"`
Usable *bool `help:"List all zones that is usable"`
UsableEipForAssociateType string `help:"With associate id filter which eip can associate"`
UsableEipForAssociateId string `help:"With associate type filter which eip can associate"`
options.BaseListOptions
}
func (opts *ElasticipListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
type EipCreateOptions struct {
options.BaseCreateOptions
Manager *string `help:"cloud provider"`
Region *string `help:"cloud region in which EIP is allocated"`
Bandwidth *int `help:"Bandwidth in Mbps"`
IpAddr *string `help:"IP address of the EIP" json:"ip_addr"`
Network *string `help:"Network of the EIP"`
BgpType *string `help:"BgpType of the EIP" positional:"false"`
ChargeType *string `help:"bandwidth charge type" choices:"traffic|bandwidth"`
}
func (opts *EipCreateOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(opts), nil
}
type EipUpdateOptions struct {
options.BaseUpdateOptions
AutoDellocate *string `help:"enable or disable automatically dellocate when dissociate from instance" choices:"true|false"`
}
func (opts *EipUpdateOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(opts), nil
}
type EipAssociateOptions struct {
options.BaseIdOptions
INSTANCE_ID string `help:"ID of instance the eip associated with"`
InstanceType string `default:"server" help:"Instance type that the eip associated with, default is server" choices:"server|natgateway"`
}
func (opts *EipAssociateOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(map[string]string{"instance_id": opts.INSTANCE_ID, "instance_type": opts.InstanceType}), nil
}
type EipDissociateOptions struct {
options.BaseIdOptions
AutoDelete bool `help:"automatically delete the dissociate EIP" json:"auto_delete,omitfalse"`
}
func (opts *EipDissociateOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(map[string]bool{"auto_delete": opts.AutoDelete}), nil
}
type EipChangeBandwidthOptions struct {
options.BaseIdOptions
BANDWIDTH int `help:"new bandwidth of EIP"`
}
func (opts *EipChangeBandwidthOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(map[string]int{"bandwidth": opts.BANDWIDTH}), nil
}
type EipChangeOwnerOptions struct {
options.BaseIdOptions
PROJECT string `help:"Project ID or change"`
//RawId bool `help:"User raw ID, instead of name"`
}
func (opts *EipChangeOwnerOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(map[string]string{"tenant": opts.PROJECT}), nil
/*
params := jsonutils.NewDict()
if opts.RawId {
projid, err := modules.Projects.GetId(s, opts.PROJECT, nil)
if err != nil {
return err
}
params.Add(jsonutils.NewString(projid), "tenant")
params.Add(jsonutils.JSONTrue, "raw_id")
} else {
params.Add(jsonutils.NewString(opts.PROJECT), "tenant")
}
*/
}

View File

@@ -0,0 +1,41 @@
// 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 compute
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type NatSkuListOption struct {
options.BaseListOptions
}
func (opts *NatSkuListOption) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
type NatSkuIdOption struct {
ID string `help:"Nat Id or name"`
}
func (opts *NatSkuIdOption) Params() (jsonutils.JSONObject, error) {
return nil, nil
}
func (opts *NatSkuIdOption) GetId() string {
return opts.ID
}

View File

@@ -12,26 +12,56 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package options
package compute
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type NatGatewayListOptions struct {
options.BaseListOptions
Vpc string `help:"vpc id or name"`
Cloudregion string `help:"cloudreigon id or name"`
}
BaseListOptions
func (opts *NatGatewayListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
type NatGatewayIdOptions struct {
ID string `help:"ID of Nat Gateway"`
}
func (opts *NatGatewayIdOptions) GetId() string {
return opts.ID
}
func (opts *NatGatewayIdOptions) Params() (jsonutils.JSONObject, error) {
return nil, nil
}
type NatGatewayDeleteOption struct {
NatGatewayIdOptions
Force bool
}
func (opts *NatGatewayDeleteOption) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(map[string]bool{"force": opts.Force}), nil
}
type NatDTableListOptions struct {
Natgateway string `help:"Natgateway name or id"`
BaseListOptions
options.BaseListOptions
}
type NatSTableListOptions struct {
Natgateway string `help:"Natgateway name or id"`
Network string `help:"Network id or name"`
BaseListOptions
options.BaseListOptions
}
type NatDDeleteShowOptions struct {
@@ -42,10 +72,6 @@ type NatSDeleteShowOptions struct {
ID string `help:"ID of the SNat"`
}
type NatGatewayIdOptions struct {
ID string `help:"ID of Nat Gateway"`
}
type NatDCreateOptions struct {
NAME string `help:"DNAT's name"`
NATGATEWAYID string `help:"The nat gateway'id to which DNat belongs"`

View File

@@ -1078,3 +1078,14 @@ type ServerRemoteUpdateOptions struct {
ServerIdOptions
computeapi.ServerRemoteUpdateInput
}
type ServerCreateEipOptions struct {
BaseIdOptions
Bandwidth int `help:"EIP bandwidth in Mbps" default:"5"`
BgpType *string `help:"desired BGP type"`
ChargeType *string `help:"bandwidth charge type" choices:"traffic|bandwidth"`
}
func (opts *ServerCreateEipOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(opts), nil
}

View File

@@ -541,6 +541,7 @@ func (region *SAliyunClient) GetCapabilities() []string {
cloudprovider.CLOUD_CAPABILITY_DNSZONE,
cloudprovider.CLOUD_CAPABILITY_INTERVPCNETWORK,
cloudprovider.CLOUD_CAPABILITY_SAML_AUTH,
cloudprovider.CLOUD_CAPABILITY_NAT,
}
return caps
}

View File

@@ -18,8 +18,10 @@ import (
"fmt"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
@@ -85,7 +87,10 @@ func (nat *SNatGetway) GetStatus() string {
default:
return api.NAT_STATUS_UNKNOWN
}
}
func (self *SNatGetway) Delete() error {
return self.vpc.region.DeleteNatGateway(self.NatGatewayId, false)
}
func (nat *SNatGetway) GetBillingType() string {
@@ -93,9 +98,26 @@ func (nat *SNatGetway) GetBillingType() string {
}
func (nat *SNatGetway) GetNatSpec() string {
if len(nat.Spec) == 0 {
return api.ALIYUN_NAT_SKU_DEFAULT
}
return nat.Spec
}
func (self *SNatGetway) Refresh() error {
nat, total, err := self.vpc.region.GetNatGateways("", self.NatGatewayId, 0, 1)
if err != nil {
return errors.Wrapf(err, "GetNatGateways")
}
if total > 1 {
return errors.Wrapf(cloudprovider.ErrDuplicateId, "get %d natgateways by id %s", total, self.NatGatewayId)
}
if total == 0 {
return errors.Wrapf(cloudprovider.ErrNotFound, self.NatGatewayId)
}
return jsonutils.Update(self, nat[0])
}
func (nat *SNatGetway) GetCreatedAt() time.Time {
return nat.CreationTime
}
@@ -203,8 +225,7 @@ func (self *SRegion) GetNatGateways(vpcId string, natGwId string, offset, limit
body, err := self.vpcRequest("DescribeNatGateways", params)
if err != nil {
log.Errorf("GetVSwitches fail %s", err)
return nil, 0, err
return nil, 0, errors.Wrapf(err, "DescribeNatGateways")
}
if self.client.debug {
@@ -214,9 +235,96 @@ func (self *SRegion) GetNatGateways(vpcId string, natGwId string, offset, limit
gateways := make([]SNatGetway, 0)
err = body.Unmarshal(&gateways, "NatGateways", "NatGateway")
if err != nil {
log.Errorf("Unmarshal gateways fail %s", err)
return nil, 0, err
return nil, 0, errors.Wrapf(err, "body.Unmarshal")
}
total, _ := body.Int("TotalCount")
return gateways, int(total), nil
}
func (self *SVpc) CreateINatGateway(opts *cloudprovider.NatGatewayCreateOptions) (cloudprovider.ICloudNatGateway, error) {
nat, err := self.region.CreateNatGateway(opts)
if err != nil {
return nil, errors.Wrapf(err, "CreateNatGateway")
}
nat.vpc = self
return nat, nil
}
func (self *SRegion) CreateNatGateway(opts *cloudprovider.NatGatewayCreateOptions) (*SNatGetway, error) {
params := map[string]string{
"RegionId": self.RegionId,
"VpcId": opts.VpcId,
"VSwitchId": opts.NetworkId,
"NatType": "Enhanced",
"Name": opts.Name,
"Description": opts.Desc,
"ClientToken": utils.GenRequestId(20),
"InstanceChargeType": "PostPaid",
"InternetChargeType": "PayBySpec",
}
if len(opts.NatSpec) == 0 || opts.NatSpec == api.ALIYUN_NAT_SKU_DEFAULT {
params["InternetChargeType"] = "PayByLcu"
} else {
params["Spec"] = opts.NatSpec
}
if opts.BillingCycle != nil {
params["InstanceChargeType"] = "PrePaid"
params["PricingCycle"] = "Month"
params["AutoPay"] = "false"
if opts.BillingCycle.GetYears() > 0 {
params["PricingCycle"] = "Year"
params["Duration"] = fmt.Sprintf("%d", opts.BillingCycle.GetYears())
} else if opts.BillingCycle.GetMonths() > 0 {
params["PricingCycle"] = "Year"
params["Duration"] = fmt.Sprintf("%d", opts.BillingCycle.GetMonths())
}
if opts.BillingCycle.AutoRenew {
params["AutoPay"] = "true"
}
}
resp, err := self.vpcRequest("CreateNatGateway", params)
if err != nil {
return nil, errors.Wrapf(err, "CreateNatGateway")
}
natId, err := resp.GetString("NatGatewayId")
if err != nil {
return nil, errors.Wrapf(err, "resp.Get(NatGatewayId)")
}
if len(natId) == 0 {
return nil, errors.Errorf("empty NatGatewayId after created")
}
var nat *SNatGetway = nil
err = cloudprovider.Wait(time.Second*5, time.Minute*15, func() (bool, error) {
nats, total, err := self.GetNatGateways("", natId, 0, 1)
if err != nil {
return false, errors.Wrapf(err, "GetNatGateways(%s)", natId)
}
if total > 1 {
return false, errors.Wrapf(cloudprovider.ErrDuplicateId, "get %d nats", total)
}
if total == 0 {
return false, errors.Wrapf(cloudprovider.ErrNotFound, "search %s after %s created", opts.Name, natId)
}
nat = &nats[0]
return true, nil
})
if err != nil {
return nil, errors.Wrapf(err, "cloudprovider.Wait")
}
return nat, nil
}
func (self *SRegion) DeleteNatGateway(natId string, isForce bool) error {
params := map[string]string{
"RegionId": self.RegionId,
"NatGatewayId": natId,
}
if isForce {
params["Force"] = "true"
}
_, err := self.vpcRequest("DeleteNatGateway", params)
return errors.Wrapf(err, "DeleteNatGateway")
}

View File

@@ -22,11 +22,13 @@ import (
func init() {
type NatGatewayListOptions struct {
Limit int `help:"page size"`
Offset int `help:"page offset"`
VpcId string `help:"Vpc Id"`
NatId string `help:"NatGateway Id"`
Limit int `help:"page size"`
Offset int `help:"page offset"`
}
shellutils.R(&NatGatewayListOptions{}, "natgateway-list", "List NAT gateways", func(cli *aliyun.SRegion, args *NatGatewayListOptions) error {
gws, total, e := cli.GetNatGateways("", "", args.Offset, args.Limit)
shellutils.R(&NatGatewayListOptions{}, "nat-list", "List NAT gateways", func(cli *aliyun.SRegion, args *NatGatewayListOptions) error {
gws, total, e := cli.GetNatGateways(args.VpcId, args.NatId, args.Offset, args.Limit)
if e != nil {
return e
}
@@ -34,6 +36,15 @@ func init() {
return nil
})
type NatGatewayDeleteOptions struct {
ID string `help:"Nat Id"`
Force bool `help:"Force Delete Nat"`
}
shellutils.R(&NatGatewayDeleteOptions{}, "nat-delete", "Delete nat gateways", func(cli *aliyun.SRegion, args *NatGatewayDeleteOptions) error {
return cli.DeleteNatGateway(args.ID, args.Force)
})
type NatSEntryListOptions struct {
ID string `help:"SNat Table ID"`
Limit int `help:"page size"`

View File

@@ -20,6 +20,7 @@ import (
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/util/billing"
)
type SBillingBase struct{}
@@ -43,3 +44,7 @@ func (self *SBillingBase) SetAutoRenew(autoRenew bool) error {
func (self *SBillingBase) IsAutoRenew() bool {
return false
}
func (self *SBillingBase) Renew(bc billing.SBillingCycle) error {
return errors.Wrap(cloudprovider.ErrNotImplemented, "Renew")
}

View File

@@ -505,6 +505,7 @@ func (self *SHuaweiClient) GetCapabilities() []string {
cloudprovider.CLOUD_CAPABILITY_EVENT,
cloudprovider.CLOUD_CAPABILITY_CLOUDID,
cloudprovider.CLOUD_CAPABILITY_SAML_AUTH,
cloudprovider.CLOUD_CAPABILITY_NAT,
}
// huawei objectstore is shared across projects(subscriptions)
// to avoid multiple project access the same bucket

View File

@@ -15,7 +15,7 @@
package multicloud
import (
"fmt"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
@@ -26,13 +26,17 @@ type SNatGatewayBase struct {
}
func (nat *SNatGatewayBase) GetIEips() ([]cloudprovider.ICloudEIP, error) {
return nil, fmt.Errorf("Not Implemented GetIEips")
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetIEips")
}
func (nat *SNatGatewayBase) GetIDNatEntries() ([]cloudprovider.ICloudNatDEntry, error) {
return nil, fmt.Errorf("Not Implemented GetINatDTable")
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetIDNatEntries")
}
func (nat *SNatGatewayBase) GetISNatEntries() ([]cloudprovider.ICloudNatSEntry, error) {
return nil, fmt.Errorf("Not Implemented GetINatSTable")
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetISNatEntries")
}
func (nat *SNatGatewayBase) Delete() error {
return errors.Wrapf(cloudprovider.ErrNotImplemented, "Delete")
}

View File

@@ -76,3 +76,7 @@ func (self *SVpc) GetExternalAccessMode() string {
func (self *SVpc) AttachInternetGateway(igwId string) error {
return errors.Wrap(cloudprovider.ErrNotSupported, "AttachInternetGateway")
}
func (self *SVpc) CreateINatGateway(opts *cloudprovider.NatGatewayCreateOptions) (cloudprovider.ICloudNatGateway, error) {
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "CreateINatGateway")
}

View File

@@ -151,6 +151,7 @@ const (
ACT_VM_ASSOCIATE = "vm_associate"
ACT_VM_DISSOCIATE = "vm_dissociate"
ACT_NATGATEWAY_ASSOCIATE = "natgateway_associate"
ACT_NATGATEWAY_DISSOCIATE = "natgateway_dissociate"
ACT_LOADBALANCER_DISSOCIATE = "loadbalancer_dissociate"