| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 |
- // 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/cloudmux/pkg/apis"
- api "yunion.io/x/cloudmux/pkg/apis/compute"
- "yunion.io/x/cloudmux/pkg/cloudprovider"
- "yunion.io/x/cloudmux/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) 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, opts *cloudprovider.SInstanceDeployOptions) 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 ""
- }
- 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(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, 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, input cloudprovider.SInstanceUpdateOptions) 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)
- }
|