huawei userdata fix

This commit is contained in:
tangbin
2020-02-15 12:55:53 +08:00
parent 22745cfbf5
commit b7737c41d1
5 changed files with 108 additions and 65 deletions
+4 -5
View File
@@ -112,11 +112,6 @@ func (self *SHuaweiGuestDriver) GetGuestInitialStateAfterRebuild() string {
func (self *SHuaweiGuestDriver) GetLinuxDefaultAccount(desc cloudprovider.SManagedVMCreateConfig) string {
userName := "root"
if desc.ImageType == "system" {
if desc.OsDistribution == "Ubuntu" {
userName = "ubuntu"
}
}
if desc.OsType == "Windows" {
userName = "Administrator"
}
@@ -131,3 +126,7 @@ func (self *SHuaweiGuestDriver) IsSupportedBillingCycle(bc billing.SBillingCycle
return false
}
func (self *SHuaweiGuestDriver) IsNeedInjectPasswordByCloudInit(desc *cloudprovider.SManagedVMCreateConfig) bool {
return true
}
+4
View File
@@ -113,6 +113,10 @@ func (self *SDisk) GetCreatedAt() time.Time {
}
func (self *SDisk) GetExpiredAt() time.Time {
if self.ExpireTime == 0 {
return time.Time{}
}
return time.Unix(self.ExpireTime/1000, 0)
}
+17 -2
View File
@@ -16,9 +16,12 @@ package huawei
import (
"fmt"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/osprofile"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
@@ -177,7 +180,7 @@ func (self *SHost) GetInstanceById(instanceId string) (*SInstance, error) {
}
func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
vmId, err := self._createVM(desc.Name, desc.ExternalImageId, desc.SysDisk, desc.Cpu, desc.MemoryMB, desc.InstanceType, desc.ExternalNetworkId, desc.IpAddr, desc.Description, desc.Password, desc.DataDisks, desc.PublicKey, desc.ExternalSecgroupId, desc.UserData, desc.BillingCycle)
vmId, err := self._createVM(desc.Name, desc.ExternalImageId, desc.SysDisk, desc.Cpu, desc.MemoryMB, desc.InstanceType, desc.ExternalNetworkId, desc.IpAddr, desc.Description, desc.Account, desc.Password, desc.DataDisks, desc.PublicKey, desc.ExternalSecgroupId, desc.UserData, desc.BillingCycle)
if err != nil {
return nil, err
}
@@ -195,7 +198,7 @@ func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error
}
func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string,
networkId string, ipAddr string, desc string, passwd string,
networkId string, ipAddr string, desc string, account string, passwd string,
diskSizes []cloudprovider.SDiskInfo, publicKey string, secgroupId string,
userData string, bc *billing.SBillingCycle) (string, error) {
net := self.zone.getNetworkById(networkId)
@@ -233,6 +236,18 @@ func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SD
log.Errorf("image %s status %s", imgId, img.Status)
return "", fmt.Errorf("image not ready")
}
// passwd, windows机型直接使用密码比较方便
if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) && len(passwd) > 0 {
keypair = ""
}
if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) {
if u, err := updateWindowsUserData(userData, img.OSVersion, account, passwd); err == nil {
userData = u
} else {
return "", errors.Wrap(err, "SHost.CreateVM.updateWindowsUserData")
}
}
disks := make([]SDisk, len(diskSizes)+1)
disks[0].SizeGB = img.SizeGB
+82 -56
View File
@@ -16,6 +16,7 @@ package huawei
import (
"context"
"encoding/base64"
"fmt"
"sort"
"strconv"
@@ -518,7 +519,6 @@ func (self *SInstance) UpdateUserData(userData string) error {
// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876349.html 使用原镜像重装
// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876971.html 更换系统盘操作系统
// 不支持调整系统盘大小
// todo: 支持注入user_data
func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) {
var err error
var jobId string
@@ -531,13 +531,28 @@ func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SMan
}
}
image, err := self.host.zone.region.GetImage(desc.ImageId)
if err != nil {
return "", errors.Wrap(err, "SInstance.RebuildRoot.GetImage")
}
// Password存在的情况下,windows 系统直接使用密码
if strings.ToLower(image.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) && len(desc.Password) > 0 {
publicKeyName = ""
}
userData, err := updateUserData(self.OSEXTSRVATTRUserData, image.OSVersion, desc.Account, desc.Password, desc.PublicKey)
if err != nil {
return "", errors.Wrap(err, "SInstance.RebuildRoot.updateUserData")
}
if self.Metadata.MeteringImageID == desc.ImageId {
jobId, err = self.host.zone.region.RebuildRoot(ctx, self.UserID, self.GetId(), desc.Password, publicKeyName, desc.PublicKey, self.OSEXTSRVATTRUserData)
jobId, err = self.host.zone.region.RebuildRoot(ctx, self.UserID, self.GetId(), desc.Password, publicKeyName, userData)
if err != nil {
return "", err
}
} else {
jobId, err = self.host.zone.region.ChangeRoot(ctx, self.UserID, self.GetId(), desc.ImageId, desc.Password, publicKeyName, desc.PublicKey, self.OSEXTSRVATTRUserData)
jobId, err = self.host.zone.region.ChangeRoot(ctx, self.UserID, self.GetId(), desc.ImageId, desc.Password, publicKeyName, userData)
if err != nil {
return "", err
}
@@ -830,20 +845,7 @@ func (self *SRegion) CreateInstance(name string, imageId string, instanceType st
}
if len(userData) > 0 {
pwd := ""
k := ""
if len(keypair) > 0 {
k = publicKey
} else {
pwd = passwd
}
udata, err := updateUserData(userData, "root", pwd, k)
if err != nil {
return "", errors.Wrap(err, "region.CreateInstance.UpdateUserData")
}
params.UserData = udata
params.UserData = userData
}
serverObj := jsonutils.Marshal(params)
@@ -1062,35 +1064,21 @@ func (self *SRegion) UpdateVM(instanceId, name string) error {
// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876349.html
// 返回job id
func (self *SRegion) RebuildRoot(ctx context.Context, userId, instanceId, passwd, publicKeyName, publicKey, userData string) (string, error) {
func (self *SRegion) RebuildRoot(ctx context.Context, userId, instanceId, passwd, publicKeyName, userData string) (string, error) {
params := jsonutils.NewDict()
reinstallObj := jsonutils.NewDict()
var udata string
var err error
if len(publicKeyName) > 0 {
reinstallObj.Add(jsonutils.NewString(publicKeyName), "keyname")
if len(userData) > 0 {
if udata, err = updateUserData(userData, "root", "", publicKey); err != nil {
return "", errors.Wrap(err, "region.RebuildRoot.UpdateUserData set root publicKey")
}
}
} else if len(passwd) > 0 {
reinstallObj.Add(jsonutils.NewString(passwd), "adminpass")
if len(userData) > 0 {
if udata, err = updateUserData(userData, "root", passwd, ""); err != nil {
return "", errors.Wrap(err, "region.RebuildRoot.UpdateUserData set root password")
}
}
} else {
return "", fmt.Errorf("both password and publicKey are empty.")
}
if len(udata) > 0 {
if len(userData) > 0 {
meta := jsonutils.NewDict()
meta.Add(jsonutils.NewString(udata), "user_data")
meta.Add(jsonutils.NewString(userData), "user_data")
reinstallObj.Add(meta, "metadata")
}
@@ -1109,35 +1097,21 @@ func (self *SRegion) RebuildRoot(ctx context.Context, userId, instanceId, passwd
// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876971.html
// 返回job id
func (self *SRegion) ChangeRoot(ctx context.Context, userId, instanceId, imageId, passwd, publicKeyName, publicKey, userData string) (string, error) {
func (self *SRegion) ChangeRoot(ctx context.Context, userId, instanceId, imageId, passwd, publicKeyName, userData string) (string, error) {
params := jsonutils.NewDict()
changeOsObj := jsonutils.NewDict()
var udata string
var err error
if len(publicKeyName) > 0 {
changeOsObj.Add(jsonutils.NewString(publicKeyName), "keyname")
if len(userData) > 0 {
if udata, err = updateUserData(userData, "root", "", publicKey); err != nil {
return "", errors.Wrap(err, "region.ChangeRoot.UpdateUserData set root publicKey")
}
}
} else if len(passwd) > 0 {
changeOsObj.Add(jsonutils.NewString(passwd), "adminpass")
if len(userData) > 0 {
if udata, err = updateUserData(userData, "root", passwd, ""); err != nil {
return "", errors.Wrap(err, "region.ChangeRoot.UpdateUserData set root password")
}
}
} else {
return "", fmt.Errorf("both password and publicKey are empty.")
}
if len(udata) > 0 {
if len(userData) > 0 {
meta := jsonutils.NewDict()
meta.Add(jsonutils.NewString(udata), "user_data")
meta.Add(jsonutils.NewString(userData), "user_data")
changeOsObj.Add(meta, "metadata")
}
@@ -1353,15 +1327,29 @@ func (self *SInstance) GetError() error {
return nil
}
func updateUserData(userData, username, password, publicKey string) (string, error) {
config, err := cloudinit.ParseUserDataBase64(userData)
if err != nil {
return "", fmt.Errorf("invalid userdata %s", userData)
func updateUserData(userData, osVersion, username, password, publicKey string) (string, error) {
winOS := strings.ToLower(osprofile.OS_TYPE_WINDOWS)
osVersion = strings.ToLower(osVersion)
config := &cloudinit.SCloudConfig{}
if strings.Contains(osVersion, winOS) {
if _config, err := cloudinit.ParseUserDataBase64(userData); err == nil {
config = _config
} else {
log.Debugf("updateWindowsUserData invalid userdata %s", userData)
}
} else {
if _config, err := cloudinit.ParseUserDataBase64(userData); err == nil {
config = _config
} else {
return "", fmt.Errorf("updateLinuxUserData invalid userdata %s", userData)
}
}
user := cloudinit.NewUser(username)
config.RemoveUser(user)
config.DisableRoot = 0
if len(password) > 0 {
config.SshPwauth = cloudinit.SSH_PASSWORD_AUTH_ON
user.Password(password)
config.MergeUser(user)
}
@@ -1371,5 +1359,43 @@ func updateUserData(userData, username, password, publicKey string) (string, err
config.MergeUser(user)
}
return config.UserDataBase64(), nil
if strings.Contains(osVersion, winOS) {
userData, err := updateWindowsUserData(config.UserDataPowerShell(), osVersion, username, password)
if err != nil {
return "", errors.Wrap(err, "updateUserData.updateWindowsUserData")
}
return userData, nil
} else {
return config.UserDataBase64(), nil
}
}
func updateWindowsUserData(userData string, osVersion string, username, password string) (string, error) {
// Windows Server 2003, Windows Vista, Windows Server 2008, Windows Server 2003 R2, Windows Server 2000, Windows Server 2012, Windows Server 2003 with SP1, Windows 8
oldVersions := []string{"2000", "2003", "2008", "2012", "Vista"}
isOldVersion := false
for i := range oldVersions {
if strings.Contains(osVersion, oldVersions[i]) {
isOldVersion = true
}
}
shells := ""
if isOldVersion {
shells += fmt.Sprintf("rem cmd\n")
if username == "Administrator" {
shells += fmt.Sprintf("net user %s %s\n", username, password)
} else {
shells += fmt.Sprintf("net user %s %s /add\n", username, password)
shells += fmt.Sprintf("net localgroup administrators %s /add\n", username)
}
shells += fmt.Sprintf("net user %s /active:yes", username)
} else {
if !strings.HasPrefix(userData, "#ps1") {
shells = fmt.Sprintf("#ps1\n%s", userData)
}
}
return base64.StdEncoding.EncodeToString([]byte(shells)), nil
}
+1 -2
View File
@@ -120,13 +120,12 @@ func init() {
Image string `help:"Image ID"`
Password string `help:"admin password"`
PublicKeyName string `help:"public key name"`
PublicKey string `help:"public key"`
UserData string `help:"cloud-init user data"`
}
shellutils.R(&InstanceRebuildRootOptions{}, "instance-rebuild-root", "Reinstall virtual server system image", func(cli *huawei.SRegion, args *InstanceRebuildRootOptions) error {
ctx := context.Background()
jobId, err := cli.ChangeRoot(ctx, args.UserId, args.ID, args.Image, args.Password, args.PublicKeyName, args.PublicKey, args.UserData)
jobId, err := cli.ChangeRoot(ctx, args.UserId, args.ID, args.Image, args.Password, args.PublicKeyName, args.UserData)
if err != nil {
return err
}