mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-06-23 03:16:59 +08:00
554 lines
14 KiB
Go
554 lines
14 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 candidate
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"yunion.io/x/jsonutils"
|
|
"yunion.io/x/log"
|
|
"yunion.io/x/pkg/errors"
|
|
"yunion.io/x/pkg/utils"
|
|
"yunion.io/x/sqlchemy"
|
|
|
|
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
|
|
computedb "yunion.io/x/onecloud/pkg/cloudcommon/db"
|
|
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
|
computemodels "yunion.io/x/onecloud/pkg/compute/models"
|
|
"yunion.io/x/onecloud/pkg/scheduler/api"
|
|
schedmodels "yunion.io/x/onecloud/pkg/scheduler/models"
|
|
)
|
|
|
|
type BaseHostDesc struct {
|
|
*computemodels.SHost
|
|
Region *computemodels.SCloudregion `json:"region"`
|
|
Zone *computemodels.SZone `json:"zone"`
|
|
Cloudprovider *computemodels.SCloudprovider `json:"cloudprovider"`
|
|
Cloudaccount *computemodels.SCloudaccount `json:"cloudaccount"`
|
|
Networks []*api.CandidateNetwork `json:"networks"`
|
|
NetInterfaces map[string][]computemodels.SNetInterface `json:"net_interfaces"`
|
|
Storages []*api.CandidateStorage `json:"storages"`
|
|
|
|
Tenants map[string]int64 `json:"tenants"`
|
|
HostSchedtags []computemodels.SSchedtag `json:"schedtags"`
|
|
|
|
InstanceGroups map[string]*api.CandidateGroup `json:"instance_groups"`
|
|
IpmiInfo types.SIPMIInfo `json:"ipmi_info"`
|
|
|
|
SharedDomains []string `json:"shared_domains"`
|
|
}
|
|
|
|
type baseHostGetter struct {
|
|
h *BaseHostDesc
|
|
}
|
|
|
|
func newBaseHostGetter(h *BaseHostDesc) *baseHostGetter {
|
|
return &baseHostGetter{h}
|
|
}
|
|
|
|
func (b baseHostGetter) Id() string {
|
|
return b.h.GetId()
|
|
}
|
|
|
|
func (b baseHostGetter) Name() string {
|
|
return b.h.GetName()
|
|
}
|
|
|
|
func (b baseHostGetter) Zone() *computemodels.SZone {
|
|
return b.h.Zone
|
|
}
|
|
|
|
func (b baseHostGetter) Host() *computemodels.SHost {
|
|
return b.h.SHost
|
|
}
|
|
|
|
func (b baseHostGetter) Cloudprovider() *computemodels.SCloudprovider {
|
|
return b.h.Cloudprovider
|
|
}
|
|
|
|
func (b baseHostGetter) IsPublic() bool {
|
|
return b.h.IsPublic
|
|
/*provider := b.Cloudprovider()
|
|
if provider == nil {
|
|
return false
|
|
}
|
|
account := provider.GetCloudaccount()
|
|
if account == nil {
|
|
return false
|
|
}
|
|
return account.ShareMode == computeapi.CLOUD_ACCOUNT_SHARE_MODE_SYSTEM*/
|
|
}
|
|
|
|
func (b baseHostGetter) DomainId() string {
|
|
return b.h.DomainId
|
|
}
|
|
|
|
func (b baseHostGetter) PublicScope() string {
|
|
return b.h.PublicScope
|
|
}
|
|
|
|
func (b baseHostGetter) SharedDomains() []string {
|
|
return b.h.SharedDomains
|
|
}
|
|
|
|
func (b baseHostGetter) Region() *computemodels.SCloudregion {
|
|
return b.h.Region
|
|
}
|
|
|
|
func (b baseHostGetter) HostType() string {
|
|
return b.h.HostType
|
|
}
|
|
|
|
func (b baseHostGetter) HostSchedtags() []computemodels.SSchedtag {
|
|
return b.h.HostSchedtags
|
|
}
|
|
|
|
func (b baseHostGetter) Storages() []*api.CandidateStorage {
|
|
return b.h.Storages
|
|
}
|
|
|
|
func (b baseHostGetter) InstanceGroups() map[string]*api.CandidateGroup {
|
|
return b.h.InstanceGroups
|
|
}
|
|
|
|
func (b baseHostGetter) GetFreeGroupCount(groupId string) (int, error) {
|
|
// Must Be
|
|
scg, ok := b.h.InstanceGroups[groupId]
|
|
if !ok {
|
|
return 0, fmt.Errorf("No such Group id")
|
|
}
|
|
free := scg.Granularity - scg.ReferCount
|
|
if free < 1 {
|
|
return 0, nil
|
|
}
|
|
pendingScg, ok := b.h.GetPendingUsage().InstanceGroupUsage[groupId]
|
|
if ok {
|
|
free -= pendingScg.ReferCount
|
|
}
|
|
return free, nil
|
|
}
|
|
|
|
func (b baseHostGetter) Networks() []*api.CandidateNetwork {
|
|
return b.h.Networks
|
|
}
|
|
|
|
func (b baseHostGetter) OvnCapable() bool {
|
|
return false
|
|
}
|
|
|
|
func (b baseHostGetter) ResourceType() string {
|
|
return reviseResourceType(b.h.ResourceType)
|
|
}
|
|
|
|
func (b baseHostGetter) NetInterfaces() map[string][]computemodels.SNetInterface {
|
|
return b.h.NetInterfaces
|
|
}
|
|
|
|
func (b baseHostGetter) Status() string {
|
|
return b.h.Status
|
|
}
|
|
|
|
func (b baseHostGetter) HostStatus() string {
|
|
return b.h.HostStatus
|
|
}
|
|
|
|
func (b baseHostGetter) Enabled() bool {
|
|
return b.h.GetEnabled()
|
|
}
|
|
|
|
func (b baseHostGetter) ProjectGuests() map[string]int64 {
|
|
return b.h.Tenants
|
|
}
|
|
|
|
func (b baseHostGetter) CreatingGuestCount() int {
|
|
return 0
|
|
}
|
|
|
|
func (b baseHostGetter) RunningCPUCount() int64 {
|
|
return 0
|
|
}
|
|
|
|
func (b baseHostGetter) TotalCPUCount(_ bool) int64 {
|
|
return int64(b.h.CpuCount)
|
|
}
|
|
|
|
func (b baseHostGetter) RunningMemorySize() int64 {
|
|
return 0
|
|
}
|
|
|
|
func (b baseHostGetter) TotalMemorySize(_ bool) int64 {
|
|
return int64(b.h.MemSize)
|
|
}
|
|
|
|
func (b baseHostGetter) GetFreeStorageSizeOfType(storageType string, useRsvd bool) int64 {
|
|
var size int64
|
|
for _, s := range b.Storages() {
|
|
if s.StorageType == storageType {
|
|
size += int64(float32(s.Capacity) * s.Cmtbound)
|
|
}
|
|
}
|
|
return size
|
|
}
|
|
|
|
func (b baseHostGetter) GetFreePort(netId string) int {
|
|
return b.h.GetFreePort(netId)
|
|
}
|
|
|
|
func (b baseHostGetter) GetIpmiInfo() types.SIPMIInfo {
|
|
return b.h.IpmiInfo
|
|
}
|
|
|
|
func (b baseHostGetter) GetQuotaKeys(s *api.SchedInfo) computemodels.SComputeResourceKeys {
|
|
return b.h.getQuotaKeys(s)
|
|
}
|
|
|
|
func reviseResourceType(resType string) string {
|
|
if resType == "" {
|
|
return computeapi.HostResourceTypeDefault
|
|
}
|
|
return resType
|
|
}
|
|
|
|
func newBaseHostDesc(host *computemodels.SHost) (*BaseHostDesc, error) {
|
|
host.ResourceType = reviseResourceType(host.ResourceType)
|
|
desc := &BaseHostDesc{
|
|
SHost: host,
|
|
}
|
|
|
|
if err := desc.fillCloudProvider(host); err != nil {
|
|
return nil, fmt.Errorf("Fill cloudprovider info error: %v", err)
|
|
}
|
|
|
|
if err := desc.fillNetworks(host); err != nil {
|
|
return nil, fmt.Errorf("Fill networks error: %v", err)
|
|
}
|
|
if err := desc.fillOnecloudVpcNetworks(); err != nil {
|
|
return nil, fmt.Errorf("Fill onecloud vpc networks error: %v", err)
|
|
}
|
|
|
|
if err := desc.fillZone(host); err != nil {
|
|
return nil, fmt.Errorf("Fill zone error: %v", err)
|
|
}
|
|
|
|
if err := desc.fillRegion(host); err != nil {
|
|
return nil, fmt.Errorf("Fill region error: %v", err)
|
|
}
|
|
|
|
if err := desc.fillResidentTenants(host); err != nil {
|
|
return nil, fmt.Errorf("Fill resident tenants error: %v", err)
|
|
}
|
|
|
|
if err := desc.fillStorages(host); err != nil {
|
|
return nil, fmt.Errorf("Fill storage error: %v", err)
|
|
}
|
|
|
|
if err := desc.fillSchedtags(); err != nil {
|
|
return nil, fmt.Errorf("Fill schedtag error: %v", err)
|
|
}
|
|
|
|
if err := desc.fillInstanceGroups(host); err != nil {
|
|
return nil, fmt.Errorf("Fill instance group error: %v", err)
|
|
}
|
|
|
|
if err := desc.fillIpmiInfo(host); err != nil {
|
|
return nil, fmt.Errorf("Fill ipmi info error: %v", err)
|
|
}
|
|
|
|
desc.fillSharedDomains()
|
|
|
|
return desc, nil
|
|
}
|
|
|
|
func (b BaseHostDesc) GetSchedDesc() *jsonutils.JSONDict {
|
|
desc := jsonutils.Marshal(b.SHost).(*jsonutils.JSONDict)
|
|
|
|
if b.Cloudprovider != nil {
|
|
p := b.Cloudprovider
|
|
cloudproviderDesc := jsonutils.NewDict()
|
|
cloudproviderDesc.Add(jsonutils.NewString(p.ProjectId), "tenant_id")
|
|
cloudproviderDesc.Add(jsonutils.NewString(p.Provider), "provider")
|
|
desc.Add(cloudproviderDesc, "cloudprovider")
|
|
}
|
|
|
|
return desc
|
|
}
|
|
|
|
func (b *BaseHostDesc) GetPendingUsage() *schedmodels.SPendingUsage {
|
|
usage, err := schedmodels.HostPendingUsageManager.GetPendingUsage(b.GetId())
|
|
if err != nil {
|
|
return schedmodels.NewPendingUsageBySchedInfo(b.GetId(), nil)
|
|
}
|
|
return usage
|
|
}
|
|
|
|
func (b *BaseHostDesc) GetFreePort(netId string) int {
|
|
var selNet *api.CandidateNetwork = nil
|
|
for _, n := range b.Networks {
|
|
if n.GetId() == netId {
|
|
selNet = n
|
|
break
|
|
}
|
|
}
|
|
if selNet == nil {
|
|
return 0
|
|
}
|
|
freeCount, _ := selNet.GetFreeAddressCount()
|
|
return freeCount
|
|
}
|
|
|
|
func (b BaseHostDesc) GetResourceType() string {
|
|
return b.ResourceType
|
|
}
|
|
|
|
func (b *BaseHostDesc) fillCloudProvider(host *computemodels.SHost) error {
|
|
b.Cloudprovider = host.GetCloudprovider()
|
|
if b.Cloudprovider != nil {
|
|
b.Cloudaccount = b.Cloudprovider.GetCloudaccount()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (b *BaseHostDesc) fillRegion(host *computemodels.SHost) error {
|
|
b.Region = host.GetRegion()
|
|
return nil
|
|
}
|
|
|
|
func (b *BaseHostDesc) fillZone(host *computemodels.SHost) error {
|
|
zone := host.GetZone()
|
|
b.Zone = zone
|
|
b.ZoneId = host.ZoneId
|
|
return nil
|
|
}
|
|
|
|
func (b *BaseHostDesc) fillResidentTenants(host *computemodels.SHost) error {
|
|
rets, err := HostResidentTenantCount(host.Id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
b.Tenants = rets
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *BaseHostDesc) fillSchedtags() error {
|
|
b.HostSchedtags = b.SHost.GetSchedtags()
|
|
return nil
|
|
}
|
|
|
|
func (b *BaseHostDesc) fillSharedDomains() error {
|
|
b.SharedDomains = b.SHost.GetSharedDomains()
|
|
return nil
|
|
}
|
|
|
|
func (b *BaseHostDesc) fillNetworks(host *computemodels.SHost) error {
|
|
hostId := host.Id
|
|
hostwires := computemodels.HostwireManager.Query().SubQuery()
|
|
sq := hostwires.Query(sqlchemy.DISTINCT("wire_id", hostwires.Field("wire_id"))).Equals("host_id", hostId)
|
|
networks := computemodels.NetworkManager.Query().SubQuery()
|
|
q := networks.Query().In("wire_id", sq)
|
|
|
|
nets := make([]computemodels.SNetwork, 0)
|
|
err := computedb.FetchModelObjects(computemodels.NetworkManager, q, &nets)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
b.Networks = make([]*api.CandidateNetwork, len(nets))
|
|
for idx, n := range nets {
|
|
b.Networks[idx] = &api.CandidateNetwork{
|
|
SNetwork: &nets[idx],
|
|
Schedtags: n.GetSchedtags(),
|
|
}
|
|
}
|
|
|
|
netifs := host.GetNetInterfaces()
|
|
netifIndexs := make(map[string][]computemodels.SNetInterface, 0)
|
|
for _, netif := range netifs {
|
|
if !netif.IsUsableServernic() {
|
|
continue
|
|
}
|
|
wire := netif.GetWire()
|
|
if wire == nil {
|
|
continue
|
|
}
|
|
if _, exist := netifIndexs[wire.Id]; !exist {
|
|
netifIndexs[wire.Id] = make([]computemodels.SNetInterface, 0)
|
|
}
|
|
netifIndexs[wire.Id] = append(netifIndexs[wire.Id], netif)
|
|
}
|
|
b.NetInterfaces = netifIndexs
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *BaseHostDesc) fillOnecloudVpcNetworks() error {
|
|
nets := computemodels.NetworkManager.Query()
|
|
wires := computemodels.WireManager.Query().SubQuery()
|
|
vpcs := computemodels.VpcManager.Query().SubQuery()
|
|
regions := computemodels.CloudregionManager.Query().SubQuery()
|
|
q := nets.AppendField(nets.QueryFields()...)
|
|
q = q.AppendField(
|
|
vpcs.Field("id", "vpc_id"),
|
|
regions.Field("provider"),
|
|
)
|
|
q = q.Join(wires, sqlchemy.Equals(wires.Field("id"), nets.Field("wire_id")))
|
|
q = q.Join(vpcs, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id")))
|
|
q = q.Join(regions, sqlchemy.Equals(regions.Field("id"), vpcs.Field("cloudregion_id")))
|
|
q = q.Filter(sqlchemy.AND(
|
|
sqlchemy.Equals(regions.Field("provider"), computeapi.CLOUD_PROVIDER_ONECLOUD),
|
|
sqlchemy.NOT(sqlchemy.Equals(vpcs.Field("id"), computeapi.DEFAULT_VPC_ID)),
|
|
))
|
|
|
|
type Row struct {
|
|
computemodels.SNetwork
|
|
VpcId string
|
|
Provider string
|
|
}
|
|
rows := []Row{}
|
|
if err := q.All(&rows); err != nil {
|
|
return errors.Wrap(err, "query onecloud vpc networks")
|
|
}
|
|
for i := range rows {
|
|
row := &rows[i]
|
|
candidateNet := &api.CandidateNetwork{
|
|
SNetwork: &row.SNetwork,
|
|
VpcId: row.VpcId,
|
|
Provider: row.Provider,
|
|
}
|
|
b.Networks = append(b.Networks, candidateNet)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (b *BaseHostDesc) fillStorages(host *computemodels.SHost) error {
|
|
ss := make([]*api.CandidateStorage, 0)
|
|
for _, s := range host.GetHoststorages() {
|
|
storage := s.GetStorage()
|
|
ss = append(ss, &api.CandidateStorage{
|
|
SStorage: storage,
|
|
Schedtags: storage.GetSchedtags(),
|
|
})
|
|
}
|
|
b.Storages = ss
|
|
return nil
|
|
}
|
|
|
|
func (b *BaseHostDesc) fillInstanceGroups(host *computemodels.SHost) error {
|
|
candidateSet := make(map[string]*api.CandidateGroup)
|
|
groups, groupSet, err := host.InstanceGroups()
|
|
if err != nil {
|
|
b.InstanceGroups = candidateSet
|
|
return err
|
|
}
|
|
for i := range groups {
|
|
id := groups[i].GetId()
|
|
candidateSet[id] = &api.CandidateGroup{
|
|
SGroup: &groups[i],
|
|
ReferCount: groupSet[id],
|
|
}
|
|
}
|
|
b.InstanceGroups = candidateSet
|
|
return nil
|
|
}
|
|
|
|
func (b *BaseHostDesc) fillIpmiInfo(host *computemodels.SHost) error {
|
|
info, err := host.GetIpmiInfo()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
b.IpmiInfo = info
|
|
return nil
|
|
}
|
|
|
|
func (h *BaseHostDesc) GetEnableStatus() string {
|
|
if h.GetEnabled() {
|
|
return "enable"
|
|
}
|
|
return "disable"
|
|
}
|
|
|
|
func (h *BaseHostDesc) GetHostType() string {
|
|
if h.HostType == api.HostTypeBaremetal && h.IsBaremetal {
|
|
return api.HostTypeBaremetal
|
|
}
|
|
return h.HostType
|
|
}
|
|
|
|
func (h *BaseHostDesc) getQuotaKeys(s *api.SchedInfo) computemodels.SComputeResourceKeys {
|
|
computeKeys := computemodels.SComputeResourceKeys{}
|
|
computeKeys.DomainId = s.Domain
|
|
computeKeys.ProjectId = s.Project
|
|
if h.Cloudprovider != nil {
|
|
computeKeys.Provider = h.Cloudaccount.Provider
|
|
computeKeys.Brand = h.Cloudaccount.Brand
|
|
computeKeys.CloudEnv = h.Cloudaccount.GetCloudEnv()
|
|
computeKeys.AccountId = h.Cloudaccount.Id
|
|
computeKeys.ManagerId = h.Cloudprovider.Id
|
|
} else {
|
|
computeKeys.Provider = computeapi.CLOUD_PROVIDER_ONECLOUD
|
|
computeKeys.Brand = computeapi.ONECLOUD_BRAND_ONECLOUD
|
|
computeKeys.CloudEnv = computeapi.CLOUD_ENV_ON_PREMISE
|
|
computeKeys.AccountId = ""
|
|
computeKeys.ManagerId = ""
|
|
}
|
|
computeKeys.RegionId = h.Region.Id
|
|
computeKeys.ZoneId = h.Zone.Id
|
|
computeKeys.Hypervisor = computeapi.HOSTTYPE_HYPERVISOR[h.HostType]
|
|
return computeKeys
|
|
}
|
|
|
|
func HostsResidentTenantStats(hostIDs []string) (map[string]map[string]interface{}, error) {
|
|
residentTenantStats, err := FetchHostsResidentTenants(hostIDs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
stat3 := make([]utils.StatItem3, len(residentTenantStats))
|
|
for i, item := range residentTenantStats {
|
|
stat3[i] = item
|
|
}
|
|
return utils.ToStatDict3(stat3)
|
|
}
|
|
|
|
func HostResidentTenantCount(id string) (map[string]int64, error) {
|
|
residentTenantDict, err := HostsResidentTenantStats([]string{id})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
tenantMap, ok := residentTenantDict[id]
|
|
if !ok {
|
|
log.V(10).Infof("Not found host ID: %s when fill resident tenants, may be no guests on it.", id)
|
|
return nil, nil
|
|
}
|
|
rets := make(map[string]int64, len(tenantMap))
|
|
for tenantID, countObj := range tenantMap {
|
|
rets[tenantID] = countObj.(int64)
|
|
}
|
|
return rets, nil
|
|
}
|
|
|
|
type DescBuilder struct {
|
|
actor BuildActor
|
|
}
|
|
|
|
func NewDescBuilder(act BuildActor) *DescBuilder {
|
|
return &DescBuilder{
|
|
actor: act,
|
|
}
|
|
}
|
|
|
|
func (d *DescBuilder) Build(ids []string) ([]interface{}, error) {
|
|
return d.actor.Do(ids)
|
|
}
|