mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-01 15:07:17 +08:00
feature: vip support (#13020)
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
@@ -15,113 +15,28 @@
|
||||
package compute
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/cmd/climc/shell"
|
||||
modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options/compute"
|
||||
)
|
||||
|
||||
func init() {
|
||||
type InstanceGroupListOptions struct {
|
||||
options.BaseListOptions
|
||||
cmd := shell.NewResourceCmd(&modules.InstanceGroups)
|
||||
cmd.List(&compute.InstanceGroupListOptions{})
|
||||
cmd.Show(&options.BaseShowOptions{})
|
||||
cmd.GetMetadata(&options.BaseIdOptions{})
|
||||
cmd.Create(&compute.InstanceGroupCreateOptions{})
|
||||
cmd.Update(&compute.InstanceGroupUpdateOptions{})
|
||||
cmd.Delete(&options.BaseIdOptions{})
|
||||
|
||||
ServiceType string `help:"Service Type"`
|
||||
ParentId string `help:"Parent ID"`
|
||||
ZoneId string `help:"Zone ID"`
|
||||
Server string `help:"Guest ID or Name"`
|
||||
}
|
||||
cmd.Perform("bind-guests", &compute.InstanceGroupBindGuestsOptions{})
|
||||
cmd.Perform("unbind-guests", &compute.InstanceGroupBindGuestsOptions{})
|
||||
|
||||
R(&InstanceGroupListOptions{}, "instance-group-list", "List instance group", func(s *mcclient.ClientSession,
|
||||
args *InstanceGroupListOptions) error {
|
||||
|
||||
params, err := options.ListStructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := modules.InstanceGroup.List(s, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printList(result, modules.InstanceGroup.GetColumns(s))
|
||||
return nil
|
||||
})
|
||||
|
||||
type InstanceGroupShowOptions struct {
|
||||
ID string `help:"ID or Name of instance group"`
|
||||
}
|
||||
R(&InstanceGroupShowOptions{}, "instance-group-show", "Show details of a instance group",
|
||||
func(s *mcclient.ClientSession, args *InstanceGroupShowOptions) error {
|
||||
|
||||
result, err := modules.InstanceGroup.GetById(s, args.ID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type InstanceGroupCreateOptions struct {
|
||||
NAME string `help:"name of instance group"`
|
||||
|
||||
ZoneId string `help:"zone id" json:"zone_id"`
|
||||
ServiceType string `help:"service type"`
|
||||
ParentId string `help:"parent id"`
|
||||
SchedStrategy string `help:"scheduler strategy"`
|
||||
Granularity string `help:"the upper limit number of guests with this group in a host"`
|
||||
ForceDispersion bool `help:"force to make guest dispersion"`
|
||||
}
|
||||
|
||||
R(&InstanceGroupCreateOptions{}, "instance-group-create", "Create a instance group",
|
||||
func(s *mcclient.ClientSession, args *InstanceGroupCreateOptions) error {
|
||||
params, err := options.StructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := modules.InstanceGroup.Create(s, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
R(&InstanceGroupShowOptions{}, "instance-group-delete", "delete a instance group",
|
||||
func(s *mcclient.ClientSession, args *InstanceGroupShowOptions) error {
|
||||
result, err := modules.InstanceGroup.Delete(s, args.ID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
type InstanceGroupUpdateOptions struct {
|
||||
ID string `help:"ID or Name of servers to update" json:"-"`
|
||||
Name string `help:"New name to change"`
|
||||
Granularity string `help:"the upper limit number of guests with this group in a host"`
|
||||
ForceDispersion string `help:"force to make guest dispersion" choices:"yes|no" json:"-"`
|
||||
}
|
||||
|
||||
R(&InstanceGroupUpdateOptions{}, "instance-group-update", "update a instance group",
|
||||
func(s *mcclient.ClientSession, args *InstanceGroupUpdateOptions) error {
|
||||
params, err := options.StructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if args.ForceDispersion == "yes" {
|
||||
params.Set("force_dispersion", jsonutils.JSONTrue)
|
||||
} else {
|
||||
params.Set("force_dispersion", jsonutils.JSONFalse)
|
||||
}
|
||||
ret, err := modules.InstanceGroup.Update(s, args.ID, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(ret)
|
||||
return nil
|
||||
})
|
||||
cmd.Perform("attachnetwork", &compute.InstanceGroupAttachnetworkOptions{})
|
||||
cmd.Perform("detachnetwork", &compute.InstanceGroupDetachnetworkOptions{})
|
||||
|
||||
cmd.Perform("create-eip", &compute.InstanceGroupCreateEipOptions{})
|
||||
cmd.Perform("associate-eip", &compute.InstanceGroupAssociateEipOptions{})
|
||||
cmd.Perform("dissociate-eip", &compute.InstanceGroupDissociateEipOptions{})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// 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"
|
||||
modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options/compute"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmd := shell.NewJointCmd(&modules.InstanceGroupGuests)
|
||||
cmd.List(&compute.InstanceGroupGuestListOptions{})
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// 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"
|
||||
modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options/compute"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmd := shell.NewJointCmd(&modules.InstancegroupNetworks)
|
||||
cmd.List(&compute.InstanceGroupNetworkListOptions{})
|
||||
}
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/identity"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules/compute"
|
||||
modules "yunion.io/x/onecloud/pkg/mcclient/modules/identity"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
)
|
||||
@@ -194,39 +193,6 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
type GroupBindGuestsOptions struct {
|
||||
ID string `help:"ID"`
|
||||
Guest []string `help:"ID or Name of Guest"`
|
||||
}
|
||||
|
||||
R(&GroupBindGuestsOptions{}, "instance-group-bind-guests", "bind instancegroup to guests",
|
||||
func(s *mcclient.ClientSession, opts *GroupBindGuestsOptions) error {
|
||||
params, err := options.StructToParams(opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sp, err := compute.InstanceGroup.PerformAction(s, opts.ID, "bind-guests", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(sp)
|
||||
return nil
|
||||
})
|
||||
|
||||
R(&GroupBindGuestsOptions{}, "instance-group-unbind-guests", "bind instancegroup to guests",
|
||||
func(s *mcclient.ClientSession, opts *GroupBindGuestsOptions) error {
|
||||
params, err := options.StructToParams(opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sp, err := compute.InstanceGroup.PerformAction(s, opts.ID, "unbind-guests", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(sp)
|
||||
return nil
|
||||
})
|
||||
|
||||
type GroupAddUsersOptions struct {
|
||||
GROUP string `help:"group Id or Name" json:"-"`
|
||||
USER []string `help:"list of user id or name" json:"user"`
|
||||
|
||||
@@ -101,7 +101,6 @@ require (
|
||||
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 // indirect
|
||||
github.com/opentracing/opentracing-go v1.0.2 // indirect
|
||||
github.com/openzipkin/zipkin-go-opentracing v0.3.4 // indirect
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.12
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pkg/term v0.0.0-20181116001808-27bbf2edb814 // indirect
|
||||
@@ -153,11 +152,11 @@ require (
|
||||
k8s.io/client-go v0.19.3
|
||||
k8s.io/cluster-bootstrap v0.19.3
|
||||
yunion.io/x/executor v0.0.0-20211018100936-39a2cd966656
|
||||
yunion.io/x/jsonutils v0.0.0-20211130131136-1ecbe9b96761
|
||||
yunion.io/x/jsonutils v0.0.0-20211213041607-f6733e38783e
|
||||
yunion.io/x/log v0.0.0-20201210064738-43181789dc74
|
||||
yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7
|
||||
yunion.io/x/pkg v0.0.0-20211116020154-6a76ba2f7e97
|
||||
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e
|
||||
yunion.io/x/sqlchemy v0.0.0-20211212072622-e63b8097854a
|
||||
yunion.io/x/sqlchemy v0.0.0-20211226083340-1ba177bc58be
|
||||
yunion.io/x/structarg v0.0.0-20200720093445-9f850fa222ce
|
||||
)
|
||||
|
||||
@@ -942,8 +942,8 @@ sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
yunion.io/x/executor v0.0.0-20211018100936-39a2cd966656 h1:0zlZD5uhZoIHgLVAWCz2aHaYk2ZrNsACCYD7R6EIBII=
|
||||
yunion.io/x/executor v0.0.0-20211018100936-39a2cd966656/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws=
|
||||
yunion.io/x/jsonutils v0.0.0-20190625054549-a964e1e8a051/go.mod h1:4N0/RVzsYL3kH3WE/H1BjUQdFiWu50JGCFQuuy+Z634=
|
||||
yunion.io/x/jsonutils v0.0.0-20211130131136-1ecbe9b96761 h1:UYAZqKFv5qebn6vFUe8gTXbKxMRiveecGRXk9VgdSmM=
|
||||
yunion.io/x/jsonutils v0.0.0-20211130131136-1ecbe9b96761/go.mod h1:p0nyMqGA/apTxxyLIU/o1k4V7Vujl2O6ey30L594sYE=
|
||||
yunion.io/x/jsonutils v0.0.0-20211213041607-f6733e38783e h1:zOVxZ0HrDOHLTm5YxkDKUm1x5jMVKbQ/iBSAyn5l1+Q=
|
||||
yunion.io/x/jsonutils v0.0.0-20211213041607-f6733e38783e/go.mod h1:p0nyMqGA/apTxxyLIU/o1k4V7Vujl2O6ey30L594sYE=
|
||||
yunion.io/x/log v0.0.0-20190514041436-04ce53b17c6b/go.mod h1:+gauLs73omeJAPlsXcevLsJLKixV+sR/E7WSYTSx1fE=
|
||||
yunion.io/x/log v0.0.0-20190629062853-9f6483a7103d/go.mod h1:LC6f/4FozL0iaAbnFt2eDX9jlsyo3WiOUPm03d7+U4U=
|
||||
yunion.io/x/log v0.0.0-20201210064738-43181789dc74 h1:7D+sQ/XaUTUEm+NCrKXOhXBKlzEd0RyS2qZ4vBGjx2o=
|
||||
@@ -957,7 +957,7 @@ yunion.io/x/pkg v0.0.0-20211116020154-6a76ba2f7e97 h1:lY+5NlWwO2aIkfNnVOGKHmZvMt
|
||||
yunion.io/x/pkg v0.0.0-20211116020154-6a76ba2f7e97/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
|
||||
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e h1:v+EzIadodSwkdZ/7bremd7J8J50Cise/HCylsOJngmo=
|
||||
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e/go.mod h1:0iFKpOs1y4lbCxeOmq3Xx/0AcQoewVPwj62eRluioEo=
|
||||
yunion.io/x/sqlchemy v0.0.0-20211212072622-e63b8097854a h1:2x6ee1ZTSEqrUpNWKByKP+BxejEYTYxx09pFmWems4A=
|
||||
yunion.io/x/sqlchemy v0.0.0-20211212072622-e63b8097854a/go.mod h1:FTdwPdGhMgh4E+UFXc9klI1Ok34fMuybTT+jLhOaIjI=
|
||||
yunion.io/x/sqlchemy v0.0.0-20211226083340-1ba177bc58be h1:LCmMlLgRLr6EmnMQtzbsys6QGY2wfFk+1IOgb2tG/7E=
|
||||
yunion.io/x/sqlchemy v0.0.0-20211226083340-1ba177bc58be/go.mod h1:FTdwPdGhMgh4E+UFXc9klI1Ok34fMuybTT+jLhOaIjI=
|
||||
yunion.io/x/structarg v0.0.0-20200720093445-9f850fa222ce h1:kU8xE7O5uZ1GSJVMZHoJ+jrNL7csUQHYGyAPW9QfNpE=
|
||||
yunion.io/x/structarg v0.0.0-20200720093445-9f850fa222ce/go.mod h1:EP6NSv2C0zzqBDTKumv8hPWLb3XvgMZDHQRfyuOrQng=
|
||||
|
||||
@@ -103,6 +103,9 @@ type ElasticipAssociateInput struct {
|
||||
// enmu: server, natgateway
|
||||
// default: server
|
||||
InstanceType string `json:"instance_type"`
|
||||
|
||||
// EIP映射的内网IP地址,可选
|
||||
IpAddr string `json:"ip_addr"`
|
||||
}
|
||||
|
||||
type ElasticDissociateInput struct {
|
||||
|
||||
@@ -27,6 +27,8 @@ const (
|
||||
EIP_ASSOCIATE_TYPE_LOADBALANCER = "loadbalancer"
|
||||
EIP_ASSOCIATE_TYPE_UNKNOWN = "unknown"
|
||||
|
||||
EIP_ASSOCIATE_TYPE_INSTANCE_GROUP = "instancegroup"
|
||||
|
||||
EIP_STATUS_READY = "ready"
|
||||
EIP_STATUS_UNKNOWN = "unknown"
|
||||
EIP_STATUS_ALLOCATE = "allocate"
|
||||
|
||||
@@ -20,7 +20,10 @@ type GroupnetworkDetails struct {
|
||||
SGroupnetwork
|
||||
|
||||
// IP子网名称
|
||||
Network string
|
||||
Network string `json:"network"`
|
||||
|
||||
// EipAddr if eip is associated with this groupnetwork
|
||||
EipAddr string `json:"eip_addr"`
|
||||
}
|
||||
|
||||
type GroupnetworkListInput struct {
|
||||
@@ -31,3 +34,25 @@ type GroupnetworkListInput struct {
|
||||
// IP地址
|
||||
IpAddr []string `json:"ip_addr"`
|
||||
}
|
||||
|
||||
type GroupAttachNetworkInput struct {
|
||||
// network id or name
|
||||
NetworkId string `json:"network_id" help:"The network to attach, optional"`
|
||||
|
||||
// candidate IPaddr
|
||||
IpAddr string `json:"ip_addr" help:"The ip address to use, optional"`
|
||||
|
||||
// Allocation direction
|
||||
AllocDir IPAllocationDirection `json:"alloc_dir" help:"ip allocation direction, optional"`
|
||||
|
||||
// Reserved
|
||||
Reserved *bool `json:"reserved" help:"the address is allocated from reserved addresses"`
|
||||
|
||||
// Required Designed IP
|
||||
RequireDesignatedIp *bool `json:"require_designated_ip" help:"fail if the designed ip is not available"`
|
||||
}
|
||||
|
||||
type GroupDetachNetworkInput struct {
|
||||
// candidate IPaddr
|
||||
IpAddr string `json:"ip_addr" help:"Ip address to detach, empty if detach all networks"`
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@ type GuestnetworkDetails struct {
|
||||
Network string `json:"network"`
|
||||
// 所属Wire
|
||||
WireId string `json:"wire_id"`
|
||||
|
||||
// EipAddr associate with this guestnetwork
|
||||
EipAddr string `json:"eip_addr"`
|
||||
}
|
||||
|
||||
type GuestnetworkShortDesc struct {
|
||||
|
||||
@@ -445,6 +445,26 @@ type ServerAssociateEipInput struct {
|
||||
Eip string `json:"eip" yunion-deprecated-by:"eip_id"`
|
||||
// 弹性公网IP的ID
|
||||
EipId string `json:"eip_id"`
|
||||
|
||||
// 弹性IP映射的内网IP地址,可选
|
||||
IpAddr string `json:"ip_addr"`
|
||||
}
|
||||
|
||||
type ServerCreateEipInput struct {
|
||||
// 计费方式,traffic or bandwidth
|
||||
ChargeType string `json:"charge_type"`
|
||||
|
||||
// Bandwidth
|
||||
Bandwidth int64 `json:"bandwidth"`
|
||||
|
||||
// bgp_type
|
||||
BgpType string `json:"bgp_type"`
|
||||
|
||||
// auto_dellocate
|
||||
AutoDellocate *bool `json:"auto_dellocate"`
|
||||
|
||||
// 弹性IP映射的内网IP地址,可选
|
||||
IpAddr string `json:"ip_addr"`
|
||||
}
|
||||
|
||||
type ServerDissociateEipInput struct {
|
||||
|
||||
@@ -42,6 +42,18 @@ type InstanceGroupDetail struct {
|
||||
|
||||
// 云主机数量
|
||||
GuestCount int `json:"guest_count"`
|
||||
|
||||
// VIP
|
||||
Vips []string `json:"vips"`
|
||||
|
||||
// EIP
|
||||
Eip string `json:"eip"`
|
||||
|
||||
// Attached NetworkId
|
||||
NetworkId string `json:"network_id"`
|
||||
|
||||
// Attached Network
|
||||
Network string `json:"network"`
|
||||
}
|
||||
|
||||
type GroupResourceInput struct {
|
||||
|
||||
@@ -399,7 +399,19 @@ func FetchIdNameMap2(manager IStandaloneModelManager, ids []string) (map[string]
|
||||
}
|
||||
|
||||
func FetchIdNameMap(manager IStandaloneModelManager, idMap map[string]string) (map[string]string, error) {
|
||||
q := manager.Query("id", "name").In("id", mapKeys(idMap))
|
||||
return FetchIdFieldMap(manager, "name", idMap)
|
||||
}
|
||||
|
||||
func FetchIdFieldMap2(manager IStandaloneModelManager, field string, ids []string) (map[string]string, error) {
|
||||
idMap := make(map[string]string, len(ids))
|
||||
for _, id := range ids {
|
||||
idMap[id] = ""
|
||||
}
|
||||
return FetchIdFieldMap(manager, field, idMap)
|
||||
}
|
||||
|
||||
func FetchIdFieldMap(manager IStandaloneModelManager, field string, idMap map[string]string) (map[string]string, error) {
|
||||
q := manager.Query("id", field).In("id", mapKeys(idMap))
|
||||
rows, err := q.Rows()
|
||||
if err != nil {
|
||||
if errors.Cause(err) == sql.ErrNoRows {
|
||||
|
||||
@@ -170,7 +170,7 @@ func (self *SBaseGuestDriver) ValidateDetachDisk(ctx context.Context, userCred m
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SBaseGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
|
||||
func (self *SBaseGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, input api.ServerCreateEipInput) error {
|
||||
return httperrors.NewInputParameterError("Not Implement ValidateCreateEip")
|
||||
}
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@ func (self *SESXiGuestDriver) ValidateCreateData(ctx context.Context, userCred m
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (self *SESXiGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
|
||||
func (self *SESXiGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, input api.ServerCreateEipInput) error {
|
||||
return httperrors.NewInputParameterError("%s not support create eip", self.GetHypervisor())
|
||||
}
|
||||
|
||||
|
||||
@@ -333,9 +333,10 @@ func (self *SKVMGuestDriver) IsSupportEip() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SKVMGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
|
||||
func (self *SKVMGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, input api.ServerCreateEipInput) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SKVMGuestDriver) RequestAssociateEip(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, eip *models.SElasticip, task taskman.ITask) error {
|
||||
defer task.ScheduleRun(nil)
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ func (self *SManagedVirtualizedGuestDriver) ValidateCreateData(ctx context.Conte
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (self *SManagedVirtualizedGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
|
||||
func (self *SManagedVirtualizedGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, input api.ServerCreateEipInput) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ func (self *SOpenStackGuestDriver) GetDeployStatus() ([]string, error) {
|
||||
return []string{api.VM_RUNNING}, nil
|
||||
}
|
||||
|
||||
func (self *SOpenStackGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
|
||||
func (self *SOpenStackGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, input api.ServerCreateEipInput) error {
|
||||
return httperrors.NewInputParameterError("%s not support create eip, it only support bind eip", self.GetHypervisor())
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
@@ -120,7 +119,7 @@ func (self *SZStackGuestDriver) ValidateResizeDisk(guest *models.SGuest, disk *m
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SZStackGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
|
||||
func (self *SZStackGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, input api.ServerCreateEipInput) error {
|
||||
return httperrors.NewInputParameterError("%s not support create eip, it only support bind eip", self.GetHypervisor())
|
||||
}
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ func (manager *SElasticipManager) ListItemFilter(
|
||||
case api.EIP_ASSOCIATE_TYPE_SERVER:
|
||||
serverObj, err := GuestManager.FetchByIdOrName(userCred, associateId)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Cause(err) == sql.ErrNoRows {
|
||||
return nil, httperrors.NewResourceNotFoundError("server %s not found", associateId)
|
||||
}
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
@@ -176,6 +176,32 @@ func (manager *SElasticipManager) ListItemFilter(
|
||||
} else {
|
||||
q = q.IsNullOrEmpty("manager_id")
|
||||
}
|
||||
case api.EIP_ASSOCIATE_TYPE_INSTANCE_GROUP:
|
||||
groupObj, err := GroupManager.FetchByIdOrName(userCred, associateId)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == sql.ErrNoRows {
|
||||
return nil, httperrors.NewResourceNotFoundError2(GroupManager.Keyword(), associateId)
|
||||
}
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
}
|
||||
group := groupObj.(*SGroup)
|
||||
net, err := group.getAttachedNetwork()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "group.getAttachedNetwork")
|
||||
}
|
||||
if net == nil {
|
||||
return nil, errors.Wrap(httperrors.ErrInvalidStatus, "group is not attached to network")
|
||||
}
|
||||
|
||||
zone, _ := net.GetZone()
|
||||
networks := NetworkManager.Query().SubQuery()
|
||||
wires := WireManager.Query().SubQuery()
|
||||
|
||||
sq := networks.Query(networks.Field("id")).Join(wires, sqlchemy.Equals(wires.Field("id"), networks.Field("wire_id"))).
|
||||
Filter(sqlchemy.Equals(wires.Field("zone_id"), zone.Id)).SubQuery()
|
||||
q = q.Filter(sqlchemy.In(q.Field("network_id"), sq))
|
||||
q = q.Filter(sqlchemy.NotEquals(q.Field("network_id"), net.Id))
|
||||
q = q.IsNullOrEmpty("manager_id")
|
||||
case api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY:
|
||||
_nat, err := validators.ValidateModel(userCred, NatGatewayManager, &query.UsableEipForAssociateId)
|
||||
if err != nil {
|
||||
@@ -430,6 +456,9 @@ func (self *SElasticip) SyncInstanceWithCloudEip(ctx context.Context, userCred m
|
||||
manager = NatGatewayManager
|
||||
case api.EIP_ASSOCIATE_TYPE_LOADBALANCER:
|
||||
manager = LoadbalancerManager
|
||||
// case api.EIP_ASSOCIATE_TYPE_INSTANCE_GROUP:
|
||||
// not supported
|
||||
// manager = GroupManager
|
||||
default:
|
||||
return errors.Error("unsupported association type")
|
||||
}
|
||||
@@ -632,6 +661,9 @@ func (self *SElasticip) IsAssociated() bool {
|
||||
if self.GetAssociateNatGateway() != nil {
|
||||
return true
|
||||
}
|
||||
if self.GetAssociateInstanceGroup() != nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -642,6 +674,17 @@ func (self *SElasticip) GetAssociateVM() *SGuest {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SElasticip) GetAssociateInstanceGroup() *SGroup {
|
||||
if self.AssociateType == api.EIP_ASSOCIATE_TYPE_INSTANCE_GROUP && len(self.AssociateId) > 0 {
|
||||
_grp, err := GroupManager.FetchById(self.AssociateId)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return _grp.(*SGroup)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SElasticip) GetAssociateLoadbalancer() *SLoadbalancer {
|
||||
if self.AssociateType == api.EIP_ASSOCIATE_TYPE_LOADBALANCER && len(self.AssociateId) > 0 {
|
||||
_lb, err := LoadbalancerManager.FetchById(self.AssociateId)
|
||||
@@ -678,6 +721,9 @@ func (self *SElasticip) GetAssociateResource() db.IModel {
|
||||
if nat := self.GetAssociateNatGateway(); nat != nil {
|
||||
return nat
|
||||
}
|
||||
if grp := self.GetAssociateInstanceGroup(); grp != nil {
|
||||
return grp
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -688,6 +734,7 @@ func (self *SElasticip) Dissociate(ctx context.Context, userCred mcclient.TokenC
|
||||
var vm *SGuest
|
||||
var nat *SNatGateway
|
||||
var lb *SLoadbalancer
|
||||
var grp *SGroup
|
||||
switch self.AssociateType {
|
||||
case api.EIP_ASSOCIATE_TYPE_SERVER:
|
||||
vm = self.GetAssociateVM()
|
||||
@@ -704,6 +751,11 @@ func (self *SElasticip) Dissociate(ctx context.Context, userCred mcclient.TokenC
|
||||
if lb == nil {
|
||||
log.Errorf("dissociate loadbalancer not exists???")
|
||||
}
|
||||
case api.EIP_ASSOCIATE_TYPE_INSTANCE_GROUP:
|
||||
grp = self.GetAssociateInstanceGroup()
|
||||
if grp == nil {
|
||||
log.Errorf("dissociate instance_group not exists???")
|
||||
}
|
||||
}
|
||||
|
||||
_, err := db.Update(self, func() error {
|
||||
@@ -732,6 +784,12 @@ func (self *SElasticip) Dissociate(ctx context.Context, userCred mcclient.TokenC
|
||||
db.OpsLog.LogEvent(lb, db.ACT_EIP_DETACH, self.GetShortDesc(ctx), userCred)
|
||||
}
|
||||
|
||||
if grp != nil {
|
||||
db.OpsLog.LogDetachEvent(ctx, grp, self, userCred, self.GetShortDesc(ctx))
|
||||
db.OpsLog.LogEvent(self, db.ACT_EIP_DETACH, grp.GetShortDesc(ctx), userCred)
|
||||
db.OpsLog.LogEvent(grp, db.ACT_EIP_DETACH, self.GetShortDesc(ctx), userCred)
|
||||
}
|
||||
|
||||
if self.Mode == api.EIP_MODE_INSTANCE_PUBLICIP {
|
||||
self.RealDelete(ctx, userCred)
|
||||
}
|
||||
@@ -795,6 +853,36 @@ func (self *SElasticip) AssociateInstance(ctx context.Context, userCred mcclient
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SElasticip) AssociateInstanceGroup(ctx context.Context, userCred mcclient.TokenCredential, insType string, ins db.IStatusStandaloneModel) error {
|
||||
switch insType {
|
||||
case api.EIP_ASSOCIATE_TYPE_INSTANCE_GROUP:
|
||||
vm := ins.(*SGroup)
|
||||
if vm.PendingDeleted || vm.Deleted {
|
||||
return fmt.Errorf("group 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 = insType
|
||||
self.AssociateId = ins.GetId()
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "db.Update")
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (self *SElasticip) AssociateNatGateway(ctx context.Context, userCred mcclient.TokenCredential, nat *SNatGateway) error {
|
||||
if nat.Deleted {
|
||||
return fmt.Errorf("nat gateway is deleted")
|
||||
@@ -1290,6 +1378,7 @@ type NewEipForVMOnHostArgs struct {
|
||||
ChargeType string
|
||||
AutoDellocate bool
|
||||
|
||||
Group *SGroup
|
||||
Guest *SGuest
|
||||
Host *SHost
|
||||
Natgateway *SNatGateway
|
||||
@@ -1302,6 +1391,7 @@ func (manager *SElasticipManager) NewEipForVMOnHost(ctx context.Context, userCre
|
||||
bgpType = args.BgpType
|
||||
chargeType = args.ChargeType
|
||||
autoDellocate = args.AutoDellocate
|
||||
grp = args.Group
|
||||
vm = args.Guest
|
||||
host = args.Host
|
||||
nat = args.Natgateway
|
||||
@@ -1314,6 +1404,9 @@ func (manager *SElasticipManager) NewEipForVMOnHost(ctx context.Context, userCre
|
||||
region, _ = host.GetRegion()
|
||||
} else if nat != nil {
|
||||
region, _ = nat.GetRegion()
|
||||
} else if grp != nil {
|
||||
net, _ := grp.getAttachedNetwork()
|
||||
region, _ = net.GetRegion()
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid host or nat")
|
||||
}
|
||||
@@ -1359,18 +1452,31 @@ func (manager *SElasticipManager) NewEipForVMOnHost(ctx context.Context, userCre
|
||||
eip.Name = fmt.Sprintf("eip-for-%s", pinyinutils.Text2Pinyin(vm.GetName()))
|
||||
} else if nat != nil {
|
||||
eip.Name = fmt.Sprintf("eip-for-%s", pinyinutils.Text2Pinyin(nat.GetName()))
|
||||
} else if grp != nil {
|
||||
eip.Name = fmt.Sprintf("eip-for-%s", pinyinutils.Text2Pinyin(grp.GetName()))
|
||||
}
|
||||
|
||||
if host != nil && host.ManagerId == "" { // kvm
|
||||
if (host != nil && host.ManagerId == "") || grp != nil { // kvm
|
||||
q := NetworkManager.Query()
|
||||
|
||||
var zoneId string
|
||||
if host != nil {
|
||||
zoneId = host.ZoneId
|
||||
} else if grp != nil {
|
||||
net, _ := grp.getAttachedNetwork()
|
||||
zone, _ := net.GetZone()
|
||||
zoneId = zone.Id
|
||||
}
|
||||
|
||||
wireq := WireManager.Query().SubQuery()
|
||||
scope, _ := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), NetworkManager.KeywordPlural(), policy.PolicyActionList)
|
||||
q := NetworkManager.Query()
|
||||
q = NetworkManager.FilterByOwner(q, userCred, scope)
|
||||
q = q.Join(wireq, sqlchemy.Equals(wireq.Field("id"), q.Field("wire_id"))).
|
||||
Filter(sqlchemy.Equals(wireq.Field("zone_id"), host.ZoneId))
|
||||
Filter(sqlchemy.Equals(wireq.Field("zone_id"), zoneId))
|
||||
|
||||
q = q.Equals("server_type", api.NETWORK_TYPE_EIP)
|
||||
q = q.Equals("bgp_type", bgpType)
|
||||
|
||||
var nets []SNetwork
|
||||
if err := db.FetchModelObjects(NetworkManager, q, &nets); err != nil {
|
||||
return nil, errors.Wrapf(err, "fetch eip networks usable in host %s(%s)",
|
||||
@@ -1415,6 +1521,8 @@ func (manager *SElasticipManager) NewEipForVMOnHost(ctx context.Context, userCre
|
||||
ownerId = vm.GetOwnerId()
|
||||
} else if nat != nil {
|
||||
ownerId = nat.GetOwnerId()
|
||||
} else if grp != nil {
|
||||
ownerId = grp.GetOwnerId()
|
||||
}
|
||||
|
||||
var provider *SCloudprovider = nil
|
||||
|
||||
@@ -79,7 +79,7 @@ func (manager *SGroupguestManager) FetchCustomizeColumns(
|
||||
rows[i] = api.GroupguestDetails{
|
||||
GroupJointResourceDetails: groupRows[i],
|
||||
}
|
||||
guestIds[i] = objs[i].(SGroupguest).GuestId
|
||||
guestIds[i] = objs[i].(*SGroupguest).GuestId
|
||||
}
|
||||
|
||||
guestIdMaps, err := db.FetchIdNameMap2(GuestManager, guestIds)
|
||||
|
||||
@@ -60,7 +60,7 @@ type SGroupnetwork struct {
|
||||
|
||||
Index int8 `nullable:"false" default:"0" list:"user" list:"user" update:"user" create:"optional"` // Column(TINYINT, nullable=False, default=0)
|
||||
|
||||
EipId string `width:"36" charset:"ascii" nullable:"true"` // Column(VARCHAR(36, charset='ascii'), nullable=True)
|
||||
EipId string `width:"36" charset:"ascii" nullable:"true" list:"user"` // Column(VARCHAR(36, charset='ascii'), nullable=True)
|
||||
}
|
||||
|
||||
func (manager *SGroupnetworkManager) GetSlaveFieldName() string {
|
||||
@@ -79,11 +79,13 @@ func (manager *SGroupnetworkManager) FetchCustomizeColumns(
|
||||
|
||||
groupRows := manager.SGroupJointsManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
||||
netIds := make([]string, len(rows))
|
||||
eipIds := make([]string, len(rows))
|
||||
for i := range rows {
|
||||
rows[i] = api.GroupnetworkDetails{
|
||||
GroupJointResourceDetails: groupRows[i],
|
||||
}
|
||||
netIds[i] = objs[i].(*SGroupnetwork).NetworkId
|
||||
eipIds[i] = objs[i].(*SGroupnetwork).EipId
|
||||
}
|
||||
|
||||
netIdMaps, err := db.FetchIdNameMap2(NetworkManager, netIds)
|
||||
@@ -98,6 +100,16 @@ func (manager *SGroupnetworkManager) FetchCustomizeColumns(
|
||||
}
|
||||
}
|
||||
|
||||
eipIdMaps, err := db.FetchIdFieldMap2(ElasticipManager, "ip_addr", eipIds)
|
||||
if err != nil {
|
||||
return rows
|
||||
}
|
||||
for i := range rows {
|
||||
if name, ok := eipIdMaps[eipIds[i]]; ok {
|
||||
rows[i].EipAddr = name
|
||||
}
|
||||
}
|
||||
|
||||
return rows
|
||||
}
|
||||
|
||||
@@ -182,3 +194,25 @@ func (manager *SGroupnetworkManager) ListItemExportKeys(ctx context.Context,
|
||||
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func (manager *SGroupnetworkManager) FetchByGroupId(groupId string) ([]SGroupnetwork, error) {
|
||||
q := manager.Query().
|
||||
Equals("group_id", groupId)
|
||||
var rets []SGroupnetwork
|
||||
if err := db.FetchModelObjects(manager, q, &rets); err != nil {
|
||||
return nil, errors.Wrap(err, "FetchModelObjects")
|
||||
}
|
||||
return rets, nil
|
||||
}
|
||||
|
||||
func (manager *SGroupnetworkManager) getVips(groupId string) ([]string, error) {
|
||||
gns, err := manager.FetchByGroupId(groupId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "manager.FetchByGroupId")
|
||||
}
|
||||
ret := make([]string, len(gns))
|
||||
for i := range gns {
|
||||
ret[i] = gns[i].IpAddr
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
@@ -24,15 +24,19 @@ import (
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/tristate"
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
"yunion.io/x/pkg/util/sets"
|
||||
"yunion.io/x/sqlchemy"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
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/policy"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/logclient"
|
||||
"yunion.io/x/onecloud/pkg/util/rbacutils"
|
||||
"yunion.io/x/onecloud/pkg/util/stringutils2"
|
||||
)
|
||||
|
||||
@@ -187,6 +191,16 @@ func (sm *SGroupManager) FetchCustomizeColumns(
|
||||
ZoneResourceInfo: zoneRows[i],
|
||||
}
|
||||
rows[i].GuestCount = objs[i].(*SGroup).GetGuestCount()
|
||||
rows[i].Vips, _ = GroupnetworkManager.getVips(objs[i].(*SGroup).Id)
|
||||
net, _ := objs[i].(*SGroup).getAttachedNetwork()
|
||||
if net != nil {
|
||||
rows[i].NetworkId = net.Id
|
||||
rows[i].Network = net.Name
|
||||
}
|
||||
eip, _ := objs[i].(*SGroup).getElasticIp()
|
||||
if eip != nil {
|
||||
rows[i].Eip = eip.IpAddr
|
||||
}
|
||||
}
|
||||
|
||||
return rows
|
||||
@@ -198,6 +212,20 @@ func (group *SGroup) GetGuestCount() int {
|
||||
return count
|
||||
}
|
||||
|
||||
func (group *SGroup) GetGuests() []SGuest {
|
||||
ggm := GroupguestManager.Query().SubQuery()
|
||||
q := GuestManager.Query()
|
||||
q = q.Join(ggm, sqlchemy.Equals(q.Field("id"), ggm.Field("guest_id")))
|
||||
q = q.Filter(sqlchemy.Equals(ggm.Field("group_id"), group.Id))
|
||||
|
||||
guests := make([]SGuest, 0)
|
||||
err := db.FetchModelObjects(GuestManager, q, &guests)
|
||||
if err != nil && errors.Cause(err) != sql.ErrNoRows {
|
||||
return nil
|
||||
}
|
||||
return guests
|
||||
}
|
||||
|
||||
func (group *SGroup) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
|
||||
q := GroupguestManager.Query().Equals("group_id", group.Id)
|
||||
count, err := q.CountWithError()
|
||||
@@ -220,6 +248,16 @@ func (group *SGroup) GetNetworks() ([]SGroupnetwork, error) {
|
||||
return groupnets, nil
|
||||
}
|
||||
|
||||
func (group *SGroup) getGroupnetworks() ([]SGroupnetwork, error) {
|
||||
ret := make([]SGroupnetwork, 0)
|
||||
q := GroupnetworkManager.Query().Equals("group_id", group.Id)
|
||||
err := db.FetchModelObjects(GroupnetworkManager, q, &ret)
|
||||
if err != nil && errors.Cause(err) != sql.ErrNoRows {
|
||||
return nil, errors.Wrap(err, "FetchModelObjects")
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (group *SGroup) PerformBindGuests(ctx context.Context, userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
|
||||
@@ -243,7 +281,29 @@ func (group *SGroup) PerformBindGuests(ctx context.Context, userCred mcclient.To
|
||||
}
|
||||
}
|
||||
|
||||
var networkId string
|
||||
gns, err := group.getGroupnetworks()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getGroupnetworks")
|
||||
}
|
||||
if len(gns) > 0 {
|
||||
networkId = gns[0].NetworkId
|
||||
}
|
||||
|
||||
for _, guestId := range guestIdSet.UnsortedList() {
|
||||
if len(networkId) > 0 {
|
||||
// need to check consistency of network
|
||||
gns, err := GuestnetworkManager.FetchByGuestId(guestId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "")
|
||||
}
|
||||
if len(gns) != 1 {
|
||||
return nil, errors.Wrap(httperrors.ErrNotSupported, "cannot join a guest without network or with more than one network to a group with VIP")
|
||||
}
|
||||
if gns[0].NetworkId != networkId {
|
||||
return nil, errors.Wrap(httperrors.ErrConflict, "cannot join a guest with network inconsist with VIP")
|
||||
}
|
||||
}
|
||||
_, err := GroupguestManager.Attach(ctx, group.Id, guestId)
|
||||
if err != nil {
|
||||
logclient.AddActionLogWithContext(ctx, group, logclient.ACT_VM_ASSOCIATE, nil, userCred, false)
|
||||
@@ -396,3 +456,386 @@ func (manager *SGroupManager) ListItemExportKeys(ctx context.Context,
|
||||
}
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func (grp *SGroup) getAttachedNetwork() (*SNetwork, error) {
|
||||
var netId string
|
||||
guests := grp.GetGuests()
|
||||
for i := range guests {
|
||||
guest := guests[i]
|
||||
nets, err := guest.GetNetworks("")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "guest.GestNetworks(%s)", guest.Name)
|
||||
}
|
||||
if len(nets) != 1 {
|
||||
return nil, errors.Wrapf(httperrors.ErrInvalidStatus, "guest (%s) has %d networks", guest.Name, len(nets))
|
||||
}
|
||||
if len(netId) == 0 {
|
||||
netId = nets[0].NetworkId
|
||||
} else if netId != nets[0].NetworkId {
|
||||
return nil, errors.Wrapf(httperrors.ErrInvalidStatus, "inconsistent networkId for member servers")
|
||||
}
|
||||
}
|
||||
if len(netId) == 0 {
|
||||
gns, err := GroupnetworkManager.FetchByGroupId(grp.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GroupnetworkManager.FetchByGroupId")
|
||||
}
|
||||
for _, gn := range gns {
|
||||
netId = gn.NetworkId
|
||||
}
|
||||
}
|
||||
if len(netId) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
netObj, err := NetworkManager.FetchById(netId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "NetworkManager.FetchById %s", netId)
|
||||
}
|
||||
return netObj.(*SNetwork), nil
|
||||
}
|
||||
|
||||
func (net *SNetwork) GetRegionalQuotaKeys(ownerId mcclient.IIdentityProvider) (quotas.IQuotaKeys, error) {
|
||||
vpc, err := net.GetVpc()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getVpc")
|
||||
}
|
||||
provider := vpc.GetCloudprovider()
|
||||
if provider == nil && len(vpc.ManagerId) > 0 {
|
||||
return nil, errors.Wrap(httperrors.ErrInvalidStatus, "no valid manager")
|
||||
}
|
||||
region, _ := net.GetRegion()
|
||||
if region == nil {
|
||||
return nil, errors.Wrap(httperrors.ErrInvalidStatus, "no valid region")
|
||||
}
|
||||
return fetchRegionalQuotaKeys(rbacutils.ScopeProject, ownerId, region, provider), nil
|
||||
}
|
||||
|
||||
func (grp *SGroup) PerformDetachnetwork(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.GroupDetachNetworkInput) (*api.SGroup, error) {
|
||||
net, err := grp.getAttachedNetwork()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getAttachedNetwork")
|
||||
}
|
||||
if net == nil {
|
||||
// no guest and no attached network
|
||||
return nil, nil
|
||||
}
|
||||
gns, err := GroupnetworkManager.FetchByGroupId(grp.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GroupnetworkManager.FetchByGroupId")
|
||||
}
|
||||
if len(gns) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
for _, gn := range gns {
|
||||
if len(input.IpAddr) == 0 || gn.IpAddr == input.IpAddr {
|
||||
if len(gn.EipId) > 0 {
|
||||
logclient.AddSimpleActionLog(grp, logclient.ACT_DETACH_NETWORK, "eip associated", userCred, false)
|
||||
return nil, errors.Wrap(httperrors.ErrInvalidStatus, "cannot detach network with eip")
|
||||
}
|
||||
// delete
|
||||
notes := struct {
|
||||
Network string
|
||||
NetworkId string
|
||||
IpAddr string
|
||||
}{
|
||||
Network: net.Name,
|
||||
NetworkId: net.Id,
|
||||
IpAddr: gn.IpAddr,
|
||||
}
|
||||
err := gn.Detach(ctx, userCred)
|
||||
if err != nil {
|
||||
logclient.AddSimpleActionLog(grp, logclient.ACT_DETACH_NETWORK, notes, userCred, false)
|
||||
return nil, errors.Wrap(err, "Detach")
|
||||
}
|
||||
logclient.AddSimpleActionLog(grp, logclient.ACT_DETACH_NETWORK, notes, userCred, true)
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (grp *SGroup) PerformAttachnetwork(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.GroupAttachNetworkInput) (*api.SGroup, error) {
|
||||
net, err := grp.getAttachedNetwork()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getAttachedNetwork")
|
||||
}
|
||||
|
||||
if len(input.NetworkId) > 0 {
|
||||
netObj, err := NetworkManager.FetchByIdOrName(userCred, input.NetworkId)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == sql.ErrNoRows {
|
||||
return nil, httperrors.NewResourceNotFoundError2(NetworkManager.Keyword(), input.NetworkId)
|
||||
} else {
|
||||
return nil, errors.Wrap(err, "NetworkManager.FetchByIdOrName")
|
||||
}
|
||||
}
|
||||
if net != nil {
|
||||
if net.Id != netObj.GetId() {
|
||||
return nil, errors.Wrap(httperrors.ErrConflict, "provided network inconsistent with existing network")
|
||||
}
|
||||
} else {
|
||||
net = netObj.(*SNetwork)
|
||||
}
|
||||
} else if net == nil {
|
||||
return nil, errors.Wrap(httperrors.ErrInputParameter, "please specify network")
|
||||
}
|
||||
|
||||
if len(input.IpAddr) > 0 {
|
||||
addr, err := netutils.NewIPV4Addr(input.IpAddr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(httperrors.ErrInputParameter, "invalid ip_addr %s", input.IpAddr)
|
||||
}
|
||||
if !net.GetIPRange().Contains(addr) {
|
||||
return nil, errors.Wrapf(httperrors.ErrInputParameter, "ip_addr %s not in range", input.IpAddr)
|
||||
}
|
||||
}
|
||||
|
||||
// check quota
|
||||
var inicCnt, enicCnt int
|
||||
var saveQuota bool
|
||||
if net.IsExitNetwork() {
|
||||
enicCnt = 1
|
||||
} else {
|
||||
inicCnt = 1
|
||||
}
|
||||
pendingUsage := &SRegionQuota{
|
||||
Port: inicCnt,
|
||||
Eport: enicCnt,
|
||||
}
|
||||
keys, err := net.GetRegionalQuotaKeys(grp.GetOwnerId())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetRegionalQuotaKeys")
|
||||
}
|
||||
pendingUsage.SetKeys(keys)
|
||||
err = quotas.CheckSetPendingQuota(ctx, userCred, pendingUsage)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewOutOfQuotaError("%v", err)
|
||||
}
|
||||
defer quotas.CancelPendingUsage(ctx, userCred, pendingUsage, pendingUsage, saveQuota)
|
||||
|
||||
ipAddr, err := net.GetFreeIP(ctx, userCred, nil, nil, input.IpAddr, input.AllocDir, input.Reserved != nil && *input.Reserved)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(input.IpAddr) > 0 && ipAddr != input.IpAddr && input.RequireDesignatedIp != nil && *input.RequireDesignatedIp {
|
||||
return nil, errors.Wrapf(httperrors.ErrConflict, "candidate ip %s is occupied!", input.IpAddr)
|
||||
}
|
||||
|
||||
gn := SGroupnetwork{}
|
||||
gn.NetworkId = net.Id
|
||||
gn.GroupId = grp.Id
|
||||
gn.IpAddr = ipAddr
|
||||
|
||||
gn.SetModelManager(GroupnetworkManager, &gn)
|
||||
|
||||
err = GroupnetworkManager.TableSpec().Insert(ctx, &gn)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Insert")
|
||||
}
|
||||
|
||||
notes := struct {
|
||||
Network string
|
||||
NetworkId string
|
||||
IpAddr string
|
||||
}{
|
||||
Network: net.Name,
|
||||
NetworkId: net.Id,
|
||||
IpAddr: gn.IpAddr,
|
||||
}
|
||||
db.OpsLog.LogAttachEvent(ctx, grp, net, userCred, jsonutils.Marshal(notes))
|
||||
logclient.AddActionLogWithContext(ctx, grp, logclient.ACT_ATTACH_NETWORK, notes, userCred, true)
|
||||
|
||||
saveQuota = true
|
||||
|
||||
guests := grp.GetGuests()
|
||||
for _, g := range guests {
|
||||
host, _ := g.GetHost()
|
||||
host.ClearSchedDescCache()
|
||||
g.StartSyncTask(ctx, userCred, false, "")
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (grp *SGroup) GetVpc() (*SVpc, error) {
|
||||
net, err := grp.getAttachedNetwork()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getAttachedNetwork")
|
||||
}
|
||||
return net.GetVpc()
|
||||
}
|
||||
|
||||
func (grp *SGroup) isEipAssociable() (*SNetwork, error) {
|
||||
err := ValidateAssociateEip(grp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
net, err := grp.getAttachedNetwork()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getAttachedNetwork")
|
||||
}
|
||||
if net == nil {
|
||||
return nil, errors.Wrap(httperrors.ErrInvalidStatus, "group no attached network")
|
||||
}
|
||||
|
||||
gns, err := grp.getGroupnetworks()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getGroupnetworks")
|
||||
}
|
||||
if len(gns) == 0 {
|
||||
return nil, errors.Wrap(httperrors.ErrInvalidStatus, "group no vips")
|
||||
}
|
||||
|
||||
return net, nil
|
||||
}
|
||||
|
||||
func (grp *SGroup) PerformAssociateEip(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ServerAssociateEipInput) (jsonutils.JSONObject, error) {
|
||||
net, err := grp.isEipAssociable()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "grp.isEipAssociable")
|
||||
}
|
||||
|
||||
eipStr := input.EipId
|
||||
if len(eipStr) == 0 {
|
||||
return nil, httperrors.NewMissingParameterError("eip_id")
|
||||
}
|
||||
eipObj, err := ElasticipManager.FetchByIdOrName(userCred, eipStr)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, httperrors.NewResourceNotFoundError("eip %s not found", eipStr)
|
||||
} else {
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
}
|
||||
}
|
||||
|
||||
eip := eipObj.(*SElasticip)
|
||||
|
||||
if eip.Mode == api.EIP_MODE_INSTANCE_PUBLICIP {
|
||||
return nil, httperrors.NewUnsupportOperationError("fixed eip cannot be associated")
|
||||
}
|
||||
|
||||
if eip.IsAssociated() {
|
||||
return nil, httperrors.NewConflictError("eip has been associated")
|
||||
}
|
||||
|
||||
if net.Id == eip.NetworkId {
|
||||
return nil, httperrors.NewInputParameterError("cannot associate eip with same network")
|
||||
}
|
||||
|
||||
eipZone, _ := eip.GetZone()
|
||||
if eipZone != nil {
|
||||
insZone, _ := net.GetZone()
|
||||
if eipZone.Id != insZone.Id {
|
||||
return nil, httperrors.NewInputParameterError("cannot associate eip and instance in different zone")
|
||||
}
|
||||
}
|
||||
|
||||
grp.SetStatus(userCred, api.INSTANCE_ASSOCIATE_EIP, "associate eip")
|
||||
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(grp.Id), "instance_id")
|
||||
params.Add(jsonutils.NewString(api.EIP_ASSOCIATE_TYPE_INSTANCE_GROUP), "instance_type")
|
||||
if len(input.IpAddr) > 0 {
|
||||
params.Add(jsonutils.NewString(input.IpAddr), "ip_addr")
|
||||
}
|
||||
|
||||
err = eip.StartEipAssociateTask(ctx, userCred, params, "")
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (grp *SGroup) PerformCreateEip(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ServerCreateEipInput) (jsonutils.JSONObject, error) {
|
||||
net, err := grp.isEipAssociable()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "grp.isEipAssociable")
|
||||
}
|
||||
|
||||
var (
|
||||
region, _ = net.GetRegion()
|
||||
regionDriver = region.GetDriver()
|
||||
|
||||
bw = input.Bandwidth
|
||||
chargeType = input.ChargeType
|
||||
bgpType = input.BgpType
|
||||
autoDellocate = (input.AutoDellocate != nil && *input.AutoDellocate)
|
||||
)
|
||||
|
||||
if chargeType == "" {
|
||||
chargeType = regionDriver.GetEipDefaultChargeType()
|
||||
}
|
||||
|
||||
if chargeType == api.EIP_CHARGE_TYPE_BY_BANDWIDTH {
|
||||
if bw == 0 {
|
||||
return nil, httperrors.NewMissingParameterError("bandwidth")
|
||||
}
|
||||
}
|
||||
|
||||
eipPendingUsage := &SRegionQuota{Eip: 1}
|
||||
keys, err := net.GetRegionalQuotaKeys(grp.GetOwnerId())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "")
|
||||
}
|
||||
eipPendingUsage.SetKeys(keys)
|
||||
err = quotas.CheckSetPendingQuota(ctx, userCred, eipPendingUsage)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewOutOfQuotaError("Out of eip quota: %s", err)
|
||||
}
|
||||
|
||||
eip, err := ElasticipManager.NewEipForVMOnHost(ctx, userCred, &NewEipForVMOnHostArgs{
|
||||
Bandwidth: int(bw),
|
||||
BgpType: bgpType,
|
||||
ChargeType: chargeType,
|
||||
AutoDellocate: autoDellocate,
|
||||
|
||||
Group: grp,
|
||||
PendingUsage: eipPendingUsage,
|
||||
})
|
||||
if err != nil {
|
||||
quotas.CancelPendingUsage(ctx, userCred, eipPendingUsage, eipPendingUsage, false)
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
}
|
||||
|
||||
opts := api.ElasticipAssociateInput{
|
||||
InstanceId: grp.Id,
|
||||
InstanceType: api.EIP_ASSOCIATE_TYPE_INSTANCE_GROUP,
|
||||
IpAddr: input.IpAddr,
|
||||
}
|
||||
|
||||
err = eip.AllocateAndAssociateInstance(ctx, userCred, grp, opts, "")
|
||||
if err != nil {
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (grp *SGroup) getElasticIp() (*SElasticip, error) {
|
||||
return ElasticipManager.getEip(api.EIP_ASSOCIATE_TYPE_INSTANCE_GROUP, grp.Id, api.EIP_MODE_STANDALONE_EIP)
|
||||
}
|
||||
|
||||
func (grp *SGroup) PerformDissociateEip(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ServerDissociateEipInput) (jsonutils.JSONObject, error) {
|
||||
eip, err := grp.getElasticIp()
|
||||
if err != nil {
|
||||
log.Errorf("Fail to get Eip %s", err)
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
}
|
||||
if eip == nil {
|
||||
return nil, httperrors.NewInvalidStatusError("No eip to dissociate")
|
||||
}
|
||||
|
||||
err = db.IsObjectRbacAllowed(ctx, eip, userCred, policy.PolicyActionGet)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "eip is not accessible")
|
||||
}
|
||||
|
||||
grp.SetStatus(userCred, api.INSTANCE_DISSOCIATE_EIP, "associate eip")
|
||||
|
||||
autoDelete := (input.AudoDelete != nil && *input.AudoDelete)
|
||||
|
||||
err = eip.StartEipDissociateTask(ctx, userCred, autoDelete, "")
|
||||
if err != nil {
|
||||
log.Errorf("fail to start dissociate task %s", err)
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -2883,8 +2883,7 @@ func (self *SGuest) PerformAssociateEip(ctx context.Context, userCred mcclient.T
|
||||
return nil, httperrors.NewUnsupportOperationError("fixed eip cannot be associated")
|
||||
}
|
||||
|
||||
eipVm := eip.GetAssociateVM()
|
||||
if eipVm != nil {
|
||||
if eip.IsAssociated() {
|
||||
return nil, httperrors.NewConflictError("eip has been associated")
|
||||
}
|
||||
|
||||
@@ -2927,6 +2926,9 @@ func (self *SGuest) PerformAssociateEip(ctx context.Context, userCred mcclient.T
|
||||
params.Add(jsonutils.NewString(self.ExternalId), "instance_external_id")
|
||||
params.Add(jsonutils.NewString(self.Id), "instance_id")
|
||||
params.Add(jsonutils.NewString(api.EIP_ASSOCIATE_TYPE_SERVER), "instance_type")
|
||||
if len(input.IpAddr) > 0 {
|
||||
params.Add(jsonutils.NewString(input.IpAddr), "ip_addr")
|
||||
}
|
||||
|
||||
err = eip.StartEipAssociateTask(ctx, userCred, params, "")
|
||||
|
||||
@@ -2960,16 +2962,16 @@ func (self *SGuest) PerformDissociateEip(ctx context.Context, userCred mcclient.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (self *SGuest) PerformCreateEip(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
func (self *SGuest) PerformCreateEip(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ServerCreateEipInput) (jsonutils.JSONObject, error) {
|
||||
var (
|
||||
host, _ = self.GetHost()
|
||||
region, _ = host.GetRegion()
|
||||
regionDriver = region.GetDriver()
|
||||
|
||||
bw int64
|
||||
chargeType string
|
||||
bgpType string
|
||||
autoDellocate bool
|
||||
bw = input.Bandwidth
|
||||
chargeType = input.ChargeType
|
||||
bgpType = input.BgpType
|
||||
autoDellocate = (input.AutoDellocate != nil && *input.AutoDellocate)
|
||||
)
|
||||
|
||||
err := ValidateAssociateEip(self)
|
||||
@@ -2977,21 +2979,17 @@ func (self *SGuest) PerformCreateEip(ctx context.Context, userCred mcclient.Toke
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chargeType, _ = data.GetString("charge_type")
|
||||
if chargeType == "" {
|
||||
chargeType = regionDriver.GetEipDefaultChargeType()
|
||||
}
|
||||
|
||||
bw, _ = data.Int("bandwidth")
|
||||
if chargeType == api.EIP_CHARGE_TYPE_BY_BANDWIDTH {
|
||||
if bw == 0 {
|
||||
return nil, httperrors.NewMissingParameterError("bandwidth")
|
||||
}
|
||||
}
|
||||
bgpType, _ = data.GetString("bgp_type")
|
||||
autoDellocate, _ = data.Bool("auto_dellocate")
|
||||
|
||||
err = self.GetDriver().ValidateCreateEip(ctx, userCred, data)
|
||||
err = self.GetDriver().ValidateCreateEip(ctx, userCred, input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ type IGuestDriver interface {
|
||||
|
||||
IsSupportEip() bool
|
||||
IsSupportPublicIp() bool
|
||||
ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error
|
||||
ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, input api.ServerCreateEipInput) error
|
||||
|
||||
NeedStopForChangeSpec(ctx context.Context, guest *SGuest, cpuChanged, memChanged bool) bool
|
||||
|
||||
|
||||
@@ -128,6 +128,7 @@ func (manager *SGuestnetworkManager) FetchCustomizeColumns(
|
||||
|
||||
guestRows := manager.SGuestJointsManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
||||
netIds := make([]string, len(rows))
|
||||
eipIds := make([]string, len(rows))
|
||||
for i := range rows {
|
||||
rows[i] = api.GuestnetworkDetails{
|
||||
GuestJointResourceDetails: guestRows[i],
|
||||
@@ -136,6 +137,7 @@ func (manager *SGuestnetworkManager) FetchCustomizeColumns(
|
||||
iNet, _ := NetworkManager.FetchById(netIds[i])
|
||||
net := iNet.(*SNetwork)
|
||||
rows[i].WireId = net.WireId
|
||||
eipIds[i] = objs[i].(*SGuestnetwork).EipId
|
||||
}
|
||||
|
||||
netIdMaps, err := db.FetchIdNameMap2(NetworkManager, netIds)
|
||||
@@ -150,6 +152,18 @@ func (manager *SGuestnetworkManager) FetchCustomizeColumns(
|
||||
}
|
||||
}
|
||||
|
||||
eipIdMaps, err := db.FetchIdFieldMap2(ElasticipManager, "ip_addr", eipIds)
|
||||
if err != nil {
|
||||
log.Errorf("FetchIdFieldMap2 fail %s", err)
|
||||
return rows
|
||||
}
|
||||
|
||||
for i := range rows {
|
||||
if ip, ok := eipIdMaps[eipIds[i]]; ok {
|
||||
rows[i].EipAddr = ip
|
||||
}
|
||||
}
|
||||
|
||||
return rows
|
||||
}
|
||||
|
||||
@@ -640,6 +654,9 @@ func (self *SGuestnetwork) ValidateUpdateData(
|
||||
func (manager *SGuestnetworkManager) DeleteGuestNics(ctx context.Context, userCred mcclient.TokenCredential, gns []SGuestnetwork, reserve bool) error {
|
||||
for i := range gns {
|
||||
gn := gns[i]
|
||||
if len(gn.EipId) > 0 {
|
||||
return errors.Wrapf(httperrors.ErrInvalidStatus, "eip associate with %s", gn.IpAddr)
|
||||
}
|
||||
guest := gn.GetGuest()
|
||||
net := gn.GetNetwork()
|
||||
if regutils.MatchIP4Addr(gn.IpAddr) || regutils.MatchIP6Addr(gn.Ip6Addr) {
|
||||
@@ -916,21 +933,26 @@ func (manager *SGuestnetworkManager) FetchByIdsAndIpMac(guestId string, netId st
|
||||
return ign.(*SGuestnetwork), nil
|
||||
}
|
||||
|
||||
func (manager *SGuestnetworkManager) FetchByGuestIdIndex(guestId string, index int8) (*SGuestnetwork, error) {
|
||||
func (manager *SGuestnetworkManager) FetchByGuestId(guestId string) ([]SGuestnetwork, error) {
|
||||
q := manager.Query().
|
||||
Equals("guest_id", guestId).
|
||||
Equals("index", index)
|
||||
Equals("guest_id", guestId)
|
||||
q = q.Asc(q.Field("index"))
|
||||
var rets []SGuestnetwork
|
||||
if err := db.FetchModelObjects(manager, q, &rets); err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "FetchModelObjects")
|
||||
}
|
||||
if len(rets) > 1 {
|
||||
return nil, errors.Errorf("guest %s has conflict nic index (%d)", guestId, index)
|
||||
return rets, nil
|
||||
}
|
||||
|
||||
func (manager *SGuestnetworkManager) FetchByGuestIdIndex(guestId string, index int8) (*SGuestnetwork, error) {
|
||||
rets, err := manager.FetchByGuestId(guestId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "FetchByGuestId")
|
||||
}
|
||||
if len(rets) == 0 {
|
||||
return nil, errors.ErrNotFound
|
||||
if index >= 0 && int(index) < len(rets) {
|
||||
return &rets[index], nil
|
||||
}
|
||||
return &rets[0], nil
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SGuestnetwork) GetShortDesc(ctx context.Context) *jsonutils.JSONDict {
|
||||
|
||||
@@ -917,6 +917,7 @@ func (self *SKVMRegionDriver) RequestDeleteVpc(ctx context.Context, userCred mcc
|
||||
func (self *SKVMRegionDriver) GetEipDefaultChargeType() string {
|
||||
return api.EIP_CHARGE_TYPE_BY_BANDWIDTH
|
||||
}
|
||||
|
||||
func (self *SKVMRegionDriver) ValidateEipChargeType(chargeType string) error {
|
||||
if chargeType != api.EIP_CHARGE_TYPE_BY_BANDWIDTH {
|
||||
return httperrors.NewInputParameterError("%s only supports eip charge type %q",
|
||||
@@ -1418,52 +1419,87 @@ func (self *SKVMRegionDriver) GetMaxElasticcacheSecurityGroupCount() int {
|
||||
|
||||
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 {
|
||||
if input.InstanceType == api.EIP_ASSOCIATE_TYPE_SERVER {
|
||||
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")
|
||||
if len(input.IpAddr) > 0 {
|
||||
q = q.Equals("ip_addr", input.IpAddr)
|
||||
}
|
||||
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)
|
||||
}
|
||||
} else if input.InstanceType == api.EIP_ASSOCIATE_TYPE_INSTANCE_GROUP {
|
||||
group := obj.(*models.SGroup)
|
||||
|
||||
lockman.LockObject(ctx, group)
|
||||
defer lockman.ReleaseObject(ctx, group)
|
||||
|
||||
var groupnics []models.SGroupnetwork
|
||||
{
|
||||
gneq := models.GroupnetworkManager.Query()
|
||||
q := gneq.Equals("group_id", group.Id).
|
||||
IsNullOrEmpty("eip_id")
|
||||
if len(input.IpAddr) > 0 {
|
||||
q = q.Equals("ip_addr", input.IpAddr)
|
||||
}
|
||||
if err := db.FetchModelObjects(models.GroupnetworkManager, q, &groupnics); err != nil {
|
||||
return nil, errors.Wrapf(err, "db.FetchModelObjects")
|
||||
}
|
||||
if len(groupnics) == 0 {
|
||||
return nil, errors.Errorf("guest has no nics to associate eip")
|
||||
}
|
||||
}
|
||||
|
||||
groupnic := &groupnics[0]
|
||||
lockman.LockObject(ctx, groupnic)
|
||||
defer lockman.ReleaseObject(ctx, groupnic)
|
||||
if _, err := db.Update(groupnic, func() error {
|
||||
groupnic.EipId = eip.Id
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, errors.Wrapf(err, "set associated eip for groupnic %s (guest:%s, network:%s)",
|
||||
groupnic.IpAddr, groupnic.GroupId, groupnic.NetworkId)
|
||||
}
|
||||
} else {
|
||||
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.AssociateInstance(ctx, userCred, input.InstanceType, obj); err != nil {
|
||||
return nil, errors.Wrapf(err, "associate eip %s(%s) to %s %s(%s)", eip.Name, eip.Id, obj.Keyword(), obj.GetName(), obj.GetId())
|
||||
}
|
||||
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)
|
||||
|
||||
@@ -80,8 +80,6 @@ func InitHandlers(app *appsrv.Application) {
|
||||
models.InfrasUsageManager,
|
||||
models.InfrasPendingUsageManager,
|
||||
|
||||
models.GroupguestManager,
|
||||
|
||||
models.CloudproviderCapabilityManager,
|
||||
|
||||
models.ScalingTimerManager,
|
||||
@@ -256,6 +254,7 @@ func InitHandlers(app *appsrv.Application) {
|
||||
models.LoadbalancernetworkManager,
|
||||
models.GuestdiskManager,
|
||||
models.GroupnetworkManager,
|
||||
models.GroupguestManager,
|
||||
models.StoragecachedimageManager,
|
||||
models.CloudproviderRegionManager,
|
||||
models.DBInstanceNetworkManager,
|
||||
|
||||
@@ -79,6 +79,13 @@ func (self *EipAssociateTask) GetAssociateObj() (db.IStatusStandaloneModel, api.
|
||||
nat := natObj.(*models.SNatGateway)
|
||||
input.InstanceExternalId = nat.ExternalId
|
||||
return nat, input, nil
|
||||
case api.EIP_ASSOCIATE_TYPE_INSTANCE_GROUP:
|
||||
grpObj, err := models.GroupManager.FetchById(input.InstanceId)
|
||||
if err != nil {
|
||||
return nil, input, errors.Wrapf(err, "GroupManager.FetchById(%s)", input.InstanceId)
|
||||
}
|
||||
grp := grpObj.(*models.SGroup)
|
||||
return grp, input, nil
|
||||
default:
|
||||
return nil, input, fmt.Errorf("invalid instance type %s", input.InstanceType)
|
||||
}
|
||||
@@ -123,6 +130,10 @@ func (self *EipAssociateTask) OnAssociateEipComplete(ctx context.Context, obj db
|
||||
nat := ins.(*models.SNatGateway)
|
||||
nat.StartSyncstatus(ctx, self.UserCred, "")
|
||||
logclient.AddActionLogWithStartable(self, eip, logclient.ACT_NATGATEWAY_ASSOCIATE, ins, self.UserCred, true)
|
||||
case api.EIP_ASSOCIATE_TYPE_INSTANCE_GROUP:
|
||||
grp := ins.(*models.SGroup)
|
||||
grp.SetStatus(self.UserCred, "init", "success")
|
||||
logclient.AddActionLogWithStartable(self, eip, logclient.ACT_NATGATEWAY_ASSOCIATE, ins, self.UserCred, true)
|
||||
}
|
||||
logclient.AddActionLogWithStartable(self, ins, logclient.ACT_EIP_ASSOCIATE, nil, self.UserCred, true)
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"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"
|
||||
"yunion.io/x/onecloud/pkg/util/logclient"
|
||||
)
|
||||
|
||||
@@ -52,6 +53,9 @@ func (self *EipDissociateTask) TaskFail(ctx context.Context, eip *models.SElasti
|
||||
case *models.SLoadbalancer:
|
||||
srv.SetStatus(self.UserCred, api.VM_DISSOCIATE_EIP_FAILED, msg.String())
|
||||
logOp = logclient.ACT_LOADBALANCER_DISSOCIATE
|
||||
case *models.SGroup:
|
||||
srv.SetStatus(self.UserCred, api.VM_DISSOCIATE_EIP_FAILED, msg.String())
|
||||
logOp = logclient.ACT_INSTANCE_GROUP_DISSOCIATE
|
||||
}
|
||||
db.OpsLog.LogEvent(model, db.ACT_EIP_DETACH, msg, self.GetUserCred())
|
||||
logclient.AddActionLogWithStartable(self, model, logclient.ACT_EIP_DISSOCIATE, msg, self.UserCred, false)
|
||||
@@ -80,6 +84,9 @@ func (self *EipDissociateTask) OnInit(ctx context.Context, obj db.IStandaloneMod
|
||||
} else if nat := eip.GetAssociateNatGateway(); nat != nil {
|
||||
model = nat
|
||||
logOp = logclient.ACT_NATGATEWAY_DISSOCIATE
|
||||
} else if grp := eip.GetAssociateInstanceGroup(); grp != nil {
|
||||
model = grp
|
||||
logOp = logclient.ACT_INSTANCE_GROUP_DISSOCIATE
|
||||
} else {
|
||||
self.TaskFail(ctx, eip, jsonutils.NewString("unsupported associate type"), nil)
|
||||
return
|
||||
@@ -103,24 +110,48 @@ func (self *EipDissociateTask) OnInit(ctx context.Context, obj db.IStandaloneMod
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var guestnics []models.SGuestnetwork
|
||||
q := models.GuestnetworkManager.Query().
|
||||
Equals("guest_id", model.GetId()).
|
||||
Equals("eip_id", eip.Id)
|
||||
if err := db.FetchModelObjects(models.GuestnetworkManager, q, &guestnics); err != nil {
|
||||
msg := errors.Wrapf(err, "fetch guest nic associated with eip %s(%s)", eip.Name, eip.Id).Error()
|
||||
self.TaskFail(ctx, eip, jsonutils.NewString(msg), model)
|
||||
return
|
||||
}
|
||||
var errs []error
|
||||
for i := range guestnics {
|
||||
guestnic := &guestnics[i]
|
||||
if _, err := db.Update(guestnic, func() error {
|
||||
guestnic.EipId = ""
|
||||
return nil
|
||||
}); err != nil {
|
||||
errs = append(errs, errors.Wrapf(err, "nic %s", guestnic.Ifname))
|
||||
switch eip.AssociateType {
|
||||
case api.EIP_ASSOCIATE_TYPE_SERVER:
|
||||
var guestnics []models.SGuestnetwork
|
||||
q := models.GuestnetworkManager.Query().
|
||||
Equals("guest_id", model.GetId()).
|
||||
Equals("eip_id", eip.Id)
|
||||
if err := db.FetchModelObjects(models.GuestnetworkManager, q, &guestnics); err != nil {
|
||||
msg := errors.Wrapf(err, "fetch guest nic associated with eip %s(%s)", eip.Name, eip.Id).Error()
|
||||
self.TaskFail(ctx, eip, jsonutils.NewString(msg), model)
|
||||
return
|
||||
}
|
||||
for i := range guestnics {
|
||||
guestnic := &guestnics[i]
|
||||
if _, err := db.Update(guestnic, func() error {
|
||||
guestnic.EipId = ""
|
||||
return nil
|
||||
}); err != nil {
|
||||
errs = append(errs, errors.Wrapf(err, "nic %s", guestnic.Ifname))
|
||||
}
|
||||
}
|
||||
case api.EIP_ASSOCIATE_TYPE_INSTANCE_GROUP:
|
||||
var groupnics []models.SGroupnetwork
|
||||
q := models.GroupnetworkManager.Query().
|
||||
Equals("group_id", model.GetId()).
|
||||
Equals("eip_id", eip.Id)
|
||||
if err := db.FetchModelObjects(models.GroupnetworkManager, q, &groupnics); err != nil {
|
||||
msg := errors.Wrapf(err, "fetch group nic associated with eip %s(%s)", eip.Name, eip.Id).Error()
|
||||
self.TaskFail(ctx, eip, jsonutils.NewString(msg), model)
|
||||
return
|
||||
}
|
||||
for i := range groupnics {
|
||||
groupnic := &groupnics[i]
|
||||
if _, err := db.Update(groupnic, func() error {
|
||||
groupnic.EipId = ""
|
||||
return nil
|
||||
}); err != nil {
|
||||
errs = append(errs, errors.Wrapf(err, "nic %s", groupnic.IpAddr))
|
||||
}
|
||||
}
|
||||
default:
|
||||
errs = append(errs, errors.Wrapf(httperrors.ErrNotSupported, "not supported type", eip.AssociateType))
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
err := errors.NewAggregate(errs)
|
||||
@@ -145,6 +176,8 @@ func (self *EipDissociateTask) OnInit(ctx context.Context, obj db.IStandaloneMod
|
||||
switch srv := model.(type) {
|
||||
case *models.SGuest:
|
||||
srv.StartSyncstatus(ctx, self.UserCred, "")
|
||||
case *models.SGroup:
|
||||
srv.SetStatus(self.UserCred, "init", "success")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,14 +20,14 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
InstanceGroup modulebase.ResourceManager
|
||||
InstanceGroups modulebase.ResourceManager
|
||||
)
|
||||
|
||||
func init() {
|
||||
InstanceGroup = modules.NewComputeManager("instancegroup", "instancegroups",
|
||||
InstanceGroups = modules.NewComputeManager("instancegroup", "instancegroups",
|
||||
[]string{"ID", "Name", "Service_Type", "Parent_Id", "Zone_Id", "Sched_Strategy", "Domain_Id", "Project_Id",
|
||||
"Granularity", "Is_Froced_Sep"},
|
||||
"Granularity", "Is_Froced_Sep", "ips", "eip"},
|
||||
[]string{})
|
||||
|
||||
modules.RegisterCompute(&InstanceGroup)
|
||||
modules.RegisterCompute(&InstanceGroups)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// 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/mcclient/modulebase"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
)
|
||||
|
||||
var (
|
||||
InstanceGroupGuests modulebase.JointResourceManager
|
||||
)
|
||||
|
||||
func init() {
|
||||
InstanceGroupGuests = modules.NewJointComputeManager(
|
||||
"groupguest", "groupguests",
|
||||
[]string{
|
||||
"Group_ID", "Instance_Group",
|
||||
"Guest_ID", "Server",
|
||||
},
|
||||
[]string{},
|
||||
&InstanceGroups,
|
||||
&Servers,
|
||||
)
|
||||
|
||||
modules.RegisterCompute(&InstanceGroupGuests)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// 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/mcclient/modulebase"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
)
|
||||
|
||||
var (
|
||||
InstancegroupNetworks modulebase.JointResourceManager
|
||||
)
|
||||
|
||||
func init() {
|
||||
InstancegroupNetworks = modules.NewJointComputeManager(
|
||||
"groupnetwork",
|
||||
"groupnetworks",
|
||||
[]string{"Group_ID", "Instance_Group",
|
||||
"Network_ID", "Network",
|
||||
"Ip_Addr",
|
||||
},
|
||||
[]string{},
|
||||
&InstanceGroups,
|
||||
&Networks)
|
||||
modules.RegisterCompute(&InstancegroupNetworks)
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
// 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/pkg/errors"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
)
|
||||
|
||||
type InstanceGroupListOptions struct {
|
||||
options.BaseListOptions
|
||||
|
||||
ServiceType string `help:"Service Type"`
|
||||
ParentId string `help:"Parent ID"`
|
||||
ZoneId string `help:"Zone ID"`
|
||||
Server string `help:"Guest ID or Name"`
|
||||
}
|
||||
|
||||
func (opts *InstanceGroupListOptions) Params() (jsonutils.JSONObject, error) {
|
||||
params, err := options.ListStructToParams(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return params, nil
|
||||
}
|
||||
|
||||
type InstanceGroupCreateOptions struct {
|
||||
NAME string `help:"name of instance group"`
|
||||
|
||||
ZoneId string `help:"zone id" json:"zone_id"`
|
||||
ServiceType string `help:"service type"`
|
||||
ParentId string `help:"parent id"`
|
||||
SchedStrategy string `help:"scheduler strategy"`
|
||||
Granularity string `help:"the upper limit number of guests with this group in a host"`
|
||||
ForceDispersion bool `help:"force to make guest dispersion"`
|
||||
}
|
||||
|
||||
func (opts *InstanceGroupCreateOptions) Params() (jsonutils.JSONObject, error) {
|
||||
params, err := options.StructToParams(opts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "StructToParams")
|
||||
}
|
||||
return params, nil
|
||||
}
|
||||
|
||||
type InstanceGroupUpdateOptions struct {
|
||||
options.BaseIdOptions
|
||||
|
||||
Name string `help:"New name to change"`
|
||||
Granularity string `help:"the upper limit number of guests with this group in a host"`
|
||||
ForceDispersion string `help:"force to make guest dispersion" choices:"yes|no" json:"-"`
|
||||
}
|
||||
|
||||
func (opts *InstanceGroupUpdateOptions) Params() (jsonutils.JSONObject, error) {
|
||||
params, err := options.StructToParams(opts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "StructToParams")
|
||||
}
|
||||
if opts.ForceDispersion == "yes" {
|
||||
params.Set("force_dispersion", jsonutils.JSONTrue)
|
||||
} else {
|
||||
params.Set("force_dispersion", jsonutils.JSONFalse)
|
||||
}
|
||||
return params, nil
|
||||
}
|
||||
|
||||
type InstanceGroupBindGuestsOptions struct {
|
||||
options.BaseIdOptions
|
||||
Guest []string `help:"ID or Name of Guest"`
|
||||
}
|
||||
|
||||
func (opts *InstanceGroupBindGuestsOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return options.StructToParams(opts)
|
||||
}
|
||||
|
||||
type InstanceGroupAttachnetworkOptions struct {
|
||||
options.BaseIdOptions
|
||||
|
||||
api.GroupAttachNetworkInput
|
||||
}
|
||||
|
||||
func (opts *InstanceGroupAttachnetworkOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return jsonutils.Marshal(opts), nil
|
||||
}
|
||||
|
||||
type InstanceGroupDetachnetworkOptions struct {
|
||||
options.BaseIdOptions
|
||||
|
||||
api.GroupDetachNetworkInput
|
||||
}
|
||||
|
||||
func (opts *InstanceGroupDetachnetworkOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return jsonutils.Marshal(opts), nil
|
||||
}
|
||||
|
||||
type InstanceGroupCreateEipOptions struct {
|
||||
options.BaseIdOptions
|
||||
|
||||
api.ServerCreateEipInput
|
||||
}
|
||||
|
||||
func (opts *InstanceGroupCreateEipOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return jsonutils.Marshal(opts), nil
|
||||
}
|
||||
|
||||
type InstanceGroupAssociateEipOptions struct {
|
||||
options.BaseIdOptions
|
||||
|
||||
api.ServerAssociateEipInput
|
||||
}
|
||||
|
||||
func (opts *InstanceGroupAssociateEipOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return jsonutils.Marshal(opts), nil
|
||||
}
|
||||
|
||||
type InstanceGroupDissociateEipOptions struct {
|
||||
options.BaseIdOptions
|
||||
|
||||
api.ServerDissociateEipInput
|
||||
}
|
||||
|
||||
func (opts *InstanceGroupDissociateEipOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return jsonutils.Marshal(opts), nil
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// 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 InstanceGroupGuestListOptions struct {
|
||||
options.BaseListOptions
|
||||
|
||||
Group string `help:"Group ID or Name"`
|
||||
Server string `help:"Gest ID or Name"`
|
||||
}
|
||||
|
||||
func (opts *InstanceGroupGuestListOptions) GetMasterOpt() string {
|
||||
return opts.Group
|
||||
}
|
||||
|
||||
func (opts *InstanceGroupGuestListOptions) GetSlaveOpt() string {
|
||||
return opts.Server
|
||||
}
|
||||
|
||||
func (opts *InstanceGroupGuestListOptions) Params() (jsonutils.JSONObject, error) {
|
||||
params, err := options.ListStructToParams(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if opts.Group != "" {
|
||||
params.Add(jsonutils.NewString(opts.Group), "group_id")
|
||||
}
|
||||
if opts.Server != "" {
|
||||
params.Add(jsonutils.NewString(opts.Server), "guest_id")
|
||||
}
|
||||
return params, nil
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// 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 InstanceGroupNetworkListOptions struct {
|
||||
options.BaseListOptions
|
||||
|
||||
Group string `help:"Guest ID or Name"`
|
||||
Network string `help:"Network ID or Name"`
|
||||
}
|
||||
|
||||
func (opts *InstanceGroupNetworkListOptions) GetMasterOpt() string {
|
||||
return opts.Group
|
||||
}
|
||||
|
||||
func (opts *InstanceGroupNetworkListOptions) GetSlaveOpt() string {
|
||||
return opts.Network
|
||||
}
|
||||
|
||||
func (opts *InstanceGroupNetworkListOptions) Params() (jsonutils.JSONObject, error) {
|
||||
params, err := options.ListStructToParams(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if opts.Group != "" {
|
||||
params.Add(jsonutils.NewString(opts.Group), "group_id")
|
||||
}
|
||||
if opts.Network != "" {
|
||||
params.Add(jsonutils.NewString(opts.Network), "network_id")
|
||||
}
|
||||
return params, nil
|
||||
}
|
||||
@@ -98,6 +98,7 @@ const (
|
||||
ACT_VM_SNAPSHOT_AND_CLONE = "vm_snapshot_and_clone"
|
||||
ACT_VM_BLOCK_STREAM = "vm_block_stream"
|
||||
ACT_ATTACH_NETWORK = "attach_network"
|
||||
ACT_DETACH_NETWORK = "detach_network"
|
||||
ACT_VM_CONVERT = "vm_convert"
|
||||
ACT_FREEZE = "freeze"
|
||||
ACT_UNFREEZE = "unfreeze"
|
||||
@@ -158,6 +159,8 @@ const (
|
||||
ACT_NATGATEWAY_DISSOCIATE = "natgateway_dissociate"
|
||||
ACT_LOADBALANCER_DISSOCIATE = "loadbalancer_dissociate"
|
||||
|
||||
ACT_INSTANCE_GROUP_DISSOCIATE = "instancegroup_dissociate"
|
||||
|
||||
ACT_PREPARE = "prepare"
|
||||
ACT_PROBE = "probe"
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
compute_models "yunion.io/x/onecloud/pkg/compute/models"
|
||||
)
|
||||
|
||||
@@ -63,6 +65,7 @@ type Network struct {
|
||||
Vpc *Vpc `json:"-"`
|
||||
Wire *Wire `json:"-"`
|
||||
Guestnetworks Guestnetworks `json:"-"`
|
||||
Groupnetworks Groupnetworks `json:"-"`
|
||||
Elasticips Elasticips `json:"-"`
|
||||
}
|
||||
|
||||
@@ -108,6 +111,8 @@ type Guest struct {
|
||||
AdminSecurityGroup *SecurityGroup `json:"-"`
|
||||
SecurityGroups SecurityGroups `json:"-"`
|
||||
Guestnetworks Guestnetworks `json:"-"`
|
||||
|
||||
Groups Groups `json:"-"`
|
||||
}
|
||||
|
||||
func (el *Guest) Copy() *Guest {
|
||||
@@ -116,6 +121,16 @@ func (el *Guest) Copy() *Guest {
|
||||
}
|
||||
}
|
||||
|
||||
func (el *Guest) GetVips() []string {
|
||||
ret := make([]string, 0)
|
||||
for _, g := range el.Groups {
|
||||
for _, gn := range g.Groupnetworks {
|
||||
ret = append(ret, fmt.Sprintf("%s/%d", gn.IpAddr, gn.Network.GuestIpMask))
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type Host struct {
|
||||
compute_models.SHost
|
||||
}
|
||||
@@ -172,6 +187,7 @@ type Elasticip struct {
|
||||
|
||||
Network *Network `json:"-"`
|
||||
Guestnetwork *Guestnetwork `json:"-"`
|
||||
Groupnetwork *Groupnetwork `json:"-"`
|
||||
}
|
||||
|
||||
func (el *Elasticip) Copy() *Elasticip {
|
||||
@@ -189,3 +205,54 @@ func (el *DnsRecord) Copy() *DnsRecord {
|
||||
SDnsRecord: el.SDnsRecord,
|
||||
}
|
||||
}
|
||||
|
||||
type Groupguest struct {
|
||||
compute_models.SGroupguest
|
||||
|
||||
Group *Group `json:"-"`
|
||||
Guest *Guest `json:"-"`
|
||||
}
|
||||
|
||||
func (el *Groupguest) Copy() *Groupguest {
|
||||
return &Groupguest{
|
||||
SGroupguest: el.SGroupguest,
|
||||
}
|
||||
}
|
||||
|
||||
type Groupnetwork struct {
|
||||
compute_models.SGroupnetwork
|
||||
|
||||
Network *Network `json:"-"`
|
||||
Group *Group `json:"-"`
|
||||
|
||||
Elasticip *Elasticip `json:"-"`
|
||||
}
|
||||
|
||||
func (el *Groupnetwork) Copy() *Groupnetwork {
|
||||
return &Groupnetwork{
|
||||
SGroupnetwork: el.SGroupnetwork,
|
||||
}
|
||||
}
|
||||
|
||||
func (el *Groupnetwork) GetGuestNetworks() []*Guestnetwork {
|
||||
ret := make([]*Guestnetwork, 0)
|
||||
for _, gg := range el.Group.Groupguests {
|
||||
for _, gn := range gg.Guest.Guestnetworks {
|
||||
ret = append(ret, gn)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type Group struct {
|
||||
compute_models.SGroup
|
||||
|
||||
Groupguests Groupguests `json:"-"`
|
||||
Groupnetworks Groupnetworks `json:"-"`
|
||||
}
|
||||
|
||||
func (el *Group) Copy() *Group {
|
||||
return &Group{
|
||||
SGroup: el.SGroup,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,10 @@ type (
|
||||
DnsRecords map[string]*DnsRecord
|
||||
|
||||
RouteTables map[string]*RouteTable
|
||||
|
||||
Groupguests map[string]*Groupguest
|
||||
Groupnetworks map[string]*Groupnetwork
|
||||
Groups map[string]*Group
|
||||
)
|
||||
|
||||
func (set Vpcs) ModelManager() mcclient_modulebase.IBaseManager {
|
||||
@@ -259,6 +263,29 @@ func (set Guests) joinSecurityGroups(subEntries SecurityGroups) bool {
|
||||
return correct
|
||||
}
|
||||
|
||||
func (set Guests) joinGroupguests(groups Groups, groupGuests Groupguests) bool {
|
||||
for _, gg := range groupGuests {
|
||||
if guest, ok := set[gg.GuestId]; ok {
|
||||
if guest.Groups == nil {
|
||||
guest.Groups = Groups{}
|
||||
}
|
||||
if _, ok := groups[gg.GroupId]; !ok {
|
||||
grp := &Group{}
|
||||
grp.Id = gg.GroupId
|
||||
grp.Groupguests = Groupguests{}
|
||||
grp.Groupnetworks = Groupnetworks{}
|
||||
groups.AddModel(grp)
|
||||
}
|
||||
grp := groups[gg.GroupId]
|
||||
grp.Groupguests.AddModel(gg)
|
||||
guest.Groups.AddModel(grp)
|
||||
gg.Guest = guest
|
||||
gg.Group = grp
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (set Hosts) ModelManager() mcclient_modulebase.IBaseManager {
|
||||
return &mcclient_modules.Hosts
|
||||
}
|
||||
@@ -304,6 +331,7 @@ func (set Networks) Copy() apihelper.IModelSet {
|
||||
func (ms Networks) joinGuestnetworks(subEntries Guestnetworks) bool {
|
||||
for _, m := range ms {
|
||||
m.Guestnetworks = Guestnetworks{}
|
||||
m.Groupnetworks = Groupnetworks{}
|
||||
}
|
||||
for _, subEntry := range subEntries {
|
||||
netId := subEntry.NetworkId
|
||||
@@ -681,3 +709,107 @@ func (set RouteTables) Copy() apihelper.IModelSet {
|
||||
}
|
||||
return setCopy
|
||||
}
|
||||
|
||||
func (set Groupguests) ModelManager() mcclient_modulebase.IBaseManager {
|
||||
return &mcclient_modules.InstanceGroupGuests
|
||||
}
|
||||
|
||||
func (set Groupguests) NewModel() db.IModel {
|
||||
return &Groupguest{}
|
||||
}
|
||||
|
||||
func (set Groupguests) AddModel(i db.IModel) {
|
||||
m := i.(*Groupguest)
|
||||
k := fmt.Sprintf("%d", m.RowId)
|
||||
set[k] = m
|
||||
}
|
||||
|
||||
func (set Groupguests) Copy() apihelper.IModelSet {
|
||||
setCopy := Groupguests{}
|
||||
for id, el := range set {
|
||||
setCopy[id] = el.Copy()
|
||||
}
|
||||
return setCopy
|
||||
}
|
||||
|
||||
func (set Groupnetworks) ModelManager() mcclient_modulebase.IBaseManager {
|
||||
return &mcclient_modules.InstancegroupNetworks
|
||||
}
|
||||
|
||||
func (set Groupnetworks) NewModel() db.IModel {
|
||||
return &Groupnetwork{}
|
||||
}
|
||||
|
||||
func (set Groupnetworks) AddModel(i db.IModel) {
|
||||
m := i.(*Groupnetwork)
|
||||
k := fmt.Sprintf("%d", m.RowId)
|
||||
set[k] = m
|
||||
}
|
||||
|
||||
func (set Groupnetworks) Copy() apihelper.IModelSet {
|
||||
setCopy := Groupnetworks{}
|
||||
for id, el := range set {
|
||||
setCopy[id] = el.Copy()
|
||||
}
|
||||
return setCopy
|
||||
}
|
||||
|
||||
func (set Groupnetworks) joinElasticips(subEntries Elasticips) bool {
|
||||
correct := true
|
||||
for _, gn := range set {
|
||||
eipId := gn.EipId
|
||||
if eipId == "" {
|
||||
continue
|
||||
}
|
||||
eip, ok := subEntries[eipId]
|
||||
if !ok {
|
||||
log.Warningf("groupnetwork %s: eip %s not found", gn.GroupId, eipId)
|
||||
correct = false
|
||||
continue
|
||||
}
|
||||
if eip.Groupnetwork != nil {
|
||||
if eip.Groupnetwork != gn {
|
||||
log.Errorf("eip %s associated to more than 1 groupnetwork: %s(%s), %s(%s)", eipId,
|
||||
eip.Groupnetwork.GroupId, eip.Groupnetwork.IpAddr, gn.GroupId, gn.IpAddr)
|
||||
correct = false
|
||||
}
|
||||
continue
|
||||
}
|
||||
eip.Groupnetwork = gn
|
||||
gn.Elasticip = eip
|
||||
}
|
||||
return correct
|
||||
}
|
||||
|
||||
func (set Groups) ModelManager() mcclient_modulebase.IBaseManager {
|
||||
return &mcclient_modules.InstanceGroups
|
||||
}
|
||||
|
||||
func (set Groups) NewModel() db.IModel {
|
||||
return &Group{}
|
||||
}
|
||||
|
||||
func (set Groups) AddModel(i db.IModel) {
|
||||
m := i.(*Group)
|
||||
set[m.Id] = m
|
||||
}
|
||||
|
||||
func (set Groups) Copy() apihelper.IModelSet {
|
||||
setCopy := Groups{}
|
||||
for id, el := range set {
|
||||
setCopy[id] = el.Copy()
|
||||
}
|
||||
return setCopy
|
||||
}
|
||||
|
||||
func (set Groups) joinGroupnetworks(subEntries Groupnetworks, networks Networks) bool {
|
||||
for _, gn := range subEntries {
|
||||
gn.Network = networks[gn.NetworkId]
|
||||
if group, ok := set[gn.GroupId]; ok {
|
||||
gn.Group = group
|
||||
group.Groupnetworks.AddModel(gn)
|
||||
}
|
||||
gn.Network.Groupnetworks.AddModel(gn)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -36,6 +36,9 @@ type ModelSetsMaxUpdatedAt struct {
|
||||
DnsRecords time.Time
|
||||
|
||||
RouteTables time.Time
|
||||
|
||||
Groupguests time.Time
|
||||
Groupnetworks time.Time
|
||||
}
|
||||
|
||||
func NewModelSetsMaxUpdatedAt() *ModelSetsMaxUpdatedAt {
|
||||
@@ -55,6 +58,9 @@ func NewModelSetsMaxUpdatedAt() *ModelSetsMaxUpdatedAt {
|
||||
DnsRecords: apihelper.PseudoZeroTime,
|
||||
|
||||
RouteTables: apihelper.PseudoZeroTime,
|
||||
|
||||
Groupguests: apihelper.PseudoZeroTime,
|
||||
Groupnetworks: apihelper.PseudoZeroTime,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +80,10 @@ type ModelSets struct {
|
||||
DnsRecords DnsRecords
|
||||
|
||||
RouteTables RouteTables
|
||||
|
||||
Groupguests Groupguests
|
||||
Groupnetworks Groupnetworks
|
||||
Groups Groups
|
||||
}
|
||||
|
||||
func NewModelSets() *ModelSets {
|
||||
@@ -93,6 +103,10 @@ func NewModelSets() *ModelSets {
|
||||
DnsRecords: DnsRecords{},
|
||||
|
||||
RouteTables: RouteTables{},
|
||||
|
||||
Groupguests: Groupguests{},
|
||||
Groupnetworks: Groupnetworks{},
|
||||
Groups: Groups{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +128,9 @@ func (mss *ModelSets) ModelSetList() []apihelper.IModelSet {
|
||||
mss.DnsRecords,
|
||||
|
||||
mss.RouteTables,
|
||||
|
||||
mss.Groupguests,
|
||||
mss.Groupnetworks,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,6 +155,9 @@ func (mss *ModelSets) copy_() *ModelSets {
|
||||
DnsRecords: mss.DnsRecords.Copy().(DnsRecords),
|
||||
|
||||
RouteTables: mss.RouteTables.Copy().(RouteTables),
|
||||
|
||||
Groupguests: mss.Groupguests.Copy().(Groupguests),
|
||||
Groupnetworks: mss.Groupnetworks.Copy().(Groupnetworks),
|
||||
}
|
||||
return mssCopy
|
||||
}
|
||||
@@ -174,6 +194,7 @@ func (mss *ModelSets) ApplyUpdates(mssNews apihelper.IModelSets) apihelper.Model
|
||||
|
||||
func (mss *ModelSets) join() bool {
|
||||
mss.Guests.initJoin()
|
||||
mss.Groups = Groups{}
|
||||
var p []bool
|
||||
p = append(p, mss.Vpcs.joinWires(mss.Wires))
|
||||
p = append(p, mss.Vpcs.joinRouteTables(mss.RouteTables))
|
||||
@@ -184,11 +205,14 @@ func (mss *ModelSets) join() bool {
|
||||
p = append(p, mss.Networks.joinElasticips(mss.Elasticips))
|
||||
p = append(p, mss.Guests.joinHosts(mss.Hosts))
|
||||
p = append(p, mss.Guests.joinSecurityGroups(mss.SecurityGroups))
|
||||
p = append(p, mss.Guests.joinGroupguests(mss.Groups, mss.Groupguests))
|
||||
p = append(p, mss.SecurityGroups.joinSecurityGroupRules(mss.SecurityGroupRules))
|
||||
p = append(p, mss.Guestsecgroups.join(mss.SecurityGroups, mss.Guests))
|
||||
p = append(p, mss.Guestnetworks.joinGuests(mss.Guests))
|
||||
p = append(p, mss.Guestnetworks.joinElasticips(mss.Elasticips))
|
||||
p = append(p, mss.Guestnetworks.joinNetworkAddresses(mss.NetworkAddresses))
|
||||
p = append(p, mss.Groups.joinGroupnetworks(mss.Groupnetworks, mss.Networks))
|
||||
p = append(p, mss.Groupnetworks.joinElasticips(mss.Elasticips))
|
||||
for _, b := range p {
|
||||
if !b {
|
||||
return false
|
||||
|
||||
@@ -485,6 +485,7 @@ func (keeper *OVNNorthboundKeeper) ClaimGuestnetwork(ctx context.Context, guestn
|
||||
subIPs = append(subIPs, na.IpAddr)
|
||||
subIPms = append(subIPms, fmt.Sprintf("%s/%d", na.IpAddr, na.Network.GuestIpMask))
|
||||
}
|
||||
subIPms = append(subIPms, guestnetwork.Guest.GetVips()...)
|
||||
sort.Strings(subIPs[1:])
|
||||
sort.Strings(subIPms[1:])
|
||||
gnp := &ovn_nb.LogicalSwitchPort{
|
||||
@@ -808,6 +809,136 @@ func (keeper *OVNNorthboundKeeper) ClaimDnsRecords(ctx context.Context, vpcs age
|
||||
return keeper.cli.Must(ctx, "ClaimDnsRecords", args)
|
||||
}
|
||||
|
||||
func (keeper *OVNNorthboundKeeper) ClaimGroupnetwork(ctx context.Context, groupnetwork *agentmodels.Groupnetwork) error {
|
||||
var (
|
||||
network = groupnetwork.Network
|
||||
vpc = network.Vpc
|
||||
eip = groupnetwork.Elasticip
|
||||
|
||||
lportName = vipName(groupnetwork.NetworkId, groupnetwork.GroupId, groupnetwork.IpAddr)
|
||||
ocVersion = fmt.Sprintf("vip.%s.%d", groupnetwork.UpdatedAt, groupnetwork.UpdateVersion)
|
||||
ocGnrDefaultRef = fmt.Sprintf("gnrDefault-vip/%s/%s/%s", vpc.Id, groupnetwork.GroupId, groupnetwork.IpAddr)
|
||||
ocAclRef = fmt.Sprintf("acl-eip/%s/%s/%s", network.Id, groupnetwork.GroupId, groupnetwork.IpAddr)
|
||||
ocQosEipRef = fmt.Sprintf("qos-eip-vip/%s/%s/%s/v2", vpc.Id, groupnetwork.GroupId, groupnetwork.IpAddr)
|
||||
)
|
||||
|
||||
gns := groupnetwork.GetGuestNetworks()
|
||||
gnsNames := make([]string, len(gns))
|
||||
for i, gn := range gns {
|
||||
gnsNames[i] = gnpName(gn.NetworkId, gn.Ifname)
|
||||
}
|
||||
sort.Strings(gnsNames)
|
||||
gnp := &ovn_nb.LogicalSwitchPort{
|
||||
Name: lportName,
|
||||
Type: "virtual",
|
||||
Options: map[string]string{
|
||||
"virtual-ip": groupnetwork.IpAddr,
|
||||
"virtual-parents": strings.Join(gnsNames, ","),
|
||||
},
|
||||
PortSecurity: []string{},
|
||||
}
|
||||
|
||||
var (
|
||||
gnrDefault *ovn_nb.LogicalRouterStaticRoute
|
||||
qosEipIn *ovn_nb.QoS
|
||||
qosEipOut *ovn_nb.QoS
|
||||
hasQoSEip bool
|
||||
)
|
||||
{
|
||||
gnrDefaultPolicy := "src-ip"
|
||||
if eip != nil && vpcHasEipgw(vpc) {
|
||||
log.Infof("groupnetwork %s has eip %s", groupnetwork.IpAddr, eip.IpAddr)
|
||||
gnrDefault = &ovn_nb.LogicalRouterStaticRoute{
|
||||
Policy: &gnrDefaultPolicy,
|
||||
IpPrefix: groupnetwork.IpAddr + "/32",
|
||||
Nexthop: apis.VpcEipGatewayIP3().String(),
|
||||
OutputPort: ptr(vpcRepName(vpc.Id)),
|
||||
ExternalIds: map[string]string{
|
||||
externalKeyOcRef: ocGnrDefaultRef,
|
||||
},
|
||||
}
|
||||
if bwMbps := eip.Bandwidth; bwMbps > 0 {
|
||||
var (
|
||||
kbps = int64(bwMbps * 1000)
|
||||
kbur = int64(kbps * 2)
|
||||
eipgwVip = apis.VpcEipGatewayIP3().String()
|
||||
)
|
||||
hasQoSEip = true
|
||||
qosEipIn = &ovn_nb.QoS{
|
||||
Priority: 2000,
|
||||
Direction: "from-lport",
|
||||
Match: fmt.Sprintf("inport == %q && ip4 && ip4.dst == %s", vpcEipLspName(vpc.Id, eipgwVip), groupnetwork.IpAddr),
|
||||
Bandwidth: map[string]int64{
|
||||
"rate": kbps,
|
||||
"burst": kbur,
|
||||
},
|
||||
ExternalIds: map[string]string{
|
||||
externalKeyOcRef: ocQosEipRef,
|
||||
},
|
||||
}
|
||||
qosEipOut = &ovn_nb.QoS{
|
||||
Priority: 3000,
|
||||
Direction: "from-lport",
|
||||
Match: fmt.Sprintf("inport == %q && ip4 && ip4.src == %s", vpcErpName(vpc.Id), groupnetwork.IpAddr),
|
||||
Bandwidth: map[string]int64{
|
||||
"rate": kbps,
|
||||
"burst": kbur,
|
||||
},
|
||||
ExternalIds: map[string]string{
|
||||
externalKeyOcRef: ocQosEipRef,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var acl *ovn_nb.ACL
|
||||
{
|
||||
acl = &ovn_nb.ACL{
|
||||
Priority: 1,
|
||||
Direction: aclDirToLport,
|
||||
Match: fmt.Sprintf(`is_chassis_resident("%s") && ip4`, gnp.Name),
|
||||
Action: "allow-related",
|
||||
ExternalIds: map[string]string{
|
||||
externalKeyOcRef: ocAclRef,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
irows := []types.IRow{
|
||||
gnp,
|
||||
acl,
|
||||
}
|
||||
if gnrDefault != nil {
|
||||
irows = append(irows, gnrDefault)
|
||||
}
|
||||
if hasQoSEip {
|
||||
irows = append(irows, qosEipIn, qosEipOut)
|
||||
}
|
||||
allFound, args := cmp(&keeper.DB, ocVersion, irows...)
|
||||
if allFound {
|
||||
return nil
|
||||
}
|
||||
|
||||
args = append(args, ovnCreateArgs(gnp, gnp.Name)...)
|
||||
args = append(args, "--", "add", "Logical_Switch", netLsName(groupnetwork.NetworkId), "ports", "@"+gnp.Name)
|
||||
aclRef := "vipacl"
|
||||
args = append(args, ovnCreateArgs(acl, aclRef)...)
|
||||
args = append(args, "--", "add", "Logical_Switch", netLsName(groupnetwork.NetworkId), "acls", "@"+aclRef)
|
||||
if gnrDefault != nil {
|
||||
args = append(args, ovnCreateArgs(gnrDefault, "vipGnrDefault")...)
|
||||
args = append(args, "--", "add", "Logical_Router", vpcExtLrName(vpc.Id), "static_routes", "@vipGnrDefault")
|
||||
}
|
||||
if hasQoSEip {
|
||||
args = append(args, ovnCreateArgs(qosEipIn, "vipQosEipIn")...)
|
||||
args = append(args, "--", "add", "Logical_Switch", vpcEipLsName(vpc.Id), "qos_rules", "@vipQosEipIn")
|
||||
args = append(args, ovnCreateArgs(qosEipOut, "vipQosEipOut")...)
|
||||
args = append(args, "--", "add", "Logical_Switch", vpcEipLsName(vpc.Id), "qos_rules", "@vipQosEipOut")
|
||||
}
|
||||
|
||||
return keeper.cli.Must(ctx, "ClaimGroupnetworks", args)
|
||||
}
|
||||
|
||||
func (keeper *OVNNorthboundKeeper) Mark(ctx context.Context) {
|
||||
db := &keeper.DB
|
||||
itbls := []types.ITable{
|
||||
|
||||
@@ -103,3 +103,7 @@ func netMdpName(netId string) string {
|
||||
func gnpName(netId string, ifname string) string {
|
||||
return fmt.Sprintf("iface-%s-%s", netId, ifname)
|
||||
}
|
||||
|
||||
func vipName(netId string, groupId string, ipaddr string) string {
|
||||
return fmt.Sprintf("vip-%s-%s-%s", netId, groupId, ipaddr)
|
||||
}
|
||||
|
||||
@@ -43,9 +43,12 @@ type Worker struct {
|
||||
func NewWorker(opts *options.Options) worker.IWorker {
|
||||
modelSets := agentmodels.NewModelSets()
|
||||
apiOpts := &apihelper.Options{
|
||||
CommonOptions: opts.CommonOptions,
|
||||
SyncInterval: opts.APISyncInterval,
|
||||
ListBatchSize: opts.APIListBatchSize,
|
||||
CommonOptions: opts.CommonOptions,
|
||||
SyncInterval: opts.APISyncInterval,
|
||||
ListBatchSize: opts.APIListBatchSize,
|
||||
IncludeDetails: false,
|
||||
|
||||
IncludeOtherCloudEnv: false,
|
||||
}
|
||||
apih, err := apihelper.NewAPIHelper(apiOpts, modelSets)
|
||||
if err != nil {
|
||||
@@ -163,6 +166,9 @@ func (w *Worker) run(ctx context.Context, mss *agentmodels.ModelSets) (err error
|
||||
}
|
||||
ovndb.ClaimGuestnetwork(ctx, guestnetwork)
|
||||
}
|
||||
for _, groupnetwork := range network.Groupnetworks {
|
||||
ovndb.ClaimGroupnetwork(ctx, groupnetwork)
|
||||
}
|
||||
}
|
||||
routes := resolveRoutes(vpc, mss)
|
||||
ovndb.ClaimRoutes(ctx, vpc, routes)
|
||||
|
||||
Vendored
+2
-2
@@ -1186,7 +1186,7 @@ sigs.k8s.io/yaml
|
||||
yunion.io/x/executor/apis
|
||||
yunion.io/x/executor/client
|
||||
yunion.io/x/executor/server
|
||||
# yunion.io/x/jsonutils v0.0.0-20211130131136-1ecbe9b96761
|
||||
# yunion.io/x/jsonutils v0.0.0-20211213041607-f6733e38783e
|
||||
yunion.io/x/jsonutils
|
||||
# yunion.io/x/log v0.0.0-20201210064738-43181789dc74
|
||||
yunion.io/x/log
|
||||
@@ -1229,7 +1229,7 @@ yunion.io/x/pkg/util/workqueue
|
||||
yunion.io/x/pkg/utils
|
||||
# yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e
|
||||
yunion.io/x/s3cli
|
||||
# yunion.io/x/sqlchemy v0.0.0-20211212072622-e63b8097854a
|
||||
# yunion.io/x/sqlchemy v0.0.0-20211226083340-1ba177bc58be
|
||||
yunion.io/x/sqlchemy
|
||||
yunion.io/x/sqlchemy/backends
|
||||
yunion.io/x/sqlchemy/backends/clickhouse
|
||||
|
||||
+3
@@ -115,6 +115,9 @@ func DeepCopy(obj JSONObject) JSONObject {
|
||||
vc.Set(mk, mvc)
|
||||
}
|
||||
return vc
|
||||
case *JSONValue:
|
||||
vc := *v
|
||||
return &vc
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
+4
-1
@@ -23,6 +23,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/gotypes"
|
||||
"yunion.io/x/pkg/tristate"
|
||||
"yunion.io/x/pkg/util/timeutils"
|
||||
@@ -169,8 +170,10 @@ func (c *STristateColumn) IsZero(val interface{}) bool {
|
||||
// NewTristateColumn return an instance of STristateColumn
|
||||
func NewTristateColumn(name string, tagmap map[string]string, isPointer bool) STristateColumn {
|
||||
if _, ok := tagmap[sqlchemy.TAG_NULLABLE]; ok {
|
||||
// simply warning, for backward compatiblity reason
|
||||
// tristate always nullable
|
||||
delete(tagmap, sqlchemy.TAG_NULLABLE)
|
||||
// delete(tagmap, sqlchemy.TAG_NULLABLE)
|
||||
log.Warningf("TristateColumn should have no nullable tag")
|
||||
}
|
||||
bc := STristateColumn{SBaseWidthColumn: sqlchemy.NewBaseWidthColumn(name, "TINYINT", tagmap, isPointer)}
|
||||
return bc
|
||||
|
||||
Reference in New Issue
Block a user