mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-05-19 07:37:55 +08:00
423 lines
11 KiB
Go
423 lines
11 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 nutanix
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/url"
|
|
"sort"
|
|
"strings"
|
|
|
|
"yunion.io/x/jsonutils"
|
|
"yunion.io/x/log"
|
|
"yunion.io/x/pkg/errors"
|
|
"yunion.io/x/pkg/utils"
|
|
|
|
"yunion.io/x/onecloud/pkg/apis"
|
|
api "yunion.io/x/onecloud/pkg/apis/compute"
|
|
"yunion.io/x/onecloud/pkg/cloudprovider"
|
|
"yunion.io/x/onecloud/pkg/multicloud"
|
|
)
|
|
|
|
type Boot struct {
|
|
UefiBoot bool `json:"uefi_boot"`
|
|
}
|
|
|
|
type VMFeatures struct {
|
|
VGACONSOLE bool `json:"VGA_CONSOLE"`
|
|
AGENTVM bool `json:"AGENT_VM"`
|
|
}
|
|
|
|
type DiskAddress struct {
|
|
DeviceBus string `json:"device_bus"`
|
|
DeviceIndex int `json:"device_index"`
|
|
DiskLabel string `json:"disk_label"`
|
|
NdfsFilepath string `json:"ndfs_filepath"`
|
|
VmdiskUUID string `json:"vmdisk_uuid"`
|
|
DeviceUUID string `json:"device_uuid"`
|
|
}
|
|
|
|
type VMDiskInfo struct {
|
|
IsCdrom bool `json:"is_cdrom"`
|
|
IsEmpty bool `json:"is_empty"`
|
|
FlashModeEnabled bool `json:"flash_mode_enabled"`
|
|
IsScsiPassthrough bool `json:"is_scsi_passthrough"`
|
|
IsHotRemoveEnabled bool `json:"is_hot_remove_enabled"`
|
|
IsThinProvisioned bool `json:"is_thin_provisioned"`
|
|
Shared bool `json:"shared"`
|
|
SourceDiskAddress SourceDiskAddress `json:"source_disk_address,omitempty"`
|
|
StorageContainerUUID string `json:"storage_container_uuid,omitempty"`
|
|
Size int64 `json:"size,omitempty"`
|
|
DataSourceURL string `json:"data_source_url"`
|
|
DiskAddress DiskAddress `json:"disk_address,omitempty"`
|
|
}
|
|
|
|
type SourceDiskAddress struct {
|
|
VmdiskUUID string `json:"vmdisk_uuid"`
|
|
}
|
|
|
|
type VMNics struct {
|
|
MacAddress string `json:"mac_address"`
|
|
NetworkUUID string `json:"network_uuid"`
|
|
NicUUID string `json:"nic_uuid"`
|
|
Model string `json:"model"`
|
|
VlanMode string `json:"vlan_mode"`
|
|
IsConnected bool `json:"is_connected"`
|
|
}
|
|
|
|
type SInstance struct {
|
|
multicloud.STagBase
|
|
multicloud.SInstanceBase
|
|
|
|
host *SHost
|
|
|
|
AllowLiveMigrate bool `json:"allow_live_migrate"`
|
|
GpusAssigned bool `json:"gpus_assigned"`
|
|
Boot Boot `json:"boot"`
|
|
HaPriority int `json:"ha_priority"`
|
|
HostUUID string `json:"host_uuid"`
|
|
MemoryMb int `json:"memory_mb"`
|
|
Name string `json:"name"`
|
|
NumCoresPerVcpu int `json:"num_cores_per_vcpu"`
|
|
NumVcpus int `json:"num_vcpus"`
|
|
PowerState string `json:"power_state"`
|
|
Timezone string `json:"timezone"`
|
|
UUID string `json:"uuid"`
|
|
VMFeatures VMFeatures `json:"vm_features"`
|
|
VMLogicalTimestamp int `json:"vm_logical_timestamp"`
|
|
MachineType string `json:"machine_type"`
|
|
|
|
VMDiskInfo []VMDiskInfo `json:"vm_disk_info"`
|
|
VMNics []VMNics `json:"vm_nics"`
|
|
}
|
|
|
|
func (self *SRegion) GetInstances() ([]SInstance, error) {
|
|
vms := []SInstance{}
|
|
params := url.Values{}
|
|
params.Set("include_vm_disk_config", "true")
|
|
params.Set("include_vm_nic_config", "true")
|
|
return vms, self.listAll("vms", params, &vms)
|
|
}
|
|
|
|
func (self *SRegion) GetInstance(id string) (*SInstance, error) {
|
|
vm := &SInstance{}
|
|
params := url.Values{}
|
|
params.Set("include_vm_disk_config", "true")
|
|
params.Set("include_vm_nic_config", "true")
|
|
return vm, self.get("vms", id, params, vm)
|
|
}
|
|
|
|
func (self *SInstance) GetName() string {
|
|
return self.Name
|
|
}
|
|
|
|
func (self *SInstance) GetId() string {
|
|
return self.UUID
|
|
}
|
|
|
|
func (self *SInstance) GetGlobalId() string {
|
|
return self.UUID
|
|
}
|
|
|
|
func (self *SInstance) Refresh() error {
|
|
ins, err := self.host.zone.region.GetInstance(self.UUID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return jsonutils.Update(self, ins)
|
|
}
|
|
|
|
func (self *SInstance) AssignSecurityGroup(id string) error {
|
|
return cloudprovider.ErrNotSupported
|
|
}
|
|
|
|
func (self *SInstance) CreateDisk(ctx context.Context, opts *cloudprovider.GuestDiskCreateOptions) (string, error) {
|
|
driver := opts.Driver
|
|
if !utils.IsInStringArray(driver, []string{"ide", "scsi", "pci", "sata"}) {
|
|
driver = "scsi"
|
|
}
|
|
idx, ids := -1, []int{}
|
|
for _, disk := range self.VMDiskInfo {
|
|
if disk.DiskAddress.DeviceBus == driver {
|
|
ids = append(ids, disk.DiskAddress.DeviceIndex)
|
|
}
|
|
}
|
|
sort.Ints(ids)
|
|
for _, id := range ids {
|
|
if id == idx+1 {
|
|
idx = id
|
|
}
|
|
}
|
|
params := map[string]interface{}{
|
|
"vm_disks": []map[string]interface{}{
|
|
{
|
|
"is_cdrom": false,
|
|
"disk_address": map[string]interface{}{
|
|
"device_bus": driver,
|
|
"device_index": idx + 1,
|
|
},
|
|
"vm_disk_create": map[string]interface{}{
|
|
"storage_container_uuid": opts.StorageId,
|
|
"size": opts.SizeMb * 1024 * 1024,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ret := struct {
|
|
TaskUUID string
|
|
}{}
|
|
res := fmt.Sprintf("vms/%s/disks/attach", self.UUID)
|
|
err := self.host.zone.region.post(res, jsonutils.Marshal(params), &ret)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return self.host.zone.region.cli.wait(ret.TaskUUID)
|
|
}
|
|
|
|
func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error {
|
|
return cloudprovider.ErrNotSupported
|
|
}
|
|
|
|
func (self *SInstance) ChangeConfig(ctx context.Context, opts *cloudprovider.SManagedVMChangeConfig) error {
|
|
params := map[string]interface{}{
|
|
"memory_mb": opts.MemoryMB,
|
|
"num_cores_per_vcpu": self.NumCoresPerVcpu,
|
|
"num_vcpus": opts.Cpu / self.NumCoresPerVcpu,
|
|
}
|
|
return self.host.zone.region.update("vms", self.UUID, jsonutils.Marshal(params), nil)
|
|
}
|
|
|
|
func (self *SInstance) DeleteVM(ctx context.Context) error {
|
|
return self.host.zone.region.DeleteVM(self.UUID)
|
|
}
|
|
|
|
func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error {
|
|
return cloudprovider.ErrNotSupported
|
|
}
|
|
|
|
func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error {
|
|
return cloudprovider.ErrNotImplemented
|
|
}
|
|
|
|
func (self *SInstance) GetBios() cloudprovider.TBiosType {
|
|
if self.Boot.UefiBoot {
|
|
return cloudprovider.UEFI
|
|
}
|
|
return cloudprovider.BIOS
|
|
}
|
|
|
|
func (self *SInstance) GetBootOrder() string {
|
|
return "dcn"
|
|
}
|
|
|
|
func (self *SInstance) GetError() error {
|
|
return nil
|
|
}
|
|
|
|
func (self *SInstance) GetHostname() string {
|
|
return self.Name
|
|
}
|
|
|
|
func (self *SInstance) GetHypervisor() string {
|
|
return api.HYPERVISOR_NUTANIX
|
|
}
|
|
|
|
func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
|
|
disks, err := self.host.zone.region.GetDisks("", self.GetGlobalId())
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "GetInstanceDisks")
|
|
}
|
|
cdroms := []string{}
|
|
for _, disk := range self.VMDiskInfo {
|
|
if disk.IsCdrom && len(disk.DiskAddress.VmdiskUUID) > 0 {
|
|
cdroms = append(cdroms, disk.DiskAddress.VmdiskUUID)
|
|
}
|
|
}
|
|
isSys := true
|
|
ret := []cloudprovider.ICloudDisk{}
|
|
for i := range disks {
|
|
if utils.IsInStringArray(disks[i].UUID, cdroms) { // skip cdrom disk
|
|
continue
|
|
}
|
|
storage, err := self.host.zone.GetIStorageById(disks[i].StorageContainerUUID)
|
|
if err != nil {
|
|
log.Errorf("can not found disk %s storage %s", disks[i].DiskAddress, disks[i].StorageContainerUUID)
|
|
continue
|
|
}
|
|
disks[i].isSys = isSys
|
|
disks[i].storage = storage.(*SStorage)
|
|
isSys = false
|
|
ret = append(ret, &disks[i])
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) {
|
|
return nil, cloudprovider.ErrNotSupported
|
|
}
|
|
|
|
func (self *SInstance) GetIHost() cloudprovider.ICloudHost {
|
|
return self.host
|
|
}
|
|
|
|
func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) {
|
|
nics, err := self.host.zone.region.GetInstanceNics(self.GetGlobalId())
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "GetInstanceNics")
|
|
}
|
|
ret := []cloudprovider.ICloudNic{}
|
|
for i := range nics {
|
|
nics[i].ins = self
|
|
ret = append(ret, &nics[i])
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
func (self *SInstance) GetInstanceType() string {
|
|
return fmt.Sprintf("ecs.g1.c%dm%d", self.GetVcpuCount(), self.GetVmemSizeMB()/1024)
|
|
}
|
|
|
|
func (self *SInstance) GetMachine() string {
|
|
return self.MachineType
|
|
}
|
|
|
|
// "UNKNOWN", "OFF", "POWERING_ON", "ON", "SHUTTING_DOWN", "POWERING_OFF", "PAUSING", "PAUSED", "SUSPENDING", "SUSPENDED", "RESUMING", "RESETTING", "MIGRATING"
|
|
func (self *SInstance) GetStatus() string {
|
|
switch strings.ToUpper(self.PowerState) {
|
|
case "OFF":
|
|
return api.VM_READY
|
|
case "POWERING_ON":
|
|
return api.VM_START_START
|
|
case "ON":
|
|
return api.VM_RUNNING
|
|
case "SHUTTING_DOWN":
|
|
return api.VM_START_STOP
|
|
case "POWERING_OFF":
|
|
return api.VM_START_STOP
|
|
case "PAUSING", "PAUSED":
|
|
return api.VM_READY
|
|
case "SUSPENDING", "SUSPENDED":
|
|
return api.VM_SUSPEND
|
|
case "RESUMING":
|
|
return api.VM_RESUMING
|
|
case "RESETTING":
|
|
return api.VM_RUNNING
|
|
case "MIGRATING":
|
|
return api.VM_MIGRATING
|
|
}
|
|
return api.VM_UNKNOWN
|
|
}
|
|
|
|
func (self *SInstance) GetFullOsName() string {
|
|
return ""
|
|
}
|
|
|
|
func (self *SInstance) GetOsType() cloudprovider.TOsType {
|
|
if strings.Contains(strings.ToLower(self.Name), "win") {
|
|
return cloudprovider.OsTypeWindows
|
|
}
|
|
return cloudprovider.OsTypeLinux
|
|
}
|
|
|
|
func (ins *SInstance) GetOsDist() string {
|
|
return ""
|
|
}
|
|
|
|
func (ins *SInstance) GetOsVersion() string {
|
|
return ""
|
|
}
|
|
|
|
func (ins *SInstance) GetOsLang() string {
|
|
return ""
|
|
}
|
|
|
|
func (ins *SInstance) GetOsArch() string {
|
|
return apis.OS_ARCH_X86_64
|
|
}
|
|
|
|
func (self *SInstance) GetProjectId() string {
|
|
return ""
|
|
}
|
|
|
|
func (self *SInstance) GetSecurityGroupIds() ([]string, error) {
|
|
return []string{}, nil
|
|
}
|
|
|
|
func (self *SInstance) GetVNCInfo() (jsonutils.JSONObject, error) {
|
|
return nil, cloudprovider.ErrNotImplemented
|
|
}
|
|
|
|
func (self *SInstance) GetVcpuCount() int {
|
|
return self.NumCoresPerVcpu * self.NumVcpus
|
|
}
|
|
|
|
func (self *SInstance) GetVmemSizeMB() int {
|
|
return self.MemoryMb
|
|
}
|
|
|
|
func (self *SInstance) GetVga() string {
|
|
return "std"
|
|
}
|
|
|
|
func (self *SInstance) GetVdi() string {
|
|
return "vnc"
|
|
}
|
|
|
|
func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) {
|
|
return "", cloudprovider.ErrNotSupported
|
|
}
|
|
|
|
func (self *SInstance) SetSecurityGroups(secgroupIds []string) error {
|
|
return cloudprovider.ErrNotSupported
|
|
}
|
|
|
|
func (self *SInstance) StartVM(ctx context.Context) error {
|
|
return self.host.zone.region.SetInstancePowerState(self.UUID, "on")
|
|
}
|
|
|
|
func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error {
|
|
act := "acpi_shutdown"
|
|
if opts.IsForce {
|
|
act = "off"
|
|
}
|
|
return self.host.zone.region.SetInstancePowerState(self.UUID, act)
|
|
}
|
|
|
|
func (self *SInstance) UpdateUserData(userData string) error {
|
|
return cloudprovider.ErrNotImplemented
|
|
}
|
|
|
|
func (self *SInstance) UpdateVM(ctx context.Context, name string) error {
|
|
return cloudprovider.ErrNotSupported
|
|
}
|
|
|
|
func (self *SRegion) SetInstancePowerState(id string, state string) error {
|
|
res := fmt.Sprintf("vms/%s/set_power_state", id)
|
|
ret := struct {
|
|
TaskUUID string
|
|
}{}
|
|
err := self.post(res, jsonutils.Marshal(map[string]string{"transition": state}), &ret)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = self.cli.wait(ret.TaskUUID)
|
|
return err
|
|
}
|
|
|
|
func (self *SRegion) DeleteVM(id string) error {
|
|
return self.delete("vms", id)
|
|
}
|