feature: vip support (#13020)

Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
Jian Qiu
2022-01-02 08:49:32 +08:00
committed by GitHub
parent 3555090f41
commit 9fa6696e3c
46 changed files with 1632 additions and 250 deletions
+16 -101
View File
@@ -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{})
}
-34
View File
@@ -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"`
+2 -3
View File
@@ -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
)
+4 -4
View File
@@ -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=
+3
View File
@@ -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 {
+2
View File
@@ -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"
+26 -1
View File
@@ -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"`
}
+3
View File
@@ -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 {
+20
View File
@@ -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 {
+12
View File
@@ -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 {
+13 -1
View File
@@ -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 {
+1 -1
View File
@@ -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")
}
+1 -1
View File
@@ -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())
}
+2 -1
View File
@@ -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)
+1 -1
View File
@@ -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
}
+1 -1
View File
@@ -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())
}
+1 -2
View File
@@ -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())
}
+112 -4
View File
@@ -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
+1 -1
View File
@@ -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)
+35 -1
View File
@@ -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
}
+443
View File
@@ -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
}
+10 -12
View File
@@ -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
}
+1 -1
View File
@@ -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
+31 -9
View File
@@ -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 {
+79 -43
View File
@@ -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)
+1 -2
View File
@@ -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,
+11
View File
@@ -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)
}
+49 -16
View File
@@ -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
}
+3
View File
@@ -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"
+67
View File
@@ -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,
}
}
+132
View File
@@ -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
}
+24
View File
@@ -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
+131
View File
@@ -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{
+4
View File
@@ -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)
}
+9 -3
View File
@@ -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)
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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