Files
cloudpods/pkg/compute/models/guestnetworks.go
T
2020-01-03 13:58:05 +08:00

786 lines
24 KiB
Go

// 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"
"crypto/md5"
"crypto/rand"
"database/sql"
"fmt"
"io"
"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"
"yunion.io/x/onecloud/pkg/util/rbacutils"
)
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
}
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" ` // Column(VARCHAR(36, charset='ascii'), nullable=False)
MacAddr string `width:"32" charset:"ascii" nullable:"false" list:"user"` // Column(VARCHAR(32, charset='ascii'), nullable=False)
IpAddr string `width:"16" charset:"ascii" nullable:"false" list:"user"` // Column(VARCHAR(16, charset='ascii'), nullable=True)
Ip6Addr string `width:"64" charset:"ascii" nullable:"true" list:"user"` // Column(VARCHAR(64, charset='ascii'), nullable=True)
Driver string `width:"16" charset:"ascii" nullable:"true" list:"user" update:"user"` // Column(VARCHAR(16, charset='ascii'), nullable=True)
BwLimit int `nullable:"false" default:"0" list:"user"` // Column(Integer, nullable=False, default=0) # Mbps
Index int8 `nullable:"false" default:"0" list:"user" update:"user"` // Column(TINYINT, nullable=False, default=0)
Virtual bool `default:"false" list:"user"` // Column(Boolean, default=False)
Ifname string `width:"16" charset:"ascii" nullable:"true" list:"user" update:"user"` // Column(VARCHAR(16, charset='ascii'), nullable=True)
TeamWith string `width:"32" charset:"ascii" nullable:"false" list:"user"`
}
func (manager *SGuestnetworkManager) GetSlaveFieldName() string {
return "network_id"
}
func (joint *SGuestnetwork) Master() db.IStandaloneModel {
return db.JointMaster(joint)
}
func (joint *SGuestnetwork) Slave() db.IStandaloneModel {
return db.JointSlave(joint)
}
func (self *SGuestnetwork) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict {
extra := self.SGuestJointsBase.GetCustomizeColumns(ctx, userCred, query)
return db.JointModelExtra(self, extra)
}
func (self *SGuestnetwork) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*jsonutils.JSONDict, error) {
extra, err := self.SGuestJointsBase.GetExtraDetails(ctx, userCred, query)
if err != nil {
return nil, err
}
return db.JointModelExtra(self, extra), nil
}
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
}
}
ifname, err = gn.checkOrAllocateIfname(network, ifname)
if err != nil {
return nil, err
}
gn.Ifname = ifname
gn.TeamWith = teamWithMac
err = manager.TableSpec().Insert(&gn)
if err != nil {
return nil, err
}
return &gn, nil
}
func (self *SGuestnetwork) getVirtualRand(width int, randomized bool) string {
hash := md5.New()
io.WriteString(hash, self.GuestId)
io.WriteString(hash, self.NetworkId)
if randomized {
io.WriteString(hash, fmt.Sprintf("%d", time.Now().Unix()))
}
hex := fmt.Sprintf("%x", hash.Sum(nil))
return hex[:width]
}
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 {
rand := self.getVirtualRand(3, randomized)
return fmt.Sprintf("%s-%s", nName, rand)
} 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.getGeneralJsonDesc(host, 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()
hostWire, err := guestGetHostWireFromNetwork(host, network)
if err != nil {
log.Errorln(err)
}
return self.getGeneralJsonDesc(host, network, hostWire)
}
func (self *SGuestnetwork) getGeneralJsonDesc(host *SHost, network *SNetwork, hostwire *SHostwire) jsonutils.JSONObject {
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.NewString(hostwire.Bridge), "bridge")
desc.Add(jsonutils.NewString(hostwire.WireId), "wire_id")
desc.Add(jsonutils.NewInt(int64(network.VlanId)), "vlan")
desc.Add(jsonutils.NewString(hostwire.Interface), "interface")
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, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
if data.Contains("index") {
index, err := data.Int("index")
if err != nil {
return nil, httperrors.NewInternalServerError("fail to fetch index %s", err)
}
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 nil, httperrors.NewInternalServerError("checkout nic index uniqueness fail %s", err)
}
if count > 0 {
return nil, httperrors.NewDuplicateResourceError("NIC Index %d has been occupied", index)
}
}
return self.SJointResourceBase.ValidateUpdateData(ctx, userCred, query, data)
}
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"))
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 := jsonutils.NewDict()
if len(self.IpAddr) > 0 {
desc.Add(jsonutils.NewString(self.IpAddr), "ip_addr")
desc.Add(jsonutils.NewBool(self.IsExit()), "is_exit")
}
if len(self.Ip6Addr) > 0 {
desc.Add(jsonutils.NewString(self.Ip6Addr), "ip6_addr")
}
desc.Add(jsonutils.NewString(self.MacAddr), "mac")
if len(self.TeamWith) > 0 {
desc.Add(jsonutils.NewString(self.TeamWith), "team_with")
}
return desc
}
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
}