mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-10-30 18:23:35 +08:00
170 lines
4.9 KiB
Go
170 lines
4.9 KiB
Go
package models
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"yunion.io/x/log"
|
|
"yunion.io/x/pkg/util/netutils"
|
|
"yunion.io/x/pkg/util/regutils"
|
|
|
|
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
|
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
|
|
"yunion.io/x/onecloud/pkg/mcclient"
|
|
)
|
|
|
|
type SLoadbalancernetworkManager struct {
|
|
db.SVirtualJointResourceBaseManager
|
|
}
|
|
|
|
var LoadbalancernetworkManager *SLoadbalancernetworkManager
|
|
|
|
func init() {
|
|
db.InitManager(func() {
|
|
LoadbalancernetworkManager = &SLoadbalancernetworkManager{
|
|
SVirtualJointResourceBaseManager: db.NewVirtualJointResourceBaseManager(
|
|
SLoadbalancerNetwork{},
|
|
"loadbalancernetworks_tbl",
|
|
"loadbalancernetwork",
|
|
"loadbalancernetworks",
|
|
LoadbalancerManager,
|
|
NetworkManager,
|
|
),
|
|
}
|
|
})
|
|
}
|
|
|
|
type SLoadbalancerNetwork struct {
|
|
db.SVirtualJointResourceBase
|
|
|
|
LoadbalancerId string `width:"36" charset:"ascii" nullable:"false" list:"admin"`
|
|
NetworkId string `width:"36" charset:"ascii" nullable:"false" list:"admin"`
|
|
IpAddr string `width:"16" charset:"ascii" list:"admin"`
|
|
}
|
|
|
|
func (ln *SLoadbalancerNetwork) Network() *SNetwork {
|
|
network, _ := ln.GetModelManager().FetchById(ln.NetworkId)
|
|
if network != nil {
|
|
return network.(*SNetwork)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type SLoadbalancerNetworkRequestData struct {
|
|
Loadbalancer *SLoadbalancer
|
|
NetworkId string
|
|
reserved bool // allocate from reserved
|
|
Address string // the address user intends to use
|
|
strategy IPAddlocationDirection // allocate bottom up, top down, randomly
|
|
}
|
|
|
|
type SLoadbalancerNetworkDeleteData struct {
|
|
loadbalancer *SLoadbalancer
|
|
reserve bool // reserve after delete
|
|
}
|
|
|
|
func (m *SLoadbalancernetworkManager) NewLoadbalancerNetwork(ctx context.Context, userCred mcclient.TokenCredential, req *SLoadbalancerNetworkRequestData) (*SLoadbalancerNetwork, error) {
|
|
networkMan := db.GetModelManager("network").(*SNetworkManager)
|
|
if networkMan == nil {
|
|
return nil, fmt.Errorf("failed getting network manager")
|
|
}
|
|
im, err := networkMan.FetchById(req.NetworkId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
network := im.(*SNetwork)
|
|
ln := &SLoadbalancerNetwork{
|
|
LoadbalancerId: req.Loadbalancer.Id,
|
|
NetworkId: network.Id,
|
|
}
|
|
ln.SetModelManager(m)
|
|
|
|
lockman.LockObject(ctx, network)
|
|
defer lockman.ReleaseObject(ctx, network)
|
|
usedMap := network.GetUsedAddresses()
|
|
recentReclaimed := map[string]bool{}
|
|
ipAddr, err := network.GetFreeIP(ctx, userCred,
|
|
usedMap, recentReclaimed, req.Address, req.strategy, req.reserved)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ln.IpAddr = ipAddr
|
|
err = m.TableSpec().Insert(ln)
|
|
if err != nil {
|
|
// NOTE no need to free ipAddr as GetFreeIP has no side effect
|
|
return nil, err
|
|
}
|
|
return ln, err
|
|
}
|
|
|
|
func (m *SLoadbalancernetworkManager) DeleteLoadbalancerNetwork(ctx context.Context, userCred mcclient.TokenCredential, req *SLoadbalancerNetworkDeleteData) error {
|
|
q := m.Query().Equals("loadbalancer_id", req.loadbalancer.Id)
|
|
lns := []SLoadbalancerNetwork{}
|
|
err := db.FetchModelObjects(m, q, &lns)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// TODO pack up errors and continue, then return as a whole
|
|
for _, ln := range lns {
|
|
err := ln.Delete(ctx, userCred)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if req.reserve && regutils.MatchIP4Addr(ln.IpAddr) {
|
|
note := fmt.Sprintf("reserved from loadbalancer delete: %s",
|
|
req.loadbalancer.Id)
|
|
reservedIpMan := db.GetModelManager("reservedip").(*SReservedipManager)
|
|
network := ln.Network()
|
|
err := reservedIpMan.ReserveIP(userCred, network, ln.IpAddr, note)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *SLoadbalancernetworkManager) SyncLoadbalancerNetwork(ctx context.Context, userCred mcclient.TokenCredential, req *SLoadbalancerNetworkRequestData) error {
|
|
_network, err := NetworkManager.FetchById(req.NetworkId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
network := _network.(*SNetwork)
|
|
ip, err := netutils.NewIPV4Addr(req.Address)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !network.isAddressInRange(ip) {
|
|
return fmt.Errorf("address %s is not in the range of network %s(%s)", req.Address, network.Id, network.Name)
|
|
}
|
|
q := m.Query().Equals("loadbalancer_id", req.Loadbalancer.Id).Equals("network_id", req.NetworkId)
|
|
lns := []SLoadbalancerNetwork{}
|
|
if err := db.FetchModelObjects(m, q, &lns); err != nil {
|
|
return err
|
|
}
|
|
if len(lns) == 0 {
|
|
ln := &SLoadbalancerNetwork{LoadbalancerId: req.Loadbalancer.Id, NetworkId: req.NetworkId, IpAddr: req.Address}
|
|
return m.TableSpec().Insert(ln)
|
|
}
|
|
for i := 0; i < len(lns); i++ {
|
|
if i == 0 {
|
|
if lns[i].IpAddr != req.Address {
|
|
_, err := db.Update(&lns[i], func() error {
|
|
lns[i].IpAddr = req.Address
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
log.Errorf("update loadbalancer network ipaddr %s error: %v", lns[i].LoadbalancerId, err)
|
|
}
|
|
}
|
|
} else {
|
|
lns[i].Delete(ctx, userCred)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (lbNetwork *SLoadbalancerNetwork) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
|
|
return db.DeleteModel(ctx, userCred, lbNetwork)
|
|
}
|