yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/incloudsphere/instance.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package incloudsphere
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"net/url"
    21  	"strings"
    22  
    23  	"yunion.io/x/jsonutils"
    24  	"yunion.io/x/pkg/errors"
    25  
    26  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    27  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    28  	"yunion.io/x/cloudmux/pkg/multicloud"
    29  	"yunion.io/x/onecloud/pkg/util/imagetools"
    30  )
    31  
    32  type Cdrom struct {
    33  	Path           string `json:"path"`
    34  	Type           string `json:"type"`
    35  	Connected      bool   `json:"connected"`
    36  	StartConnected bool   `json:"startConnected"`
    37  	CifsDto        string `json:"cifsDto"`
    38  	DataStore      struct {
    39  		Id   string `json:"id"`
    40  		Name string `json:"name"`
    41  	} `json:"dataStore"`
    42  }
    43  
    44  type Floppy struct {
    45  	Path      string `json:"path"`
    46  	DataStore string `json:"dataStore"`
    47  	VfdType   string `json:"vfdType"`
    48  }
    49  
    50  type FtpServerHost struct {
    51  	Id string `json:"id"`
    52  	Ip string `json:"ip"`
    53  }
    54  
    55  type VvSourceDto struct {
    56  	SourceType    string        `json:"sourceType"`
    57  	FilePath      string        `json:"filePath"`
    58  	Name          string        `json:"name"`
    59  	FtpServerHost FtpServerHost `json:"ftpServerHost"`
    60  }
    61  
    62  type Volume struct {
    63  	Id                 string      `json:"id"`
    64  	UUID               string      `json:"uuid"`
    65  	Size               float64     `json:"size"`
    66  	RealSize           float64     `json:"realSize"`
    67  	Name               string      `json:"name"`
    68  	FileName           string      `json:"fileName"`
    69  	Offset             int         `json:"offset"`
    70  	Shared             bool        `json:"shared"`
    71  	DeleteModel        string      `json:"deleteModel"`
    72  	VolumePolicy       string      `json:"volumePolicy"`
    73  	Format             string      `json:"format"`
    74  	BlockDeviceId      string      `json:"blockDeviceId"`
    75  	DiskType           string      `json:"diskType"`
    76  	DataStoreId        string      `json:"dataStoreId"`
    77  	DataStoreName      string      `json:"dataStoreName"`
    78  	DataStoreSize      float64     `json:"dataStoreSize"`
    79  	FreeStorage        float64     `json:"freeStorage"`
    80  	DataStoreType      string      `json:"dataStoreType"`
    81  	DataStoreReplicate int         `json:"dataStoreReplicate"`
    82  	VMName             string      `json:"vmName"`
    83  	VMStatus           string      `json:"vmStatus"`
    84  	Type               string      `json:"type"`
    85  	Description        string      `json:"description"`
    86  	Bootable           bool        `json:"bootable"`
    87  	VolumeStatus       string      `json:"volumeStatus"`
    88  	MountedHostIds     string      `json:"mountedHostIds"`
    89  	Md5                string      `json:"md5"`
    90  	DataSize           int         `json:"dataSize"`
    91  	OpenStackId        string      `json:"openStackId"`
    92  	VvSourceDto        VvSourceDto `json:"vvSourceDto"`
    93  	FormatDisk         bool        `json:"formatDisk"`
    94  	ToBeConverted      bool        `json:"toBeConverted"`
    95  	RelatedVms         string      `json:"relatedVms"`
    96  	XactiveDataStoreId string      `json:"xactiveDataStoreId"`
    97  	ClusterSize        int         `json:"clusterSize"`
    98  	ScsiId             string      `json:"scsiId"`
    99  	SecondaryUUID      string      `json:"secondaryUuid"`
   100  	SecondaryVolumes   []struct{}  `json:"secondaryVolumes"`
   101  }
   102  
   103  type Disks struct {
   104  	Id              string  `json:"id"`
   105  	Label           string  `json:"label"`
   106  	ScsiId          string  `json:"scsiId"`
   107  	Enabled         bool    `json:"enabled"`
   108  	WriteBps        int     `json:"writeBps"`
   109  	ReadBps         int     `json:"readBps"`
   110  	TotalBps        int     `json:"totalBps"`
   111  	TotalIops       int     `json:"totalIops"`
   112  	WriteIops       int     `json:"writeIops"`
   113  	ReadIops        int     `json:"readIops"`
   114  	Volume          Volume  `json:"volume"`
   115  	BusModel        string  `json:"busModel"`
   116  	Usage           float64 `json:"usage"`
   117  	MonReadIops     float64 `json:"monReadIops"`
   118  	MonWriteIops    float64 `json:"monWriteIops"`
   119  	ReadThroughput  float64 `json:"readThroughput"`
   120  	WriteThroughput float64 `json:"writeThroughput"`
   121  	ReadWriteModel  string  `json:"readWriteModel"`
   122  	EnableNativeIO  bool    `json:"enableNativeIO"`
   123  	EnableKernelIO  bool    `json:"enableKernelIO"`
   124  	L2CacheSize     int     `json:"l2CacheSize"`
   125  	QueueNum        int     `json:"queueNum"`
   126  }
   127  
   128  type CdpInfo struct {
   129  	CdpBackupDatastoreId string `json:"cdpBackupDatastoreId"`
   130  	BackupDataStoreName  string `json:"backupDataStoreName"`
   131  	StartTime            string `json:"startTime"`
   132  	EndTime              string `json:"endTime"`
   133  	EnableCDP            bool   `json:"enableCDP"`
   134  	CdpAvgWriteMBps      int    `json:"cdpAvgWriteMBps"`
   135  	CdpRemainTimes       int    `json:"cdpRemainTimes"`
   136  	CdpLogSpaceSize      int    `json:"cdpLogSpaceSize"`
   137  	IntervalTime         int    `json:"intervalTime"`
   138  }
   139  
   140  type GuestOSAuthInfo struct {
   141  	UserName string `json:"userName"`
   142  	UserPwd  string `json:"userPwd"`
   143  }
   144  
   145  type SInstance struct {
   146  	multicloud.SInstanceBase
   147  	InCloudSphereTags
   148  
   149  	host *SHost
   150  
   151  	osInfo *imagetools.ImageInfo
   152  
   153  	Id                 string `json:"id"`
   154  	CustomVMId         string `json:"customVmId"`
   155  	Name               string `json:"name"`
   156  	State              string `json:"state"`
   157  	Status             string `json:"status"`
   158  	HostId             string `json:"hostId"`
   159  	HostName           string `json:"hostName"`
   160  	HostIP             string `json:"hostIp"`
   161  	HostStatus         string `json:"hostStatus"`
   162  	HostMemory         int64  `json:"hostMemory"`
   163  	DataCenterId       string `json:"dataCenterId"`
   164  	HaEnabled          bool   `json:"haEnabled"`
   165  	RouterFlag         bool   `json:"routerFlag"`
   166  	Migratable         bool   `json:"migratable"`
   167  	HostBinded         bool   `json:"hostBinded"`
   168  	ToolsInstalled     bool   `json:"toolsInstalled"`
   169  	ToolsVersion       string `json:"toolsVersion"`
   170  	ToolsType          string `json:"toolsType"`
   171  	ToolsVersionStatus string `json:"toolsVersionStatus"`
   172  	ToolsRunningStatus string `json:"toolsRunningStatus"`
   173  	ToolsNeedUpdate    bool   `json:"toolsNeedUpdate"`
   174  	Description        string `json:"description"`
   175  	HaMaxLimit         int64  `json:"haMaxLimit"`
   176  	Template           bool   `json:"template"`
   177  	Initialized        bool   `json:"initialized"`
   178  	GuestosLabel       string `json:"guestosLabel"`
   179  	GuestosType        string `json:"guestosType"`
   180  	GuestOSInfo        struct {
   181  		Model               string `json:"model"`
   182  		SocketLimit         int    `json:"socketLimit"`
   183  		SupportCpuHotPlug   bool   `json:"supportCpuHotPlug"`
   184  		SupportDiskHotPlug  bool   `json:"supportDiskHotPlug"`
   185  		SupportMemHotPlug   bool   `json:"supportMemHotPlug"`
   186  		SupportUefiBootMode bool   `json:"supportUefiBootMode"`
   187  	} `json:"guestOsInfo"`
   188  	InnerName         string `json:"innerName"`
   189  	UUId              string `json:"uuid"`
   190  	MaxMemory         int64  `json:"maxMemory"`
   191  	Memory            int    `json:"memory"`
   192  	MemoryUsage       int64  `json:"memoryUsage"`
   193  	MemHotplugEnabled bool   `json:"memHotplugEnabled"`
   194  	EnableHugeMemPage bool   `json:"enableHugeMemPage"`
   195  	CPUNum            int    `json:"cpuNum"`
   196  	CPUSocket         int    `json:"cpuSocket"`
   197  	CPUCore           int64  `json:"cpuCore"`
   198  	CPUUsage          int64  `json:"cpuUsage"`
   199  	MaxCPUNum         int64  `json:"maxCpuNum"`
   200  	CPUHotplugEnabled bool   `json:"cpuHotplugEnabled"`
   201  	CPUModelType      string `json:"cpuModelType"`
   202  	CPUModelEnabled   bool   `json:"cpuModelEnabled"`
   203  	RunningTime       int64  `json:"runningTime"`
   204  	Boot              string `json:"boot"`
   205  	BootMode          string `json:"bootMode"`
   206  	SplashTime        int64  `json:"splashTime"`
   207  	StoragePriority   int64  `json:"storagePriority"`
   208  	USB               string `json:"usb"`
   209  
   210  	//Usbs                     []interface{}   `json:"usbs"`
   211  	Cdrom  Cdrom          `json:"cdrom"`
   212  	Floppy Floppy         `json:"floppy"`
   213  	Disks  []Disks        `json:"disks"`
   214  	Nics   []SInstanceNic `json:"nics"`
   215  
   216  	//Gpus                     []interface{}   `json:"gpus"`
   217  	//VMPcis                   []interface{}   `json:"vmPcis"`
   218  	ConfigLocation           string          `json:"configLocation"`
   219  	HotplugEnabled           bool            `json:"hotplugEnabled"`
   220  	VNCPort                  int64           `json:"vncPort"`
   221  	VNCPasswd                string          `json:"vncPasswd"`
   222  	VNCSharePolicy           string          `json:"vncSharePolicy"`
   223  	CPUBindType              string          `json:"cpuBindType"`
   224  	VcpuPin                  string          `json:"vcpuPin"`
   225  	VcpuPins                 []string        `json:"vcpuPins"`
   226  	CPUShares                int64           `json:"cpuShares"`
   227  	PanickPolicy             string          `json:"panickPolicy"`
   228  	DataStoreId              string          `json:"dataStoreId"`
   229  	SdsdomainId              string          `json:"sdsdomainId"`
   230  	ClockModel               string          `json:"clockModel"`
   231  	CPULimit                 int64           `json:"cpuLimit"`
   232  	MemShares                int64           `json:"memShares"`
   233  	CPUReservation           int64           `json:"cpuReservation"`
   234  	MemReservation           int64           `json:"memReservation"`
   235  	LastBackup               string          `json:"lastBackup"`
   236  	VMType                   string          `json:"vmType"`
   237  	SystemVMType             string          `json:"systemVmType"`
   238  	MemBalloonEnabled        bool            `json:"memBalloonEnabled"`
   239  	Completed                bool            `json:"completed"`
   240  	GraphicsCardModel        string          `json:"graphicsCardModel"`
   241  	GraphicsCardMemory       int64           `json:"graphicsCardMemory"`
   242  	GraphicsCards            string          `json:"graphicsCards"`
   243  	VMHostName               string          `json:"vmHostName"`
   244  	DiskTotalSize            int64           `json:"diskTotalSize"`
   245  	DiskUsedSize             float64         `json:"diskUsedSize"`
   246  	DiskUsage                float64         `json:"diskUsage"`
   247  	StartPriority            string          `json:"startPriority"`
   248  	OwnerName                string          `json:"ownerName"`
   249  	Version                  string          `json:"version"`
   250  	EnableReplicate          bool            `json:"enableReplicate"`
   251  	ReplicationDatastoreId   string          `json:"replicationDatastoreId"`
   252  	ReplicationDatastoreName string          `json:"replicationDatastoreName"`
   253  	RecoveryFlag             bool            `json:"recoveryFlag"`
   254  	SpiceUSBNum              int64           `json:"spiceUsbNum"`
   255  	CDPInfo                  CdpInfo         `json:"cdpInfo"`
   256  	GuestOSAuthInfo          GuestOSAuthInfo `json:"guestOSAuthInfo"`
   257  	AwareNUMAEnabled         bool            `json:"awareNumaEnabled"`
   258  	DrxEnabled               bool            `json:"drxEnabled"`
   259  	SecretLevel              string          `json:"secretLevel"`
   260  	//VmfpgaDevs               []interface{}   `json:"vmfpgaDevs"`
   261  }
   262  
   263  func (self *SInstance) GetName() string {
   264  	return self.Name
   265  }
   266  
   267  func (self *SInstance) GetId() string {
   268  	return self.Id
   269  }
   270  
   271  func (self *SInstance) GetGlobalId() string {
   272  	return self.GetId()
   273  }
   274  
   275  func (self *SInstance) Refresh() error {
   276  	ins, err := self.host.zone.region.GetInstance(self.Id)
   277  	if err != nil {
   278  		return err
   279  	}
   280  	return jsonutils.Update(self, ins)
   281  }
   282  
   283  func (self *SInstance) AssignSecurityGroup(id string) error {
   284  	return cloudprovider.ErrNotSupported
   285  }
   286  
   287  func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error {
   288  	return self.host.zone.region.AttachDisk(self.Id, diskId)
   289  }
   290  
   291  func (self *SInstance) CreateDisk(ctx context.Context, opts *cloudprovider.GuestDiskCreateOptions) (string, error) {
   292  	return "", cloudprovider.ErrNotSupported
   293  }
   294  
   295  func (self *SInstance) ChangeConfig(ctx context.Context, opts *cloudprovider.SManagedVMChangeConfig) error {
   296  	return self.host.zone.region.ChangeConfig(self.Id, opts.Cpu, opts.MemoryMB)
   297  }
   298  
   299  func (self *SInstance) DeleteVM(ctx context.Context) error {
   300  	return self.host.zone.region.DeleteVM(self.Id)
   301  }
   302  
   303  func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error {
   304  	return self.host.zone.region.ResetVmPassword(self.Id, username, password)
   305  }
   306  
   307  func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error {
   308  	return self.host.zone.region.DetachDisk(self.Id, diskId)
   309  }
   310  
   311  func (self *SInstance) GetBios() cloudprovider.TBiosType {
   312  	return cloudprovider.ToBiosType(self.BootMode)
   313  }
   314  
   315  func (self *SInstance) GetBootOrder() string {
   316  	return strings.ToLower(self.Boot)
   317  }
   318  
   319  func (self *SInstance) GetError() error {
   320  	return nil
   321  }
   322  
   323  func (self *SInstance) GetHostname() string {
   324  	return self.HostName
   325  }
   326  
   327  func (self *SInstance) GetHypervisor() string {
   328  	return api.HYPERVISOR_INCLOUD_SPHERE
   329  }
   330  
   331  func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
   332  	ret := []cloudprovider.ICloudDisk{}
   333  	for i := range self.Disks {
   334  		disk, err := self.host.zone.region.GetDisk(self.Disks[i].Volume.Id)
   335  		if err != nil {
   336  			return nil, err
   337  		}
   338  		ret = append(ret, disk)
   339  	}
   340  	return ret, nil
   341  }
   342  
   343  func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) {
   344  	return nil, cloudprovider.ErrNotSupported
   345  }
   346  
   347  func (self *SInstance) GetIHost() cloudprovider.ICloudHost {
   348  	return self.host
   349  }
   350  
   351  func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) {
   352  	ret := []cloudprovider.ICloudNic{}
   353  	for i := range self.Nics {
   354  		self.Nics[i].ins = self
   355  		ret = append(ret, &self.Nics[i])
   356  	}
   357  	return ret, nil
   358  }
   359  
   360  func (self *SInstance) GetInstanceType() string {
   361  	return fmt.Sprintf("ecs.g1.c%dm%d", self.GetVcpuCount(), self.GetVmemSizeMB()/1024)
   362  }
   363  
   364  func (self *SInstance) GetMachine() string {
   365  	return ""
   366  }
   367  
   368  /*
   369  PENDING 开启准备中
   370  STARTING 开启或恢复中
   371  STARTED 开启的
   372  PAUSING 暂停中
   373  PAUSED 暂停的
   374  RESTARTING 重启中
   375  STOPPING 关机中
   376  STOPPED 关闭的
   377  HOT_SAVING 开机快照中
   378  COLD_SAVING 关机快照中
   379  PRE_MIGRATE 迁移准备中
   380  HOT_MIGRATING 热迁移中
   381  COLD_MIGRATING 冷迁移中
   382  REVERTING 恢复快照中
   383  EXPORTING 导出中
   384  IMPORTING 导入中
   385  COLD_BACKUPING 关机备份中
   386  HOT_BACKUPING 开机备份中
   387  COLD_MODIFYING 冷配置中
   388  HOT_MODIFYING 热配置中
   389  COLD_COPING 关机复制中
   390  */
   391  
   392  func (self *SInstance) GetStatus() string {
   393  	switch strings.ToUpper(self.Status) {
   394  	case "COLD_COPING", "COLD_BACKUPING", "COLD_SAVING", "STOPPED":
   395  		return api.VM_READY
   396  	case "PENDING", "STARTING":
   397  		return api.VM_START_START
   398  	case "STARTED", "HOT_SAVING", "HOT_BACKUPING":
   399  		return api.VM_RUNNING
   400  	case "PAUSING", "RESTARTING", "STOPPING":
   401  		return api.VM_START_STOP
   402  	case "REVERTING", "EXPORTING", "IMPORTING", "COLD_MODIFYING", "HOT_MODIFYING":
   403  		return api.VM_RESUMING
   404  	case "PRE_MIGRATE", "HOT_MIGRATING", "COLD_MIGRATING":
   405  		return api.VM_MIGRATING
   406  	}
   407  	return strings.ToLower(self.Status)
   408  }
   409  
   410  func (i *SInstance) GetFullOsName() string {
   411  	return i.GuestOSInfo.Model
   412  }
   413  
   414  func (i *SInstance) GetOsType() cloudprovider.TOsType {
   415  	return cloudprovider.TOsType(i.GuestosType)
   416  }
   417  
   418  func (i *SInstance) GetOsArch() string {
   419  	return i.GetIHost().GetCpuArchitecture()
   420  }
   421  
   422  func (i *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo {
   423  	if i.osInfo == nil {
   424  		osInfo := imagetools.NormalizeImageInfo(i.GuestOSInfo.Model, "", "", "", "")
   425  		i.osInfo = &osInfo
   426  	}
   427  	return i.osInfo
   428  }
   429  
   430  func (i *SInstance) GetOsDist() string {
   431  	return i.getNormalizedOsInfo().OsDistro
   432  }
   433  
   434  func (i *SInstance) GetOsVersion() string {
   435  	return i.getNormalizedOsInfo().OsVersion
   436  }
   437  
   438  func (i *SInstance) GetOsLang() string {
   439  	return i.getNormalizedOsInfo().OsLang
   440  }
   441  
   442  func (self *SInstance) GetProjectId() string {
   443  	return ""
   444  }
   445  
   446  func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) {
   447  	ret := &cloudprovider.ServerVncOutput{
   448  		Protocol: "vnc",
   449  		Host:     self.host.Name,
   450  		Port:     self.VNCPort,
   451  		Id:       self.Id,
   452  		Password: "1q@W3e$R",
   453  	}
   454  	return ret, nil
   455  }
   456  
   457  func (self *SInstance) GetVcpuCount() int {
   458  	return int(self.CPUNum)
   459  }
   460  
   461  func (self *SInstance) GetVmemSizeMB() int {
   462  	return int(self.Memory)
   463  }
   464  
   465  func (self *SInstance) GetVga() string {
   466  	return "std"
   467  }
   468  
   469  func (self *SInstance) GetVdi() string {
   470  	return "vnc"
   471  }
   472  
   473  func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) {
   474  	return "", cloudprovider.ErrNotSupported
   475  }
   476  
   477  func (self *SInstance) GetSecurityGroupIds() ([]string, error) {
   478  	return []string{}, nil
   479  }
   480  
   481  func (self *SInstance) SetSecurityGroups(secgroupIds []string) error {
   482  	return cloudprovider.ErrNotSupported
   483  }
   484  
   485  func (self *SInstance) StartVM(ctx context.Context) error {
   486  	return self.host.zone.region.StartVm(self.Id, "", "")
   487  }
   488  
   489  func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error {
   490  	if self.GetStatus() == api.VM_READY {
   491  		return nil
   492  	}
   493  	return self.host.zone.region.StopVm(self.Id)
   494  }
   495  
   496  func (self *SInstance) UpdateUserData(userData string) error {
   497  	return cloudprovider.ErrNotSupported
   498  }
   499  
   500  func (self *SInstance) UpdateVM(ctx context.Context, name string) error {
   501  	return cloudprovider.ErrNotSupported
   502  }
   503  
   504  func (self *SRegion) GetInstances(hostId string) ([]SInstance, error) {
   505  	ret := []SInstance{}
   506  	res := fmt.Sprintf("/hosts/%s/vms", hostId)
   507  	return ret, self.list(res, url.Values{}, &ret)
   508  }
   509  
   510  func (self *SRegion) GetInstance(id string) (*SInstance, error) {
   511  	ret := &SInstance{}
   512  	res := fmt.Sprintf("/vms/%s", id)
   513  	return ret, self.get(res, nil, ret)
   514  }
   515  
   516  func (self *SRegion) StartVm(id string, password, publicKey string) error {
   517  	res := fmt.Sprintf("/vms/%s", id)
   518  	params := url.Values{}
   519  	params.Set("action", "poweron")
   520  	if len(password) > 0 {
   521  		params.Set("os-passwd", password)
   522  	}
   523  	if len(publicKey) > 0 {
   524  		params.Set("publicKey", publicKey)
   525  	}
   526  	return self.put(res, params, nil, nil)
   527  }
   528  
   529  func (self *SRegion) StopVm(id string) error {
   530  	res := fmt.Sprintf("/vms/%s", id)
   531  	params := url.Values{}
   532  	params.Set("action", "poweroff")
   533  	return self.put(res, params, nil, nil)
   534  }
   535  
   536  func (self *SRegion) AttachDisk(vmId, diskId string) error {
   537  	disk, err := self.GetDisk(diskId)
   538  	if err != nil {
   539  		return errors.Wrapf(err, "GetDisk(%s)", diskId)
   540  	}
   541  	vm, err := self.GetInstance(vmId)
   542  	if err != nil {
   543  		return errors.Wrapf(err, "GetInstance(%s)", vmId)
   544  	}
   545  	vm.VNCPasswd = ""
   546  	diskInfo := Disks{
   547  		BusModel:       "VIRTIO",
   548  		ReadWriteModel: "NONE",
   549  		QueueNum:       1,
   550  		Volume: Volume{
   551  			Id:   disk.Id,
   552  			Size: disk.Size,
   553  		},
   554  	}
   555  	vm.Disks = append(vm.Disks, diskInfo)
   556  	return self.put("/vms/"+vm.Id, nil, jsonutils.Marshal(vm), nil)
   557  }
   558  
   559  func (self *SRegion) DetachDisk(vmId, diskId string) error {
   560  	vm, err := self.GetInstance(vmId)
   561  	if err != nil {
   562  		return errors.Wrapf(err, "GetInstance(%s)", vmId)
   563  	}
   564  	vm.VNCPasswd = ""
   565  	disks := []Disks{}
   566  	for i := 0; i < len(vm.Disks); i++ {
   567  		if vm.Disks[i].Volume.Id == diskId {
   568  			continue
   569  		}
   570  		disks = append(disks, vm.Disks[i])
   571  	}
   572  	vm.Disks = disks
   573  	return self.put("/vms/"+vm.Id, nil, jsonutils.Marshal(vm), nil)
   574  }
   575  
   576  func (self *SRegion) ChangeConfig(vmId string, cpu int, memMb int) error {
   577  	vm, err := self.GetInstance(vmId)
   578  	if err != nil {
   579  		return errors.Wrapf(err, "GetInstance(%s)", vmId)
   580  	}
   581  	vm.VNCPasswd = ""
   582  	changed := false
   583  	if cpu > 0 {
   584  		vm.CPUCore = 1
   585  		vm.CPUNum = cpu
   586  		vm.CPUSocket = cpu
   587  		changed = true
   588  	}
   589  	if memMb > 0 {
   590  		vm.Memory = memMb
   591  		changed = true
   592  	}
   593  	if !changed {
   594  		return nil
   595  	}
   596  	return self.put("/vms/"+vm.Id, nil, jsonutils.Marshal(vm), nil)
   597  }
   598  
   599  func (self *SRegion) ResetVmPassword(vmId string, username, password string) error {
   600  	params := url.Values{}
   601  	params.Set("action", "updateOsAuth")
   602  	body := map[string]interface{}{
   603  		"userName": username,
   604  		"userPwd":  password,
   605  	}
   606  	return self.put("/vms/"+vmId, params, jsonutils.Marshal(body), nil)
   607  }
   608  
   609  func (self *SRegion) DeleteVM(vmId string) error {
   610  	params := url.Values{}
   611  	params.Set("type", "force")
   612  	return self.del("/vms/"+vmId, params, nil)
   613  }