mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-01 15:07:17 +08:00
Merge pull request #6364 from yousong/feature/yousong-eip
Feature/yousong eip
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
FROM registry.cn-beijing.aliyuncs.com/yunionio/host-base:v0.1.0
|
||||
FROM registry.cn-beijing.aliyuncs.com/yunionio/host-base:v0.2.0
|
||||
|
||||
MAINTAINER "Yaoqi Wan wanyaoqi@yunionyun.com"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM registry.cn-beijing.aliyuncs.com/yunionio/openvswitch:2.9.6-1
|
||||
FROM registry.cn-beijing.aliyuncs.com/yunionio/openvswitch:2.10.4-0
|
||||
|
||||
MAINTAINER "Yousong Zhou <zhouyousong@yunion.cn>"
|
||||
|
||||
|
||||
@@ -46,9 +46,9 @@ func init() {
|
||||
})
|
||||
|
||||
type EipCreateOptions struct {
|
||||
MANAGER string `help:"cloud provider"`
|
||||
REGION string `help:"cloud region in which EIP is allocated"`
|
||||
NAME string `help:"name of the EIP"`
|
||||
Manager string `help:"cloud provider"`
|
||||
Region string `help:"cloud region in which EIP is allocated"`
|
||||
Bandwidth int `help:"Bandwidth in Mbps"`
|
||||
Ip string `help:"IP address of the EIP"`
|
||||
Network string `help:"Network of the EIP"`
|
||||
@@ -56,9 +56,13 @@ func init() {
|
||||
}
|
||||
R(&EipCreateOptions{}, "eip-create", "Create an EIP", func(s *mcclient.ClientSession, args *EipCreateOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(args.MANAGER), "manager")
|
||||
params.Add(jsonutils.NewString(args.REGION), "region")
|
||||
params.Add(jsonutils.NewString(args.NAME), "name")
|
||||
if args.Region != "" {
|
||||
params.Add(jsonutils.NewString(args.Region), "region")
|
||||
}
|
||||
if args.Manager != "" {
|
||||
params.Add(jsonutils.NewString(args.Manager), "manager")
|
||||
}
|
||||
if args.Bandwidth != 0 {
|
||||
params.Add(jsonutils.NewInt(int64(args.Bandwidth)), "bandwidth")
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ func init() {
|
||||
Region string `help:"search networks belongs to a CloudRegion" json:"cloudregion"`
|
||||
City string `help:"search networks belongs to a city"`
|
||||
Usable *bool `help:"search usable networks"`
|
||||
ServerType string `help:"search networks belongs to a ServerType" choices:"guest|baremetal|container|pxe|ipmi"`
|
||||
ServerType string `help:"search networks belongs to a ServerType" choices:"baremetal|container|eip|guest|ipmi|pxe"`
|
||||
Schedtag string `help:"filter networks by schedtag"`
|
||||
|
||||
Status string `help:"filter by network status"`
|
||||
@@ -68,7 +68,7 @@ func init() {
|
||||
ID string `help:"ID or Name of zone to update"`
|
||||
Name string `help:"Name of zone"`
|
||||
Desc string `metavar:"<DESCRIPTION>" help:"Description"`
|
||||
ServerType string `help:"server type," choices:"baremetal|guest|container|pxe|ipmi"`
|
||||
ServerType string `help:"server type," choices:"baremetal|container|eip|guest|ipmi|pxe"`
|
||||
StartIp string `help:"Start ip"`
|
||||
EndIp string `help:"end ip"`
|
||||
NetMask int64 `help:"Netmask"`
|
||||
@@ -227,7 +227,7 @@ func init() {
|
||||
VlanId int64 `help:"Vlan ID" default:"1"`
|
||||
IfnameHint string `help:"Hint for ifname generation"`
|
||||
AllocPolicy string `help:"Address allocation policy" choices:"none|stepdown|stepup|random"`
|
||||
ServerType string `help:"Server type" choices:"baremetal|guest|container|pxe|ipmi"`
|
||||
ServerType string `help:"Server type" choices:"baremetal|container|eip|guest|ipmi|pxe"`
|
||||
Desc string `help:"Description" metavar:"DESCRIPTION"`
|
||||
}
|
||||
R(&NetworkCreateOptions{}, "network-create", "Create a virtual network", func(s *mcclient.ClientSession, args *NetworkCreateOptions) error {
|
||||
|
||||
@@ -29,9 +29,10 @@ func init() {
|
||||
type VpcListOptions struct {
|
||||
options.BaseListOptions
|
||||
|
||||
Usable *bool `help:"Filter usable vpcs"`
|
||||
Region string `help:"ID or Name of region" json:"-"`
|
||||
Globalvpc string `help:"Filter by globalvpc"`
|
||||
Usable *bool `help:"Filter usable vpcs"`
|
||||
Region string `help:"ID or Name of region" json:"-"`
|
||||
Globalvpc string `help:"Filter by globalvpc"`
|
||||
ExternalAccessMode string `help:"Filter by external access mode" choices:"distgw|eip|eip-distgw"`
|
||||
}
|
||||
R(&VpcListOptions{}, "vpc-list", "List VPCs", func(s *mcclient.ClientSession, opts *VpcListOptions) error {
|
||||
params, err := options.ListStructToParams(opts)
|
||||
@@ -58,13 +59,14 @@ func init() {
|
||||
})
|
||||
|
||||
type VpcCreateOptions struct {
|
||||
REGION string `help:"ID or name of the region where the VPC is created"`
|
||||
Id string `help:"ID of the new VPC"`
|
||||
NAME string `help:"Name of the VPC"`
|
||||
CIDR string `help:"CIDR block"`
|
||||
Default bool `help:"default VPC for the region" default:"false"`
|
||||
Desc string `help:"Description of the VPC"`
|
||||
Manager string `help:"ID or Name of Cloud provider"`
|
||||
REGION string `help:"ID or name of the region where the VPC is created"`
|
||||
Id string `help:"ID of the new VPC"`
|
||||
NAME string `help:"Name of the VPC"`
|
||||
CIDR string `help:"CIDR block"`
|
||||
Default bool `help:"default VPC for the region" default:"false"`
|
||||
Desc string `help:"Description of the VPC"`
|
||||
Manager string `help:"ID or Name of Cloud provider"`
|
||||
ExternalAccessMode string `help:"Filter by external access mode" choices:"distgw|eip|eip-distgw" default:"eip-distgw"`
|
||||
}
|
||||
R(&VpcCreateOptions{}, "vpc-create", "Create a VPC", func(s *mcclient.ClientSession, args *VpcCreateOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
@@ -73,6 +75,9 @@ func init() {
|
||||
if len(args.Id) > 0 {
|
||||
params.Add(jsonutils.NewString(args.Id), "id")
|
||||
}
|
||||
if len(args.ExternalAccessMode) > 0 {
|
||||
params.Add(jsonutils.NewString(args.ExternalAccessMode), "external_access_mode")
|
||||
}
|
||||
if len(args.Desc) > 0 {
|
||||
params.Add(jsonutils.NewString(args.Desc), "description")
|
||||
}
|
||||
@@ -112,15 +117,19 @@ func init() {
|
||||
})
|
||||
|
||||
type VpcUpdateOptions struct {
|
||||
ID string `help:"ID or name of the VPC"`
|
||||
Name string `help:"New name of the VPC"`
|
||||
Desc string `help:"Description of the VPC"`
|
||||
ID string `help:"ID or name of the VPC"`
|
||||
Name string `help:"New name of the VPC"`
|
||||
Desc string `help:"Description of the VPC"`
|
||||
ExternalAccessMode string `help:"Filter by external access mode" choices:"distgw|eip|eip-distgw"`
|
||||
}
|
||||
R(&VpcUpdateOptions{}, "vpc-update", "Update a VPC", func(s *mcclient.ClientSession, args *VpcUpdateOptions) error {
|
||||
params := jsonutils.NewDict()
|
||||
if len(args.Name) > 0 {
|
||||
params.Add(jsonutils.NewString(args.Name), "name")
|
||||
}
|
||||
if len(args.ExternalAccessMode) > 0 {
|
||||
params.Add(jsonutils.NewString(args.ExternalAccessMode), "external_access_mode")
|
||||
}
|
||||
if len(args.Desc) > 0 {
|
||||
params.Add(jsonutils.NewString(args.Desc), "description")
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ require (
|
||||
yunion.io/x/executor v0.0.0-20200227030256-a18417815e74
|
||||
yunion.io/x/jsonutils v0.0.0-20200415132054-2bf8a5e94501
|
||||
yunion.io/x/log v0.0.0-20200313080802-57a4ce5966b3
|
||||
yunion.io/x/ovsdb v0.0.0-20200512112253-a3601d1ee987
|
||||
yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7
|
||||
yunion.io/x/pkg v0.0.0-20200516092703-0a53bc9270aa
|
||||
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e
|
||||
yunion.io/x/sqlchemy v0.0.0-20200312002602-1177cd8fbc57
|
||||
|
||||
@@ -769,6 +769,8 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yousong/ovsdb v0.0.0-20200526055947-05168ba66aaf h1:MfwaIeKiVUqeWZSKyO5GwOccti0O/ENZDdqOkB3OPnU=
|
||||
github.com/yousong/ovsdb v0.0.0-20200526055947-05168ba66aaf/go.mod h1:0vLkNEhlmA64HViPBAnSTUMrx5QP1CLsxXmxDKQ80tc=
|
||||
github.com/yunionio/go-ceph v0.0.0-20190912101231-6f05a06b3859 h1:wu596gn6sV3j5wy+GDfiG8nwtzIDpalJihfmC/TjoYc=
|
||||
github.com/yunionio/go-ceph v0.0.0-20190912101231-6f05a06b3859/go.mod h1:8XuBae5AzsgotLArJSewMruYVaQs8AlfsK5jBCG8T9Y=
|
||||
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
|
||||
@@ -1117,6 +1119,10 @@ yunion.io/x/log v0.0.0-20200313080802-57a4ce5966b3 h1:5Wc5hkB8PtMudmHuzCyok960Ru
|
||||
yunion.io/x/log v0.0.0-20200313080802-57a4ce5966b3/go.mod h1:LC6f/4FozL0iaAbnFt2eDX9jlsyo3WiOUPm03d7+U4U=
|
||||
yunion.io/x/ovsdb v0.0.0-20200512112253-a3601d1ee987 h1:BlHpXbNhqG1rZ57io0+XI4L9ckWunn7LHR2JQikGqQg=
|
||||
yunion.io/x/ovsdb v0.0.0-20200512112253-a3601d1ee987/go.mod h1:0vLkNEhlmA64HViPBAnSTUMrx5QP1CLsxXmxDKQ80tc=
|
||||
yunion.io/x/ovsdb v0.0.0-20200526062315-c921cb58f76e h1:v5AnakAKVOvYoYEtsTkntcr4MIgawTAI106/5mmaMAs=
|
||||
yunion.io/x/ovsdb v0.0.0-20200526062315-c921cb58f76e/go.mod h1:0vLkNEhlmA64HViPBAnSTUMrx5QP1CLsxXmxDKQ80tc=
|
||||
yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7 h1:gjqNa2uQzIEXyySsbvVz0UltTEbGsnFFlvnzOpCfHdo=
|
||||
yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7/go.mod h1:0vLkNEhlmA64HViPBAnSTUMrx5QP1CLsxXmxDKQ80tc=
|
||||
yunion.io/x/pkg v0.0.0-20190620104149-945c25821dbf/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
|
||||
yunion.io/x/pkg v0.0.0-20190628082551-f4033ba2ea30/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
|
||||
yunion.io/x/pkg v0.0.0-20200302034534-fdf44d54b070/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
|
||||
|
||||
@@ -61,6 +61,8 @@ type SElasticipCreateInput struct {
|
||||
// enum: traffic, bandwidth
|
||||
ChargeType string `json:"charge_type"`
|
||||
|
||||
Mode string `json:"mode"`
|
||||
|
||||
// 子网名称或Id
|
||||
// 私有云创建此参数必传,例如Openstack, ZStack
|
||||
Network string `json:"network"`
|
||||
|
||||
@@ -27,6 +27,7 @@ const (
|
||||
NETWORK_TYPE_CONTAINER = "container"
|
||||
NETWORK_TYPE_PXE = "pxe"
|
||||
NETWORK_TYPE_IPMI = "ipmi"
|
||||
NETWORK_TYPE_EIP = "eip"
|
||||
|
||||
STATIC_ALLOC = "static"
|
||||
|
||||
@@ -53,6 +54,7 @@ var (
|
||||
NETWORK_TYPE_CONTAINER,
|
||||
NETWORK_TYPE_PXE,
|
||||
NETWORK_TYPE_IPMI,
|
||||
NETWORK_TYPE_EIP,
|
||||
}
|
||||
|
||||
REGIONAL_NETWORK_PROVIDERS = []string{
|
||||
|
||||
@@ -72,6 +72,16 @@ type VpcCreateInput struct {
|
||||
|
||||
// CIDR_BLOCK
|
||||
CidrBlock string `json:"cidr_block"`
|
||||
|
||||
// Vpc外网访问模式
|
||||
ExternalAccessMode string `json:"external_access_mode"`
|
||||
}
|
||||
|
||||
type VpcUpdateInput struct {
|
||||
apis.EnabledStatusInfrasResourceBaseUpdateInput
|
||||
|
||||
// Vpc外网访问模式
|
||||
ExternalAccessMode string `json:"external_access_mode"`
|
||||
}
|
||||
|
||||
type VpcResourceInput struct {
|
||||
@@ -81,6 +91,9 @@ type VpcResourceInput struct {
|
||||
// Deprecated
|
||||
// filter by vpc Id
|
||||
VpcId string `json:"vpc_id" "yunion:deprecated-by":"vpc"`
|
||||
|
||||
// Vpc外网访问模式
|
||||
ExternalAccessMode string `json:"external_access_mode"`
|
||||
}
|
||||
|
||||
type VpcFilterListInputBase struct {
|
||||
|
||||
@@ -4,6 +4,20 @@ import (
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
)
|
||||
|
||||
const (
|
||||
VPC_EXTERNAL_ACCESS_MODE_DISTGW = "distgw" // distgw only
|
||||
VPC_EXTERNAL_ACCESS_MODE_EIP_DISTGW = "eip-distgw" // eip when available, distgw otherwise
|
||||
VPC_EXTERNAL_ACCESS_MODE_EIP = "eip" // eip only
|
||||
)
|
||||
|
||||
var (
|
||||
VPC_EXTERNAL_ACCESS_MODES = []string{
|
||||
VPC_EXTERNAL_ACCESS_MODE_DISTGW,
|
||||
VPC_EXTERNAL_ACCESS_MODE_EIP_DISTGW,
|
||||
VPC_EXTERNAL_ACCESS_MODE_EIP,
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
sVpcMappedCidr = "100.64.0.0/17"
|
||||
VpcMappedIPMask = 17
|
||||
@@ -25,10 +39,24 @@ const (
|
||||
// reserved: [10.64.127.0 , 10.64.127.255]
|
||||
)
|
||||
|
||||
const (
|
||||
sVpcEipGatewayCidr = "100.64.128.0/17"
|
||||
VpcEipGatewayIPMask = 17
|
||||
sVpcEipGatewayIP = "100.64.128.2"
|
||||
VpcEipGatewayMac = "ee:ee:ee:ee:ee:ef"
|
||||
|
||||
sVpcEipGatewayIP3 = "100.64.128.3"
|
||||
VpcEipGatewayMac3 = "ee:ee:ee:ee:ee:f0"
|
||||
)
|
||||
|
||||
var (
|
||||
vpcMappedCidr netutils.IPV4Prefix
|
||||
vpcMappedGatewayIP netutils.IPV4Addr
|
||||
|
||||
vpcEipGatewayCidr netutils.IPV4Prefix
|
||||
vpcEipGatewayIP netutils.IPV4Addr
|
||||
vpcEipGatewayIP3 netutils.IPV4Addr
|
||||
|
||||
vpcMappedHostIPStart netutils.IPV4Addr
|
||||
vpcMappedHostIPEnd netutils.IPV4Addr
|
||||
|
||||
@@ -53,6 +81,10 @@ func init() {
|
||||
vpcMappedCidr = mp(netutils.NewIPV4Prefix(sVpcMappedCidr))
|
||||
vpcMappedGatewayIP = mi(netutils.NewIPV4Addr(sVpcMappedGatewayIP))
|
||||
|
||||
vpcEipGatewayCidr = mp(netutils.NewIPV4Prefix(sVpcEipGatewayCidr))
|
||||
vpcEipGatewayIP = mi(netutils.NewIPV4Addr(sVpcEipGatewayIP))
|
||||
vpcEipGatewayIP3 = mi(netutils.NewIPV4Addr(sVpcEipGatewayIP3))
|
||||
|
||||
vpcMappedHostIPStart = mi(netutils.NewIPV4Addr(sVpcMappedHostIPStart))
|
||||
vpcMappedHostIPEnd = mi(netutils.NewIPV4Addr(sVpcMappedHostIPEnd))
|
||||
|
||||
@@ -68,6 +100,18 @@ func VpcMappedGatewayIP() netutils.IPV4Addr {
|
||||
return vpcMappedGatewayIP
|
||||
}
|
||||
|
||||
func VpcEipGatewayCidr() netutils.IPV4Prefix {
|
||||
return vpcEipGatewayCidr
|
||||
}
|
||||
|
||||
func VpcEipGatewayIP() netutils.IPV4Addr {
|
||||
return vpcEipGatewayIP
|
||||
}
|
||||
|
||||
func VpcEipGatewayIP3() netutils.IPV4Addr {
|
||||
return vpcEipGatewayIP3
|
||||
}
|
||||
|
||||
func VpcMappedHostIPStart() netutils.IPV4Addr {
|
||||
return vpcMappedHostIPStart
|
||||
}
|
||||
|
||||
@@ -919,6 +919,8 @@ type SGuestnetwork struct {
|
||||
TeamWith string `json:"team_with"`
|
||||
// IPv4映射地址,当子网属于私有云vpc的时候分配,用于访问外网
|
||||
MappedIpAddr string `json:"mapped_ip_addr"`
|
||||
// 网卡关联的Eip实例
|
||||
EipId string `json:"eip_id"`
|
||||
}
|
||||
|
||||
// SGuestsecgroup is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SGuestsecgroup.
|
||||
@@ -2097,6 +2099,8 @@ type SVpc struct {
|
||||
// CIDR地址段
|
||||
// example: 192.168.222.0/24
|
||||
CidrBlock string `json:"cidr_block"`
|
||||
// Vpc外网访问模式
|
||||
ExternalAccessMode string `json:"external_access_mode"`
|
||||
}
|
||||
|
||||
// SVpcResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SVpcResourceBase.
|
||||
|
||||
@@ -23,10 +23,13 @@ import (
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/utils"
|
||||
"yunion.io/x/sqlchemy"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
@@ -302,6 +305,59 @@ func (self *SKVMGuestDriver) OnDeleteGuestFinalCleanup(ctx context.Context, gues
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SKVMGuestDriver) IsSupportEip() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SKVMGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) 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)
|
||||
|
||||
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 err
|
||||
}
|
||||
if len(guestnics) == 0 {
|
||||
return 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 errors.Wrapf(err, "set associated eip for guestnic %s (guest:%s, network:%s)",
|
||||
guestnic.Ifname, guestnic.GuestId, guestnic.NetworkId)
|
||||
}
|
||||
|
||||
if err := eip.AssociateVM(ctx, userCred, guest); err != nil {
|
||||
return errors.Wrapf(err, "associate eip %s(%s) to vm %s(%s)", eip.Name, eip.Id, guest.Name, guest.Id)
|
||||
}
|
||||
if err := eip.SetStatus(userCred, api.EIP_STATUS_READY, api.EIP_STATUS_ASSOCIATE); err != nil {
|
||||
return errors.Wrapf(err, "set eip status to %s", api.EIP_STATUS_ALLOCATE)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SKVMGuestDriver) NeedStopForChangeSpec(guest *models.SGuest, cpuChanged, memChanged bool) bool {
|
||||
return guest.GetMetadata("hotplug_cpu_mem", nil) != "enable" ||
|
||||
(memChanged && guest.GetMetadata("__hugepage", nil) == "native")
|
||||
|
||||
@@ -80,7 +80,7 @@ type SElasticip struct {
|
||||
// | elastic_ip | 弹性公网IP |
|
||||
//
|
||||
// example: elastic_ip
|
||||
Mode string `width:"32" charset:"ascii" list:"user"`
|
||||
Mode string `width:"32" charset:"ascii" get:"user" list:"user" create:"optional"`
|
||||
|
||||
// IP地址
|
||||
IpAddr string `width:"17" charset:"ascii" list:"user" create:"optional"`
|
||||
@@ -148,7 +148,7 @@ func (manager *SElasticipManager) ListItemFilter(
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
}
|
||||
guest := serverObj.(*SGuest)
|
||||
if utils.IsInStringArray(guest.Hypervisor, api.PRIVATE_CLOUD_HYPERVISORS) {
|
||||
if guest.Hypervisor == api.HYPERVISOR_KVM || utils.IsInStringArray(guest.Hypervisor, api.PRIVATE_CLOUD_HYPERVISORS) {
|
||||
zone := guest.getZone()
|
||||
networks := NetworkManager.Query().SubQuery()
|
||||
wires := WireManager.Query().SubQuery()
|
||||
@@ -161,7 +161,11 @@ func (manager *SElasticipManager) ListItemFilter(
|
||||
q = q.Equals("cloudregion_id", region.Id)
|
||||
}
|
||||
managerId := guest.GetHost().ManagerId
|
||||
q = q.Equals("manager_id", managerId)
|
||||
if managerId != "" {
|
||||
q = q.Equals("manager_id", managerId)
|
||||
} else {
|
||||
q = q.IsNullOrEmpty("manager_id")
|
||||
}
|
||||
default:
|
||||
return nil, httperrors.NewInputParameterError("Not support associate type %s, only support %s", associateType, api.EIP_ASSOCIATE_VALID_TYPES)
|
||||
}
|
||||
@@ -772,24 +776,29 @@ func (manager *SElasticipManager) getEipByExtEip(ctx context.Context, userCred m
|
||||
}
|
||||
|
||||
func (manager *SElasticipManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.SElasticipCreateInput) (*jsonutils.JSONDict, error) {
|
||||
var (
|
||||
region *SCloudregion
|
||||
provider *SCloudprovider
|
||||
err error
|
||||
)
|
||||
for _, cloudregion := range []string{input.Cloudregion, input.Region, input.RegionId} {
|
||||
if len(cloudregion) > 0 {
|
||||
input.Cloudregion = cloudregion
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(input.Cloudregion) == 0 {
|
||||
return nil, httperrors.NewMissingParameterError("cloudregion")
|
||||
if input.Cloudregion == "" {
|
||||
input.Cloudregion = api.DEFAULT_REGION_ID
|
||||
}
|
||||
_region, err := CloudregionManager.FetchByIdOrName(nil, input.Cloudregion)
|
||||
if err != nil {
|
||||
if obj, err := CloudregionManager.FetchByIdOrName(nil, input.Cloudregion); err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
} else {
|
||||
return nil, httperrors.NewResourceNotFoundError("Region %s not found", input.Cloudregion)
|
||||
}
|
||||
} else {
|
||||
region = obj.(*SCloudregion)
|
||||
}
|
||||
region := _region.(*SCloudregion)
|
||||
input.CloudregionId = region.GetId()
|
||||
|
||||
for _, cloudprovider := range []string{input.Cloudprovider, input.Manager, input.ManagerId} {
|
||||
@@ -798,20 +807,21 @@ func (manager *SElasticipManager) ValidateCreateData(ctx context.Context, userCr
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(input.Cloudprovider) == 0 {
|
||||
return nil, httperrors.NewMissingParameterError("cloudprovider")
|
||||
if input.Cloudprovider != "" {
|
||||
providerObj, err := CloudproviderManager.FetchByIdOrName(nil, input.Cloudprovider)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
} else {
|
||||
return nil, httperrors.NewResourceNotFoundError("Cloud provider %s not found", input.Cloudprovider)
|
||||
}
|
||||
}
|
||||
provider = providerObj.(*SCloudprovider)
|
||||
input.ManagerId = provider.Id
|
||||
}
|
||||
|
||||
providerObj, err := CloudproviderManager.FetchByIdOrName(nil, input.Cloudprovider)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
} else {
|
||||
return nil, httperrors.NewResourceNotFoundError("Cloud provider %s not found", input.Cloudprovider)
|
||||
}
|
||||
}
|
||||
provider := providerObj.(*SCloudprovider)
|
||||
input.ManagerId = provider.Id
|
||||
// publicIp cannot be created standalone
|
||||
input.Mode = api.EIP_MODE_STANDALONE_EIP
|
||||
|
||||
if len(input.ChargeType) == 0 {
|
||||
input.ChargeType = api.EIP_CHARGE_TYPE_DEFAULT
|
||||
@@ -821,19 +831,19 @@ func (manager *SElasticipManager) ValidateCreateData(ctx context.Context, userCr
|
||||
return nil, httperrors.NewInputParameterError("charge type %s not supported", input.ChargeType)
|
||||
}
|
||||
|
||||
input.VirtualResourceCreateInput, err = manager.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.VirtualResourceCreateInput)
|
||||
if err != nil {
|
||||
if input.VirtualResourceCreateInput, err = manager.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.VirtualResourceCreateInput); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = region.GetDriver().ValidateCreateEipData(ctx, userCred, &input)
|
||||
if err = region.GetDriver().ValidateCreateEipData(ctx, userCred, &input); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//避免参数重名后还有pending.eip残留
|
||||
eipPendingUsage := &SRegionQuota{Eip: 1}
|
||||
quotaKeys := fetchRegionalQuotaKeys(rbacutils.ScopeProject, ownerId, region, provider)
|
||||
eipPendingUsage.SetKeys(quotaKeys)
|
||||
err = quotas.CheckSetPendingQuota(ctx, userCred, eipPendingUsage)
|
||||
if err != nil {
|
||||
if err = quotas.CheckSetPendingQuota(ctx, userCred, eipPendingUsage); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -883,7 +893,7 @@ func (self *SElasticip) startEipAllocateTask(ctx context.Context, userCred mccli
|
||||
}
|
||||
|
||||
func (self *SElasticip) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
|
||||
log.Infof("Elasticip delete do nothing")
|
||||
// Elasticip delete do nothing
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -961,6 +971,8 @@ func (self *SElasticip) PerformAssociate(ctx context.Context, userCred mcclient.
|
||||
return nil, httperrors.NewInvalidStatusError("cannot associate pending delete server")
|
||||
}
|
||||
|
||||
// IMPORTANT: this serves as a guard against a guest to have multiple
|
||||
// associated elastic_ips
|
||||
seip, _ := server.GetEip()
|
||||
if seip != nil {
|
||||
return nil, httperrors.NewInvalidStatusError("instance is already associated with eip")
|
||||
@@ -1088,16 +1100,9 @@ func (self *SElasticip) PerformDissociate(ctx context.Context, userCred mcclient
|
||||
}
|
||||
|
||||
autoDelete := jsonutils.QueryBoolean(data, "auto_delete", false)
|
||||
switch self.AssociateType {
|
||||
case api.EIP_ASSOCIATE_TYPE_SERVER:
|
||||
guest := self.GetAssociateVM()
|
||||
if guest == nil {
|
||||
return nil, httperrors.NewInputParameterError("unable to found guest for elasticip %s(%s)", self.Name, self.IpAddr)
|
||||
}
|
||||
return nil, guest.StartGuestDissociateEipTask(ctx, userCred, self, autoDelete, "")
|
||||
default:
|
||||
return nil, self.StartEipDissociateTask(ctx, userCred, autoDelete, "")
|
||||
}
|
||||
|
||||
err := self.StartEipDissociateTask(ctx, userCred, autoDelete, "")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (self *SElasticip) StartEipDissociateTask(ctx context.Context, userCred mcclient.TokenCredential, autoDelete bool, parentTaskId string) error {
|
||||
@@ -1146,8 +1151,11 @@ func (self *SElasticip) PerformSyncstatus(ctx context.Context, userCred mcclient
|
||||
if self.Mode == api.EIP_MODE_INSTANCE_PUBLICIP {
|
||||
return nil, httperrors.NewUnsupportOperationError("fixed eip cannot sync status")
|
||||
}
|
||||
|
||||
return nil, StartResourceSyncStatusTask(ctx, userCred, self, "EipSyncstatusTask", "")
|
||||
if self.IsManaged() {
|
||||
return nil, StartResourceSyncStatusTask(ctx, userCred, self, "EipSyncstatusTask", "")
|
||||
} else {
|
||||
return nil, self.SetStatus(userCred, api.EIP_STATUS_READY, "eip sync status")
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SElasticip) AllowPerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
||||
@@ -1155,15 +1163,13 @@ func (self *SElasticip) AllowPerformSync(ctx context.Context, userCred mcclient.
|
||||
}
|
||||
|
||||
func (self *SElasticip) PerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
/*if self.Status != EIP_STATUS_READY && !strings.HasSuffix(self.Status, "_fail") {
|
||||
return nil, httperrors.NewInvalidStatusError("eip cannot syncstatus in status %s", self.Status)
|
||||
}*/
|
||||
|
||||
if self.Mode == api.EIP_MODE_INSTANCE_PUBLICIP {
|
||||
return nil, httperrors.NewUnsupportOperationError("fixed eip cannot sync status")
|
||||
}
|
||||
|
||||
return nil, StartResourceSyncStatusTask(ctx, userCred, self, "EipSyncstatusTask", "")
|
||||
if self.IsManaged() {
|
||||
return nil, StartResourceSyncStatusTask(ctx, userCred, self, "EipSyncstatusTask", "")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (self *SElasticip) GetExtraDetails(
|
||||
@@ -1229,6 +1235,32 @@ func (manager *SElasticipManager) NewEipForVMOnHost(ctx context.Context, userCre
|
||||
eip.ManagerId = host.ManagerId
|
||||
eip.CloudregionId = region.Id
|
||||
eip.Name = fmt.Sprintf("eip-for-%s", vm.GetName())
|
||||
if host.ManagerId == "" {
|
||||
hostq := HostManager.Query().SubQuery()
|
||||
wireq := WireManager.Query().SubQuery()
|
||||
hostwireq := HostwireManager.Query().SubQuery()
|
||||
q := NetworkManager.Query()
|
||||
q = q.Join(wireq, sqlchemy.Equals(wireq.Field("id"), q.Field("wire_id")))
|
||||
q = q.Join(hostwireq, sqlchemy.Equals(hostwireq.Field("wire_id"), wireq.Field("id")))
|
||||
q = q.Join(hostq, sqlchemy.Equals(hostq.Field("id"), host.Id))
|
||||
q = q.Equals("server_type", api.NETWORK_TYPE_EIP)
|
||||
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)",
|
||||
host.Name, host.Id)
|
||||
}
|
||||
for i := range nets {
|
||||
net := &nets[i]
|
||||
cnt, err := net.GetFreeAddressCount()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if cnt > 0 {
|
||||
eip.NetworkId = net.Id
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
eip.Name, err = db.GenerateName(manager, userCred, eip.Name)
|
||||
@@ -1280,13 +1312,15 @@ func (self *SElasticip) PerformChangeBandwidth(ctx context.Context, userCred mcc
|
||||
return nil, httperrors.NewInputParameterError("Invalid bandwidth")
|
||||
}
|
||||
|
||||
factory, err := self.GetProviderFactory()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if self.IsManaged() {
|
||||
factory, err := self.GetProviderFactory()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := factory.ValidateChangeBandwidth(self.AssociateId, bandwidth); err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
if err := factory.ValidateChangeBandwidth(self.AssociateId, bandwidth); err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
err = self.StartEipChangeBandwidthTask(ctx, userCred, bandwidth)
|
||||
|
||||
@@ -2901,32 +2901,18 @@ func (self *SGuest) PerformDissociateEip(ctx context.Context, userCred mcclient.
|
||||
return nil, httperrors.NewInvalidStatusError("No eip to dissociate")
|
||||
}
|
||||
|
||||
if eip.Mode != api.EIP_MODE_STANDALONE_EIP {
|
||||
return nil, httperrors.NewNotSupportedError("%s not support dissociate", eip.Mode)
|
||||
}
|
||||
self.SetStatus(userCred, api.VM_DISSOCIATE_EIP, "associate eip")
|
||||
|
||||
autoDelete := jsonutils.QueryBoolean(data, "auto_delete", false)
|
||||
err = self.StartGuestDissociateEipTask(ctx, userCred, eip, autoDelete, "")
|
||||
|
||||
err = eip.StartEipDissociateTask(ctx, userCred, autoDelete, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "StartGuestDissociateEipTask")
|
||||
log.Errorf("fail to start dissociate task %s", err)
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (self *SGuest) StartGuestDissociateEipTask(ctx context.Context, userCred mcclient.TokenCredential, eip *SElasticip, autoDelete bool, parentTaskId string) error {
|
||||
self.SetStatus(userCred, api.VM_DISSOCIATE_EIP, "associate eip")
|
||||
eip.SetStatus(userCred, api.EIP_STATUS_DISSOCIATE, "start to dissociate")
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewBool(autoDelete), "auto_delete")
|
||||
task, err := taskman.TaskManager.NewTask(ctx, "GuestDissociateEipTask", self, userCred, params, parentTaskId, "", nil)
|
||||
if err != nil {
|
||||
eip.SetStatus(userCred, api.EIP_STATUS_READY, "")
|
||||
return errors.Wrap(err, "NewTask")
|
||||
}
|
||||
task.ScheduleRun(nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SGuest) AllowPerformCreateEip(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
||||
return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "create-eip")
|
||||
}
|
||||
@@ -2946,25 +2932,24 @@ func (self *SGuest) PerformCreateEip(ctx context.Context, userCred mcclient.Toke
|
||||
}
|
||||
autoDellocate, _ := data.Bool("auto_dellocate")
|
||||
|
||||
if len(self.ExternalId) == 0 {
|
||||
return nil, httperrors.NewInvalidStatusError("Not a managed VM")
|
||||
}
|
||||
host := self.GetHost()
|
||||
if host == nil {
|
||||
return nil, httperrors.NewInvalidStatusError("No host???")
|
||||
}
|
||||
|
||||
_, err := host.GetDriver()
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInvalidStatusError("No valid cloud provider")
|
||||
{
|
||||
if self.ExternalId != "" {
|
||||
_, err := host.GetDriver()
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInvalidStatusError("No valid cloud provider")
|
||||
}
|
||||
}
|
||||
region := host.GetRegion()
|
||||
if region == nil {
|
||||
return nil, httperrors.NewInvalidStatusError("No cloudregion???")
|
||||
}
|
||||
}
|
||||
|
||||
region := host.GetRegion()
|
||||
if region == nil {
|
||||
return nil, httperrors.NewInvalidStatusError("No cloudregion???")
|
||||
}
|
||||
|
||||
err = self.GetDriver().ValidateCreateEip(ctx, userCred, data)
|
||||
err := self.GetDriver().ValidateCreateEip(ctx, userCred, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -100,6 +100,9 @@ type SGuestnetwork struct {
|
||||
|
||||
// IPv4映射地址,当子网属于私有云vpc的时候分配,用于访问外网
|
||||
MappedIpAddr string `width:"16" charset:"ascii" nullable:"true" list:"user"`
|
||||
|
||||
// 网卡关联的Eip实例
|
||||
EipId string `width:"36" charset:"ascii" nullable:"true" list:"user"`
|
||||
}
|
||||
|
||||
func (manager *SGuestnetworkManager) GetSlaveFieldName() string {
|
||||
|
||||
@@ -323,15 +323,22 @@ func (manager *SGuestManager) ListItemFilter(
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
}
|
||||
eip := eipObj.(*SElasticip)
|
||||
hostTable := HostManager.Query().SubQuery()
|
||||
zoneTable := ZoneManager.Query().SubQuery()
|
||||
hostQ := hostTable.Query(hostTable.Field("id")).Join(zoneTable,
|
||||
sqlchemy.Equals(zoneTable.Field("id"), hostTable.Field("zone_id"))).Equals("manager_id", eip.ManagerId)
|
||||
|
||||
if len(eip.NetworkId) > 0 {
|
||||
sq := GuestnetworkManager.Query("guest_id").Equals("network_id", eip.NetworkId).SubQuery()
|
||||
q = q.NotIn("id", sq)
|
||||
}
|
||||
|
||||
hostTable := HostManager.Query().SubQuery()
|
||||
zoneTable := ZoneManager.Query().SubQuery()
|
||||
hostQ := hostTable.Query(hostTable.Field("id"))
|
||||
hostQ = hostQ.Join(zoneTable,
|
||||
sqlchemy.Equals(zoneTable.Field("id"), hostTable.Field("zone_id")))
|
||||
if eip.ManagerId != "" {
|
||||
hostQ = hostQ.Equals("manager_id", eip.ManagerId)
|
||||
} else {
|
||||
hostQ = hostQ.IsNullOrEmpty("manager_id")
|
||||
}
|
||||
region := eip.GetRegion()
|
||||
regionTable := CloudregionManager.Query().SubQuery()
|
||||
sq := hostQ.Join(regionTable, sqlchemy.Equals(zoneTable.Field("cloudregion_id"), regionTable.Field("id"))).
|
||||
|
||||
@@ -1360,6 +1360,9 @@ func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred
|
||||
if vpc.Status != api.VPC_STATUS_AVAILABLE {
|
||||
return input, httperrors.NewInvalidStatusError("VPC not ready")
|
||||
}
|
||||
if input.ServerType == api.NETWORK_TYPE_EIP && vpc.Id != api.DEFAULT_VPC_ID {
|
||||
return input, httperrors.NewInputParameterError("eip network can only exist in default vpc, got %s(%s)", vpc.Name, vpc.Id)
|
||||
}
|
||||
|
||||
var (
|
||||
ipStart = ipRange.StartIp()
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/compare"
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
"yunion.io/x/pkg/utils"
|
||||
"yunion.io/x/sqlchemy"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
@@ -80,11 +81,8 @@ type SVpc struct {
|
||||
// example: 192.168.222.0/24
|
||||
CidrBlock string `charset:"ascii" nullable:"true" list:"domain" create:"domain_optional"`
|
||||
|
||||
// 区域Id
|
||||
// CloudregionId string `width:"36" charset:"ascii" nullable:"false" list:"domain" create:"domain_required" default:"default"`
|
||||
|
||||
// 全局VPC Id
|
||||
// GlobalvpcId string `width:"36" charset:"ascii" list:"user" json:"globalvpc_id"`
|
||||
// Vpc外网访问模式
|
||||
ExternalAccessMode string `width:"16" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
|
||||
}
|
||||
|
||||
func (manager *SVpcManager) GetContextManagers() [][]db.IModelManager {
|
||||
@@ -127,6 +125,19 @@ func (self *SVpc) GetNatgateways() ([]SNatGateway, error) {
|
||||
return nats, nil
|
||||
}
|
||||
|
||||
func (self *SVpc) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.VpcUpdateInput) (api.VpcUpdateInput, error) {
|
||||
if input.ExternalAccessMode != "" {
|
||||
if !utils.IsInStringArray(input.ExternalAccessMode, api.VPC_EXTERNAL_ACCESS_MODES) {
|
||||
return input, httperrors.NewInputParameterError("invalid external_access_mode %q, want %s",
|
||||
input.ExternalAccessMode, api.VPC_EXTERNAL_ACCESS_MODES)
|
||||
}
|
||||
}
|
||||
if _, err := self.SEnabledStatusInfrasResourceBase.ValidateUpdateData(ctx, userCred, query, input.EnabledStatusInfrasResourceBaseUpdateInput); err != nil {
|
||||
return input, err
|
||||
}
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (self *SVpc) ValidateDeleteCondition(ctx context.Context) error {
|
||||
cnt, err := self.GetNetworkCount()
|
||||
if err != nil {
|
||||
@@ -561,8 +572,7 @@ func (self *SVpc) markAllNetworksUnknown(userCred mcclient.TokenCredential) erro
|
||||
}
|
||||
|
||||
func (manager *SVpcManager) InitializeData() error {
|
||||
vpcObj, err := manager.FetchById(api.DEFAULT_VPC_ID)
|
||||
if err != nil {
|
||||
if vpcObj, err := manager.FetchById(api.DEFAULT_VPC_ID); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
defVpc := SVpc{}
|
||||
defVpc.SetModelManager(VpcManager, &defVpc)
|
||||
@@ -594,6 +604,27 @@ func (manager *SVpcManager) InitializeData() error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
{ // initialize default external_access_mode for onecloud vpc
|
||||
var vpcs []SVpc
|
||||
q := manager.Query().
|
||||
IsNullOrEmpty("manager_id").
|
||||
IsNullOrEmpty("external_id").
|
||||
IsNullOrEmpty("external_access_mode")
|
||||
if err := db.FetchModelObjects(manager, q, &vpcs); err != nil {
|
||||
return errors.Wrap(err, "fetch onecloud vpc with external_access_mode not set")
|
||||
}
|
||||
for i := range vpcs {
|
||||
vpc := &vpcs[i]
|
||||
if _, err := db.Update(vpc, func() error {
|
||||
vpc.ExternalAccessMode = api.VPC_EXTERNAL_ACCESS_MODE_EIP_DISTGW
|
||||
return nil
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "db set default external_access_mode")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -635,8 +666,14 @@ func (manager *SVpcManager) ValidateCreateData(
|
||||
input.Cloudprovider = managerObj.GetId()
|
||||
// data.Add(jsonutils.NewString(managerObj.GetId()), "manager_id")
|
||||
} else {
|
||||
// data.Set("status", jsonutils.NewString(api.VPC_STATUS_AVAILABLE))
|
||||
input.Status = api.VPC_STATUS_AVAILABLE
|
||||
if input.ExternalAccessMode == "" {
|
||||
input.ExternalAccessMode = api.VPC_EXTERNAL_ACCESS_MODE_EIP_DISTGW
|
||||
}
|
||||
if !utils.IsInStringArray(input.ExternalAccessMode, api.VPC_EXTERNAL_ACCESS_MODES) {
|
||||
return input, httperrors.NewInputParameterError("invalid external_access_mode %q, want %s",
|
||||
input.Status, api.VPC_EXTERNAL_ACCESS_MODES)
|
||||
}
|
||||
}
|
||||
|
||||
cidrBlock := input.CidrBlock
|
||||
|
||||
@@ -16,6 +16,7 @@ package regiondrivers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
@@ -897,7 +898,34 @@ func (self *SKVMRegionDriver) RequestDeleteVpc(ctx context.Context, userCred mcc
|
||||
}
|
||||
|
||||
func (self *SKVMRegionDriver) ValidateCreateEipData(ctx context.Context, userCred mcclient.TokenCredential, input *api.SElasticipCreateInput) error {
|
||||
return httperrors.NewNotImplementedError("Not Implement EIP")
|
||||
if len(input.Network) == 0 {
|
||||
return httperrors.NewMissingParameterError("network")
|
||||
}
|
||||
_network, err := models.NetworkManager.FetchByIdOrName(userCred, input.Network)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return httperrors.NewResourceNotFoundError("failed to found network %s", input.Network)
|
||||
}
|
||||
return httperrors.NewGeneralError(err)
|
||||
}
|
||||
network := _network.(*models.SNetwork)
|
||||
if network.ServerType != api.NETWORK_TYPE_EIP {
|
||||
return httperrors.NewInputParameterError("bad network type %q, want %q", network.ServerType, api.NETWORK_TYPE_EIP)
|
||||
}
|
||||
input.NetworkId = network.Id
|
||||
|
||||
vpc := network.GetVpc()
|
||||
if vpc == nil {
|
||||
return httperrors.NewInputParameterError("failed to found vpc for network %s(%s)", network.Name, network.Id)
|
||||
}
|
||||
region, err := vpc.GetRegion()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if region.GetDriver().GetProvider() != self.GetProvider() {
|
||||
return httperrors.NewUnsupportOperationError("network %s(%s) does not belong to %s", network.Name, network.Id, self.GetProvider())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SKVMRegionDriver) ValidateSnapshotDelete(ctx context.Context, snapshot *models.SSnapshot) error {
|
||||
|
||||
@@ -61,15 +61,10 @@ func (self *EipAllocateTask) setGuestAllocateEipFailed(eip *models.SElasticip, r
|
||||
}
|
||||
|
||||
func (self *EipAllocateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
|
||||
eip := obj.(*models.SElasticip)
|
||||
|
||||
iregion, err := eip.GetIRegion()
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("fail to find iregion for eip %s", err)
|
||||
eip.SetStatus(self.UserCred, api.EIP_STATUS_ALLOCATE_FAIL, msg)
|
||||
self.onFailed(ctx, eip, msg)
|
||||
return
|
||||
}
|
||||
var (
|
||||
eip = obj.(*models.SElasticip)
|
||||
eipIsManaged = eip.IsManaged()
|
||||
)
|
||||
|
||||
args := &cloudprovider.SEip{
|
||||
Name: eip.Name,
|
||||
@@ -79,7 +74,7 @@ func (self *EipAllocateTask) OnInit(ctx context.Context, obj db.IStandaloneModel
|
||||
IP: eip.IpAddr,
|
||||
}
|
||||
|
||||
if len(eip.NetworkId) > 0 {
|
||||
if eip.NetworkId != "" {
|
||||
_network, err := models.NetworkManager.FetchById(eip.NetworkId)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("failed to found network %s error: %v", eip.NetworkId, err)
|
||||
@@ -87,18 +82,18 @@ func (self *EipAllocateTask) OnInit(ctx context.Context, obj db.IStandaloneModel
|
||||
return
|
||||
}
|
||||
network := _network.(*models.SNetwork)
|
||||
ip, _ := self.GetParams().GetString("ip")
|
||||
if len(ip) > 0 {
|
||||
reqIp, _ := self.GetParams().GetString("ip")
|
||||
if reqIp != "" || !eipIsManaged {
|
||||
lockman.LockObject(ctx, network)
|
||||
defer lockman.ReleaseObject(ctx, network)
|
||||
|
||||
ipAddr, err := network.GetFreeIP(ctx, self.UserCred, nil, nil, ip, api.IPAllocationNone, false)
|
||||
ipAddr, err := network.GetFreeIP(ctx, self.UserCred, nil, nil, reqIp, api.IPAllocationNone, false)
|
||||
if err != nil {
|
||||
self.onFailed(ctx, eip, err.Error())
|
||||
return
|
||||
}
|
||||
if ipAddr != ip {
|
||||
msg := fmt.Sprintf("candidate ip %s is occupied!", ip)
|
||||
if reqIp != "" && ipAddr != reqIp {
|
||||
msg := fmt.Sprintf("requested ip %s is occupied!", reqIp)
|
||||
self.onFailed(ctx, eip, msg)
|
||||
return
|
||||
}
|
||||
@@ -110,37 +105,49 @@ func (self *EipAllocateTask) OnInit(ctx context.Context, obj db.IStandaloneModel
|
||||
self.onFailed(ctx, eip, err.Error())
|
||||
return
|
||||
}
|
||||
if !eipIsManaged {
|
||||
eip.SetStatus(self.UserCred, api.EIP_STATUS_READY, "allocated from network")
|
||||
}
|
||||
}
|
||||
args.NetworkExternalId = network.ExternalId
|
||||
}
|
||||
|
||||
_cloudprovider := eip.GetCloudprovider()
|
||||
args.ProjectId, err = _cloudprovider.SyncProject(ctx, self.GetUserCred(), eip.ProjectId)
|
||||
if err != nil {
|
||||
log.Errorf("failed to sync project %s for create %s eip %s error: %v", eip.ProjectId, _cloudprovider.Provider, eip.Name, err)
|
||||
}
|
||||
if eipIsManaged {
|
||||
var err error
|
||||
|
||||
extEip, err := iregion.CreateEIP(args)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("create eip fail %s", err)
|
||||
eip.SetStatus(self.UserCred, api.EIP_STATUS_ALLOCATE_FAIL, msg)
|
||||
self.onFailed(ctx, eip, msg)
|
||||
return
|
||||
}
|
||||
_cloudprovider := eip.GetCloudprovider()
|
||||
args.ProjectId, err = _cloudprovider.SyncProject(ctx, self.GetUserCred(), eip.ProjectId)
|
||||
if err != nil {
|
||||
log.Errorf("failed to sync project %s for create %s eip %s error: %v", eip.ProjectId, _cloudprovider.Provider, eip.Name, err)
|
||||
}
|
||||
|
||||
err = eip.SyncWithCloudEip(ctx, self.UserCred, eip.GetCloudprovider(), extEip, nil)
|
||||
iregion, err := eip.GetIRegion()
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("fail to find iregion for eip %s", err)
|
||||
eip.SetStatus(self.UserCred, api.EIP_STATUS_ALLOCATE_FAIL, msg)
|
||||
self.onFailed(ctx, eip, msg)
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("sync eip fail %s", err)
|
||||
eip.SetStatus(self.UserCred, api.EIP_STATUS_ALLOCATE_FAIL, msg)
|
||||
self.onFailed(ctx, eip, msg)
|
||||
return
|
||||
extEip, err := iregion.CreateEIP(args)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("create eip fail %s", err)
|
||||
eip.SetStatus(self.UserCred, api.EIP_STATUS_ALLOCATE_FAIL, msg)
|
||||
self.onFailed(ctx, eip, msg)
|
||||
return
|
||||
}
|
||||
|
||||
if err := eip.SyncWithCloudEip(ctx, self.UserCred, eip.GetCloudprovider(), extEip, nil); err != nil {
|
||||
msg := fmt.Sprintf("sync eip fail %s", err)
|
||||
eip.SetStatus(self.UserCred, api.EIP_STATUS_ALLOCATE_FAIL, msg)
|
||||
self.onFailed(ctx, eip, msg)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if self.Params != nil && self.Params.Contains("instance_id") {
|
||||
self.SetStage("on_eip_associate_complete", nil)
|
||||
err = eip.StartEipAssociateTask(ctx, self.UserCred, self.Params, self.GetId())
|
||||
if err != nil {
|
||||
if err := eip.StartEipAssociateTask(ctx, self.UserCred, self.Params, self.GetId()); err != nil {
|
||||
msg := fmt.Sprintf("start associate task fail %s", err)
|
||||
self.SetStageFailed(ctx, msg)
|
||||
}
|
||||
|
||||
@@ -44,14 +44,6 @@ func (self *EipChangeBandwidthTask) TaskFail(ctx context.Context, eip *models.SE
|
||||
|
||||
func (self *EipChangeBandwidthTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
|
||||
eip := obj.(*models.SElasticip)
|
||||
|
||||
extEip, err := eip.GetIEip()
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("fail to find iEip %s", err)
|
||||
self.TaskFail(ctx, eip, msg)
|
||||
return
|
||||
}
|
||||
|
||||
bandwidth, _ := self.Params.Int("bandwidth")
|
||||
if bandwidth <= 0 {
|
||||
msg := fmt.Sprintf("invalid bandwidth %d", bandwidth)
|
||||
@@ -59,22 +51,29 @@ func (self *EipChangeBandwidthTask) OnInit(ctx context.Context, obj db.IStandalo
|
||||
return
|
||||
}
|
||||
|
||||
err = extEip.ChangeBandwidth(int(bandwidth))
|
||||
if eip.IsManaged() {
|
||||
extEip, err := eip.GetIEip()
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("fail to find iEip %s", err)
|
||||
self.TaskFail(ctx, eip, msg)
|
||||
return
|
||||
}
|
||||
|
||||
err = extEip.ChangeBandwidth(int(bandwidth))
|
||||
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("fail to find iEip %s", err)
|
||||
self.TaskFail(ctx, eip, msg)
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("fail to find iEip %s", err)
|
||||
self.TaskFail(ctx, eip, msg)
|
||||
return
|
||||
}
|
||||
|
||||
err = eip.DoChangeBandwidth(self.UserCred, int(bandwidth))
|
||||
|
||||
if err != nil {
|
||||
if err := eip.DoChangeBandwidth(self.UserCred, int(bandwidth)); err != nil {
|
||||
msg := fmt.Sprintf("fail to synchronize iEip bandwidth %s", err)
|
||||
self.TaskFail(ctx, eip, msg)
|
||||
return
|
||||
}
|
||||
|
||||
logclient.AddActionLogWithStartable(self, eip, logclient.ACT_CHANGE_BANDWIDTH, nil, self.UserCred, true)
|
||||
self.SetStageComplete(ctx, nil)
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ func (self *EipDeallocateTask) taskFail(ctx context.Context, eip *models.SElasti
|
||||
func (self *EipDeallocateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
|
||||
eip := obj.(*models.SElasticip)
|
||||
|
||||
if len(eip.ExternalId) > 0 {
|
||||
if eip.ExternalId != "" {
|
||||
expEip, err := eip.GetIEip()
|
||||
if err != nil {
|
||||
if errors.Cause(err) != cloudprovider.ErrNotFound && errors.Cause(err) != cloudprovider.ErrInvalidProvider {
|
||||
@@ -66,6 +66,10 @@ func (self *EipDeallocateTask) OnInit(ctx context.Context, obj db.IStandaloneMod
|
||||
}
|
||||
}
|
||||
|
||||
if eip.IsManaged() {
|
||||
// TODO clear out guestnics
|
||||
}
|
||||
|
||||
err := eip.RealDelete(ctx, self.UserCred)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("fail to delete EIP %s", err)
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
@@ -63,7 +64,6 @@ func (self *EipDissociateTask) OnInit(ctx context.Context, obj db.IStandaloneMod
|
||||
eip := obj.(*models.SElasticip)
|
||||
|
||||
if eip.IsAssociated() {
|
||||
|
||||
var (
|
||||
model db.IModel
|
||||
logOp string
|
||||
@@ -85,25 +85,52 @@ func (self *EipDissociateTask) OnInit(ctx context.Context, obj db.IStandaloneMod
|
||||
self.TaskFail(ctx, eip, "unsupported associate type", nil)
|
||||
return
|
||||
}
|
||||
lockman.LockObject(ctx, model)
|
||||
defer lockman.ReleaseObject(ctx, model)
|
||||
|
||||
extEip, err := eip.GetIEip()
|
||||
if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound {
|
||||
msg := fmt.Sprintf("fail to find iEIP for eip %s", err)
|
||||
self.TaskFail(ctx, eip, msg, model)
|
||||
return
|
||||
}
|
||||
|
||||
if err == nil && len(extEip.GetAssociationExternalId()) > 0 {
|
||||
err = extEip.Dissociate()
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("fail to remote dissociate eip %s", err)
|
||||
if eip.IsManaged() {
|
||||
extEip, err := eip.GetIEip()
|
||||
if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound {
|
||||
msg := fmt.Sprintf("fail to find iEIP for eip %s", err)
|
||||
self.TaskFail(ctx, eip, msg, model)
|
||||
return
|
||||
}
|
||||
if err == nil && len(extEip.GetAssociationExternalId()) > 0 {
|
||||
err = extEip.Dissociate()
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("fail to remote dissociate eip %s", err)
|
||||
self.TaskFail(ctx, eip, msg, model)
|
||||
return
|
||||
}
|
||||
}
|
||||
} 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, 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))
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
err := errors.NewAggregate(errs)
|
||||
msg := errors.Wrapf(err, "disassociate eip %s(%s)", eip.Name, eip.Id).Error()
|
||||
self.TaskFail(ctx, eip, msg, model)
|
||||
}
|
||||
}
|
||||
|
||||
err = eip.Dissociate(ctx, self.UserCred)
|
||||
if err != nil {
|
||||
if err := eip.Dissociate(ctx, self.UserCred); err != nil {
|
||||
msg := fmt.Sprintf("fail to local dissociate eip %s", err)
|
||||
self.TaskFail(ctx, eip, msg, model)
|
||||
return
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/util/logclient"
|
||||
)
|
||||
|
||||
type GuestDissociateEipTask struct {
|
||||
SGuestBaseTask
|
||||
}
|
||||
|
||||
func init() {
|
||||
taskman.RegisterTask(GuestDissociateEipTask{})
|
||||
}
|
||||
|
||||
func (self *GuestDissociateEipTask) TaskFail(ctx context.Context, guest *models.SGuest, eip *models.SElasticip, err error) {
|
||||
guest.SetStatus(self.UserCred, api.VM_DISSOCIATE_EIP_FAILED, err.Error())
|
||||
if eip != nil {
|
||||
eip.SetStatus(self.UserCred, api.EIP_STATUS_READY, err.Error())
|
||||
logclient.AddActionLogWithStartable(self, eip, logclient.ACT_VM_DISSOCIATE, err, self.UserCred, false)
|
||||
}
|
||||
self.SetStageFailed(ctx, err.Error())
|
||||
db.OpsLog.LogEvent(guest, db.ACT_EIP_DETACH, err.Error(), self.GetUserCred())
|
||||
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_EIP_DISSOCIATE, err, self.UserCred, false)
|
||||
}
|
||||
|
||||
func (self *GuestDissociateEipTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
|
||||
guest := obj.(*models.SGuest)
|
||||
eip, err := guest.GetEip()
|
||||
if err != nil {
|
||||
self.TaskFail(ctx, guest, nil, errors.Wrap(err, "guest.GetEip"))
|
||||
return
|
||||
}
|
||||
|
||||
extEip, err := eip.GetIEip()
|
||||
if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound {
|
||||
self.TaskFail(ctx, guest, eip, errors.Wrap(err, "eip.GetIEip"))
|
||||
return
|
||||
}
|
||||
|
||||
if err == nil && len(extEip.GetAssociationExternalId()) > 0 {
|
||||
err = extEip.Dissociate()
|
||||
if err != nil {
|
||||
self.TaskFail(ctx, guest, eip, errors.Wrap(err, "extEip.Dissociate"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = eip.Dissociate(ctx, self.UserCred)
|
||||
if err != nil {
|
||||
self.TaskFail(ctx, guest, eip, errors.Wrap(err, "eip.Dissociate"))
|
||||
return
|
||||
}
|
||||
|
||||
eip.SetStatus(self.UserCred, api.EIP_STATUS_READY, "dissociate")
|
||||
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_EIP_DISSOCIATE, nil, self.UserCred, true)
|
||||
logclient.AddActionLogWithStartable(self, eip, logclient.ACT_VM_DISSOCIATE, nil, self.UserCred, true)
|
||||
|
||||
guest.StartSyncstatus(ctx, self.UserCred, "")
|
||||
self.SetStageComplete(ctx, nil)
|
||||
|
||||
autoDelete := jsonutils.QueryBoolean(self.GetParams(), "auto_delete", false)
|
||||
|
||||
if eip.AutoDellocate.IsTrue() || autoDelete {
|
||||
eip.StartEipDeallocateTask(ctx, self.UserCred, "")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -118,10 +118,16 @@ type SHostOptions struct {
|
||||
AllowSwitchVMs bool `help:"allow machines run as switch (spoof mac)" default:"true"`
|
||||
AllowRouterVMs bool `help:"allow machines run as router (spoof ip)" default:"true"`
|
||||
|
||||
SdnPidFile string `help:"pid file for sdnagent" default:"$SDN_PID_FILE|/var/run/yunion-sdnagent.pid"`
|
||||
SdnEnableGuestMan bool `help:"enable guest network manager in sdnagent" default:"$SDN_ENABLE_GUEST_MAN|true"`
|
||||
SdnEnableEipMan bool `help:"enable eip network manager in sdnagent" default:"$SDN_ENABLE_EIP_MAN|false"`
|
||||
|
||||
OvnSouthDatabase string `help:"address for accessing ovn south database" default:"$HOST_OVN_SOUTH_DATABASE|unix:/var/run/openvswitch/ovnsb_db.sock"`
|
||||
OvnEncapIp string `help:"encap ip for ovn datapath. Default to output src address of default route" default:"$HOST_OVN_ENCAP_IP"`
|
||||
OvnIntegrationBridge string `help:"name of integration bridge for logical ports" default:"$HOST_OVN_INTEGRATION_BRIDGE|brvpc"`
|
||||
OvnMappedBridge string `help:"name of bridge for mapped traffic management" default:"$HOST_OVN_MAPPED_BRIDGE|brmapped"`
|
||||
OvnEipBridge string `help:"name of bridge for eip traffic management" default:"$HOST_OVN_EIP_BRIDGE|breip"`
|
||||
OvnUnderlayMtu int `help:"mtu of ovn underlay network" default:"1500"`
|
||||
|
||||
EnableHealthChecker bool `help:"enable host health checker" default:"true"`
|
||||
HealthDriver string `help:"Component save host health state" default:"etcd"`
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package iproute2
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
)
|
||||
|
||||
func IsErrSrch(err error) bool {
|
||||
err = errors.Cause(err)
|
||||
if e, ok := err.(syscall.Errno); ok && e == 3 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -48,6 +48,10 @@ func (l *Link) addErr(err error, fmtStr string, vals ...interface{}) {
|
||||
l.errs = append(l.errs, errors.Wrapf(err, fmtStr, vals...))
|
||||
}
|
||||
|
||||
func (l *Link) addErr2(err error) {
|
||||
l.errs = append(l.errs, err)
|
||||
}
|
||||
|
||||
func (l *Link) Err() error {
|
||||
err := errors.NewAggregate(l.errs)
|
||||
if err != nil {
|
||||
|
||||
+85
-33
@@ -89,25 +89,57 @@ func (route *Route) AddByIPNet(ipnet *net.IPNet, gw net.IP) *Route {
|
||||
}
|
||||
|
||||
func (route *Route) AddByCidr(cidr string, gwStr string) *Route {
|
||||
var (
|
||||
dst *net.IPNet
|
||||
gw net.IP
|
||||
err error
|
||||
)
|
||||
if _, dst, err = net.ParseCIDR(cidr); err != nil {
|
||||
route.addErr(err, "parse cidr")
|
||||
dst, gw, err := route.parseCidr(cidr, gwStr)
|
||||
if err != nil {
|
||||
route.addErr2(err)
|
||||
return route
|
||||
}
|
||||
|
||||
return route.AddByIPNet(dst, gw)
|
||||
}
|
||||
|
||||
func (route *Route) parseCidr(cidr, gwStr string) (dst *net.IPNet, gw net.IP, err error) {
|
||||
if _, dst, err = net.ParseCIDR(cidr); err != nil {
|
||||
err = errors.Wrap(err, "parse cidr")
|
||||
return
|
||||
}
|
||||
|
||||
if gwStr != "" {
|
||||
gw = net.ParseIP(gwStr)
|
||||
if len(gw) == 0 {
|
||||
route.addErr(errBadIP, "gwStr: %s", gwStr)
|
||||
return route
|
||||
err = errors.Wrapf(errBadIP, "gwStr: %s", gwStr)
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
return route.AddByIPNet(dst, gw)
|
||||
func (route *Route) parse(netStr, maskStr, gwStr string) (ip net.IP, mask net.IPMask, gw net.IP, err error) {
|
||||
if ip = net.ParseIP(netStr); len(ip) == 0 {
|
||||
err = errors.Wrapf(errBadIP, "netStr %s", netStr)
|
||||
return
|
||||
}
|
||||
if maskIp := net.ParseIP(maskStr); len(maskIp) == 0 {
|
||||
err = errors.Wrapf(errBadIP, "maskStr %s", maskStr)
|
||||
return
|
||||
} else {
|
||||
if ip := maskIp.To4(); len(ip) > 0 {
|
||||
maskIp = ip
|
||||
}
|
||||
mask = net.IPMask(maskIp)
|
||||
ones, bits := mask.Size()
|
||||
if ones == 0 && bits == 0 {
|
||||
err = errors.Wrapf(errBadIP, "bad mask %s", maskStr)
|
||||
return
|
||||
}
|
||||
}
|
||||
if gwStr != "" {
|
||||
if gw = net.ParseIP(gwStr); len(gw) == 0 {
|
||||
err = errors.Wrapf(errBadIP, "gwStr %s", gwStr)
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (route *Route) Add(netStr, maskStr, gwStr string) *Route {
|
||||
@@ -117,29 +149,9 @@ func (route *Route) Add(netStr, maskStr, gwStr string) *Route {
|
||||
gw net.IP
|
||||
)
|
||||
|
||||
if ip = net.ParseIP(netStr); len(ip) == 0 {
|
||||
route.addErr(errBadIP, "netStr %s", netStr)
|
||||
return route
|
||||
}
|
||||
if maskIp := net.ParseIP(maskStr); len(maskIp) == 0 {
|
||||
route.addErr(errBadIP, "maskStr %s", maskStr)
|
||||
return route
|
||||
} else {
|
||||
if ip := maskIp.To4(); len(ip) > 0 {
|
||||
maskIp = ip
|
||||
}
|
||||
mask = net.IPMask(maskIp)
|
||||
ones, bits := mask.Size()
|
||||
if ones == 0 && bits == 0 {
|
||||
route.addErr(errBadIP, "bad mask %s", maskStr)
|
||||
return route
|
||||
}
|
||||
}
|
||||
if gwStr != "" {
|
||||
if gw = net.ParseIP(gwStr); len(gw) == 0 {
|
||||
route.addErr(errBadIP, "gwStr %s", gwStr)
|
||||
return route
|
||||
}
|
||||
ip, mask, gw, err := route.parse(netStr, maskStr, gwStr)
|
||||
if err != nil {
|
||||
route.addErr2(err)
|
||||
}
|
||||
|
||||
ipnet := &net.IPNet{
|
||||
@@ -149,6 +161,46 @@ func (route *Route) Add(netStr, maskStr, gwStr string) *Route {
|
||||
return route.AddByIPNet(ipnet, gw)
|
||||
}
|
||||
|
||||
func (route *Route) Del(netStr, maskStr string) *Route {
|
||||
ip, mask, _, err := route.parse(netStr, maskStr, "")
|
||||
if err != nil {
|
||||
route.addErr2(err)
|
||||
return route
|
||||
}
|
||||
ipnet := &net.IPNet{
|
||||
IP: ip,
|
||||
Mask: mask,
|
||||
}
|
||||
return route.DelByIPNet(ipnet)
|
||||
}
|
||||
|
||||
func (route *Route) DelByCidr(cidr string) *Route {
|
||||
dst, _, err := route.parseCidr(cidr, "")
|
||||
if err != nil {
|
||||
route.addErr2(err)
|
||||
return route
|
||||
}
|
||||
|
||||
return route.DelByIPNet(dst)
|
||||
}
|
||||
|
||||
func (route *Route) DelByIPNet(ipnet *net.IPNet) *Route {
|
||||
link, ok := route.link()
|
||||
if !ok {
|
||||
return route
|
||||
}
|
||||
|
||||
r := &netlink.Route{
|
||||
LinkIndex: link.Attrs().Index,
|
||||
Dst: ipnet,
|
||||
}
|
||||
if err := netlink.RouteDel(r); err != nil {
|
||||
route.addErr(err, "RouteDel %s", r)
|
||||
return route
|
||||
}
|
||||
return route
|
||||
}
|
||||
|
||||
func RouteGetByDst(dstStr string) ([]netlink.Route, error) {
|
||||
dstIp := net.ParseIP(dstStr)
|
||||
routes, err := netlink.RouteGet(dstIp)
|
||||
|
||||
@@ -48,4 +48,16 @@ func TestRoute(t *testing.T) {
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
t.Run("route del", func(t *testing.T) {
|
||||
ifname := genDummyName(t)
|
||||
dum := addDummy(t, ifname)
|
||||
defer delDummy(t, dum)
|
||||
|
||||
r := NewRoute(ifname)
|
||||
r.DelByCidr("10.1.1.30/32")
|
||||
if err := r.Err(); !IsErrSrch(err) {
|
||||
t.Errorf("expecting ESRCH, got %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ type Network struct {
|
||||
Vpc *Vpc `json:"-"`
|
||||
Wire *Wire `json:"-"`
|
||||
Guestnetworks Guestnetworks `json:"-"`
|
||||
Elasticips Elasticips `json:"-"`
|
||||
}
|
||||
|
||||
func (el *Network) Copy() *Network {
|
||||
@@ -60,8 +61,9 @@ func (el *Network) Copy() *Network {
|
||||
type Guestnetwork struct {
|
||||
compute_models.SGuestnetwork
|
||||
|
||||
Guest *Guest `json:"-"`
|
||||
Network *Network `json:"-"`
|
||||
Guest *Guest `json:"-"`
|
||||
Network *Network `json:"-"`
|
||||
Elasticip *Elasticip `json:"-"`
|
||||
}
|
||||
|
||||
func (el *Guestnetwork) Copy() *Guestnetwork {
|
||||
@@ -134,3 +136,16 @@ func (el *SecurityGroupRule) Copy() *SecurityGroupRule {
|
||||
SSecurityGroupRule: el.SSecurityGroupRule,
|
||||
}
|
||||
}
|
||||
|
||||
type Elasticip struct {
|
||||
compute_models.SElasticip
|
||||
|
||||
Network *Network `json:"-"`
|
||||
Guestnetwork *Guestnetwork `json:"-"`
|
||||
}
|
||||
|
||||
func (el *Elasticip) Copy() *Elasticip {
|
||||
return &Elasticip{
|
||||
SElasticip: el.SElasticip,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ type (
|
||||
Hosts map[string]*Host
|
||||
SecurityGroups map[string]*SecurityGroup
|
||||
SecurityGroupRules map[string]*SecurityGroupRule
|
||||
Elasticips map[string]*Elasticip
|
||||
|
||||
Guestnetworks map[string]*Guestnetwork // key: guestId/ifname
|
||||
Guestsecgroups map[string]*Guestsecgroup // key: guestId/secgroupId
|
||||
@@ -293,6 +294,30 @@ func (ms Networks) joinGuestnetworks(subEntries Guestnetworks) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (ms Networks) joinElasticips(subEntries Elasticips) bool {
|
||||
for _, m := range ms {
|
||||
m.Elasticips = Elasticips{}
|
||||
}
|
||||
correct := true
|
||||
for _, subEntry := range subEntries {
|
||||
netId := subEntry.NetworkId
|
||||
m, ok := ms[netId]
|
||||
if !ok {
|
||||
log.Warningf("eip %s(%s): network %s not found", subEntry.Name, subEntry.Id, netId)
|
||||
correct = false
|
||||
continue
|
||||
}
|
||||
if _, ok := m.Elasticips[subEntry.Id]; ok {
|
||||
log.Warningf("elasticip %s(%s) already joined", subEntry.Name, subEntry.Id)
|
||||
correct = false
|
||||
continue
|
||||
}
|
||||
subEntry.Network = m
|
||||
m.Elasticips[subEntry.Id] = subEntry
|
||||
}
|
||||
return correct
|
||||
}
|
||||
|
||||
func (set Guestnetworks) ModelManager() mcclient_modulebase.IBaseManager {
|
||||
return &mcclient_modules.Servernetworks
|
||||
}
|
||||
@@ -332,6 +357,33 @@ func (set Guestnetworks) joinGuests(subEntries Guests) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (set Guestnetworks) joinElasticips(subEntries Elasticips) bool {
|
||||
correct := true
|
||||
for _, gn := range set {
|
||||
eipId := gn.EipId
|
||||
if eipId == "" {
|
||||
continue
|
||||
}
|
||||
eip, ok := subEntries[eipId]
|
||||
if !ok {
|
||||
log.Warningf("guestnetwork %s(%s): eip %s not found", gn.GuestId, gn.Ifname, eipId)
|
||||
correct = false
|
||||
continue
|
||||
}
|
||||
if eip.Guestnetwork != nil {
|
||||
if eip.Guestnetwork != gn {
|
||||
log.Errorf("eip %s associated to more than 1 guestnetwork: %s(%s), %s(%s)", eipId,
|
||||
eip.Guestnetwork.GuestId, eip.Guestnetwork.Ifname, gn.GuestId, gn.Ifname)
|
||||
correct = false
|
||||
}
|
||||
continue
|
||||
}
|
||||
eip.Guestnetwork = gn
|
||||
gn.Elasticip = eip
|
||||
}
|
||||
return correct
|
||||
}
|
||||
|
||||
func (set SecurityGroups) ModelManager() mcclient_modulebase.IBaseManager {
|
||||
return &mcclient_modules.SecGroups
|
||||
}
|
||||
@@ -459,3 +511,24 @@ func (set Guestsecgroups) join(secgroups SecurityGroups, guests Guests) bool {
|
||||
c1 := set.joinGuests(guests)
|
||||
return c0 && c1
|
||||
}
|
||||
|
||||
func (set Elasticips) ModelManager() mcclient_modulebase.IBaseManager {
|
||||
return &mcclient_modules.Elasticips
|
||||
}
|
||||
|
||||
func (set Elasticips) NewModel() db.IModel {
|
||||
return &Elasticip{}
|
||||
}
|
||||
|
||||
func (set Elasticips) AddModel(i db.IModel) {
|
||||
m := i.(*Elasticip)
|
||||
set[m.Id] = m
|
||||
}
|
||||
|
||||
func (set Elasticips) Copy() apihelper.IModelSet {
|
||||
setCopy := Elasticips{}
|
||||
for id, el := range set {
|
||||
setCopy[id] = el.Copy()
|
||||
}
|
||||
return setCopy
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ type ModelSetsMaxUpdatedAt struct {
|
||||
SecurityGroupRules time.Time
|
||||
Guestnetworks time.Time
|
||||
Guestsecgroups time.Time
|
||||
Elasticips time.Time
|
||||
}
|
||||
|
||||
func NewModelSetsMaxUpdatedAt() *ModelSetsMaxUpdatedAt {
|
||||
@@ -43,6 +44,7 @@ func NewModelSetsMaxUpdatedAt() *ModelSetsMaxUpdatedAt {
|
||||
SecurityGroupRules: apihelper.PseudoZeroTime,
|
||||
Guestnetworks: apihelper.PseudoZeroTime,
|
||||
Guestsecgroups: apihelper.PseudoZeroTime,
|
||||
Elasticips: apihelper.PseudoZeroTime,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +58,7 @@ type ModelSets struct {
|
||||
SecurityGroupRules SecurityGroupRules
|
||||
Guestnetworks Guestnetworks
|
||||
Guestsecgroups Guestsecgroups
|
||||
Elasticips Elasticips
|
||||
}
|
||||
|
||||
func NewModelSets() *ModelSets {
|
||||
@@ -69,6 +72,7 @@ func NewModelSets() *ModelSets {
|
||||
SecurityGroupRules: SecurityGroupRules{},
|
||||
Guestnetworks: Guestnetworks{},
|
||||
Guestsecgroups: Guestsecgroups{},
|
||||
Elasticips: Elasticips{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +88,7 @@ func (mss *ModelSets) ModelSetList() []apihelper.IModelSet {
|
||||
mss.SecurityGroupRules,
|
||||
mss.Guestnetworks,
|
||||
mss.Guestsecgroups,
|
||||
mss.Elasticips,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +107,7 @@ func (mss *ModelSets) copy_() *ModelSets {
|
||||
SecurityGroupRules: mss.SecurityGroupRules.Copy().(SecurityGroupRules),
|
||||
Guestnetworks: mss.Guestnetworks.Copy().(Guestnetworks),
|
||||
Guestsecgroups: mss.Guestsecgroups.Copy().(Guestsecgroups),
|
||||
Elasticips: mss.Elasticips.Copy().(Elasticips),
|
||||
}
|
||||
return mssCopy
|
||||
}
|
||||
@@ -143,11 +149,13 @@ func (mss *ModelSets) join() bool {
|
||||
p = append(p, mss.Wires.joinNetworks(mss.Networks))
|
||||
p = append(p, mss.Vpcs.joinNetworks(mss.Networks))
|
||||
p = append(p, mss.Networks.joinGuestnetworks(mss.Guestnetworks))
|
||||
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.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))
|
||||
for _, b := range p {
|
||||
if !b {
|
||||
return false
|
||||
|
||||
@@ -39,6 +39,7 @@ type VpcAgentOptions struct {
|
||||
|
||||
OvnWorkerCheckInterval int `default:"180"`
|
||||
OvnNorthDatabase string `help:"address for accessing ovn north database. Default to local unix socket"`
|
||||
OvnUnderlayMtu int `help:"mtu of ovn underlay network" default:"1500"`
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
@@ -67,6 +68,10 @@ func (opts *Options) ValidateThenInit() error {
|
||||
opts.OvnWorkerCheckInterval = 60
|
||||
}
|
||||
|
||||
if opts.OvnUnderlayMtu <= 576 {
|
||||
opts.OvnUnderlayMtu = 576
|
||||
}
|
||||
|
||||
if db, err := ovsutils.NormalizeDbHost(opts.OvnNorthDatabase); err != nil {
|
||||
return err
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package ovn
|
||||
|
||||
import (
|
||||
apis "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
agentmodels "yunion.io/x/onecloud/pkg/vpcagent/models"
|
||||
)
|
||||
|
||||
func vpcHasDistgw(vpc *agentmodels.Vpc) bool {
|
||||
mode := vpc.ExternalAccessMode
|
||||
switch mode {
|
||||
case
|
||||
apis.VPC_EXTERNAL_ACCESS_MODE_DISTGW,
|
||||
apis.VPC_EXTERNAL_ACCESS_MODE_EIP_DISTGW:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func vpcHasEipgw(vpc *agentmodels.Vpc) bool {
|
||||
mode := vpc.ExternalAccessMode
|
||||
switch mode {
|
||||
case
|
||||
apis.VPC_EXTERNAL_ACCESS_MODE_EIP,
|
||||
apis.VPC_EXTERNAL_ACCESS_MODE_EIP_DISTGW:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
+261
-58
@@ -51,6 +51,7 @@ func DumpOVNNorthbound(ctx context.Context, cli *ovnutil.OvnNbCtl) (*OVNNorthbou
|
||||
&db.LogicalRouterStaticRoute,
|
||||
&db.ACL,
|
||||
&db.DHCPOptions,
|
||||
&db.QoS,
|
||||
}
|
||||
args := []string{"--format=json", "list", "<tbl>"}
|
||||
for _, itbl := range itbls {
|
||||
@@ -85,41 +86,91 @@ func (keeper *OVNNorthboundKeeper) ClaimVpc(ctx context.Context, vpc *agentmodel
|
||||
vpcLr := &ovn_nb.LogicalRouter{
|
||||
Name: vpcLrName(vpc.Id),
|
||||
}
|
||||
vpcHostLs := &ovn_nb.LogicalSwitch{
|
||||
Name: vpcHostLsName(vpc.Id),
|
||||
}
|
||||
vpcRhp := &ovn_nb.LogicalRouterPort{
|
||||
Name: vpcRhpName(vpc.Id),
|
||||
Mac: apis.VpcMappedGatewayMac,
|
||||
Networks: []string{fmt.Sprintf("%s/%d", apis.VpcMappedGatewayIP(), apis.VpcMappedIPMask)},
|
||||
}
|
||||
vpcHrp := &ovn_nb.LogicalSwitchPort{
|
||||
Name: vpcHrpName(vpc.Id),
|
||||
Type: "router",
|
||||
Addresses: []string{"router"},
|
||||
Options: map[string]string{
|
||||
"router-port": vpcRhpName(vpc.Id),
|
||||
},
|
||||
}
|
||||
allFound, args := cmp(&keeper.DB, ocVersion,
|
||||
vpcLr,
|
||||
vpcHostLs,
|
||||
vpcRhp,
|
||||
vpcHrp,
|
||||
irows := []types.IRow{vpcLr}
|
||||
|
||||
// distgw
|
||||
var (
|
||||
vpcHostLs *ovn_nb.LogicalSwitch
|
||||
vpcRhp *ovn_nb.LogicalRouterPort
|
||||
vpcHrp *ovn_nb.LogicalSwitchPort
|
||||
)
|
||||
if vpcHasDistgw(vpc) {
|
||||
vpcHostLs = &ovn_nb.LogicalSwitch{
|
||||
Name: vpcHostLsName(vpc.Id),
|
||||
}
|
||||
vpcRhp = &ovn_nb.LogicalRouterPort{
|
||||
Name: vpcRhpName(vpc.Id),
|
||||
Mac: apis.VpcMappedGatewayMac,
|
||||
Networks: []string{fmt.Sprintf("%s/%d", apis.VpcMappedGatewayIP(), apis.VpcMappedIPMask)},
|
||||
}
|
||||
vpcHrp = &ovn_nb.LogicalSwitchPort{
|
||||
Name: vpcHrpName(vpc.Id),
|
||||
Type: "router",
|
||||
Addresses: []string{"router"},
|
||||
Options: map[string]string{
|
||||
"router-port": vpcRhpName(vpc.Id),
|
||||
},
|
||||
}
|
||||
irows = append(irows,
|
||||
vpcHostLs,
|
||||
vpcRhp,
|
||||
vpcHrp,
|
||||
)
|
||||
}
|
||||
|
||||
// eipgw
|
||||
var (
|
||||
vpcEipLs *ovn_nb.LogicalSwitch
|
||||
vpcRep *ovn_nb.LogicalRouterPort
|
||||
vpcErp *ovn_nb.LogicalSwitchPort
|
||||
)
|
||||
if vpcHasEipgw(vpc) {
|
||||
vpcEipLs = &ovn_nb.LogicalSwitch{
|
||||
Name: vpcEipLsName(vpc.Id),
|
||||
}
|
||||
vpcRep = &ovn_nb.LogicalRouterPort{
|
||||
Name: vpcRepName(vpc.Id),
|
||||
Mac: apis.VpcEipGatewayMac,
|
||||
Networks: []string{fmt.Sprintf("%s/%d", apis.VpcEipGatewayIP(), apis.VpcEipGatewayIPMask)},
|
||||
}
|
||||
vpcErp = &ovn_nb.LogicalSwitchPort{
|
||||
Name: vpcErpName(vpc.Id),
|
||||
Type: "router",
|
||||
Addresses: []string{"router"},
|
||||
Options: map[string]string{
|
||||
"router-port": vpcRepName(vpc.Id),
|
||||
},
|
||||
}
|
||||
irows = append(irows,
|
||||
vpcEipLs,
|
||||
vpcRep,
|
||||
vpcErp,
|
||||
)
|
||||
}
|
||||
|
||||
allFound, args := cmp(&keeper.DB, ocVersion, irows...)
|
||||
if allFound {
|
||||
return nil
|
||||
}
|
||||
args = append(args, ovnCreateArgs(vpcLr, vpcLr.Name)...)
|
||||
args = append(args, ovnCreateArgs(vpcHostLs, vpcHostLs.Name)...)
|
||||
args = append(args, ovnCreateArgs(vpcRhp, vpcRhp.Name)...)
|
||||
args = append(args, ovnCreateArgs(vpcHrp, vpcHrp.Name)...)
|
||||
args = append(args, "--", "add", "Logical_Switch", vpcHostLs.Name, "ports", "@"+vpcHrp.Name)
|
||||
args = append(args, "--", "add", "Logical_Router", vpcLr.Name, "ports", "@"+vpcRhp.Name)
|
||||
if vpcHasDistgw(vpc) {
|
||||
args = append(args, ovnCreateArgs(vpcHostLs, vpcHostLs.Name)...)
|
||||
args = append(args, ovnCreateArgs(vpcRhp, vpcRhp.Name)...)
|
||||
args = append(args, ovnCreateArgs(vpcHrp, vpcHrp.Name)...)
|
||||
args = append(args, "--", "add", "Logical_Switch", vpcHostLs.Name, "ports", "@"+vpcHrp.Name)
|
||||
args = append(args, "--", "add", "Logical_Router", vpcLr.Name, "ports", "@"+vpcRhp.Name)
|
||||
}
|
||||
if vpcHasEipgw(vpc) {
|
||||
args = append(args, ovnCreateArgs(vpcEipLs, vpcEipLs.Name)...)
|
||||
args = append(args, ovnCreateArgs(vpcRep, vpcRep.Name)...)
|
||||
args = append(args, ovnCreateArgs(vpcErp, vpcErp.Name)...)
|
||||
args = append(args, "--", "add", "Logical_Switch", vpcEipLs.Name, "ports", "@"+vpcErp.Name)
|
||||
args = append(args, "--", "add", "Logical_Router", vpcLr.Name, "ports", "@"+vpcRep.Name)
|
||||
}
|
||||
return keeper.cli.Must(ctx, "ClaimVpc", args)
|
||||
}
|
||||
|
||||
func (keeper *OVNNorthboundKeeper) ClaimNetwork(ctx context.Context, network *agentmodels.Network) error {
|
||||
func (keeper *OVNNorthboundKeeper) ClaimNetwork(ctx context.Context, network *agentmodels.Network, mtu int) error {
|
||||
var (
|
||||
rpMac = mac.HashMac(network.Id, "rp")
|
||||
dhcpMac = mac.HashMac(network.Id, "dhcp")
|
||||
@@ -151,6 +202,7 @@ func (keeper *OVNNorthboundKeeper) ClaimNetwork(ctx context.Context, network *ag
|
||||
mdIp, "0.0.0.0",
|
||||
"0.0.0.0/0", network.GuestGateway,
|
||||
}
|
||||
mtu -= 58
|
||||
dhcpopts := &ovn_nb.DHCPOptions{
|
||||
Cidr: fmt.Sprintf("%s/%d", network.GuestIpStart, network.GuestIpMask),
|
||||
Options: map[string]string{
|
||||
@@ -159,6 +211,7 @@ func (keeper *OVNNorthboundKeeper) ClaimNetwork(ctx context.Context, network *ag
|
||||
"lease_time": fmt.Sprintf("%d", 86400),
|
||||
"router": network.GuestGateway,
|
||||
"classless_static_route": fmt.Sprintf("{%s}", strings.Join(routes, ",")),
|
||||
"mtu": fmt.Sprintf("%d", mtu),
|
||||
},
|
||||
ExternalIds: map[string]string{
|
||||
externalKeyOcRef: network.Id,
|
||||
@@ -200,7 +253,7 @@ func (keeper *OVNNorthboundKeeper) ClaimVpcHost(ctx context.Context, vpc *agentm
|
||||
)
|
||||
vpcHostLsp := &ovn_nb.LogicalSwitchPort{
|
||||
Name: vpcHostLspName(vpc.Id, host.Id),
|
||||
Addresses: []string{fmt.Sprintf("%s %s", mac.HashMac(host.Id), host.OvnMappedIpAddr)},
|
||||
Addresses: []string{fmt.Sprintf("%s %s", mac.HashVpcHostDistgwMac(host.Id), host.OvnMappedIpAddr)},
|
||||
}
|
||||
if m := keeper.DB.LogicalSwitchPort.FindOneMatchNonZeros(vpcHostLsp); m != nil {
|
||||
m.SetExternalId(externalKeyOcVersion, ocVersion)
|
||||
@@ -222,18 +275,50 @@ func (keeper *OVNNorthboundKeeper) ClaimVpcHost(ctx context.Context, vpc *agentm
|
||||
return keeper.cli.Must(ctx, "ClaimVpcHost", args)
|
||||
}
|
||||
|
||||
func (keeper *OVNNorthboundKeeper) ClaimVpcEipgw(ctx context.Context, vpc *agentmodels.Vpc) error {
|
||||
var (
|
||||
ocVersion = fmt.Sprintf("%s.%d", vpc.UpdatedAt, vpc.UpdateVersion)
|
||||
eipgwVip = apis.VpcEipGatewayIP3().String()
|
||||
)
|
||||
vpcEipLsp := &ovn_nb.LogicalSwitchPort{
|
||||
Name: vpcEipLspName(vpc.Id, eipgwVip),
|
||||
Addresses: []string{fmt.Sprintf("%s %s", apis.VpcEipGatewayMac3, eipgwVip)},
|
||||
}
|
||||
if m := keeper.DB.LogicalSwitchPort.FindOneMatchNonZeros(vpcEipLsp); m != nil {
|
||||
m.SetExternalId(externalKeyOcVersion, ocVersion)
|
||||
return nil
|
||||
} else {
|
||||
args := []string{
|
||||
"--bare", "--columns=_uuid", "find", vpcEipLsp.OvsdbTableName(),
|
||||
fmt.Sprintf("name=%q", vpcEipLsp.Name),
|
||||
}
|
||||
res := keeper.cli.Must(ctx, "find vpcEipLsp", args)
|
||||
vpcEipLspUuid := strings.TrimSpace(res.Output)
|
||||
if vpcEipLspUuid != "" {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
var args []string
|
||||
args = append(args, ovnCreateArgs(vpcEipLsp, vpcEipLsp.Name)...)
|
||||
args = append(args, "--", "add", "Logical_Switch", vpcEipLsName(vpc.Id), "ports", "@"+vpcEipLsp.Name)
|
||||
return keeper.cli.Must(ctx, "ClaimVpcEipgw", args)
|
||||
}
|
||||
|
||||
func (keeper *OVNNorthboundKeeper) ClaimGuestnetwork(ctx context.Context, guestnetwork *agentmodels.Guestnetwork) error {
|
||||
var (
|
||||
guest = guestnetwork.Guest
|
||||
network = guestnetwork.Network
|
||||
vpc = network.Vpc
|
||||
host = guest.Host
|
||||
eip = guestnetwork.Elasticip
|
||||
|
||||
lportName = gnpName(guestnetwork.NetworkId, guestnetwork.Ifname)
|
||||
ocVersion = fmt.Sprintf("%s.%d", guestnetwork.UpdatedAt, guestnetwork.UpdateVersion)
|
||||
ocGnrRef = fmt.Sprintf("gnr/%s/%s/%s", vpc.Id, guestnetwork.GuestId, guestnetwork.Ifname)
|
||||
ocAclRef = fmt.Sprintf("acl/%s/%s/%s", network.Id, guestnetwork.GuestId, guestnetwork.Ifname)
|
||||
dhcpOpt string
|
||||
lportName = gnpName(guestnetwork.NetworkId, guestnetwork.Ifname)
|
||||
ocVersion = fmt.Sprintf("%s.%d", guestnetwork.UpdatedAt, guestnetwork.UpdateVersion)
|
||||
ocGnrDefaultRef = fmt.Sprintf("gnrDefault/%s/%s/%s", vpc.Id, guestnetwork.GuestId, guestnetwork.Ifname)
|
||||
ocAclRef = fmt.Sprintf("acl/%s/%s/%s", network.Id, guestnetwork.GuestId, guestnetwork.Ifname)
|
||||
ocQosRef = fmt.Sprintf("qos/%s/%s/%s", network.Id, guestnetwork.GuestId, guestnetwork.Ifname)
|
||||
ocQosEipRef = fmt.Sprintf("qos-eip/%s/%s/%s", vpc.Id, guestnetwork.GuestId, guestnetwork.Ifname)
|
||||
dhcpOpt string
|
||||
)
|
||||
|
||||
{
|
||||
@@ -262,16 +347,107 @@ func (keeper *OVNNorthboundKeeper) ClaimGuestnetwork(ctx context.Context, guestn
|
||||
Addresses: []string{fmt.Sprintf("%s %s", guestnetwork.MacAddr, guestnetwork.IpAddr)},
|
||||
PortSecurity: []string{fmt.Sprintf("%s %s/%d", guestnetwork.MacAddr, guestnetwork.IpAddr, guestnetwork.Network.GuestIpMask)},
|
||||
Dhcpv4Options: &dhcpOpt,
|
||||
Options: map[string]string{},
|
||||
}
|
||||
|
||||
gnrPolicy := "src-ip"
|
||||
gnr := &ovn_nb.LogicalRouterStaticRoute{
|
||||
Policy: &gnrPolicy,
|
||||
IpPrefix: guestnetwork.IpAddr + "/32",
|
||||
Nexthop: host.OvnMappedIpAddr,
|
||||
ExternalIds: map[string]string{
|
||||
externalKeyOcRef: ocGnrRef,
|
||||
},
|
||||
var qosVif []*ovn_nb.QoS
|
||||
if bwMbps := guestnetwork.BwLimit; bwMbps > 0 {
|
||||
var (
|
||||
kbps = int64(bwMbps * 1000)
|
||||
kbur = int64(kbps * 2)
|
||||
)
|
||||
qosVif = []*ovn_nb.QoS{
|
||||
&ovn_nb.QoS{
|
||||
Priority: 2000,
|
||||
Direction: "from-lport",
|
||||
Match: fmt.Sprintf("inport == %q", lportName),
|
||||
Bandwidth: map[string]int64{
|
||||
"rate": kbps,
|
||||
"burst": kbur,
|
||||
},
|
||||
ExternalIds: map[string]string{
|
||||
externalKeyOcRef: ocQosRef,
|
||||
},
|
||||
},
|
||||
&ovn_nb.QoS{
|
||||
Priority: 1000,
|
||||
Direction: "to-lport",
|
||||
Match: fmt.Sprintf("outport == %q", lportName),
|
||||
Bandwidth: map[string]int64{
|
||||
"rate": kbps,
|
||||
"burst": kbur,
|
||||
},
|
||||
ExternalIds: map[string]string{
|
||||
externalKeyOcRef: ocQosRef,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
gnrDefault *ovn_nb.LogicalRouterStaticRoute
|
||||
qosEip []*ovn_nb.QoS
|
||||
)
|
||||
{
|
||||
gnrDefaultPolicy := "src-ip"
|
||||
ptr := func(s string) *string {
|
||||
return &s
|
||||
}
|
||||
if eip != nil && vpcHasEipgw(vpc) {
|
||||
gnrDefault = &ovn_nb.LogicalRouterStaticRoute{
|
||||
Policy: &gnrDefaultPolicy,
|
||||
IpPrefix: guestnetwork.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()
|
||||
)
|
||||
qosEip = []*ovn_nb.QoS{
|
||||
&ovn_nb.QoS{
|
||||
Priority: 2000,
|
||||
Direction: "from-lport",
|
||||
Match: fmt.Sprintf("inport == %q && ip4 && ip4.dst == %s", vpcEipLspName(vpc.Id, eipgwVip), guestnetwork.IpAddr),
|
||||
Bandwidth: map[string]int64{
|
||||
"rate": kbps,
|
||||
"burst": kbur,
|
||||
},
|
||||
ExternalIds: map[string]string{
|
||||
externalKeyOcRef: ocQosEipRef,
|
||||
},
|
||||
},
|
||||
&ovn_nb.QoS{
|
||||
Priority: 3000,
|
||||
Direction: "from-lport",
|
||||
Match: fmt.Sprintf("inport == %q", lportName),
|
||||
Bandwidth: map[string]int64{
|
||||
"rate": kbps,
|
||||
"burst": kbur,
|
||||
},
|
||||
ExternalIds: map[string]string{
|
||||
externalKeyOcRef: ocQosEipRef,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
} else if vpcHasDistgw(vpc) {
|
||||
gnrDefault = &ovn_nb.LogicalRouterStaticRoute{
|
||||
Policy: &gnrDefaultPolicy,
|
||||
IpPrefix: guestnetwork.IpAddr + "/32",
|
||||
Nexthop: host.OvnMappedIpAddr,
|
||||
OutputPort: ptr(vpcRhpName(vpc.Id)),
|
||||
ExternalIds: map[string]string{
|
||||
externalKeyOcRef: ocGnrDefaultRef,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var acls []*ovn_nb.ACL
|
||||
@@ -291,24 +467,46 @@ func (keeper *OVNNorthboundKeeper) ClaimGuestnetwork(ctx context.Context, guestn
|
||||
}
|
||||
|
||||
irows := []types.IRow{
|
||||
gnp, gnr,
|
||||
gnp,
|
||||
}
|
||||
if gnrDefault != nil {
|
||||
irows = append(irows, gnrDefault)
|
||||
}
|
||||
for _, acl := range acls {
|
||||
irows = append(irows, acl)
|
||||
}
|
||||
for _, qos := range qosVif {
|
||||
irows = append(irows, qos)
|
||||
}
|
||||
for _, qos := range qosEip {
|
||||
irows = append(irows, qos)
|
||||
}
|
||||
allFound, args := cmp(&keeper.DB, ocVersion, irows...)
|
||||
if allFound {
|
||||
return nil
|
||||
}
|
||||
|
||||
args = append(args, ovnCreateArgs(gnp, gnp.Name)...)
|
||||
args = append(args, ovnCreateArgs(gnr, "gnr")...)
|
||||
args = append(args, "--", "add", "Logical_Switch", netLsName(guestnetwork.NetworkId), "ports", "@"+gnp.Name)
|
||||
args = append(args, "--", "add", "Logical_Router", vpcLrName(vpc.Id), "static_routes", "@gnr")
|
||||
if gnrDefault != nil {
|
||||
args = append(args, ovnCreateArgs(gnrDefault, "gnrDefault")...)
|
||||
args = append(args, "--", "add", "Logical_Router", vpcLrName(vpc.Id), "static_routes", "@gnrDefault")
|
||||
}
|
||||
for i, acl := range acls {
|
||||
ref := fmt.Sprintf("acl%d", i)
|
||||
args = append(args, ovnCreateArgs(acl, ref)...)
|
||||
args = append(args, "--", "add", "Logical_Switch", netLsName(guestnetwork.NetworkId), "acls", "@"+ref)
|
||||
}
|
||||
for i, qos := range qosVif {
|
||||
ref := fmt.Sprintf("qosVif%d", i)
|
||||
args = append(args, ovnCreateArgs(qos, ref)...)
|
||||
args = append(args, "--", "add", "Logical_Switch", netLsName(guestnetwork.NetworkId), "qos_rules", "@"+ref)
|
||||
}
|
||||
for i, qos := range qosEip {
|
||||
ref := fmt.Sprintf("qosEip%d", i)
|
||||
args = append(args, ovnCreateArgs(qos, ref)...)
|
||||
args = append(args, "--", "add", "Logical_Switch", vpcEipLsName(vpc.Id), "qos_rules", "@"+ref)
|
||||
}
|
||||
return keeper.cli.Must(ctx, "ClaimGuestnetwork", args)
|
||||
}
|
||||
|
||||
@@ -322,6 +520,7 @@ func (keeper *OVNNorthboundKeeper) Mark(ctx context.Context) {
|
||||
&db.LogicalRouterStaticRoute,
|
||||
&db.ACL,
|
||||
&db.DHCPOptions,
|
||||
&db.QoS,
|
||||
}
|
||||
for _, itbl := range itbls {
|
||||
for _, irow := range itbl.Rows() {
|
||||
@@ -359,13 +558,8 @@ func (keeper *OVNNorthboundKeeper) Sweep(ctx context.Context) error {
|
||||
for _, irow := range db.LogicalRouterStaticRoute.Rows() {
|
||||
_, ok := irow.GetExternalId(externalKeyOcVersion)
|
||||
if !ok {
|
||||
ref, ok := irow.GetExternalId(externalKeyOcRef)
|
||||
if ok {
|
||||
parts := strings.SplitN(ref, "/", 4)
|
||||
if len(parts) == 4 {
|
||||
vpcId := parts[1]
|
||||
args = append(args, "--", "remove", "Logical_Router", vpcLrName(vpcId), "static_routes", irow.OvsdbUuid())
|
||||
}
|
||||
for _, lr := range db.LogicalRouter.FindLogicalRouterStaticRouteReferrer_static_routes(irow.OvsdbUuid()) {
|
||||
args = append(args, "--", "--if-exists", "remove", "Logical_Router", lr.Name, "static_routes", irow.OvsdbUuid())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -378,13 +572,8 @@ func (keeper *OVNNorthboundKeeper) Sweep(ctx context.Context) error {
|
||||
for _, irow := range db.ACL.Rows() {
|
||||
_, ok := irow.GetExternalId(externalKeyOcVersion)
|
||||
if !ok {
|
||||
ref, ok := irow.GetExternalId(externalKeyOcRef)
|
||||
if ok {
|
||||
parts := strings.SplitN(ref, "/", 4)
|
||||
if len(parts) == 4 {
|
||||
networkId := parts[1]
|
||||
args = append(args, "--", "remove", "Logical_Switch", netLsName(networkId), "acls", irow.OvsdbUuid())
|
||||
}
|
||||
for _, ls := range db.LogicalSwitch.FindACLReferrer_acls(irow.OvsdbUuid()) {
|
||||
args = append(args, "--", "--if-exists", "remove", "Logical_Switch", ls.Name, "acls", irow.OvsdbUuid())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -392,5 +581,19 @@ func (keeper *OVNNorthboundKeeper) Sweep(ctx context.Context) error {
|
||||
keeper.cli.Must(ctx, "Sweep acls", args)
|
||||
}
|
||||
}
|
||||
{ // remove unused QoS rows
|
||||
var args []string
|
||||
for _, irow := range db.QoS.Rows() {
|
||||
_, ok := irow.GetExternalId(externalKeyOcVersion)
|
||||
if !ok {
|
||||
for _, ls := range db.LogicalSwitch.FindQoSReferrer_qos_rules(irow.OvsdbUuid()) {
|
||||
args = append(args, "--", "--if-exists", "remove", "Logical_Switch", ls.Name, "qos_rules", irow.OvsdbUuid())
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(args) > 0 {
|
||||
keeper.cli.Must(ctx, "Sweep qos", args)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -20,3 +20,7 @@ func HashMac(in ...string) string {
|
||||
}
|
||||
return mac
|
||||
}
|
||||
|
||||
func HashVpcHostDistgwMac(hostId string) string {
|
||||
return HashMac(hostId)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ func vpcLrName(vpcId string) string {
|
||||
return fmt.Sprintf("vpc-r/%s", vpcId)
|
||||
}
|
||||
|
||||
// distgw
|
||||
func vpcHostLsName(vpcId string) string {
|
||||
return fmt.Sprintf("vpc-h/%s", vpcId)
|
||||
}
|
||||
@@ -24,6 +25,23 @@ func vpcHostLspName(vpcId string, hostId string) string {
|
||||
return fmt.Sprintf("vpc-h/%s/%s", vpcId, hostId)
|
||||
}
|
||||
|
||||
// eipgw
|
||||
func vpcEipLsName(vpcId string) string {
|
||||
return fmt.Sprintf("vpc-e/%s", vpcId)
|
||||
}
|
||||
|
||||
func vpcRepName(vpcId string) string {
|
||||
return fmt.Sprintf("vpc-re/%s", vpcId)
|
||||
}
|
||||
|
||||
func vpcErpName(vpcId string) string {
|
||||
return fmt.Sprintf("vpc-er/%s", vpcId)
|
||||
}
|
||||
|
||||
func vpcEipLspName(vpcId string, eipgwId string) string {
|
||||
return fmt.Sprintf("vpc-ep/%s/%s", vpcId, eipgwId)
|
||||
}
|
||||
|
||||
func netLsName(netId string) string {
|
||||
return fmt.Sprintf("subnet/%s", netId)
|
||||
}
|
||||
|
||||
+35
-29
@@ -120,41 +120,47 @@ func (w *Worker) run(ctx context.Context, mss *agentmodels.ModelSets) (err error
|
||||
continue
|
||||
}
|
||||
ovndb.ClaimVpc(ctx, vpc)
|
||||
if vpcHasEipgw(vpc) {
|
||||
ovndb.ClaimVpcEipgw(ctx, vpc)
|
||||
}
|
||||
for _, network := range vpc.Networks {
|
||||
ovndb.ClaimNetwork(ctx, network)
|
||||
ovndb.ClaimNetwork(ctx, network, w.opts.OvnUnderlayMtu)
|
||||
for _, guestnetwork := range network.Guestnetworks {
|
||||
if guestnetwork.Guest == nil {
|
||||
continue
|
||||
}
|
||||
var (
|
||||
guest = guestnetwork.Guest
|
||||
network = guestnetwork.Network
|
||||
vpc = network.Vpc
|
||||
host = guest.Host
|
||||
)
|
||||
if host.OvnVersion == "" {
|
||||
// Just in case. This should never happen
|
||||
log.Errorf("host %s(%s) of vpc guestnetwork (%s,%s) has no ovn support",
|
||||
host.Id, host.Name, guestnetwork.NetworkId, guestnetwork.IpAddr)
|
||||
continue
|
||||
}
|
||||
if host.OvnMappedIpAddr == "" {
|
||||
// trigger ovn mapped ip addr allocation
|
||||
apiVersion := "v2"
|
||||
s := auth.GetAdminSession(ctx, w.opts.Region, apiVersion)
|
||||
j, err := mcclient_modules.Hosts.Update(s, host.Id, nil)
|
||||
if err != nil {
|
||||
log.Errorf("host %s(%s) dummy update err: %v", host.Id, host.Name, err)
|
||||
continue
|
||||
}
|
||||
j.Unmarshal(host) // update local copy in place
|
||||
if host.OvnMappedIpAddr == "" {
|
||||
log.Errorf("host %s(%s) has no mapped addr", host.Id, host.Name)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
ovndb.ClaimVpcHost(ctx, vpc, host)
|
||||
if vpcHasDistgw(vpc) {
|
||||
var (
|
||||
guest = guestnetwork.Guest
|
||||
network = guestnetwork.Network
|
||||
vpc = network.Vpc
|
||||
host = guest.Host
|
||||
)
|
||||
if host.OvnVersion == "" {
|
||||
// Just in case. This should never happen
|
||||
log.Errorf("host %s(%s) of vpc guestnetwork (%s,%s) has no ovn support",
|
||||
host.Id, host.Name, guestnetwork.NetworkId, guestnetwork.IpAddr)
|
||||
continue
|
||||
}
|
||||
if host.OvnMappedIpAddr == "" {
|
||||
// trigger ovn mapped ip addr allocation
|
||||
apiVersion := "v2"
|
||||
s := auth.GetAdminSession(ctx, w.opts.Region, apiVersion)
|
||||
j, err := mcclient_modules.Hosts.Update(s, host.Id, nil)
|
||||
if err != nil {
|
||||
log.Errorf("host %s(%s) dummy update err: %v", host.Id, host.Name, err)
|
||||
continue
|
||||
}
|
||||
j.Unmarshal(host) // update local copy in place
|
||||
if host.OvnMappedIpAddr == "" {
|
||||
log.Errorf("host %s(%s) has no mapped addr", host.Id, host.Name)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
ovndb.ClaimVpcHost(ctx, vpc, host)
|
||||
}
|
||||
ovndb.ClaimGuestnetwork(ctx, guestnetwork)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,6 +161,7 @@ func OvnNbctlArgsDestroy(irows []types.IRow) []string {
|
||||
newArgs = []string{"--", "--if-exists", "lrp-del", irow.OvsdbUuid()}
|
||||
case *ovn_nb.LogicalRouterStaticRoute:
|
||||
case *ovn_nb.ACL:
|
||||
case *ovn_nb.QoS:
|
||||
default:
|
||||
if !irow.OvsdbIsRoot() {
|
||||
panic(irow.OvsdbTableName())
|
||||
|
||||
Vendored
+1
-1
@@ -996,7 +996,7 @@ yunion.io/x/jsonutils
|
||||
# yunion.io/x/log v0.0.0-20200313080802-57a4ce5966b3
|
||||
yunion.io/x/log
|
||||
yunion.io/x/log/hooks
|
||||
# yunion.io/x/ovsdb v0.0.0-20200512112253-a3601d1ee987
|
||||
# yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7
|
||||
yunion.io/x/ovsdb/cli_util
|
||||
yunion.io/x/ovsdb/schema/ovn_nb
|
||||
yunion.io/x/ovsdb/types
|
||||
|
||||
+752
@@ -23,8 +23,11 @@ type OVNNorthbound struct {
|
||||
LogicalRouterStaticRoute LogicalRouterStaticRouteTable
|
||||
LogicalSwitch LogicalSwitchTable
|
||||
LogicalSwitchPort LogicalSwitchPortTable
|
||||
Meter MeterTable
|
||||
MeterBand MeterBandTable
|
||||
NAT NATTable
|
||||
NBGlobal NBGlobalTable
|
||||
PortGroup PortGroupTable
|
||||
QoS QoSTable
|
||||
SSL SSLTable
|
||||
}
|
||||
@@ -93,6 +96,16 @@ func (db OVNNorthbound) FindOneMatchNonZeros(irow types.IRow) types.IRow {
|
||||
return r
|
||||
}
|
||||
return nil
|
||||
case *Meter:
|
||||
if r := db.Meter.FindOneMatchNonZeros(row); r != nil {
|
||||
return r
|
||||
}
|
||||
return nil
|
||||
case *MeterBand:
|
||||
if r := db.MeterBand.FindOneMatchNonZeros(row); r != nil {
|
||||
return r
|
||||
}
|
||||
return nil
|
||||
case *NAT:
|
||||
if r := db.NAT.FindOneMatchNonZeros(row); r != nil {
|
||||
return r
|
||||
@@ -103,6 +116,11 @@ func (db OVNNorthbound) FindOneMatchNonZeros(irow types.IRow) types.IRow {
|
||||
return r
|
||||
}
|
||||
return nil
|
||||
case *PortGroup:
|
||||
if r := db.PortGroup.FindOneMatchNonZeros(row); r != nil {
|
||||
return r
|
||||
}
|
||||
return nil
|
||||
case *QoS:
|
||||
if r := db.QoS.FindOneMatchNonZeros(row); r != nil {
|
||||
return r
|
||||
@@ -179,6 +197,16 @@ func (db OVNNorthbound) FindOneMatchByAnyIndex(irow types.IRow) types.IRow {
|
||||
return r
|
||||
}
|
||||
return nil
|
||||
case *Meter:
|
||||
if r := db.Meter.OvsdbGetByAnyIndex(row); r != nil {
|
||||
return r
|
||||
}
|
||||
return nil
|
||||
case *MeterBand:
|
||||
if r := db.MeterBand.OvsdbGetByAnyIndex(row); r != nil {
|
||||
return r
|
||||
}
|
||||
return nil
|
||||
case *NAT:
|
||||
if r := db.NAT.OvsdbGetByAnyIndex(row); r != nil {
|
||||
return r
|
||||
@@ -189,6 +217,11 @@ func (db OVNNorthbound) FindOneMatchByAnyIndex(irow types.IRow) types.IRow {
|
||||
return r
|
||||
}
|
||||
return nil
|
||||
case *PortGroup:
|
||||
if r := db.PortGroup.OvsdbGetByAnyIndex(row); r != nil {
|
||||
return r
|
||||
}
|
||||
return nil
|
||||
case *QoS:
|
||||
if r := db.QoS.OvsdbGetByAnyIndex(row); r != nil {
|
||||
return r
|
||||
@@ -258,6 +291,7 @@ type ACL struct {
|
||||
ExternalIds map[string]string `json:"external_ids"`
|
||||
Log bool `json:"log"`
|
||||
Match string `json:"match"`
|
||||
Meter *string `json:"meter"`
|
||||
Name *string `json:"name"`
|
||||
Priority int64 `json:"priority"`
|
||||
Severity *string `json:"severity"`
|
||||
@@ -284,6 +318,7 @@ func (row *ACL) OvsdbCmdArgs() []string {
|
||||
r = append(r, types.OvsdbCmdArgsMapStringString("external_ids", row.ExternalIds)...)
|
||||
r = append(r, types.OvsdbCmdArgsBoolean("log", row.Log)...)
|
||||
r = append(r, types.OvsdbCmdArgsString("match", row.Match)...)
|
||||
r = append(r, types.OvsdbCmdArgsStringOptional("meter", row.Meter)...)
|
||||
r = append(r, types.OvsdbCmdArgsStringOptional("name", row.Name)...)
|
||||
r = append(r, types.OvsdbCmdArgsInteger("priority", row.Priority)...)
|
||||
r = append(r, types.OvsdbCmdArgsStringOptional("severity", row.Severity)...)
|
||||
@@ -311,6 +346,8 @@ func (row *ACL) SetColumn(name string, val interface{}) (err error) {
|
||||
row.Log = types.EnsureBoolean(val)
|
||||
case "match":
|
||||
row.Match = types.EnsureString(val)
|
||||
case "meter":
|
||||
row.Meter = types.EnsureStringOptional(val)
|
||||
case "name":
|
||||
row.Name = types.EnsureStringOptional(val)
|
||||
case "priority":
|
||||
@@ -345,6 +382,9 @@ func (row *ACL) MatchNonZeros(row1 *ACL) bool {
|
||||
if !types.MatchStringIfNonZero(row.Match, row1.Match) {
|
||||
return false
|
||||
}
|
||||
if !types.MatchStringOptionalIfNonZero(row.Meter, row1.Meter) {
|
||||
return false
|
||||
}
|
||||
if !types.MatchStringOptionalIfNonZero(row.Name, row1.Name) {
|
||||
return false
|
||||
}
|
||||
@@ -1546,6 +1586,54 @@ func (row *LogicalRouter) MatchNonZeros(row1 *LogicalRouter) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (tbl LogicalRouterTable) FindLoadBalancerReferrer_load_balancer(refUuid string) (r []*LogicalRouter) {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
for _, val := range row.LoadBalancer {
|
||||
if val == refUuid {
|
||||
r = append(r, row)
|
||||
}
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (tbl LogicalRouterTable) FindNATReferrer_nat(refUuid string) (r []*LogicalRouter) {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
for _, val := range row.Nat {
|
||||
if val == refUuid {
|
||||
r = append(r, row)
|
||||
}
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (tbl LogicalRouterTable) FindLogicalRouterPortReferrer_ports(refUuid string) (r []*LogicalRouter) {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
for _, val := range row.Ports {
|
||||
if val == refUuid {
|
||||
r = append(r, row)
|
||||
}
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (tbl LogicalRouterTable) FindLogicalRouterStaticRouteReferrer_static_routes(refUuid string) (r []*LogicalRouter) {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
for _, val := range row.StaticRoutes {
|
||||
if val == refUuid {
|
||||
r = append(r, row)
|
||||
}
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (row *LogicalRouter) HasExternalIds() bool {
|
||||
return true
|
||||
}
|
||||
@@ -1760,6 +1848,18 @@ func (row *LogicalRouterPort) MatchNonZeros(row1 *LogicalRouterPort) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (tbl LogicalRouterPortTable) FindGatewayChassisReferrer_gateway_chassis(refUuid string) (r []*LogicalRouterPort) {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
for _, val := range row.GatewayChassis {
|
||||
if val == refUuid {
|
||||
r = append(r, row)
|
||||
}
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (row *LogicalRouterPort) HasExternalIds() bool {
|
||||
return true
|
||||
}
|
||||
@@ -2107,6 +2207,66 @@ func (row *LogicalSwitch) MatchNonZeros(row1 *LogicalSwitch) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (tbl LogicalSwitchTable) FindACLReferrer_acls(refUuid string) (r []*LogicalSwitch) {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
for _, val := range row.Acls {
|
||||
if val == refUuid {
|
||||
r = append(r, row)
|
||||
}
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (tbl LogicalSwitchTable) FindDNSReferrer_dns_records(refUuid string) (r []*LogicalSwitch) {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
for _, val := range row.DnsRecords {
|
||||
if val == refUuid {
|
||||
r = append(r, row)
|
||||
}
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (tbl LogicalSwitchTable) FindLoadBalancerReferrer_load_balancer(refUuid string) (r []*LogicalSwitch) {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
for _, val := range row.LoadBalancer {
|
||||
if val == refUuid {
|
||||
r = append(r, row)
|
||||
}
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (tbl LogicalSwitchTable) FindLogicalSwitchPortReferrer_ports(refUuid string) (r []*LogicalSwitch) {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
for _, val := range row.Ports {
|
||||
if val == refUuid {
|
||||
r = append(r, row)
|
||||
}
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (tbl LogicalSwitchTable) FindQoSReferrer_qos_rules(refUuid string) (r []*LogicalSwitch) {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
for _, val := range row.QosRules {
|
||||
if val == refUuid {
|
||||
r = append(r, row)
|
||||
}
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (row *LogicalSwitch) HasExternalIds() bool {
|
||||
return true
|
||||
}
|
||||
@@ -2356,6 +2516,26 @@ func (row *LogicalSwitchPort) MatchNonZeros(row1 *LogicalSwitchPort) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (tbl LogicalSwitchPortTable) FindDHCPOptionsReferrer_dhcpv4_options(refUuid string) (r []*LogicalSwitchPort) {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
if row.Dhcpv4Options != nil && *row.Dhcpv4Options == refUuid {
|
||||
r = append(r, row)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (tbl LogicalSwitchPortTable) FindDHCPOptionsReferrer_dhcpv6_options(refUuid string) (r []*LogicalSwitchPort) {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
if row.Dhcpv6Options != nil && *row.Dhcpv6Options == refUuid {
|
||||
r = append(r, row)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (row *LogicalSwitchPort) HasExternalIds() bool {
|
||||
return true
|
||||
}
|
||||
@@ -2386,6 +2566,353 @@ func (row *LogicalSwitchPort) RemoveExternalId(k string) (string, bool) {
|
||||
return r, ok
|
||||
}
|
||||
|
||||
type MeterTable []Meter
|
||||
|
||||
var _ types.ITable = &MeterTable{}
|
||||
|
||||
func (tbl MeterTable) OvsdbTableName() string {
|
||||
return "Meter"
|
||||
}
|
||||
|
||||
func (tbl MeterTable) OvsdbIsRoot() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (tbl MeterTable) Rows() []types.IRow {
|
||||
r := make([]types.IRow, len(tbl))
|
||||
for i := range tbl {
|
||||
r[i] = &tbl[i]
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (tbl MeterTable) NewRow() types.IRow {
|
||||
return &Meter{}
|
||||
}
|
||||
|
||||
func (tbl *MeterTable) AppendRow(irow types.IRow) {
|
||||
row := irow.(*Meter)
|
||||
*tbl = append(*tbl, *row)
|
||||
}
|
||||
|
||||
func (tbl MeterTable) OvsdbHasIndex() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (row *Meter) MatchByName(row1 *Meter) bool {
|
||||
if !types.MatchString(row.Name, row1.Name) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (tbl MeterTable) GetByName(row1 *Meter) *Meter {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
if row.MatchByName(row1) {
|
||||
return row
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tbl MeterTable) OvsdbGetByAnyIndex(irow1 types.IRow) types.IRow {
|
||||
row1 := irow1.(*Meter)
|
||||
if !(types.IsZeroString(row1.Name)) {
|
||||
if row := tbl.GetByName(row1); row != nil {
|
||||
return row
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tbl MeterTable) FindOneMatchNonZeros(row1 *Meter) *Meter {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
if row.MatchNonZeros(row1) {
|
||||
return row
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Meter struct {
|
||||
Uuid string `json:"_uuid"`
|
||||
Version string `json:"_version"`
|
||||
Bands []string `json:"bands"`
|
||||
ExternalIds map[string]string `json:"external_ids"`
|
||||
Name string `json:"name"`
|
||||
Unit string `json:"unit"`
|
||||
}
|
||||
|
||||
var _ types.IRow = &Meter{}
|
||||
|
||||
func (row *Meter) OvsdbTableName() string {
|
||||
return "Meter"
|
||||
}
|
||||
|
||||
func (row *Meter) OvsdbIsRoot() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (row *Meter) OvsdbUuid() string {
|
||||
return row.Uuid
|
||||
}
|
||||
|
||||
func (row *Meter) OvsdbCmdArgs() []string {
|
||||
r := []string{}
|
||||
r = append(r, types.OvsdbCmdArgsUuidMultiples("bands", row.Bands)...)
|
||||
r = append(r, types.OvsdbCmdArgsMapStringString("external_ids", row.ExternalIds)...)
|
||||
r = append(r, types.OvsdbCmdArgsString("name", row.Name)...)
|
||||
r = append(r, types.OvsdbCmdArgsString("unit", row.Unit)...)
|
||||
return r
|
||||
}
|
||||
|
||||
func (row *Meter) SetColumn(name string, val interface{}) (err error) {
|
||||
defer func() {
|
||||
if panicErr := recover(); panicErr != nil {
|
||||
err = errors.Wrapf(panicErr.(error), "%s: %#v", name, fmt.Sprintf("%#v", val))
|
||||
}
|
||||
}()
|
||||
switch name {
|
||||
case "_uuid":
|
||||
row.Uuid = types.EnsureUuid(val)
|
||||
case "_version":
|
||||
row.Version = types.EnsureUuid(val)
|
||||
case "bands":
|
||||
row.Bands = types.EnsureUuidMultiples(val)
|
||||
case "external_ids":
|
||||
row.ExternalIds = types.EnsureMapStringString(val)
|
||||
case "name":
|
||||
row.Name = types.EnsureString(val)
|
||||
case "unit":
|
||||
row.Unit = types.EnsureString(val)
|
||||
default:
|
||||
panic(types.ErrUnknownColumn)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (row *Meter) MatchNonZeros(row1 *Meter) bool {
|
||||
if !types.MatchUuidIfNonZero(row.Uuid, row1.Uuid) {
|
||||
return false
|
||||
}
|
||||
if !types.MatchUuidIfNonZero(row.Version, row1.Version) {
|
||||
return false
|
||||
}
|
||||
if !types.MatchUuidMultiplesIfNonZero(row.Bands, row1.Bands) {
|
||||
return false
|
||||
}
|
||||
if !types.MatchMapStringStringIfNonZero(row.ExternalIds, row1.ExternalIds) {
|
||||
return false
|
||||
}
|
||||
if !types.MatchStringIfNonZero(row.Name, row1.Name) {
|
||||
return false
|
||||
}
|
||||
if !types.MatchStringIfNonZero(row.Unit, row1.Unit) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (tbl MeterTable) FindMeterBandReferrer_bands(refUuid string) (r []*Meter) {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
for _, val := range row.Bands {
|
||||
if val == refUuid {
|
||||
r = append(r, row)
|
||||
}
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (row *Meter) HasExternalIds() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (row *Meter) SetExternalId(k, v string) {
|
||||
if row.ExternalIds == nil {
|
||||
row.ExternalIds = map[string]string{}
|
||||
}
|
||||
row.ExternalIds[k] = v
|
||||
}
|
||||
|
||||
func (row *Meter) GetExternalId(k string) (string, bool) {
|
||||
if row.ExternalIds == nil {
|
||||
return "", false
|
||||
}
|
||||
r, ok := row.ExternalIds[k]
|
||||
return r, ok
|
||||
}
|
||||
|
||||
func (row *Meter) RemoveExternalId(k string) (string, bool) {
|
||||
if row.ExternalIds == nil {
|
||||
return "", false
|
||||
}
|
||||
r, ok := row.ExternalIds[k]
|
||||
if ok {
|
||||
delete(row.ExternalIds, k)
|
||||
}
|
||||
return r, ok
|
||||
}
|
||||
|
||||
type MeterBandTable []MeterBand
|
||||
|
||||
var _ types.ITable = &MeterBandTable{}
|
||||
|
||||
func (tbl MeterBandTable) OvsdbTableName() string {
|
||||
return "Meter_Band"
|
||||
}
|
||||
|
||||
func (tbl MeterBandTable) OvsdbIsRoot() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (tbl MeterBandTable) Rows() []types.IRow {
|
||||
r := make([]types.IRow, len(tbl))
|
||||
for i := range tbl {
|
||||
r[i] = &tbl[i]
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (tbl MeterBandTable) NewRow() types.IRow {
|
||||
return &MeterBand{}
|
||||
}
|
||||
|
||||
func (tbl *MeterBandTable) AppendRow(irow types.IRow) {
|
||||
row := irow.(*MeterBand)
|
||||
*tbl = append(*tbl, *row)
|
||||
}
|
||||
|
||||
func (tbl MeterBandTable) OvsdbHasIndex() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (tbl MeterBandTable) OvsdbGetByAnyIndex(irow1 types.IRow) types.IRow {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tbl MeterBandTable) FindOneMatchNonZeros(row1 *MeterBand) *MeterBand {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
if row.MatchNonZeros(row1) {
|
||||
return row
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type MeterBand struct {
|
||||
Uuid string `json:"_uuid"`
|
||||
Version string `json:"_version"`
|
||||
Action string `json:"action"`
|
||||
BurstSize int64 `json:"burst_size"`
|
||||
ExternalIds map[string]string `json:"external_ids"`
|
||||
Rate int64 `json:"rate"`
|
||||
}
|
||||
|
||||
var _ types.IRow = &MeterBand{}
|
||||
|
||||
func (row *MeterBand) OvsdbTableName() string {
|
||||
return "Meter_Band"
|
||||
}
|
||||
|
||||
func (row *MeterBand) OvsdbIsRoot() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (row *MeterBand) OvsdbUuid() string {
|
||||
return row.Uuid
|
||||
}
|
||||
|
||||
func (row *MeterBand) OvsdbCmdArgs() []string {
|
||||
r := []string{}
|
||||
r = append(r, types.OvsdbCmdArgsString("action", row.Action)...)
|
||||
r = append(r, types.OvsdbCmdArgsInteger("burst_size", row.BurstSize)...)
|
||||
r = append(r, types.OvsdbCmdArgsMapStringString("external_ids", row.ExternalIds)...)
|
||||
r = append(r, types.OvsdbCmdArgsInteger("rate", row.Rate)...)
|
||||
return r
|
||||
}
|
||||
|
||||
func (row *MeterBand) SetColumn(name string, val interface{}) (err error) {
|
||||
defer func() {
|
||||
if panicErr := recover(); panicErr != nil {
|
||||
err = errors.Wrapf(panicErr.(error), "%s: %#v", name, fmt.Sprintf("%#v", val))
|
||||
}
|
||||
}()
|
||||
switch name {
|
||||
case "_uuid":
|
||||
row.Uuid = types.EnsureUuid(val)
|
||||
case "_version":
|
||||
row.Version = types.EnsureUuid(val)
|
||||
case "action":
|
||||
row.Action = types.EnsureString(val)
|
||||
case "burst_size":
|
||||
row.BurstSize = types.EnsureInteger(val)
|
||||
case "external_ids":
|
||||
row.ExternalIds = types.EnsureMapStringString(val)
|
||||
case "rate":
|
||||
row.Rate = types.EnsureInteger(val)
|
||||
default:
|
||||
panic(types.ErrUnknownColumn)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (row *MeterBand) MatchNonZeros(row1 *MeterBand) bool {
|
||||
if !types.MatchUuidIfNonZero(row.Uuid, row1.Uuid) {
|
||||
return false
|
||||
}
|
||||
if !types.MatchUuidIfNonZero(row.Version, row1.Version) {
|
||||
return false
|
||||
}
|
||||
if !types.MatchStringIfNonZero(row.Action, row1.Action) {
|
||||
return false
|
||||
}
|
||||
if !types.MatchIntegerIfNonZero(row.BurstSize, row1.BurstSize) {
|
||||
return false
|
||||
}
|
||||
if !types.MatchMapStringStringIfNonZero(row.ExternalIds, row1.ExternalIds) {
|
||||
return false
|
||||
}
|
||||
if !types.MatchIntegerIfNonZero(row.Rate, row1.Rate) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (row *MeterBand) HasExternalIds() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (row *MeterBand) SetExternalId(k, v string) {
|
||||
if row.ExternalIds == nil {
|
||||
row.ExternalIds = map[string]string{}
|
||||
}
|
||||
row.ExternalIds[k] = v
|
||||
}
|
||||
|
||||
func (row *MeterBand) GetExternalId(k string) (string, bool) {
|
||||
if row.ExternalIds == nil {
|
||||
return "", false
|
||||
}
|
||||
r, ok := row.ExternalIds[k]
|
||||
return r, ok
|
||||
}
|
||||
|
||||
func (row *MeterBand) RemoveExternalId(k string) (string, bool) {
|
||||
if row.ExternalIds == nil {
|
||||
return "", false
|
||||
}
|
||||
r, ok := row.ExternalIds[k]
|
||||
if ok {
|
||||
delete(row.ExternalIds, k)
|
||||
}
|
||||
return r, ok
|
||||
}
|
||||
|
||||
type NATTable []NAT
|
||||
|
||||
var _ types.ITable = &NATTable{}
|
||||
@@ -2696,6 +3223,28 @@ func (row *NBGlobal) MatchNonZeros(row1 *NBGlobal) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (tbl NBGlobalTable) FindConnectionReferrer_connections(refUuid string) (r []*NBGlobal) {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
for _, val := range row.Connections {
|
||||
if val == refUuid {
|
||||
r = append(r, row)
|
||||
}
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (tbl NBGlobalTable) FindSSLReferrer_ssl(refUuid string) (r []*NBGlobal) {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
if row.Ssl != nil && *row.Ssl == refUuid {
|
||||
r = append(r, row)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (row *NBGlobal) HasExternalIds() bool {
|
||||
return true
|
||||
}
|
||||
@@ -2726,6 +3275,209 @@ func (row *NBGlobal) RemoveExternalId(k string) (string, bool) {
|
||||
return r, ok
|
||||
}
|
||||
|
||||
type PortGroupTable []PortGroup
|
||||
|
||||
var _ types.ITable = &PortGroupTable{}
|
||||
|
||||
func (tbl PortGroupTable) OvsdbTableName() string {
|
||||
return "Port_Group"
|
||||
}
|
||||
|
||||
func (tbl PortGroupTable) OvsdbIsRoot() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (tbl PortGroupTable) Rows() []types.IRow {
|
||||
r := make([]types.IRow, len(tbl))
|
||||
for i := range tbl {
|
||||
r[i] = &tbl[i]
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (tbl PortGroupTable) NewRow() types.IRow {
|
||||
return &PortGroup{}
|
||||
}
|
||||
|
||||
func (tbl *PortGroupTable) AppendRow(irow types.IRow) {
|
||||
row := irow.(*PortGroup)
|
||||
*tbl = append(*tbl, *row)
|
||||
}
|
||||
|
||||
func (tbl PortGroupTable) OvsdbHasIndex() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (row *PortGroup) MatchByName(row1 *PortGroup) bool {
|
||||
if !types.MatchString(row.Name, row1.Name) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (tbl PortGroupTable) GetByName(row1 *PortGroup) *PortGroup {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
if row.MatchByName(row1) {
|
||||
return row
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tbl PortGroupTable) OvsdbGetByAnyIndex(irow1 types.IRow) types.IRow {
|
||||
row1 := irow1.(*PortGroup)
|
||||
if !(types.IsZeroString(row1.Name)) {
|
||||
if row := tbl.GetByName(row1); row != nil {
|
||||
return row
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tbl PortGroupTable) FindOneMatchNonZeros(row1 *PortGroup) *PortGroup {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
if row.MatchNonZeros(row1) {
|
||||
return row
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PortGroup struct {
|
||||
Uuid string `json:"_uuid"`
|
||||
Version string `json:"_version"`
|
||||
Acls []string `json:"acls"`
|
||||
ExternalIds map[string]string `json:"external_ids"`
|
||||
Name string `json:"name"`
|
||||
Ports []string `json:"ports"`
|
||||
}
|
||||
|
||||
var _ types.IRow = &PortGroup{}
|
||||
|
||||
func (row *PortGroup) OvsdbTableName() string {
|
||||
return "Port_Group"
|
||||
}
|
||||
|
||||
func (row *PortGroup) OvsdbIsRoot() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (row *PortGroup) OvsdbUuid() string {
|
||||
return row.Uuid
|
||||
}
|
||||
|
||||
func (row *PortGroup) OvsdbCmdArgs() []string {
|
||||
r := []string{}
|
||||
r = append(r, types.OvsdbCmdArgsUuidMultiples("acls", row.Acls)...)
|
||||
r = append(r, types.OvsdbCmdArgsMapStringString("external_ids", row.ExternalIds)...)
|
||||
r = append(r, types.OvsdbCmdArgsString("name", row.Name)...)
|
||||
r = append(r, types.OvsdbCmdArgsUuidMultiples("ports", row.Ports)...)
|
||||
return r
|
||||
}
|
||||
|
||||
func (row *PortGroup) SetColumn(name string, val interface{}) (err error) {
|
||||
defer func() {
|
||||
if panicErr := recover(); panicErr != nil {
|
||||
err = errors.Wrapf(panicErr.(error), "%s: %#v", name, fmt.Sprintf("%#v", val))
|
||||
}
|
||||
}()
|
||||
switch name {
|
||||
case "_uuid":
|
||||
row.Uuid = types.EnsureUuid(val)
|
||||
case "_version":
|
||||
row.Version = types.EnsureUuid(val)
|
||||
case "acls":
|
||||
row.Acls = types.EnsureUuidMultiples(val)
|
||||
case "external_ids":
|
||||
row.ExternalIds = types.EnsureMapStringString(val)
|
||||
case "name":
|
||||
row.Name = types.EnsureString(val)
|
||||
case "ports":
|
||||
row.Ports = types.EnsureUuidMultiples(val)
|
||||
default:
|
||||
panic(types.ErrUnknownColumn)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (row *PortGroup) MatchNonZeros(row1 *PortGroup) bool {
|
||||
if !types.MatchUuidIfNonZero(row.Uuid, row1.Uuid) {
|
||||
return false
|
||||
}
|
||||
if !types.MatchUuidIfNonZero(row.Version, row1.Version) {
|
||||
return false
|
||||
}
|
||||
if !types.MatchUuidMultiplesIfNonZero(row.Acls, row1.Acls) {
|
||||
return false
|
||||
}
|
||||
if !types.MatchMapStringStringIfNonZero(row.ExternalIds, row1.ExternalIds) {
|
||||
return false
|
||||
}
|
||||
if !types.MatchStringIfNonZero(row.Name, row1.Name) {
|
||||
return false
|
||||
}
|
||||
if !types.MatchUuidMultiplesIfNonZero(row.Ports, row1.Ports) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (tbl PortGroupTable) FindACLReferrer_acls(refUuid string) (r []*PortGroup) {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
for _, val := range row.Acls {
|
||||
if val == refUuid {
|
||||
r = append(r, row)
|
||||
}
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (tbl PortGroupTable) FindLogicalSwitchPortReferrer_ports(refUuid string) (r []*PortGroup) {
|
||||
for i := range tbl {
|
||||
row := &tbl[i]
|
||||
for _, val := range row.Ports {
|
||||
if val == refUuid {
|
||||
r = append(r, row)
|
||||
}
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (row *PortGroup) HasExternalIds() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (row *PortGroup) SetExternalId(k, v string) {
|
||||
if row.ExternalIds == nil {
|
||||
row.ExternalIds = map[string]string{}
|
||||
}
|
||||
row.ExternalIds[k] = v
|
||||
}
|
||||
|
||||
func (row *PortGroup) GetExternalId(k string) (string, bool) {
|
||||
if row.ExternalIds == nil {
|
||||
return "", false
|
||||
}
|
||||
r, ok := row.ExternalIds[k]
|
||||
return r, ok
|
||||
}
|
||||
|
||||
func (row *PortGroup) RemoveExternalId(k string) (string, bool) {
|
||||
if row.ExternalIds == nil {
|
||||
return "", false
|
||||
}
|
||||
r, ok := row.ExternalIds[k]
|
||||
if ok {
|
||||
delete(row.ExternalIds, k)
|
||||
}
|
||||
return r, ok
|
||||
}
|
||||
|
||||
type QoSTable []QoS
|
||||
|
||||
var _ types.ITable = &QoSTable{}
|
||||
|
||||
+50
-2
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "OVN_Northbound",
|
||||
"version": "5.10.0",
|
||||
"cksum": "626737541 17810",
|
||||
"version": "5.13.0",
|
||||
"cksum": "1278623084 20312",
|
||||
"tables": {
|
||||
"NB_Global": {
|
||||
"columns": {
|
||||
@@ -114,6 +114,24 @@
|
||||
"min": 0, "max": "unlimited"}}},
|
||||
"indexes": [["name"]],
|
||||
"isRoot": true},
|
||||
"Port_Group": {
|
||||
"columns": {
|
||||
"name": {"type": "string"},
|
||||
"ports": {"type": {"key": {"type": "uuid",
|
||||
"refTable": "Logical_Switch_Port",
|
||||
"refType": "weak"},
|
||||
"min": 0,
|
||||
"max": "unlimited"}},
|
||||
"acls": {"type": {"key": {"type": "uuid",
|
||||
"refTable": "ACL",
|
||||
"refType": "strong"},
|
||||
"min": 0,
|
||||
"max": "unlimited"}},
|
||||
"external_ids": {
|
||||
"type": {"key": "string", "value": "string",
|
||||
"min": 0, "max": "unlimited"}}},
|
||||
"indexes": [["name"]],
|
||||
"isRoot": true},
|
||||
"Load_Balancer": {
|
||||
"columns": {
|
||||
"name": {"type": "string"},
|
||||
@@ -148,6 +166,7 @@
|
||||
"notice", "info",
|
||||
"debug"]]},
|
||||
"min": 0, "max": 1}},
|
||||
"meter": {"type": {"key": "string", "min": 0, "max": 1}},
|
||||
"external_ids": {
|
||||
"type": {"key": "string", "value": "string",
|
||||
"min": 0, "max": "unlimited"}}},
|
||||
@@ -177,6 +196,35 @@
|
||||
"type": {"key": "string", "value": "string",
|
||||
"min": 0, "max": "unlimited"}}},
|
||||
"isRoot": false},
|
||||
"Meter": {
|
||||
"columns": {
|
||||
"name": {"type": "string"},
|
||||
"unit": {"type": {"key": {"type": "string",
|
||||
"enum": ["set", ["kbps", "pktps"]]}}},
|
||||
"bands": {"type": {"key": {"type": "uuid",
|
||||
"refTable": "Meter_Band",
|
||||
"refType": "strong"},
|
||||
"min": 1,
|
||||
"max": "unlimited"}},
|
||||
"external_ids": {
|
||||
"type": {"key": "string", "value": "string",
|
||||
"min": 0, "max": "unlimited"}}},
|
||||
"indexes": [["name"]],
|
||||
"isRoot": true},
|
||||
"Meter_Band": {
|
||||
"columns": {
|
||||
"action": {"type": {"key": {"type": "string",
|
||||
"enum": ["set", ["drop"]]}}},
|
||||
"rate": {"type": {"key": {"type": "integer",
|
||||
"minInteger": 1,
|
||||
"maxInteger": 4294967295}}},
|
||||
"burst_size": {"type": {"key": {"type": "integer",
|
||||
"minInteger": 0,
|
||||
"maxInteger": 4294967295}}},
|
||||
"external_ids": {
|
||||
"type": {"key": "string", "value": "string",
|
||||
"min": 0, "max": "unlimited"}}},
|
||||
"isRoot": false},
|
||||
"Logical_Router": {
|
||||
"columns": {
|
||||
"name": {"type": "string"},
|
||||
|
||||
+33
-2
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "OVN_Southbound",
|
||||
"version": "1.15.0",
|
||||
"cksum": "70426956 13327",
|
||||
"version": "1.16.0",
|
||||
"cksum": "3046632234 14844",
|
||||
"tables": {
|
||||
"SB_Global": {
|
||||
"columns": {
|
||||
@@ -55,6 +55,14 @@
|
||||
"max": "unlimited"}}},
|
||||
"indexes": [["name"]],
|
||||
"isRoot": true},
|
||||
"Port_Group": {
|
||||
"columns": {
|
||||
"name": {"type": "string"},
|
||||
"ports": {"type": {"key": "string",
|
||||
"min": 0,
|
||||
"max": "unlimited"}}},
|
||||
"indexes": [["name"]],
|
||||
"isRoot": true},
|
||||
"Logical_Flow": {
|
||||
"columns": {
|
||||
"logical_datapath": {"type": {"key": {"type": "uuid",
|
||||
@@ -90,6 +98,29 @@
|
||||
"indexes": [["datapath", "tunnel_key"],
|
||||
["datapath", "name"]],
|
||||
"isRoot": true},
|
||||
"Meter": {
|
||||
"columns": {
|
||||
"name": {"type": "string"},
|
||||
"unit": {"type": {"key": {"type": "string",
|
||||
"enum": ["set", ["kbps", "pktps"]]}}},
|
||||
"bands": {"type": {"key": {"type": "uuid",
|
||||
"refTable": "Meter_Band",
|
||||
"refType": "strong"},
|
||||
"min": 1,
|
||||
"max": "unlimited"}}},
|
||||
"indexes": [["name"]],
|
||||
"isRoot": true},
|
||||
"Meter_Band": {
|
||||
"columns": {
|
||||
"action": {"type": {"key": {"type": "string",
|
||||
"enum": ["set", ["drop"]]}}},
|
||||
"rate": {"type": {"key": {"type": "integer",
|
||||
"minInteger": 1,
|
||||
"maxInteger": 4294967295}}},
|
||||
"burst_size": {"type": {"key": {"type": "integer",
|
||||
"minInteger": 0,
|
||||
"maxInteger": 4294967295}}}},
|
||||
"isRoot": false},
|
||||
"Datapath_Binding": {
|
||||
"columns": {
|
||||
"tunnel_key": {
|
||||
|
||||
+4
@@ -22,6 +22,8 @@ type Table struct {
|
||||
MaxRows int
|
||||
IsRoot bool
|
||||
Indexes [][]string
|
||||
|
||||
schema *Schema
|
||||
}
|
||||
|
||||
type Columns map[string]Column
|
||||
@@ -118,6 +120,8 @@ func ParseSchema(r io.Reader) (*Schema, error) {
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
schema: sch,
|
||||
}
|
||||
for colName, pcol := range ptbl.Columns {
|
||||
col := Column{
|
||||
|
||||
+96
@@ -293,6 +293,65 @@ func (tbl *Table) gen(w writer) {
|
||||
w.Writef(`}`)
|
||||
w.Writef(``)
|
||||
|
||||
for _, colName := range tbl.OrderedColumnNames() {
|
||||
var (
|
||||
col = tbl.Columns[colName]
|
||||
)
|
||||
if col.Type.Key.Type == Uuid && col.Type.Key.RefTable != "" {
|
||||
var (
|
||||
refTbl = tbl.schema.Tables[col.Type.Key.RefTable]
|
||||
refRowTyp = refTbl.rowTypeName()
|
||||
)
|
||||
w.Writef(`func (tbl %s) Find%sReferrer_%s(refUuid string) (r []*%s) {`, tblTyp, refRowTyp, col.Name, tbl.rowTypeName())
|
||||
w.Writef(` for i := range tbl {`)
|
||||
w.Writef(` row := &tbl[i]`)
|
||||
ordinal := col.ordinal()
|
||||
switch ordinal {
|
||||
case ordinalAtom:
|
||||
w.Writef(` if row.%s == refUuid {`, col.goField())
|
||||
case ordinalOptional:
|
||||
w.Writef(` if row.%s != nil && *row.%s == refUuid {`, col.goField(), col.goField())
|
||||
case ordinalMultiples:
|
||||
w.Writef(` for _, val := range row.%s {`, col.goField())
|
||||
w.Writef(` if val == refUuid {`)
|
||||
case ordinalMap:
|
||||
w.Writef(` for val := range row.%s {`, col.goField())
|
||||
w.Writef(` if val == refUuid {`)
|
||||
default:
|
||||
panic(fmt.Sprintf("table %s column %s: unexpected ordinal %#v",
|
||||
tbl.Name, col.Name, ordinal))
|
||||
}
|
||||
w.Writef(` r = append(r, row)`)
|
||||
w.Writef(` }`)
|
||||
if ordinal == ordinalMultiples || ordinal == ordinalMap {
|
||||
w.Writef(` }`)
|
||||
}
|
||||
w.Writef(` }`)
|
||||
w.Writef(` return r`)
|
||||
w.Writef(`}`)
|
||||
w.Writef(``)
|
||||
}
|
||||
if col.Type.Value.Type.isValid() &&
|
||||
col.Type.Value.Type == Uuid && col.Type.Value.RefTable != "" {
|
||||
var (
|
||||
refTbl = tbl.schema.Tables[col.Type.Value.RefTable]
|
||||
refRowTyp = refTbl.rowTypeName()
|
||||
)
|
||||
w.Writef(`func (tbl %s) Find%sReferrer2_%s(refUuid string) (r []*%s) {`, tblTyp, refRowTyp, col.Name, tbl.rowTypeName())
|
||||
w.Writef(` for i := range tbl {`)
|
||||
w.Writef(` row := &tbl[i]`)
|
||||
w.Writef(` for _, val := range row.%s {`, col.goField())
|
||||
w.Writef(` if val == refUuid {`)
|
||||
w.Writef(` r = append(r, row)`)
|
||||
w.Writef(` }`)
|
||||
w.Writef(` }`)
|
||||
w.Writef(` }`)
|
||||
w.Writef(` return r`)
|
||||
w.Writef(`}`)
|
||||
w.Writef(``)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
_, ok := tbl.Columns["external_ids"]
|
||||
g := func(f func()) {
|
||||
@@ -393,6 +452,43 @@ func (col *Column) goTags() string {
|
||||
return fmt.Sprintf("`json:\"%s\"`", col.Name)
|
||||
}
|
||||
|
||||
type ordinal int
|
||||
|
||||
const (
|
||||
ordinalAtom ordinal = iota
|
||||
ordinalOptional
|
||||
ordinalMultiples
|
||||
ordinalMap
|
||||
)
|
||||
|
||||
func (col *Column) ordinal() ordinal {
|
||||
var (
|
||||
typ = &col.Type
|
||||
atomV = typ.Value.Type
|
||||
)
|
||||
|
||||
if atomV.isValid() {
|
||||
return ordinalMap
|
||||
}
|
||||
if typ.MaxUnlimited {
|
||||
return ordinalMultiples
|
||||
}
|
||||
min, max := typ.Min, typ.Max
|
||||
if min == 0 {
|
||||
if max == 0 {
|
||||
panic(fmt.Sprintf("column type with min, max both being 0"))
|
||||
} else if max == 1 {
|
||||
return ordinalOptional
|
||||
} else {
|
||||
return ordinalMultiples
|
||||
}
|
||||
} else if max == 1 {
|
||||
return ordinalAtom
|
||||
} else {
|
||||
return ordinalMultiples
|
||||
}
|
||||
}
|
||||
|
||||
func (col *Column) funcNameSuffix() string {
|
||||
var (
|
||||
typ = &col.Type
|
||||
|
||||
+16
-11
@@ -1,6 +1,6 @@
|
||||
{"name": "Open_vSwitch",
|
||||
"version": "7.15.1",
|
||||
"cksum": "3682332033 23608",
|
||||
"version": "7.16.1",
|
||||
"cksum": "1452282319 23860",
|
||||
"tables": {
|
||||
"Open_vSwitch": {
|
||||
"columns": {
|
||||
@@ -47,7 +47,12 @@
|
||||
"min": 0, "max": "unlimited"}},
|
||||
"iface_types": {
|
||||
"type": {"key": {"type": "string"},
|
||||
"min": 0, "max": "unlimited"}}},
|
||||
"min": 0, "max": "unlimited"}},
|
||||
"dpdk_initialized": {
|
||||
"type": "boolean"},
|
||||
"dpdk_version": {
|
||||
"type": {"key": {"type": "string"},
|
||||
"min": 0, "max": 1}}},
|
||||
"isRoot": true,
|
||||
"maxRows": 1},
|
||||
"Bridge": {
|
||||
@@ -101,7 +106,7 @@
|
||||
"OpenFlow14",
|
||||
"OpenFlow15",
|
||||
"OpenFlow16"]]},
|
||||
"min": 0, "max": "unlimited"}},
|
||||
"min": 0, "max": "unlimited"}},
|
||||
"fail_mode": {
|
||||
"type": {"key": {"type": "string",
|
||||
"enum": ["set", ["standalone", "secure"]]},
|
||||
@@ -358,16 +363,16 @@
|
||||
"Flow_Table": {
|
||||
"columns": {
|
||||
"name": {
|
||||
"type": {"key": "string", "min": 0, "max": 1}},
|
||||
"type": {"key": "string", "min": 0, "max": 1}},
|
||||
"flow_limit": {
|
||||
"type": {"key": {"type": "integer", "minInteger": 0},
|
||||
"min": 0, "max": 1}},
|
||||
"type": {"key": {"type": "integer", "minInteger": 0},
|
||||
"min": 0, "max": 1}},
|
||||
"overflow_policy": {
|
||||
"type": {"key": {"type": "string",
|
||||
"enum": ["set", ["refuse", "evict"]]},
|
||||
"min": 0, "max": 1}},
|
||||
"type": {"key": {"type": "string",
|
||||
"enum": ["set", ["refuse", "evict"]]},
|
||||
"min": 0, "max": 1}},
|
||||
"groups": {
|
||||
"type": {"key": "string", "min": 0, "max": "unlimited"}},
|
||||
"type": {"key": "string", "min": 0, "max": "unlimited"}},
|
||||
"prefixes": {
|
||||
"type": {"key": "string", "min": 0, "max": 3}},
|
||||
"external_ids": {
|
||||
|
||||
Reference in New Issue
Block a user