修正:1. 主机创建/rebuild root密码设置问题 2. climc 密码设置问题 3.

billing_type字段为空导致创建主机失败问题
This commit is contained in:
Qiu Jian
2018-09-15 00:31:58 +08:00
parent ced99b919b
commit 8c2250517f
10 changed files with 189 additions and 54 deletions
+17
View File
@@ -50,6 +50,11 @@ func init() {
if err != nil {
return err
}
if opts.NoAccountInit != nil && *opts.NoAccountInit {
params.Add(jsonutils.JSONFalse, "reset_password")
}
count := options.IntV(opts.Count)
if options.BoolV(opts.DryRun) {
results, err := modules.SchedManager.DoScheduleListResult(s, params, count)
@@ -328,6 +333,11 @@ func init() {
if err != nil {
return err
}
if opts.NoAccountInit != nil && *opts.NoAccountInit {
params.Add(jsonutils.JSONFalse, "reset_password")
}
srv, err := modules.Servers.PerformAction(s, opts.ID, "rebuild-root", params)
if err != nil {
return err
@@ -338,6 +348,13 @@ func init() {
R(&options.ServerChangeConfigOptions{}, "server-change-config", "Change configuration of VM", func(s *mcclient.ClientSession, opts *options.ServerChangeConfigOptions) error {
params, err := options.StructToParams(opts)
if len(opts.Disk) > 0 {
params.Remove("disk.0")
for i, d := range opts.Disk {
params.Set(fmt.Sprintf("disk.%d", i+1), jsonutils.NewString(d))
}
}
if err != nil {
return err
}
+3
View File
@@ -150,6 +150,9 @@ func fetchIVMinfo(desc SAliyunVMCreateConfig, iVM cloudprovider.ICloudVM, guestI
}
data.Add(jsonutils.NewString("root"), "account")
data.Add(jsonutils.NewString(encpasswd), "key")
} else {
data.Add(jsonutils.NewString(""), "account")
data.Add(jsonutils.NewString(""), "key")
}
if len(desc.OsDistribution) > 0 {
+1 -1
View File
@@ -8,7 +8,7 @@ const (
)
type SBillingResourceBase struct {
BillingType string `width:"36" charset:"ascii" nullable:"true" default:"postpaid" list:"user" create:"required"`
BillingType string `width:"36" charset:"ascii" nullable:"true" default:"postpaid" list:"user" create:"optional"`
ExpiredAt time.Time `nullable:"true" list:"user" create:"optional"`
}
+108 -42
View File
@@ -36,6 +36,7 @@ import (
"yunion.io/x/onecloud/pkg/mcclient/auth"
"yunion.io/x/onecloud/pkg/util/httputils"
"yunion.io/x/onecloud/pkg/util/logclient"
"yunion.io/x/onecloud/pkg/util/seclib2"
)
const (
@@ -272,8 +273,8 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ
if count > 0 {
sgq := guestdisks.Query(guestdisks.Field("guest_id")).
Filter(sqlchemy.AND(
sqlchemy.Equals(guestdisks.Field("disk_id"), disk.Id),
sqlchemy.IsFalse(guestdisks.Field("deleted"))))
sqlchemy.Equals(guestdisks.Field("disk_id"), disk.Id),
sqlchemy.IsFalse(guestdisks.Field("deleted"))))
q = q.Filter(sqlchemy.In(q.Field("id"), sgq))
} else {
hosts := HostManager.Query().SubQuery()
@@ -281,11 +282,11 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ
storages := StorageManager.Query().SubQuery()
sq := hosts.Query(hosts.Field("id")).
Join(hoststorages, sqlchemy.AND(
sqlchemy.Equals(hoststorages.Field("host_id"), hosts.Field("id")),
sqlchemy.IsFalse(hoststorages.Field("deleted")))).
sqlchemy.Equals(hoststorages.Field("host_id"), hosts.Field("id")),
sqlchemy.IsFalse(hoststorages.Field("deleted")))).
Join(storages, sqlchemy.AND(
sqlchemy.Equals(storages.Field("id"), hoststorages.Field("storage_id")),
sqlchemy.IsFalse(storages.Field("deleted")))).
sqlchemy.Equals(storages.Field("id"), hoststorages.Field("storage_id")),
sqlchemy.IsFalse(storages.Field("deleted")))).
Filter(sqlchemy.Equals(storages.Field("id"), disk.StorageId)).SubQuery()
q = q.In("host_id", sq)
}
@@ -339,8 +340,8 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ
isodev := IsolatedDeviceManager.Query().SubQuery()
sgq := isodev.Query(isodev.Field("guest_id")).
Filter(sqlchemy.AND(
sqlchemy.IsNotNull(isodev.Field("guest_id")),
sqlchemy.Startswith(isodev.Field("dev_type"), "GPU")))
sqlchemy.IsNotNull(isodev.Field("guest_id")),
sqlchemy.Startswith(isodev.Field("dev_type"), "GPU")))
showGpu := utils.ToBool(gpu)
cond := sqlchemy.NotIn
if showGpu {
@@ -561,6 +562,14 @@ func (manager *SGuestManager) ValidateCreateData(ctx context.Context, userCred m
data.Add(jsonutils.NewInt(int64(vmemSize)), "vmem_size")
data.Add(jsonutils.NewInt(int64(vcpuCount)), "vcpu_count")
resetPassword := jsonutils.QueryBoolean(data, "reset_password", true)
passwd, _ := data.GetString("password")
if resetPassword && len(passwd) > 0 {
if ! seclib2.MeetComplxity(passwd) {
return nil, httperrors.NewWeakPasswordError()
}
}
disk0Json, _ := data.Get("disk.0")
if disk0Json == nil {
return nil, httperrors.NewInputParameterError("No disk information provided")
@@ -2411,41 +2420,81 @@ func (self *SGuest) PerformPurge(ctx context.Context, userCred mcclient.TokenCre
return nil, err
}
func (self *SGuest) setKeypairId(userCred mcclient.TokenCredential, keypairId string) error {
diff, err := self.GetModelManager().TableSpec().Update(self, func() error {
self.KeypairId = keypairId
return nil
})
if err != nil {
db.OpsLog.LogEvent(self, db.ACT_UPDATE, diff, userCred)
}
return err
}
func (self *SGuest) AllowPerformRebuildRoot(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return self.IsOwner(userCred)
}
func (self *SGuest) PerformRebuildRoot(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
imageId, _ := data.GetString("image_id")
if utils.IsInStringArray(self.Status, []string{VM_READY, VM_RUNNING, VM_ADMIN}) {
if !data.Contains("image_id") {
gdc := self.CategorizeDisks()
imageId = gdc.Root.GetTemplateId()
if len(imageId) == 0 {
return nil, httperrors.NewBadRequestError("No template for root disk")
}
img, err := CachedimageManager.getImageInfo(ctx, userCred, imageId, false)
if err != nil {
return nil, httperrors.NewBadRequestError("Template %s not accessible: %s", imageId, err.Error())
}
osType, _ := img.Properties["os_type"]
osName := self.GetMetadata("os_name", userCred)
if len(osName) == 0 && len(osType) == 0 && strings.ToLower(osType) != strings.ToLower(osName) {
return nil, httperrors.NewBadRequestError("Cannot switch OS between %s-%s", osName, osType)
}
}
autoStart := jsonutils.QueryBoolean(data, "auto_start", false)
var needStop = false
if self.Status == VM_RUNNING {
needStop = true
}
err := self.StartRebuildRootTask(ctx, userCred, imageId, needStop, autoStart)
return nil, err
if ! utils.IsInStringArray(self.Status, []string{VM_READY, VM_RUNNING, VM_ADMIN}) {
return nil, httperrors.NewInvalidStatusError("Cannot reset root in status %s", self.Status)
}
return nil, httperrors.NewInvalidStatusError("Cannot reset root in status %s", self.Status)
if !data.Contains("image_id") {
gdc := self.CategorizeDisks()
imageId = gdc.Root.GetTemplateId()
if len(imageId) == 0 {
return nil, httperrors.NewBadRequestError("No template for root disk")
}
img, err := CachedimageManager.getImageInfo(ctx, userCred, imageId, false)
if err != nil {
return nil, httperrors.NewBadRequestError("Template %s not accessible: %s", imageId, err.Error())
}
osType, _ := img.Properties["os_type"]
osName := self.GetMetadata("os_name", userCred)
if len(osName) == 0 && len(osType) == 0 && strings.ToLower(osType) != strings.ToLower(osName) {
return nil, httperrors.NewBadRequestError("Cannot switch OS between %s-%s", osName, osType)
}
}
autoStart := jsonutils.QueryBoolean(data, "auto_start", false)
var needStop = false
if self.Status == VM_RUNNING {
needStop = true
}
resetPasswd := jsonutils.QueryBoolean(data, "reset_password", true)
passwd, _ := data.GetString("password")
if len(passwd) > 0 {
if ! seclib2.MeetComplxity(passwd) {
return nil, httperrors.NewWeakPasswordError()
}
}
keypairStr := jsonutils.GetAnyString(data, []string{"keypair", "keypair_id"})
if len(keypairStr) > 0 {
keypairObj, err := KeypairManager.FetchByIdOrName(userCred.GetUserId(), keypairStr)
if err != nil {
if err == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError("keypair %s not found", keypairStr)
} else {
return nil, httperrors.NewGeneralError(err)
}
}
if self.KeypairId != keypairObj.GetId() {
err = self.setKeypairId(userCred, keypairObj.GetId())
if err != nil {
return nil, httperrors.NewGeneralError(err)
}
}
}
err := self.StartRebuildRootTask(ctx, userCred, imageId, needStop, autoStart, passwd, resetPasswd)
return nil, err
}
func (self *SGuest) StartRebuildRootTask(ctx context.Context, userCred mcclient.TokenCredential, imageId string, needStop, autoStart bool) error {
func (self *SGuest) StartRebuildRootTask(ctx context.Context, userCred mcclient.TokenCredential, imageId string, needStop, autoStart bool, passwd string, resetPasswd bool) error {
data := jsonutils.NewDict()
data.Set("image_id", jsonutils.NewString(imageId))
if needStop {
@@ -2454,6 +2503,14 @@ func (self *SGuest) StartRebuildRootTask(ctx context.Context, userCred mcclient.
if autoStart {
data.Set("auto_start", jsonutils.JSONTrue)
}
if resetPasswd {
data.Set("reset_password", jsonutils.JSONTrue)
} else {
data.Set("reset_password", jsonutils.JSONFalse)
}
if len(passwd) > 0 {
data.Set("password", jsonutils.NewString(passwd))
}
if self.GetHypervisor() == HYPERVISOR_BAREMETAL {
task, err := taskman.TaskManager.NewTask(ctx, "BaremetalServerRebuildRootTask", self, userCred, data, "", "", nil)
if err != nil {
@@ -2875,12 +2932,12 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
}
provider, e := self.GetHost().GetDriver()
if e != nil {
/*if e != nil {
log.Errorf("Get Provider Error: %s", e)
return nil, httperrors.NewInsufficientResourceError("Provider Not Found")
}
}*/
if !provider.IsPublicCloud() {
if e != nil || !provider.IsPublicCloud() {
for storageId, needSize := range diskSizes {
iStorage, err := StorageManager.FetchById(storageId)
if err != nil {
@@ -2904,6 +2961,9 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
if jsonutils.QueryBoolean(data, "auto_start", false) {
confs.Add(jsonutils.NewBool(true), "auto_start")
}
log.Debugf("%s", confs.String())
pendingUsage := &SQuota{}
if addCpu > 0 {
pendingUsage.Cpu = addCpu
@@ -3140,17 +3200,23 @@ func (self *SGuest) GetDeployConfigOnHost(ctx context.Context, host *SHost, para
deployAction = "deploy"
}
resetPasswd := true
if deployAction == "deploy" {
resetPasswd = jsonutils.QueryBoolean(params, "reset_password", false)
}
// resetPasswd := true
// if deployAction == "deploy" {
resetPasswd := jsonutils.QueryBoolean(params, "reset_password", true)
//}
if resetPasswd {
config.Add(jsonutils.JSONTrue, "reset_password")
passwd, _ := params.GetString("password")
if len(passwd) > 0 {
config.Add(jsonutils.NewString(passwd), "password")
}
keypair := self.getKeypair()
if keypair != nil {
config.Add(jsonutils.NewString(keypair.PublicKey), "public_key")
}
} else {
config.Add(jsonutils.JSONFalse, "reset_password")
}
config.Add(jsonutils.NewString(deployAction), "action")
@@ -3883,7 +3949,7 @@ func (manager *SGuestManager) GetIpInProjectWithName(projectId, name string, isE
sqlchemy.IsFalse(guests.Field("pending_deleted"))),
sqlchemy.IsFalse(guests.Field("deleted")))).
Join(networks, sqlchemy.AND(sqlchemy.Equals(networks.Field("id"), guestnics.Field("network_id")),
sqlchemy.IsFalse(networks.Field("deleted")))).
sqlchemy.IsFalse(networks.Field("deleted")))).
Filter(sqlchemy.Equals(guests.Field("name"), name)).
Filter(sqlchemy.NotEquals(guestnics.Field("ip_addr"), "")).
Filter(sqlchemy.IsNotNull(guestnics.Field("ip_addr"))).
+11 -3
View File
@@ -139,9 +139,17 @@ func (self *KVMGuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Conte
self.SetStage("OnGuestDeployComplete", nil)
guest.SetStatus(self.UserCred, models.VM_DEPLOYING, "")
params := jsonutils.NewDict()
params.Set("reset_password", jsonutils.JSONTrue)
guest.StartGuestDeployTask(ctx, self.UserCred, params, "deploy", self.GetTaskId())
// params := jsonutils.NewDict()
// params.Set("reset_password", jsonutils.JSONTrue)
// clear logininfo
loginParams := make(map[string]interface{})
loginParams["login_account"] = "none"
loginParams["login_key"] = "none"
loginParams["login_key_timestamp"] = "none"
guest.SetAllMetadata(ctx, loginParams, self.UserCred)
guest.StartGuestDeployTask(ctx, self.UserCred, self.GetParams(), "deploy", self.GetTaskId())
}
func (self *KVMGuestRebuildRootTask) OnRebuildRootDiskCompleteFailed(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
+5
View File
@@ -100,6 +100,11 @@ func NewInputParameterError(msg string, params ...interface{}) *httputils.JSONCl
return NewJsonClientError(400, "InputParameterError", msg, err)
}
func NewWeakPasswordError() *httputils.JSONClientError {
msg, err := errorMessage("password must be 12 chars of at least one digit, letter, uppercase letter and punctuate", nil)
return NewJsonClientError(400, "WeakPasswordError", msg, err)
}
func NewInsufficientResourceError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params)
return NewJsonClientError(400, "InsufficientResourceError", msg, err)
+7 -6
View File
@@ -98,7 +98,7 @@ type ServerCreateOptions struct {
Bios string `help:"BIOS" choices:"BIOS|UEFI"`
Desc string `help:"Description" metavar:"<DESCRIPTION>" json:"description"`
Boot string `help:"Boot device" metavar:"<BOOT_DEVICE>" choices:"disk|cdrom" json:"-"`
NoAccountInit *bool `help:"Not reset account password" json:"reset_password"`
NoAccountInit *bool `help:"Not reset account password"`
AllowDelete *bool `help:"Unlock server to allow deleting" json:"-"`
ShutdownBehavior string `help:"Behavior after VM server shutdown, stop or terminate server" metavar:"<SHUTDOWN_BEHAVIOR>" choices:"stop|terminate"`
AutoStart *bool `help:"Auto start server after it is created"`
@@ -264,11 +264,12 @@ type ServerSaveImageOptions struct {
}
type ServerRebuildRootOptions struct {
ID string `help:"Server to rebuild root" json:"-"`
Image string `help:"New root Image template ID" json:"image_id"`
Keypair string `help:"ssh Keypair used for login"`
Password string `help:"Default user password"`
AutoStart *bool `help:"Auto start server after it is created"`
ID string `help:"Server to rebuild root" json:"-"`
Image string `help:"New root Image template ID" json:"image_id"`
Keypair string `help:"ssh Keypair used for login"`
Password string `help:"Default user password"`
NoAccountInit *bool `help:"Not reset account password"`
AutoStart *bool `help:"Auto start server after it is created"`
}
type ServerChangeConfigOptions struct {
+4 -1
View File
@@ -88,7 +88,10 @@ func (self *SStoragecache) GetIImages() ([]cloudprovider.ICloudImage, error) {
func (self *SStoragecache) UploadImage(userCred mcclient.TokenCredential, imageId string, osArch, osType, osDist string, extId string, isForce bool) (string, error) {
if len(extId) > 0 {
status, _ := self.region.GetImageStatus(extId)
status, err := self.region.GetImageStatus(extId)
if err != nil {
log.Errorf("GetImageStatus error %s", err)
}
if status == ImageStatusAvailable && !isForce {
return extId, nil
}
+18 -1
View File
@@ -16,7 +16,7 @@ const (
ALL_DIGITS = "0123456789"
ALL_LETTERS = "abcdefghijklmnopqrstuvwxyz"
ALL_UPPERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
ALL_PUNC = PUNC
ALL_PUNC = "~`!@#$%^&*()-_=+[]{}|:':\",./<>?"
)
type PasswordStrength struct {
@@ -72,3 +72,20 @@ func AnalyzePasswordStrenth(passwd string) PasswordStrength {
}
return ps
}
func (ps PasswordStrength) Len() int {
return ps.Punctuats + ps.Uppercases + ps.Lowercases + ps.Digits
}
func (ps PasswordStrength) MeetComplexity() bool {
if ps.Punctuats > 0 && ps.Digits > 0 && ps.Lowercases > 0 && ps.Uppercases > 0 && ps.Len() >= 12 {
return true
} else {
return false
}
}
func MeetComplxity(passwd string) bool {
ps := AnalyzePasswordStrenth(passwd)
return ps.MeetComplexity()
}
+15
View File
@@ -10,3 +10,18 @@ func TestRandomPassword2(t *testing.T) {
rand.Seed(time.Now().Unix())
t.Logf("%s", RandomPassword2(12))
}
func TestMeetComplxity(t *testing.T) {
cases := [] struct {
in string
want bool
} {
{"123456", false},
{"123abcABC!@#", true},
}
for _, c := range cases {
if c.want != MeetComplxity(c.in) {
t.Errorf("%s != %v", c.in, c.want)
}
}
}