| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917 |
- // 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 google
- import (
- "context"
- "fmt"
- "strings"
- "time"
- "yunion.io/x/jsonutils"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/util/billing"
- "yunion.io/x/pkg/util/cloudinit"
- "yunion.io/x/pkg/util/encode"
- "yunion.io/x/pkg/util/fileutils"
- "yunion.io/x/pkg/util/imagetools"
- "yunion.io/x/pkg/util/stringutils"
- "yunion.io/x/pkg/utils"
- billing_api "yunion.io/x/cloudmux/pkg/apis/billing"
- api "yunion.io/x/cloudmux/pkg/apis/compute"
- "yunion.io/x/cloudmux/pkg/cloudprovider"
- "yunion.io/x/cloudmux/pkg/multicloud"
- )
- const (
- METADATA_SSH_KEYS = "ssh-keys"
- METADATA_STARTUP_SCRIPT = "startup-script"
- METADATA_POWER_SHELL = "sysprep-specialize-script-ps1"
- METADATA_STARTUP_SCRIPT_POWER_SHELL = "windows-startup-script-ps1"
- )
- type AccessConfig struct {
- Type string
- Name string
- NatIP string
- NetworkTier string
- Kind string
- }
- type InstanceDisk struct {
- Type string
- Mode string
- Source string
- DeviceName string
- Index int
- Boot bool
- AutoDelete bool
- Licenses []string
- Interface string
- GuestOsFeatures []GuestOsFeature
- Kind string
- }
- type ServiceAccount struct {
- Email string
- scopes []string
- }
- type SInstanceTag struct {
- Items []string
- Fingerprint string
- }
- type SMetadataItem struct {
- Key string
- Value string
- }
- type SMetadata struct {
- Fingerprint string
- Items []SMetadataItem
- }
- type SInstance struct {
- multicloud.SInstanceBase
- GoogleTags
- host *SHost
- SResourceBase
- osInfo *imagetools.ImageInfo
- CreationTimestamp time.Time
- Description string
- Tags SInstanceTag
- MachineType string
- Status string
- Zone string
- CanIpForward bool
- NetworkInterfaces []SNetworkInterface
- Disks []InstanceDisk
- Metadata SMetadata
- ServiceAccounts []ServiceAccount
- Scheduling map[string]interface{}
- CpuPlatform string
- LabelFingerprint string
- StartRestricted bool
- DeletionProtection bool
- Kind string
- guestCpus int
- memoryMb int
- machineType string
- }
- func (region *SRegion) GetInstances(zone string, maxResults int, pageToken string) ([]SInstance, error) {
- instances := []SInstance{}
- params := map[string]string{}
- if len(zone) == 0 {
- return nil, fmt.Errorf("zone params can not be empty")
- }
- resource := fmt.Sprintf("zones/%s/instances", zone)
- return instances, region.List(resource, params, maxResults, pageToken, &instances)
- }
- func (region *SRegion) GetInstance(id string) (*SInstance, error) {
- instance := &SInstance{}
- return instance, region.Get("instances", id, instance)
- }
- func (instance *SInstance) GetHostname() string {
- return ""
- }
- func (instance *SInstance) fetchMachineType() error {
- if instance.guestCpus > 0 || instance.memoryMb > 0 || len(instance.machineType) > 0 {
- return nil
- }
- machinetype := SMachineType{}
- err := instance.host.zone.region.GetBySelfId(instance.MachineType, &machinetype)
- if err != nil {
- return err
- }
- instance.guestCpus = machinetype.GuestCpus
- instance.memoryMb = machinetype.MemoryMb
- instance.machineType = machinetype.Name
- return nil
- }
- func (self *SInstance) Refresh() error {
- instance, err := self.host.zone.region.GetInstance(self.Id)
- if err != nil {
- return err
- }
- err = jsonutils.Update(self, instance)
- if err != nil {
- return err
- }
- instance.Labels = self.Labels
- return nil
- }
- // PROVISIONING, STAGING, RUNNING, STOPPING, STOPPED, SUSPENDING, SUSPENDED, and TERMINATED.
- func (instance *SInstance) GetStatus() string {
- switch instance.Status {
- case "PROVISIONING":
- return api.VM_DEPLOYING
- case "STAGING":
- return api.VM_STARTING
- case "RUNNING":
- return api.VM_RUNNING
- case "STOPPING":
- return api.VM_STOPPING
- case "STOPPED":
- return api.VM_READY
- case "SUSPENDING":
- return api.VM_SUSPENDING
- case "SUSPENDED":
- return api.VM_SUSPEND
- case "TERMINATED":
- return api.VM_READY
- default:
- return api.VM_UNKNOWN
- }
- }
- func (ins *SInstance) GetPowerStates() string {
- status := ins.GetStatus()
- switch status {
- case api.VM_READY:
- return api.VM_POWER_STATES_OFF
- case api.VM_UNKNOWN:
- return api.VM_POWER_STATES_OFF
- default:
- return api.VM_POWER_STATES_ON
- }
- }
- func (instance *SInstance) GetBillingType() string {
- return billing_api.BILLING_TYPE_POSTPAID
- }
- func (instance *SInstance) GetCreatedAt() time.Time {
- return instance.CreationTimestamp
- }
- func (instance *SInstance) GetExpiredAt() time.Time {
- return time.Time{}
- }
- func (instance *SInstance) GetProjectId() string {
- return instance.host.zone.region.GetProjectId()
- }
- func (instance *SInstance) GetIHost() cloudprovider.ICloudHost {
- return instance.host
- }
- func (instance *SInstance) GetIHostId() string {
- return instance.host.GetGlobalId()
- }
- func (instance *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
- idisks := []cloudprovider.ICloudDisk{}
- for _, disk := range instance.Disks {
- _disk := &SDisk{}
- err := instance.host.zone.region.GetBySelfId(disk.Source, _disk)
- if err != nil {
- return nil, errors.Wrap(err, "GetDisk")
- }
- storage, err := instance.host.zone.region.GetStorage(_disk.Type)
- if err != nil {
- return nil, errors.Wrap(err, "GetStorage")
- }
- storage.zone = instance.host.zone
- _disk.storage = storage
- _disk.autoDelete = disk.AutoDelete
- _disk.boot = disk.Boot
- _disk.index = disk.Index
- idisks = append(idisks, _disk)
- }
- return idisks, nil
- }
- func (instance *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) {
- nics := []cloudprovider.ICloudNic{}
- for i := range instance.NetworkInterfaces {
- instance.NetworkInterfaces[i].instance = instance
- nics = append(nics, &instance.NetworkInterfaces[i])
- }
- return nics, nil
- }
- func (instance *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) {
- for _, networkinterface := range instance.NetworkInterfaces {
- for _, conf := range networkinterface.AccessConfigs {
- if len(conf.NatIP) > 0 {
- eips, err := instance.host.zone.region.GetEips(conf.NatIP, 0, "")
- if err != nil {
- return nil, errors.Wrapf(err, "region.GetEip(%s)", conf.NatIP)
- }
- if len(eips) == 1 {
- eips[0].region = instance.host.zone.region
- return &eips[0], nil
- }
- eip := &SAddress{
- region: instance.host.zone.region,
- Status: "IN_USE",
- Address: conf.NatIP,
- instanceId: instance.Id,
- }
- eip.Id = instance.Id
- eip.SelfLink = instance.SelfLink
- return eip, nil
- }
- }
- }
- return nil, nil
- }
- func (instance *SInstance) GetVcpuCount() int {
- instance.fetchMachineType()
- return instance.guestCpus
- }
- func (instance *SInstance) GetVmemSizeMB() int {
- instance.fetchMachineType()
- return instance.memoryMb
- }
- func (instance *SInstance) GetBootOrder() string {
- return "cdn"
- }
- func (instance *SInstance) GetVga() string {
- return "std"
- }
- func (instance *SInstance) GetVdi() string {
- return "vnc"
- }
- func (instance *SInstance) GetOsType() cloudprovider.TOsType {
- return cloudprovider.TOsType(instance.getNormalizedOsInfo().OsType)
- }
- func (instance *SInstance) getValidLicense() string {
- for _, disk := range instance.Disks {
- if disk.Index == 0 {
- for _, license := range disk.Licenses {
- if len(license) > 0 {
- return license
- }
- }
- }
- }
- return ""
- }
- func (instance *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo {
- if instance.osInfo != nil {
- return instance.osInfo
- }
- osinfo := imagetools.NormalizeImageInfo(instance.getValidLicense(), "", "", "", "")
- instance.osInfo = &osinfo
- return instance.osInfo
- }
- func (instance *SInstance) GetFullOsName() string {
- return instance.getValidLicense()
- }
- func (instance *SInstance) GetBios() cloudprovider.TBiosType {
- return cloudprovider.ToBiosType(instance.getNormalizedOsInfo().OsBios)
- }
- func (instance *SInstance) GetOsArch() string {
- return instance.getNormalizedOsInfo().OsArch
- }
- func (instance *SInstance) GetOsDist() string {
- return instance.getNormalizedOsInfo().OsDistro
- }
- func (instance *SInstance) GetOsVersion() string {
- return instance.getNormalizedOsInfo().OsVersion
- }
- func (instance *SInstance) GetOsLang() string {
- return instance.getNormalizedOsInfo().OsLang
- }
- func (instance *SInstance) GetMachine() string {
- return "pc"
- }
- func (instance *SInstance) GetInstanceType() string {
- instance.fetchMachineType()
- return instance.machineType
- }
- func (instance *SInstance) GetSecurityGroupIds() ([]string, error) {
- return instance.Tags.Items, nil
- }
- func (instance *SInstance) SetSecurityGroups(ids []string) error {
- instance.Tags.Items = ids
- return instance.host.zone.region.SetResourceTags(instance.SelfLink, instance.Tags)
- }
- func (instance *SInstance) GetHypervisor() string {
- return api.HYPERVISOR_GOOGLE
- }
- func (instance *SInstance) StartVM(ctx context.Context) error {
- return instance.host.zone.region.StartInstance(instance.SelfLink)
- }
- func (instance *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error {
- return instance.host.zone.region.StopInstance(instance.SelfLink)
- }
- func (instance *SInstance) DeleteVM(ctx context.Context) error {
- if instance.DeletionProtection {
- err := instance.host.zone.region.DisableDeletionProtection(instance.SelfLink)
- if err != nil {
- return errors.Wrapf(err, "DisableDeletionProtection(%s)", instance.Name)
- }
- }
- return instance.host.zone.region.Delete(instance.SelfLink)
- }
- func (instance *SInstance) UpdateVM(ctx context.Context, input cloudprovider.SInstanceUpdateOptions) error {
- return cloudprovider.ErrNotSupported
- }
- func (instance *SInstance) UpdateUserData(userData string) error {
- items := []SMetadataItem{}
- for _, item := range instance.Metadata.Items {
- if item.Key != METADATA_STARTUP_SCRIPT && item.Key != METADATA_POWER_SHELL && item.Key != METADATA_STARTUP_SCRIPT_POWER_SHELL {
- items = append(items, item)
- }
- }
- if len(userData) > 0 {
- items = append(items, SMetadataItem{Key: METADATA_STARTUP_SCRIPT, Value: userData})
- items = append(items, SMetadataItem{Key: METADATA_STARTUP_SCRIPT_POWER_SHELL, Value: userData})
- items = append(items, SMetadataItem{Key: METADATA_POWER_SHELL, Value: userData})
- }
- instance.Metadata.Items = items
- return instance.host.zone.region.SetMetadata(instance.SelfLink, instance.Metadata)
- }
- func (instance *SInstance) RebuildRoot(ctx context.Context, opts *cloudprovider.SManagedVMRebuildRootConfig) (string, error) {
- diskId, err := instance.host.zone.region.RebuildRoot(instance.Id, opts.ImageId, opts.SysSizeGB)
- if err != nil {
- return "", errors.Wrap(err, "region.RebuildRoot")
- }
- deployOpts := &cloudprovider.SInstanceDeployOptions{
- Username: opts.Account,
- Password: opts.Password,
- UserData: opts.UserData,
- PublicKey: opts.PublicKey,
- }
- return diskId, instance.DeployVM(ctx, deployOpts)
- }
- func (instance *SInstance) DeployVM(ctx context.Context, opts *cloudprovider.SInstanceDeployOptions) error {
- conf := cloudinit.SCloudConfig{
- SshPwauth: cloudinit.SSH_PASSWORD_AUTH_ON,
- }
- if len(opts.UserData) > 0 {
- config, err := cloudinit.ParseUserData(opts.UserData)
- if err == nil {
- conf.Merge(config)
- }
- }
- user := cloudinit.NewUser(opts.Username)
- if len(opts.Password) > 0 {
- user.Password(opts.Password)
- }
- if len(opts.PublicKey) > 0 {
- user.SshKey(opts.PublicKey)
- }
- if len(opts.Password) > 0 || len(opts.PublicKey) > 0 {
- conf.MergeUser(user)
- items := []SMetadataItem{}
- instance.Refresh()
- for _, item := range instance.Metadata.Items {
- if item.Key != METADATA_STARTUP_SCRIPT_POWER_SHELL && item.Key != METADATA_STARTUP_SCRIPT {
- items = append(items, item)
- }
- }
- items = append(items, SMetadataItem{Key: METADATA_STARTUP_SCRIPT_POWER_SHELL, Value: conf.UserDataPowerShell()})
- items = append(items, SMetadataItem{Key: METADATA_STARTUP_SCRIPT, Value: conf.UserDataScript()})
- instance.Metadata.Items = items
- return instance.host.zone.region.SetMetadata(instance.SelfLink, instance.Metadata)
- }
- if opts.DeleteKeypair {
- items := []SMetadataItem{}
- items = append(items, SMetadataItem{Key: METADATA_STARTUP_SCRIPT, Value: cloudinit.CLOUD_SHELL_HEADER + "\nrm -rf /root/.ssh/authorized_keys"})
- instance.Refresh()
- for _, item := range instance.Metadata.Items {
- if item.Key != METADATA_STARTUP_SCRIPT {
- items = append(items, item)
- }
- }
- instance.Metadata.Items = items
- return instance.host.zone.region.SetMetadata(instance.SelfLink, instance.Metadata)
- }
- return nil
- }
- func (instance *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error {
- return instance.host.zone.region.ChangeInstanceConfig(instance.SelfLink, instance.host.zone.Name, config.InstanceType, config.Cpu, config.MemoryMB)
- }
- func (instance *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) {
- return nil, cloudprovider.ErrNotImplemented
- }
- func (instance *SInstance) AttachDisk(ctx context.Context, diskId string) error {
- return instance.host.zone.region.AttachDisk(instance.SelfLink, diskId, false)
- }
- func (instance *SInstance) DetachDisk(ctx context.Context, diskId string) error {
- _disk, err := instance.host.zone.region.GetDisk(diskId)
- if err != nil {
- if errors.Cause(err) == cloudprovider.ErrNotFound {
- return nil
- }
- return errors.Wrapf(err, "GetDisk(%s)", diskId)
- }
- for _, disk := range instance.Disks {
- if disk.Source == _disk.SelfLink {
- return instance.host.zone.region.DetachDisk(instance.SelfLink, disk.DeviceName)
- }
- }
- return nil
- }
- func (instance *SInstance) Renew(bc billing.SBillingCycle) error {
- return cloudprovider.ErrNotSupported
- }
- func (instance *SInstance) GetError() error {
- return nil
- }
- func getDiskInfo(disk string) (cloudprovider.SDiskInfo, error) {
- result := cloudprovider.SDiskInfo{}
- diskInfo := strings.Split(disk, ":")
- for _, d := range diskInfo {
- if utils.IsInStringArray(d, []string{
- api.STORAGE_GOOGLE_PD_STANDARD, api.STORAGE_GOOGLE_PD_SSD, api.STORAGE_GOOGLE_LOCAL_SSD, api.STORAGE_GOOGLE_PD_BALANCED, api.STORAGE_GOOGLE_PD_EXTREME,
- api.STORAGE_GOOGLE_HYPERDISK_THROUGHPUT, api.STORAGE_GOOGLE_HYPERDISK_ML, api.STORAGE_GOOGLE_HYPERDISK_BALANCED, api.STORAGE_GOOGLE_HYPERDISK_EXTREME}) {
- result.StorageType = d
- } else if memSize, err := fileutils.GetSizeMb(d, 'M', 1024); err == nil {
- result.SizeGB = memSize >> 10
- } else {
- result.Name = d
- }
- }
- if len(result.StorageType) == 0 {
- result.StorageType = api.STORAGE_GOOGLE_PD_STANDARD
- }
- if result.SizeGB == 0 {
- return result, fmt.Errorf("missing disk size")
- }
- return result, nil
- }
- func (region *SRegion) CreateInstance(zone, name, desc, instanceType string, cpu, memoryMb int, networkId string, ipAddr, imageId string, disks []string) (*SInstance, error) {
- if len(instanceType) == 0 && (cpu == 0 || memoryMb == 0) {
- return nil, fmt.Errorf("missing instanceType or cpu &memory info")
- }
- if len(disks) == 0 {
- return nil, fmt.Errorf("missing disk info")
- }
- sysDisk, err := getDiskInfo(disks[0])
- if err != nil {
- return nil, errors.Wrap(err, "getDiskInfo.sys")
- }
- dataDisks := []cloudprovider.SDiskInfo{}
- for _, d := range disks[1:] {
- dataDisk, err := getDiskInfo(d)
- if err != nil {
- return nil, errors.Wrapf(err, "getDiskInfo(%s)", d)
- }
- dataDisks = append(dataDisks, dataDisk)
- }
- conf := &cloudprovider.SManagedVMCreateConfig{
- Name: name,
- Description: desc,
- ExternalImageId: imageId,
- Cpu: cpu,
- MemoryMB: memoryMb,
- ExternalNetworkId: networkId,
- IpAddr: ipAddr,
- SysDisk: sysDisk,
- DataDisks: dataDisks,
- }
- return region._createVM(zone, conf)
- }
- func (region *SRegion) _createVM(zone string, desc *cloudprovider.SManagedVMCreateConfig) (*SInstance, error) {
- if len(desc.InstanceType) == 0 {
- desc.InstanceType = fmt.Sprintf("custom-%d-%d", desc.Cpu, desc.MemoryMB)
- }
- disks := []map[string]interface{}{}
- if len(desc.SysDisk.Name) == 0 {
- desc.SysDisk.Name = fmt.Sprintf("vdisk-%s-%d", desc.Name, time.Now().UnixNano())
- }
- labels := map[string]string{}
- for k, v := range desc.Tags {
- labels[encode.EncodeGoogleLabel(k)] = encode.EncodeGoogleLabel(v)
- }
- disks = append(disks, map[string]interface{}{
- "boot": true,
- "initializeParams": map[string]interface{}{
- "diskName": normalizeString(desc.SysDisk.Name),
- "sourceImage": desc.ExternalImageId,
- "diskSizeGb": desc.SysDisk.SizeGB,
- "diskType": fmt.Sprintf("zones/%s/diskTypes/%s", zone, desc.SysDisk.StorageType),
- "labels": labels,
- },
- "autoDelete": true,
- })
- for _, disk := range desc.DataDisks {
- if len(disk.Name) == 0 {
- disk.Name = fmt.Sprintf("vdisk-%s-%d", desc.Name, time.Now().UnixNano())
- }
- disks = append(disks, map[string]interface{}{
- "boot": false,
- "initializeParams": map[string]interface{}{
- "diskName": normalizeString(disk.Name),
- "diskSizeGb": disk.SizeGB,
- "diskType": fmt.Sprintf("zones/%s/diskTypes/%s", zone, disk.StorageType),
- "labels": labels,
- },
- "autoDelete": true,
- })
- }
- networkInterface := map[string]string{
- "subnetwork": desc.ExternalNetworkId,
- }
- if !strings.HasPrefix(desc.ExternalNetworkId, "projects/") {
- vpc, err := region.GetVpc(desc.ExternalNetworkId)
- if err != nil {
- return nil, errors.Wrap(err, "region.GetNetwork")
- }
- networkInterface["subnetwork"] = getGlobalId(vpc.SelfLink)
- }
- if len(desc.IpAddr) > 0 {
- networkInterface["networkIp"] = desc.IpAddr
- }
- params := map[string]interface{}{
- "name": normalizeString(desc.NameEn),
- "description": desc.Description,
- "machineType": fmt.Sprintf("zones/%s/machineTypes/%s", zone, desc.InstanceType),
- "networkInterfaces": []map[string]string{
- networkInterface,
- },
- "disks": disks,
- }
- if len(labels) > 0 {
- params["labels"] = labels
- }
- if len(desc.ExternalSecgroupIds) > 0 {
- params["tags"] = map[string][]string{
- "items": desc.ExternalSecgroupIds,
- }
- }
- if len(desc.UserData) > 0 {
- params["metadata"] = map[string]interface{}{
- "items": []struct {
- Key string
- Value string
- }{
- {
- Key: METADATA_STARTUP_SCRIPT,
- Value: desc.UserData,
- },
- {
- Key: METADATA_POWER_SHELL,
- Value: desc.UserData,
- },
- },
- }
- }
- log.Debugf("create google instance params: %s", jsonutils.Marshal(params).String())
- instance := &SInstance{}
- resource := fmt.Sprintf("zones/%s/instances", zone)
- err := region.Insert(resource, jsonutils.Marshal(params), instance)
- if err != nil {
- return nil, err
- }
- return instance, nil
- }
- func (region *SRegion) StartInstance(id string) error {
- params := map[string]string{}
- return region.Do(id, "start", nil, jsonutils.Marshal(params))
- }
- func (region *SRegion) StopInstance(id string) error {
- params := map[string]string{}
- return region.Do(id, "stop", nil, jsonutils.Marshal(params))
- }
- func (region *SRegion) ResetInstance(id string) error {
- params := map[string]string{}
- return region.Do(id, "reset", nil, jsonutils.Marshal(params))
- }
- func (region *SRegion) DisableDeletionProtection(id string) error {
- params := map[string]string{
- "requestId": stringutils.UUID4(),
- "deletionProtection": "false",
- }
- return region.Do(id, "setDeletionProtection", params, nil)
- }
- func (region *SRegion) DetachDisk(instanceId, deviceName string) error {
- body := map[string]string{}
- params := map[string]string{"deviceName": deviceName}
- return region.Do(instanceId, "detachDisk", params, jsonutils.Marshal(body))
- }
- func (instance *SInstance) GetSerialOutput(port int) (string, error) {
- return instance.host.zone.region.GetSerialPortOutput(instance.SelfLink, port)
- }
- func (region *SRegion) GetSerialPortOutput(id string, port int) (string, error) {
- _content, content, next := "", "", 0
- var err error = nil
- for {
- _content, next, err = region.getSerialPortOutput(id, port, next)
- if err != nil {
- return content, err
- }
- content += _content
- if len(_content) == 0 {
- break
- }
- }
- return content, nil
- }
- func (region *SRegion) getSerialPortOutput(id string, port int, start int) (string, int, error) {
- resource := fmt.Sprintf("%s/serialPort?port=%d&start=%d", id, port, start)
- result := struct {
- Contents string
- Start int
- Next int
- }{}
- err := region.GetBySelfId(resource, &result)
- if err != nil {
- return "", result.Next, errors.Wrap(err, "")
- }
- return result.Contents, result.Next, nil
- }
- func (self *SRegion) AttachDisk(instanceId, diskId string, boot bool) error {
- disk, err := self.GetDisk(diskId)
- if err != nil {
- return errors.Wrapf(err, "GetDisk(%s)", diskId)
- }
- body := map[string]interface{}{
- "source": disk.SelfLink,
- "boot": boot,
- }
- if boot {
- body["autoDelete"] = true
- }
- params := map[string]string{}
- return self.Do(instanceId, "attachDisk", params, jsonutils.Marshal(body))
- }
- func (region *SRegion) ChangeInstanceConfig(id string, zone string, instanceType string, cpu int, memoryMb int) error {
- if len(instanceType) == 0 {
- instanceType = fmt.Sprintf("custom-%d-%d", cpu, memoryMb)
- }
- params := map[string]string{
- "machineType": fmt.Sprintf("zones/%s/machineTypes/%s", zone, instanceType),
- }
- return region.Do(id, "setMachineType", nil, jsonutils.Marshal(params))
- }
- func (region *SRegion) SetMetadata(id string, metadata SMetadata) error {
- return region.Do(id, "setMetadata", nil, jsonutils.Marshal(metadata))
- }
- func (region *SRegion) SetResourceTags(id string, tags SInstanceTag) error {
- return region.Do(id, "setTags", nil, jsonutils.Marshal(tags))
- }
- func (region *SRegion) SetServiceAccount(id string, email string) error {
- body := map[string]interface{}{
- "email": email,
- "scopes": []string{
- "https://www.googleapis.com/auth/devstorage.read_only",
- "https://www.googleapis.com/auth/logging.write",
- "https://www.googleapis.com/auth/monitoring.write",
- "https://www.googleapis.com/auth/servicecontrol",
- "https://www.googleapis.com/auth/service.management.readonly",
- "https://www.googleapis.com/auth/trace.append",
- },
- }
- return region.Do(id, "setsetServiceAccount", nil, jsonutils.Marshal(body))
- }
- func (region *SRegion) RebuildRoot(instanceId string, imageId string, sysDiskSizeGb int) (string, error) {
- oldDisk, diskType, deviceName := "", api.STORAGE_GOOGLE_PD_STANDARD, ""
- instance, err := region.GetInstance(instanceId)
- if err != nil {
- return "", errors.Wrap(err, "region.GetInstance")
- }
- for _, disk := range instance.Disks {
- if disk.Boot {
- oldDisk = disk.Source
- deviceName = disk.DeviceName
- break
- }
- }
- if len(oldDisk) > 0 {
- disk := &SDisk{}
- err := region.GetBySelfId(oldDisk, disk)
- if err != nil {
- return "", errors.Wrap(err, "region.GetDisk")
- }
- diskType = disk.Type
- if sysDiskSizeGb == 0 {
- sysDiskSizeGb = disk.SizeGB
- }
- }
- image, err := region.GetImage(imageId)
- if err != nil {
- return "", errors.Wrapf(err, "GetImage")
- }
- if image.DiskSizeGb > sysDiskSizeGb {
- sysDiskSizeGb = image.DiskSizeGb
- }
- zone, err := region.GetZone(instance.Zone)
- if err != nil {
- return "", errors.Wrap(err, "region.GetZone")
- }
- diskName := fmt.Sprintf("vdisk-%s-%d", instance.Name, time.Now().UnixNano())
- disk, err := region.CreateDisk(zone.Name, diskType, &cloudprovider.DiskCreateConfig{
- Name: diskName,
- SizeGb: sysDiskSizeGb,
- ImageId: imageId,
- Desc: "create for replace instance system disk",
- })
- if err != nil {
- return "", errors.Wrap(err, "region.CreateDisk.systemDisk")
- }
- if len(deviceName) > 0 {
- err = region.DetachDisk(instance.SelfLink, deviceName)
- if err != nil {
- defer region.Delete(disk.SelfLink)
- return "", errors.Wrap(err, "region.DetachDisk")
- }
- }
- err = region.AttachDisk(instance.SelfLink, disk.Id, true)
- if err != nil {
- if len(oldDisk) > 0 {
- defer region.AttachDisk(instance.SelfLink, oldDisk, true)
- }
- defer region.Delete(disk.SelfLink)
- return "", errors.Wrap(err, "region.AttachDisk.newSystemDisk")
- }
- if len(oldDisk) > 0 {
- defer region.Delete(oldDisk)
- }
- return disk.GetGlobalId(), nil
- }
- func (self *SRegion) SaveImage(diskId string, opts *cloudprovider.SaveImageOptions) (*SImage, error) {
- params := map[string]interface{}{
- "name": normalizeString(opts.Name),
- "description": opts.Notes,
- "sourceDisk": diskId,
- }
- image := &SImage{}
- err := self.Insert("global/images", jsonutils.Marshal(params), image)
- if err != nil {
- return nil, errors.Wrapf(err, "Insert")
- }
- image.storagecache = self.getStoragecache()
- return image, nil
- }
- func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) {
- for i := range self.Disks {
- if self.Disks[0].Index == 0 {
- image, err := self.host.zone.region.SaveImage(self.Disks[i].Source, opts)
- if err != nil {
- return nil, errors.Wrapf(err, "SaveImage")
- }
- return image, nil
- }
- }
- return nil, errors.Wrapf(cloudprovider.ErrNotFound, "no valid system disk found")
- }
- func (region *SRegion) SetLabels(id string, _labels map[string]string, labelFingerprint string) error {
- labels := map[string]string{}
- for k, v := range _labels {
- labels[encode.EncodeGoogleLabel(k)] = encode.EncodeGoogleLabel(v)
- }
- params := map[string]interface{}{
- "labels": labels,
- "labelFingerprint": labelFingerprint,
- }
- err := region.Do(id, "setLabels", nil, jsonutils.Marshal(params))
- if err != nil {
- return errors.Wrapf(err, `region.Do(%s, "setLabels", nil, %s)`, id, jsonutils.Marshal(params).String())
- }
- return nil
- }
- func (self *SInstance) SetTags(tags map[string]string, replace bool) error {
- if !replace {
- oldTags, _ := self.GetTags()
- for k, v := range oldTags {
- if _, ok := tags[k]; !ok {
- tags[k] = v
- }
- }
- }
- err := self.Refresh()
- if err != nil {
- return errors.Wrap(err, "self.Refresh()")
- }
- err = self.host.zone.region.SetLabels(self.SelfLink, tags, self.LabelFingerprint)
- if err != nil {
- return errors.Wrapf(err, ` self.host.zone.region.SsetLabels()`)
- }
- return nil
- }
|