yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/cloudprovider/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 cloudprovider
    16  
    17  import (
    18  	"encoding/base64"
    19  	"strings"
    20  
    21  	"yunion.io/x/jsonutils"
    22  	"yunion.io/x/pkg/errors"
    23  	"yunion.io/x/pkg/util/osprofile"
    24  
    25  	"yunion.io/x/onecloud/pkg/util/ansible"
    26  	"yunion.io/x/onecloud/pkg/util/billing"
    27  	"yunion.io/x/onecloud/pkg/util/cloudinit"
    28  	"yunion.io/x/onecloud/pkg/util/seclib2"
    29  )
    30  
    31  type TOsType string
    32  
    33  var (
    34  	OsTypeLinux   = TOsType(osprofile.OS_TYPE_LINUX)
    35  	OsTypeWindows = TOsType(osprofile.OS_TYPE_WINDOWS)
    36  )
    37  
    38  type TBiosType string
    39  
    40  var (
    41  	BIOS = TBiosType("BIOS")
    42  	UEFI = TBiosType("UEFI")
    43  )
    44  
    45  func ToBiosType(bios string) TBiosType {
    46  	switch strings.ToLower(bios) {
    47  	case "uefi", "efi":
    48  		return UEFI
    49  	default:
    50  		return BIOS
    51  	}
    52  }
    53  
    54  type SDistDefaultAccount struct {
    55  	// 操作系统发行版
    56  	OsDistribution string
    57  	// 默认用户名
    58  	DefaultAccount string
    59  	// 是否可更改
    60  	Changeable bool
    61  }
    62  
    63  type SOsDefaultAccount struct {
    64  	// 默认用户名
    65  	DefaultAccount string
    66  	// 是否可更改用户名
    67  	Changeable bool
    68  	// 禁止使用的账号
    69  	DisabledAccounts []string
    70  	// 各操作系统发行版的默认用户名信息
    71  	DistAccounts []SDistDefaultAccount
    72  }
    73  
    74  type SDefaultAccount struct {
    75  	Linux   SOsDefaultAccount
    76  	Windows SOsDefaultAccount
    77  }
    78  
    79  type StorageInfo struct {
    80  	StorageType string
    81  	MaxSizeGb   int
    82  	MinSizeGb   int
    83  	Resizable   bool
    84  	StepSizeGb  int
    85  }
    86  
    87  type Storage struct {
    88  	DataDisk []StorageInfo
    89  	SysDisk  []StorageInfo
    90  }
    91  
    92  type SInstanceCapability struct {
    93  	Provider   string
    94  	Hypervisor string
    95  	Storages   Storage
    96  
    97  	DefaultAccount SDefaultAccount
    98  }
    99  
   100  type SDiskInfo struct {
   101  	StorageExternalId string
   102  	StorageType       string
   103  	SizeGB            int
   104  	Name              string
   105  }
   106  
   107  type GuestDiskCreateOptions struct {
   108  	SizeMb    int
   109  	UUID      string
   110  	Driver    string
   111  	StorageId string
   112  }
   113  
   114  const (
   115  	CLOUD_SHELL                 = "cloud-shell"
   116  	CLOUD_SHELL_WITHOUT_ENCRYPT = "cloud-shell-without-encrypt"
   117  	CLOUD_CONFIG                = "cloud-config"
   118  	CLOUD_POWER_SHELL           = "powershell"
   119  	CLOUD_EC2                   = "ec2"
   120  )
   121  
   122  type SPublicIpInfo struct {
   123  	PublicIpBw         int
   124  	PublicIpChargeType TElasticipChargeType
   125  }
   126  
   127  type ServerStopOptions struct {
   128  	IsForce      bool
   129  	StopCharging bool
   130  }
   131  
   132  type SManagedVMCreateConfig struct {
   133  	Name                string
   134  	NameEn              string
   135  	Hostname            string
   136  	ExternalImageId     string
   137  	ImageType           string
   138  	OsType              string
   139  	OsDistribution      string
   140  	OsVersion           string
   141  	InstanceType        string // InstanceType 不为空时,直接采用InstanceType创建机器。
   142  	Cpu                 int
   143  	MemoryMB            int
   144  	ExternalNetworkId   string
   145  	ExternalVpcId       string
   146  	IpAddr              string
   147  	Description         string
   148  	SysDisk             SDiskInfo
   149  	DataDisks           []SDiskInfo
   150  	PublicKey           string
   151  	ExternalSecgroupId  string
   152  	ExternalSecgroupIds []string
   153  	Account             string
   154  	Password            string
   155  	UserData            string
   156  	ProjectId           string
   157  
   158  	SPublicIpInfo
   159  
   160  	Tags map[string]string
   161  
   162  	BillingCycle *billing.SBillingCycle
   163  
   164  	IsNeedInjectPasswordByCloudInit bool
   165  	UserDataType                    string
   166  	WindowsUserDataType             string
   167  	IsWindowsUserDataTypeNeedEncode bool
   168  }
   169  
   170  type SManagedVMChangeConfig struct {
   171  	Cpu          int
   172  	MemoryMB     int
   173  	InstanceType string
   174  }
   175  
   176  type SManagedVMRebuildRootConfig struct {
   177  	Account   string
   178  	Password  string
   179  	ImageId   string
   180  	PublicKey string
   181  	SysSizeGB int
   182  	OsType    string
   183  }
   184  
   185  func (vmConfig *SManagedVMCreateConfig) GetConfig(config *jsonutils.JSONDict) error {
   186  	err := config.Unmarshal(vmConfig, "desc")
   187  	if err != nil {
   188  		return errors.Wrapf(err, "config.Unmarshal")
   189  	}
   190  	if !vmConfig.IsNeedInjectPasswordByCloudInit {
   191  		if len(vmConfig.UserData) > 0 {
   192  			_, err := cloudinit.ParseUserData(vmConfig.UserData)
   193  			if err != nil {
   194  				return err
   195  			}
   196  		}
   197  	}
   198  	if publicKey, _ := config.GetString("public_key"); len(publicKey) > 0 {
   199  		vmConfig.PublicKey = publicKey
   200  	}
   201  	//目前所写的userData格式仅支持Linux
   202  	if strings.ToLower(vmConfig.OsType) == strings.ToLower(osprofile.OS_TYPE_LINUX) {
   203  		adminPublicKey, _ := config.GetString("admin_public_key")
   204  		projectPublicKey, _ := config.GetString("project_public_key")
   205  		vmConfig.UserData = generateUserData(adminPublicKey, projectPublicKey, vmConfig.UserData)
   206  	}
   207  
   208  	resetPassword := jsonutils.QueryBoolean(config, "reset_password", false)
   209  	vmConfig.Password, _ = config.GetString("password")
   210  	if resetPassword && len(vmConfig.Password) == 0 {
   211  		vmConfig.Password = seclib2.RandomPassword2(12)
   212  	}
   213  	if vmConfig.IsNeedInjectPasswordByCloudInit {
   214  		err = vmConfig.InjectPasswordByCloudInit()
   215  		if err != nil {
   216  			return errors.Wrapf(err, "InjectPasswordByCloudInit")
   217  		}
   218  	}
   219  	return nil
   220  }
   221  
   222  func generateUserData(adminPublicKey, projectPublicKey, oUserData string) string {
   223  	var oCloudConfig *cloudinit.SCloudConfig
   224  
   225  	if len(oUserData) > 0 {
   226  		oCloudConfig, _ = cloudinit.ParseUserData(oUserData)
   227  	}
   228  
   229  	ansibleUser := cloudinit.NewUser(ansible.PUBLIC_CLOUD_ANSIBLE_USER)
   230  	ansibleUser.SshKey(adminPublicKey).SshKey(projectPublicKey).SudoPolicy(cloudinit.USER_SUDO_NOPASSWD)
   231  
   232  	cloudConfig := cloudinit.SCloudConfig{
   233  		DisableRoot: 0,
   234  		SshPwauth:   cloudinit.SSH_PASSWORD_AUTH_ON,
   235  
   236  		Users: []cloudinit.SUser{
   237  			ansibleUser,
   238  		},
   239  	}
   240  
   241  	if oCloudConfig != nil {
   242  		cloudConfig.Merge(oCloudConfig)
   243  	}
   244  
   245  	return cloudConfig.UserData()
   246  }
   247  
   248  func (vmConfig *SManagedVMCreateConfig) GetUserData() (string, error) {
   249  	if len(vmConfig.UserData) == 0 {
   250  		return "", nil
   251  	}
   252  	oUserData, err := cloudinit.ParseUserData(vmConfig.UserData)
   253  	if err != nil {
   254  		// 用户输入非标准cloud-init数据
   255  		if !vmConfig.IsNeedInjectPasswordByCloudInit {
   256  			return base64.StdEncoding.EncodeToString([]byte(vmConfig.UserData)), nil
   257  		}
   258  		return "", err
   259  	}
   260  	if strings.ToLower(vmConfig.OsType) == strings.ToLower(osprofile.OS_TYPE_LINUX) {
   261  		switch vmConfig.UserDataType {
   262  		case CLOUD_SHELL:
   263  			return oUserData.UserDataScriptBase64(), nil
   264  		case CLOUD_SHELL_WITHOUT_ENCRYPT:
   265  			return oUserData.UserDataScript(), nil
   266  		default:
   267  			return oUserData.UserDataBase64(), nil
   268  		}
   269  	} else {
   270  		userData := ""
   271  		switch vmConfig.WindowsUserDataType {
   272  		case CLOUD_EC2:
   273  			userData = oUserData.UserDataEc2()
   274  		default:
   275  			userData = oUserData.UserDataPowerShell()
   276  		}
   277  		if vmConfig.IsWindowsUserDataTypeNeedEncode {
   278  			userData = base64.StdEncoding.EncodeToString([]byte(userData))
   279  		}
   280  		return userData, nil
   281  	}
   282  }
   283  
   284  func (vmConfig *SManagedVMCreateConfig) InjectPasswordByCloudInit() error {
   285  	loginUser := cloudinit.NewUser(vmConfig.Account)
   286  	loginUser.SudoPolicy(cloudinit.USER_SUDO_NOPASSWD)
   287  	if len(vmConfig.PublicKey) > 0 {
   288  		loginUser.SshKey(vmConfig.PublicKey)
   289  	}
   290  	if len(vmConfig.Password) > 0 {
   291  		loginUser.Password(vmConfig.Password)
   292  	}
   293  
   294  	cloudconfig := cloudinit.SCloudConfig{
   295  		DisableRoot: 0,
   296  		SshPwauth:   cloudinit.SSH_PASSWORD_AUTH_ON,
   297  		Users: []cloudinit.SUser{
   298  			loginUser,
   299  		},
   300  	}
   301  
   302  	if len(vmConfig.UserData) > 0 {
   303  		oCloudConfig, err := cloudinit.ParseUserData(vmConfig.UserData)
   304  		if err != nil {
   305  			return err
   306  		}
   307  		cloudconfig.Merge(oCloudConfig)
   308  	}
   309  	vmConfig.UserData = cloudconfig.UserData()
   310  	return nil
   311  }
   312  
   313  // +onecloud:model-api-gen
   314  type ServerVncInput struct {
   315  	// 是否使用原生vnc控制台,此选项仅对openstack有效
   316  	// default: false
   317  	Origin bool `json:"origin"`
   318  }
   319  
   320  // +onecloud:model-api-gen
   321  type ServerVncOutput struct {
   322  	Id string `json:"id"`
   323  
   324  	// baremetal
   325  	HostId string `json:"host_id"`
   326  	Zone   string `json:"zone"`
   327  
   328  	// kvm host ip
   329  	Host     string `json:"host"`
   330  	Protocol string `json:"protocol"`
   331  	Port     int64  `json:"port"`
   332  
   333  	Url          string `json:"url"`
   334  	InstanceId   string `json:"instance_id"`
   335  	InstanceName string `json:"instance_name"`
   336  	Password     string `json:"password"`
   337  	VncPassword  string `json:"vnc_password"`
   338  
   339  	OsName string `json:"os_name"`
   340  
   341  	// cloudpods
   342  	ApiServer     string `json:"api_server"`
   343  	ConnectParams string `json:"connect_params"`
   344  	Session       string `json:"session"`
   345  
   346  	Hypervisor string `json:"hypervisor"`
   347  }