Files
cloudpods/pkg/multicloud/openstack/hypervisor.go
2020-12-28 09:50:44 +08:00

361 lines
8.2 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 openstack
import (
"fmt"
"net/url"
"strconv"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
type CpuInfo struct {
Arch string
Model string
Vendor string
Feature []string
Topology map[string]int
}
type Service struct {
Host string
ID string
DisabledReason string
}
type SResource struct {
CPU int
DiskGB int
Host string
MemoryMb int
Project string
}
type SHypervisor struct {
multicloud.SHostBase
zone *SZone
CpuInfo string
Aggregates []string
CurrentWorkload int
Status string
State string
DiskAvailableLeast int
HostIP string
FreeDiskGB int
FreeRamMB int
HypervisorHostname string
HypervisorType string
HypervisorVersion string
Id string
LocalGB int
LocalGbUsed int
MemoryMB int
MemoryMbUsed int
RunningVms int
Service Service
Vcpus int
VcpusUsed int8
}
func (host *SHypervisor) GetId() string {
return host.Id
}
func (host *SHypervisor) GetName() string {
if len(host.HypervisorHostname) > 0 {
return host.HypervisorHostname
}
return host.Service.Host
}
func (host *SHypervisor) GetGlobalId() string {
return host.GetId()
}
func (host *SHypervisor) GetIWires() ([]cloudprovider.ICloudWire, error) {
vpcs, err := host.zone.region.GetIVpcs()
if err != nil {
return nil, errors.Wrapf(err, "GetIVpc")
}
ret := []cloudprovider.ICloudWire{}
for i := range vpcs {
iwires, err := vpcs[i].GetIWires()
if err != nil {
return nil, errors.Wrapf(err, "GetIWires")
}
ret = append(ret, iwires...)
}
return ret, nil
}
func (host *SHypervisor) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
istorages := []cloudprovider.ICloudStorage{}
storages, err := host.zone.region.GetStorageTypes()
if err != nil && errors.Cause(err) != ErrNoEndpoint {
return nil, errors.Wrap(err, "GetStorageTypes")
}
for i := range storages {
storages[i].zone = host.zone
istorages = append(istorages, &storages[i])
}
nova := &SNovaStorage{host: host, zone: host.zone}
istorages = append(istorages, nova)
return istorages, nil
}
func (host *SHypervisor) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
return host.zone.GetIStorageById(id)
}
func (host *SHypervisor) GetIVMs() ([]cloudprovider.ICloudVM, error) {
instances, err := host.zone.region.GetInstances(host.HypervisorHostname)
if err != nil {
return nil, err
}
iVMs := []cloudprovider.ICloudVM{}
for i := 0; i < len(instances); i++ {
instances[i].host = host
iVMs = append(iVMs, &instances[i])
}
return iVMs, nil
}
func (host *SHypervisor) GetIVMById(gid string) (cloudprovider.ICloudVM, error) {
instance, err := host.zone.region.GetInstance(gid)
if err != nil {
return nil, err
}
instance.host = host
return instance, nil
}
func (host *SHypervisor) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
instance, err := host.zone.CreateVM(host.Service.Host, desc)
if err != nil {
return nil, errors.Wrap(err, "CreateVM")
}
instance.host = host
return instance, nil
}
func (host *SHypervisor) GetEnabled() bool {
switch host.Status {
case "enabled", "":
return true
default:
return false
}
}
func (host *SHypervisor) GetAccessIp() string {
return host.HostIP
}
func (host *SHypervisor) GetAccessMac() string {
return ""
}
func (host *SHypervisor) GetSysInfo() jsonutils.JSONObject {
info := jsonutils.NewDict()
info.Add(jsonutils.NewString(CLOUD_PROVIDER_OPENSTACK), "manufacture")
return info
}
func (host *SHypervisor) GetSN() string {
return ""
}
func (host *SHypervisor) GetCpuCmtbound() float32 {
aggregates, err := host.zone.region.GetAggregates()
if err != nil || len(aggregates) == 0 {
return 16.0
}
CpuCmtbound := 1000000.0
for _, aggregate := range aggregates {
if utils.IsInStringArray(host.GetName(), aggregate.Hosts) {
if _cmtbound, ok := aggregate.Metadata["cpu_allocation_ratio"]; ok {
cmtbound, err := strconv.ParseFloat(_cmtbound, 32)
if err == nil && CpuCmtbound > cmtbound {
CpuCmtbound = cmtbound
}
}
}
}
if CpuCmtbound >= 1000000.0 {
return 16.0
}
return float32(CpuCmtbound)
}
func (host *SHypervisor) GetMemCmtbound() float32 {
aggregates, err := host.zone.region.GetAggregates()
if err != nil || len(aggregates) == 0 {
return 1.5
}
MemCmtbound := 1000000.0
for _, aggregate := range aggregates {
if utils.IsInStringArray(host.GetName(), aggregate.Hosts) {
if _cmtbound, ok := aggregate.Metadata["ram_allocation_ratio"]; ok {
cmtbound, err := strconv.ParseFloat(_cmtbound, 32)
if err == nil && MemCmtbound > cmtbound {
MemCmtbound = cmtbound
}
}
}
}
if MemCmtbound >= 1000000.0 {
return 1.5
}
return float32(MemCmtbound)
}
func (host *SHypervisor) GetCpuCount() int {
if host.Vcpus > 0 {
return host.Vcpus
}
host.Refresh()
return host.Vcpus
}
func (host *SHypervisor) GetNodeCount() int8 {
if len(host.CpuInfo) > 0 {
info, err := jsonutils.Parse([]byte(host.CpuInfo))
if err == nil {
cpuInfo := &CpuInfo{}
err = info.Unmarshal(cpuInfo)
if err == nil {
if cell, ok := cpuInfo.Topology["cells"]; ok {
return int8(cell)
}
}
}
}
return int8(host.GetCpuCount())
}
func (host *SHypervisor) GetCpuDesc() string {
return host.CpuInfo
}
func (host *SHypervisor) GetCpuMhz() int {
return 0
}
func (host *SHypervisor) GetMemSizeMB() int {
if host.MemoryMB > 0 {
return host.MemoryMB
}
host.Refresh()
return host.MemoryMB
}
func (host *SHypervisor) GetStorageSizeMB() int {
return host.LocalGB * 1024
}
func (host *SHypervisor) GetStorageType() string {
return api.DISK_TYPE_HYBRID
}
func (host *SHypervisor) GetHostType() string {
return api.HOST_TYPE_OPENSTACK
}
func (host *SHypervisor) GetHostStatus() string {
switch host.State {
case "up", "":
return api.HOST_ONLINE
default:
return api.HOST_OFFLINE
}
}
func (host *SHypervisor) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) {
return nil, cloudprovider.ErrNotSupported
}
func (host *SHypervisor) GetIsMaintenance() bool {
return false
}
func (host *SHypervisor) GetVersion() string {
version, _ := host.zone.region.GetMaxVersion(OPENSTACK_SERVICE_COMPUTE)
return version
}
func (host *SHypervisor) GetStatus() string {
return api.HOST_STATUS_RUNNING
}
func (host *SHypervisor) IsEmulated() bool {
return false
}
func (host *SHypervisor) Refresh() error {
return nil
}
func (region *SRegion) GetHypervisors() ([]SHypervisor, error) {
hypervisors := []SHypervisor{}
resource := "/os-hypervisors/detail"
query := url.Values{}
for {
resp, err := region.ecsList(resource, query)
if err != nil {
return nil, errors.Wrap(err, "ecsList")
}
part := struct {
Hypervisors []SHypervisor
HypervisorsLinks SNextLinks
}{}
err = resp.Unmarshal(&part)
if err != nil {
return nil, errors.Wrap(err, "resp.Unmarshal")
}
hypervisors = append(hypervisors, part.Hypervisors...)
marker := part.HypervisorsLinks.GetNextMark()
if len(marker) == 0 {
break
}
query.Set("marker", marker)
}
return hypervisors, nil
}
func (region *SRegion) GetHypervisor(id string) (*SHypervisor, error) {
resource := fmt.Sprintf("/os-hypervisors/%s", id)
resp, err := region.ecsGet(resource)
if err != nil {
return nil, errors.Wrap(err, "ecsGet")
}
hypervisor := &SHypervisor{}
err = resp.Unmarshal(hypervisor, "hypervisor")
if err != nil {
return nil, errors.Wrap(err, "resp.Unmarshal")
}
return hypervisor, nil
}