Files
cloudpods/pkg/compute/models/guestnetworks.go
T

957 lines
28 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package models
import (
"context"
"database/sql"
"fmt"
"math/rand"
"regexp"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/netutils"
"yunion.io/x/pkg/util/regutils"
"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/compute/options"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
randutil "yunion.io/x/onecloud/pkg/util/rand"
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
const (
MAX_IFNAME_SIZE = 13
MAX_HINT_LEN = MAX_IFNAME_SIZE - 4 // 9
HINT_BASE_LEN = 6 // 6
HINT_RAND_LEN = MAX_HINT_LEN - HINT_BASE_LEN // 3
MAX_GUESTNIC_TO_SAME_NETWORK = 2
)
type SGuestnetworkManager struct {
SGuestJointsManager
SNetworkResourceBaseManager
}
var GuestnetworkManager *SGuestnetworkManager
func init() {
db.InitManager(func() {
GuestnetworkManager = &SGuestnetworkManager{
SGuestJointsManager: NewGuestJointsManager(
SGuestnetwork{},
"guestnetworks_tbl",
"guestnetwork",
"guestnetworks",
NetworkManager,
),
}
GuestnetworkManager.SetVirtualObject(GuestnetworkManager)
GuestnetworkManager.TableSpec().AddIndex(true, "ip_addr", "guest_id")
})
}
type SGuestnetwork struct {
SGuestJointsBase
NetworkId string `width:"36" charset:"ascii" nullable:"false" list:"user" `
// MAC地址
MacAddr string `width:"32" charset:"ascii" nullable:"false" list:"user"`
// IPv4地址
IpAddr string `width:"16" charset:"ascii" nullable:"false" list:"user"`
// IPv6地址
Ip6Addr string `width:"64" charset:"ascii" nullable:"true" list:"user"`
// 虚拟网卡驱动
Driver string `width:"16" charset:"ascii" nullable:"true" list:"user" update:"user"`
// 带宽限制,单位mbps
BwLimit int `nullable:"false" default:"0" list:"user"`
// 网卡序号
Index int8 `nullable:"false" default:"0" list:"user" update:"user"`
// 是否为虚拟接口(无IP
Virtual bool `default:"false" list:"user"`
// 虚拟网卡设备名称
Ifname string `width:"16" charset:"ascii" nullable:"true" list:"user" update:"user"`
// bind配对网卡MAC地址
TeamWith string `width:"32" charset:"ascii" nullable:"false" list:"user"`
// 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 {
return "network_id"
}
func (self *SGuestnetwork) GetExtraDetails(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
isList bool,
) (api.GuestnetworkDetails, error) {
return api.GuestnetworkDetails{}, nil
}
func (manager *SGuestnetworkManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []api.GuestnetworkDetails {
rows := make([]api.GuestnetworkDetails, len(objs))
guestRows := manager.SGuestJointsManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
netIds := make([]string, len(rows))
for i := range rows {
rows[i] = api.GuestnetworkDetails{
GuestJointResourceDetails: guestRows[i],
}
netIds[i] = objs[i].(*SGuestnetwork).NetworkId
iNet, _ := NetworkManager.FetchById(netIds[i])
net := iNet.(*SNetwork)
rows[i].WireId = net.WireId
}
netIdMaps, err := db.FetchIdNameMap2(NetworkManager, netIds)
if err != nil {
log.Errorf("FetchIdNameMap2 fail %s", err)
return rows
}
for i := range rows {
if name, ok := netIdMaps[netIds[i]]; ok {
rows[i].Network = name
}
}
return rows
}
func (manager *SGuestnetworkManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return false
}
func (gn *SGuestnetwork) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return false
}
const MAX_TRIES = 10
func (manager *SGuestnetworkManager) GenerateMac(netId string, suggestion string) (string, error) {
for tried := 0; tried < MAX_TRIES; tried += 1 {
var mac string
if len(suggestion) > 0 && regutils.MatchMacAddr(suggestion) {
mac = suggestion
suggestion = ""
} else {
b := make([]byte, 4)
_, err := rand.Read(b)
if err != nil {
log.Errorf("generate random mac failed: %s", err)
continue
}
mac = fmt.Sprintf("00:22:%02x:%02x:%02x:%02x", b[0], b[1], b[2], b[3])
}
q := manager.Query().Equals("mac_addr", mac)
if len(netId) > 0 {
q = q.Equals("network_id", netId)
}
cnt, err := q.CountWithError()
if err != nil {
log.Errorf("find mac %s error %s", mac, err)
return "", err
}
if cnt == 0 {
return mac, nil
}
}
return "", fmt.Errorf("maximal retry reached")
}
func (manager *SGuestnetworkManager) newGuestNetwork(
ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, network *SNetwork,
index int8, address string, mac string, driver string, bwLimit int,
virtual bool, reserved bool,
allocDir api.IPAllocationDirection,
requiredDesignatedIp bool,
reUseAddr bool,
ifname string, teamWithMac string,
) (*SGuestnetwork, error) {
gn := SGuestnetwork{}
gn.SetModelManager(GuestnetworkManager, &gn)
gn.GuestId = guest.Id
gn.NetworkId = network.Id
gn.Index = index
gn.Virtual = virtual
if len(driver) == 0 {
driver = "virtio"
}
gn.Driver = driver
if bwLimit >= 0 {
gn.BwLimit = bwLimit
}
lockman.LockObject(ctx, network)
defer lockman.ReleaseObject(ctx, network)
macAddr, err := manager.GenerateMac(network.Id, mac)
if err != nil {
return nil, err
}
if len(macAddr) == 0 {
log.Errorf("Mac address generate fails")
return nil, fmt.Errorf("mac address generate fails")
}
gn.MacAddr = macAddr
if !virtual {
if len(address) > 0 && reUseAddr {
ipAddr, err := netutils.NewIPV4Addr(address)
if err != nil {
return nil, errors.Wrapf(err, "Reuse invalid address %s", address)
}
if !network.IsAddressInRange(ipAddr) {
return nil, errors.Wrapf(httperrors.ErrOutOfRange, "%s not in network address range", address)
}
// if reuse Ip address, no need to check address availability
// assign it anyway
gn.IpAddr = address
} else {
addrTable := network.GetUsedAddresses()
recentAddrTable := manager.getRecentlyReleasedIPAddresses(network.Id, network.getAllocTimoutDuration())
ipAddr, err := network.GetFreeIP(ctx, userCred, addrTable, recentAddrTable, address, allocDir, reserved)
if err != nil {
return nil, err
}
if len(address) > 0 && ipAddr != address && requiredDesignatedIp {
return nil, fmt.Errorf("candidate ip %s is occupied!", address)
}
gn.IpAddr = ipAddr
}
if vpc := network.GetVpc(); vpc == nil {
return nil, fmt.Errorf("cannot find vpc of network %s(%s)", network.Id, network.Name)
} else if vpc.Id != api.DEFAULT_VPC_ID && vpc.GetProviderName() == api.CLOUD_PROVIDER_ONECLOUD {
var err error
GuestnetworkManager.lockAllocMappedAddr(ctx)
defer GuestnetworkManager.unlockAllocMappedAddr(ctx)
gn.MappedIpAddr, err = GuestnetworkManager.allocMappedIpAddr(ctx)
if err != nil {
return nil, err
}
}
}
ifname, err = gn.checkOrAllocateIfname(network, ifname)
if err != nil {
return nil, err
}
gn.Ifname = ifname
gn.TeamWith = teamWithMac
err = manager.TableSpec().Insert(ctx, &gn)
if err != nil {
return nil, err
}
return &gn, nil
}
func (self *SGuestnetwork) generateIfname(network *SNetwork, virtual bool, randomized bool) string {
// It may happen that external networks when synced can miss ifname hint
network.ensureIfnameHint()
pattern := regexp.MustCompile(`\W+`)
nName := pattern.ReplaceAllString(network.IfnameHint, "")
if len(nName) > MAX_IFNAME_SIZE-4 {
nName = nName[:(MAX_IFNAME_SIZE - 4)]
}
if virtual {
return fmt.Sprintf("%s-%s", nName, randutil.String(3))
} else {
ip, _ := netutils.NewIPV4Addr(self.IpAddr)
cliaddr := ip.CliAddr(network.GuestIpMask)
return fmt.Sprintf("%s-%d", nName, uint32(cliaddr))
}
}
func (man *SGuestnetworkManager) ifnameUsed(ifname string) bool {
// inviable names are always used
if ifname == "" {
return true
}
if len(ifname) > MAX_IFNAME_SIZE {
return true
}
isa := func(c byte) bool {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
}
if !isa(ifname[0]) {
return true
}
for i := range ifname[1:] {
c := ifname[i]
if isa(c) || c >= '0' || c <= '9' || c == '_' || c == '-' {
continue
}
return true
}
count, err := GuestnetworkManager.Query().Equals("ifname", ifname).CountWithError()
if err != nil {
panic(errors.Wrap(err, "query if ifname is used"))
}
return count > 0
}
func (self *SGuestnetwork) checkOrAllocateIfname(network *SNetwork, preferIfname string) (string, error) {
man := GuestnetworkManager
if !man.ifnameUsed(preferIfname) {
return preferIfname, nil
}
ifname := self.generateIfname(network, self.Virtual, false)
if !man.ifnameUsed(ifname) {
return ifname, nil
}
if !self.Virtual {
ifname = self.generateIfname(network, true, false)
}
found := false
for i := 0; i < 5; i++ {
if !man.ifnameUsed(ifname) {
found = true
break
}
ifname = self.generateIfname(network, true, true)
}
if !found {
return "", httperrors.NewConflictError("cannot allocate ifname")
}
return ifname, nil
}
func (self *SGuestnetwork) GetGuest() *SGuest {
guest, _ := GuestManager.FetchById(self.GuestId)
if guest != nil {
return guest.(*SGuest)
}
return nil
}
func (gn *SGuestnetwork) GetNetwork() *SNetwork {
net, _ := NetworkManager.FetchById(gn.NetworkId)
if net != nil {
return net.(*SNetwork)
}
return nil
}
func (self *SGuestnetwork) GetTeamGuestnetwork() (*SGuestnetwork, error) {
if len(self.TeamWith) > 0 {
return GuestnetworkManager.FetchByIdsAndIpMac(self.GuestId, self.NetworkId, "", self.TeamWith)
}
return nil, nil
}
func (self *SGuestnetwork) getJsonDescAtBaremetal(host *SHost) jsonutils.JSONObject {
network := self.GetNetwork()
hostwire := host.getHostwireOfIdAndMac(network.WireId, self.MacAddr)
return self.getJsonDescHostwire(network, hostwire)
}
func guestGetHostWireFromNetwork(host *SHost, network *SNetwork) (*SHostwire, error) {
hostwires := host.getHostwiresOfId(network.WireId)
var hostWire *SHostwire
for i := 0; i < len(hostwires); i++ {
if netInter, _ := NetInterfaceManager.FetchByMac(hostwires[i].MacAddr); netInter != nil {
if netInter.NicType != api.NIC_TYPE_IPMI {
hostWire = &hostwires[i]
break
}
}
}
if hostWire == nil {
return nil, fmt.Errorf("Host %s has no net interface on wire %s as guest network %s",
host.Name, network.WireId, api.NIC_TYPE_ADMIN)
}
return hostWire, nil
}
func (self *SGuestnetwork) getJsonDescAtHost(host *SHost) jsonutils.JSONObject {
network := self.GetNetwork()
if network.isOneCloudVpcNetwork() {
return self.getJsonDescOneCloudVpc(network)
} else {
hostWire, err := guestGetHostWireFromNetwork(host, network)
if err != nil {
log.Errorln(err)
}
return self.getJsonDescHostwire(network, hostWire)
}
}
func (self *SGuestnetwork) getJsonDescHostwire(network *SNetwork, hostwire *SHostwire) *jsonutils.JSONDict {
desc := self.getJsonDesc(network)
if hostwire != nil {
desc.Add(jsonutils.NewString(hostwire.Bridge), "bridge")
desc.Add(jsonutils.NewString(hostwire.WireId), "wire_id")
desc.Add(jsonutils.NewString(hostwire.Interface), "interface")
}
return desc
}
func (self *SGuestnetwork) getJsonDescOneCloudVpc(network *SNetwork) *jsonutils.JSONDict {
if self.MappedIpAddr == "" {
var (
err error
addr string
)
addr, err = GuestnetworkManager.allocMappedIpAddr(context.TODO())
if err != nil {
log.Errorf("getJsonDescOneCloudVpc: row %d: alloc mapped ipaddr: %v", self.RowId, err)
} else {
if _, err := db.Update(self, func() error {
self.MappedIpAddr = addr
return nil
}); err != nil {
log.Errorf("getJsonDescOneCloudVpc: row %d: db update mapped addr: %v", self.RowId, err)
self.MappedIpAddr = ""
}
}
}
vpc := network.GetVpc()
vpcDesc := jsonutils.NewDict()
vpcDesc.Set("id", jsonutils.NewString(vpc.Id))
vpcDesc.Set("provider", jsonutils.NewString(api.VPC_PROVIDER_OVN))
vpcDesc.Set("mapped_ip_addr", jsonutils.NewString(self.MappedIpAddr))
desc := self.getJsonDesc(network)
desc.Set("vpc", vpcDesc)
return desc
}
func (self *SGuestnetwork) getJsonDesc(network *SNetwork) *jsonutils.JSONDict {
desc := jsonutils.NewDict()
desc.Add(jsonutils.NewString(network.Name), "net")
desc.Add(jsonutils.NewString(self.NetworkId), "net_id")
desc.Add(jsonutils.NewString(self.MacAddr), "mac")
if self.Virtual {
desc.Add(jsonutils.JSONTrue, "virtual")
if len(self.TeamWith) > 0 {
teamGN, _ := self.GetTeamGuestnetwork()
if teamGN != nil {
log.Debugf("%#v", teamGN)
desc.Add(jsonutils.NewString(teamGN.IpAddr), "ip")
}
} else {
desc.Add(jsonutils.NewString(network.GetNetAddr().String()), "ip")
}
} else {
desc.Add(jsonutils.JSONFalse, "virtual")
desc.Add(jsonutils.NewString(self.IpAddr), "ip")
}
if len(network.GuestGateway) > 0 {
desc.Add(jsonutils.NewString(network.GuestGateway), "gateway")
}
desc.Add(jsonutils.NewString(network.GetDNS()), "dns")
desc.Add(jsonutils.NewString(network.GetDomain()), "domain")
routes := network.GetRoutes()
if routes != nil && len(routes) > 0 {
desc.Add(jsonutils.Marshal(routes), "routes")
}
desc.Add(jsonutils.NewString(self.GetIfname()), "ifname")
desc.Add(jsonutils.NewInt(int64(network.GuestIpMask)), "masklen")
desc.Add(jsonutils.NewString(self.Driver), "driver")
desc.Add(jsonutils.NewInt(int64(network.VlanId)), "vlan")
desc.Add(jsonutils.NewInt(int64(self.getBandwidth())), "bw")
desc.Add(jsonutils.NewInt(int64(self.getMtu())), "mtu")
desc.Add(jsonutils.NewInt(int64(self.Index)), "index")
vips := self.GetVirtualIPs()
if len(vips) > 0 {
desc.Add(jsonutils.NewStringArray(vips), "virtual_ips")
}
if len(network.ExternalId) > 0 {
desc.Add(jsonutils.NewString(network.ExternalId), "external_id")
}
if len(self.TeamWith) > 0 {
desc.Add(jsonutils.NewString(self.TeamWith), "team_with")
}
guest := self.getGuest()
if guest.GetHypervisor() != api.HYPERVISOR_KVM {
desc.Add(jsonutils.JSONTrue, "manual")
}
return desc
}
func (manager *SGuestnetworkManager) GetGuestByAddress(address string) *SGuest {
networks := manager.TableSpec().Instance()
guests := GuestManager.Query()
q := guests.Join(networks, sqlchemy.AND(
sqlchemy.IsFalse(networks.Field("deleted")),
sqlchemy.Equals(networks.Field("ip_addr"), address),
sqlchemy.Equals(networks.Field("guest_id"), guests.Field("id")),
))
guest := &SGuest{}
guest.SetModelManager(GuestManager, guest)
err := q.First(guest)
if err == nil {
return guest
}
return nil
}
func (self *SGuestnetwork) GetDetailedString() string {
network := self.GetNetwork()
return fmt.Sprintf("eth%d:%s/%d/%s/%d/%s/%s/%d", self.Index, self.IpAddr, network.GuestIpMask,
self.MacAddr, network.VlanId, network.Name, self.Driver, self.getBandwidth())
}
func (self *SGuestnetwork) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input api.GuestnetworkUpdateInput,
) (api.GuestnetworkUpdateInput, error) {
if input.Index != nil {
index := *input.Index
q := GuestnetworkManager.Query().SubQuery()
count, err := q.Query().Filter(sqlchemy.Equals(q.Field("guest_id"), self.GuestId)).
Filter(sqlchemy.NotEquals(q.Field("network_id"), self.NetworkId)).
Filter(sqlchemy.Equals(q.Field("index"), index)).CountWithError()
if err != nil {
return input, httperrors.NewInternalServerError("checkout nic index uniqueness fail %s", err)
}
if count > 0 {
return input, httperrors.NewDuplicateResourceError("NIC Index %d has been occupied", index)
}
}
var err error
input.GuestJointBaseUpdateInput, err = self.SGuestJointsBase.ValidateUpdateData(ctx, userCred, query, input.GuestJointBaseUpdateInput)
if err != nil {
return input, errors.Wrap(err, "SGuestJointsBase.ValidateUpdateData")
}
return input, nil
}
func (manager *SGuestnetworkManager) DeleteGuestNics(ctx context.Context, userCred mcclient.TokenCredential, gns []SGuestnetwork, reserve bool) error {
for i := range gns {
gn := gns[i]
guest := gn.GetGuest()
net := gn.GetNetwork()
if regutils.MatchIP4Addr(gn.IpAddr) || regutils.MatchIP6Addr(gn.Ip6Addr) {
net.updateDnsRecord(&gn, false)
if regutils.MatchIP4Addr(gn.IpAddr) {
// ??
// netman.get_manager().netmap_remove_node(gn.ip_addr)
}
}
// ??
// gn.Delete(ctx, userCred)
err := gn.Delete(ctx, userCred)
if err != nil {
log.Errorf("%s", err)
}
gn.LogDetachEvent(ctx, userCred, guest, net)
if reserve && regutils.MatchIP4Addr(gn.IpAddr) {
ReservedipManager.ReserveIP(userCred, net, gn.IpAddr, "Delete to reserve")
}
}
return nil
}
func (manager *SGuestnetworkManager) getGuestNicByIP(ip string, networkId string) (*SGuestnetwork, error) {
gn := SGuestnetwork{}
q := manager.Query()
q = q.Equals("ip_addr", ip).Equals("network_id", networkId)
err := q.First(&gn)
if err != nil {
if err != sql.ErrNoRows {
log.Errorf("getGuestNicByIP fail %s", err)
return nil, err
}
return nil, nil
}
gn.SetModelManager(manager, &gn)
return &gn, nil
}
func (self *SGuestnetwork) LogDetachEvent(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, network *SNetwork) {
if network == nil {
netTmp, _ := NetworkManager.FetchById(self.NetworkId)
network = netTmp.(*SNetwork)
}
db.OpsLog.LogDetachEvent(ctx, guest, network, userCred, nil)
}
func (self *SGuestnetwork) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
return db.DeleteModel(ctx, userCred, self)
}
func (self *SGuestnetwork) Detach(ctx context.Context, userCred mcclient.TokenCredential) error {
return db.DetachJoint(ctx, userCred, self)
}
func totalGuestNicCount(
scope rbacutils.TRbacScope,
ownerId mcclient.IIdentityProvider,
rangeObjs []db.IStandaloneModel,
includeSystem bool,
providers []string,
brands []string,
cloudEnv string,
) GuestnicsCount {
guests := GuestManager.Query().SubQuery()
hosts := HostManager.Query().SubQuery()
guestnics := GuestnetworkManager.Query().SubQuery()
q := guestnics.Query()
q = q.Join(guests, sqlchemy.Equals(guests.Field("id"), guestnics.Field("guest_id")))
q = q.Join(hosts, sqlchemy.Equals(guests.Field("host_id"), hosts.Field("id")))
q = CloudProviderFilter(q, hosts.Field("manager_id"), providers, brands, cloudEnv)
q = RangeObjectsFilter(q, rangeObjs, nil, hosts.Field("zone_id"), hosts.Field("manager_id"), hosts.Field("id"), nil)
switch scope {
case rbacutils.ScopeSystem:
// do nothing
case rbacutils.ScopeDomain:
q = q.Filter(sqlchemy.Equals(guests.Field("domain_id"), ownerId.GetProjectDomainId()))
case rbacutils.ScopeProject:
q = q.Filter(sqlchemy.Equals(guests.Field("tenant_id"), ownerId.GetProjectId()))
}
if !includeSystem {
q = q.Filter(sqlchemy.OR(sqlchemy.IsNull(guests.Field("is_system")),
sqlchemy.IsFalse(guests.Field("is_system"))))
}
return calculateNics(q)
}
type GuestnicsCount struct {
InternalNicCount int
InternalVirtualNicCount int
ExternalNicCount int
ExternalVirtualNicCount int
InternalBandwidth int
ExternalBandwidth int
}
func calculateNics(q *sqlchemy.SQuery) GuestnicsCount {
cnt := GuestnicsCount{}
gns := make([]SGuestnetwork, 0)
err := db.FetchModelObjects(GuestnetworkManager, q, &gns)
if err != nil {
log.Errorf("guestnics total count query error %s", err)
}
for _, gn := range gns {
if gn.IsExit() {
if gn.Virtual {
cnt.ExternalVirtualNicCount += 1
} else {
cnt.ExternalNicCount += 1
}
cnt.ExternalBandwidth += gn.BwLimit
} else {
if gn.Virtual {
cnt.InternalVirtualNicCount += 1
} else {
cnt.InternalNicCount += 1
}
cnt.InternalBandwidth += gn.BwLimit
}
}
return cnt
}
func (self *SGuestnetwork) IsExit() bool {
if self.IpAddr != "" {
addr, err := netutils.NewIPV4Addr(self.IpAddr)
if err == nil {
return netutils.IsExitAddress(addr)
}
}
net := self.GetNetwork()
if net != nil {
return net.IsExitNetwork()
}
return false
}
func (self *SGuestnetwork) getBandwidth() int {
if self.BwLimit > 0 && self.BwLimit <= api.MAX_BANDWIDTH {
return self.BwLimit
} else {
net := self.GetNetwork()
if net != nil {
wire := net.GetWire()
if wire != nil {
return wire.Bandwidth
}
}
return options.Options.DefaultBandwidth
}
}
func (self *SGuestnetwork) getMtu() int {
net := self.GetNetwork()
if net != nil {
wire := net.GetWire()
if wire != nil {
return wire.Mtu
}
}
return options.Options.DefaultMtu
}
func (self *SGuestnetwork) IsAllocated() bool {
if regutils.MatchMacAddr(self.MacAddr) && (self.Virtual || regutils.MatchIP4Addr(self.IpAddr)) {
return true
} else {
return false
}
}
func GetIPTenantIdPairs() {
/*
from guests import Guests
from hosts import Hosts
from sqlalchemy.sql.expression import bindparam
q = Guestnics.query(Guestnics.ip_addr, Guestnics.mac_addr,
bindparam('tunnel_key', None), # XXX: tunnel_key for VPC
Guests.tenant_id, Guests.name,
bindparam('tunnel_ip', None), Hosts.access_ip) \
.join(Guests, and_(Guests.id==Guestnics.guest_id,
Guests.deleted==False)) \
.join(Hosts, and_(Hosts.id==Guests.host_id,
Hosts.deleted==False))
return q.all()
*/
}
func (self *SGuestnetwork) GetVirtualIPs() []string {
ips := make([]string, 0)
guest := self.GetGuest()
net := self.GetNetwork()
for _, guestgroup := range guest.GetGroups() {
group := guestgroup.GetGroup()
groupnets, err := group.GetNetworks()
if err != nil {
continue
}
for _, groupnetwork := range groupnets {
gnet := groupnetwork.GetNetwork()
if gnet.WireId == net.WireId {
ips = append(ips, groupnetwork.IpAddr)
}
}
}
return ips
}
func (self *SGuestnetwork) GetIfname() string {
return self.Ifname
}
func (manager *SGuestnetworkManager) getRecentlyReleasedIPAddresses(networkId string, recentDuration time.Duration) map[string]bool {
if recentDuration == 0 {
return nil
}
since := time.Now().UTC().Add(-recentDuration)
q := manager.RawQuery("ip_addr")
q = q.Equals("network_id", networkId).IsTrue("deleted")
q = q.GT("deleted_at", since).Distinct()
rows, err := q.Rows()
if err != nil {
log.Errorf("GetRecentlyReleasedIPAddresses fail %s", err)
return nil
}
defer rows.Close()
ret := make(map[string]bool)
for rows.Next() {
var ip string
err = rows.Scan(&ip)
if err != nil {
log.Errorf("scan error %s", err)
} else {
ret[ip] = true
}
}
return ret
}
func (manager *SGuestnetworkManager) FilterByParams(q *sqlchemy.SQuery, params jsonutils.JSONObject) *sqlchemy.SQuery {
macStr := jsonutils.GetAnyString(params, []string{"mac", "mac_addr"})
if len(macStr) > 0 {
q = q.Filter(sqlchemy.Equals(q.Field("mac_addr"), macStr))
}
ipStr := jsonutils.GetAnyString(params, []string{"ipaddr", "ip_addr", "ip"})
if len(ipStr) > 0 {
q = q.Filter(sqlchemy.Equals(q.Field("ip_addr"), ipStr))
}
ip6Str := jsonutils.GetAnyString(params, []string{"ip6addr", "ip6_addr", "ip6"})
if len(ip6Str) > 0 {
q = q.Filter(sqlchemy.Equals(q.Field("ip6_addr"), ip6Str))
}
return q
}
func (manager *SGuestnetworkManager) FetchByIdsAndIpMac(guestId string, netId string, ipAddr string, mac string) (*SGuestnetwork, error) {
query := jsonutils.NewDict()
if len(mac) > 0 {
query.Add(jsonutils.NewString(mac), "mac_addr")
}
if len(ipAddr) > 0 {
query.Add(jsonutils.NewString(ipAddr), "ip_addr")
}
ign, err := db.FetchJointByIds(manager, guestId, netId, query)
if err != nil {
return nil, err
}
return ign.(*SGuestnetwork), nil
}
func (self *SGuestnetwork) GetShortDesc(ctx context.Context) *jsonutils.JSONDict {
desc := api.GuestnetworkShortDesc{}
if len(self.IpAddr) > 0 {
desc.IpAddr = self.IpAddr
desc.IsExit = self.IsExit()
}
if len(self.Ip6Addr) > 0 {
desc.Ip6Addr = self.Ip6Addr
}
desc.Mac = self.MacAddr
if len(self.TeamWith) > 0 {
desc.TeamWith = self.TeamWith
}
return jsonutils.Marshal(desc).(*jsonutils.JSONDict)
}
func (self *SGuestnetwork) ToNetworkConfig() *api.NetworkConfig {
net := self.GetNetwork()
if net == nil {
return nil
}
ret := &api.NetworkConfig{
Index: int(self.Index),
Network: net.Id,
Wire: net.GetWire().Id,
Mac: self.MacAddr,
Address: self.IpAddr,
Driver: self.Driver,
BwLimit: self.BwLimit,
Project: net.ProjectId,
Domain: net.DomainId,
Ifname: self.Ifname,
NetType: net.ServerType,
}
return ret
}
func (manager *SGuestnetworkManager) ListItemFilter(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.GuestnetworkListInput,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SGuestJointsManager.ListItemFilter(ctx, q, userCred, query.GuestJointsListInput)
if err != nil {
return nil, errors.Wrap(err, "SGuestJointsManager.ListItemFilter")
}
q, err = manager.SNetworkResourceBaseManager.ListItemFilter(ctx, q, userCred, query.NetworkFilterListInput)
if err != nil {
return nil, errors.Wrap(err, "SNetworkResourceBaseManager.ListItemFilter")
}
if len(query.MacAddr) > 0 {
q = q.In("mac_addr", query.MacAddr)
}
if len(query.IpAddr) > 0 {
q = q.In("ip_addr", query.IpAddr)
}
if len(query.Ip6Addr) > 0 {
q = q.In("ip6_addr", query.Ip6Addr)
}
if len(query.Driver) > 0 {
q = q.In("driver", query.Driver)
}
if len(query.Ifname) > 0 {
q = q.In("ifname", query.Ifname)
}
if len(query.TeamWith) > 0 {
q = q.In("team_with", query.TeamWith)
}
return q, nil
}
func (manager *SGuestnetworkManager) OrderByExtraFields(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.GuestnetworkListInput,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SGuestJointsManager.OrderByExtraFields(ctx, q, userCred, query.GuestJointsListInput)
if err != nil {
return nil, errors.Wrap(err, "SGuestJointsManager.OrderByExtraFields")
}
q, err = manager.SNetworkResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.NetworkFilterListInput)
if err != nil {
return nil, errors.Wrap(err, "SNetworkResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
func (manager *SGuestnetworkManager) ListItemExportKeys(ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
keys stringutils2.SSortedStrings,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SGuestJointsManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SGuestJointsManager.ListItemExportKeys")
}
if keys.ContainsAny(manager.SNetworkResourceBaseManager.GetExportKeys()...) {
q, err = manager.SNetworkResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SNetworkResourceBaseManager.ListItemExportKeys")
}
}
return q, nil
}