diff --git a/cmd/climc/shell/compute/servers.go b/cmd/climc/shell/compute/servers.go index 0379c60b45..2c4ca63705 100644 --- a/cmd/climc/shell/compute/servers.go +++ b/cmd/climc/shell/compute/servers.go @@ -109,6 +109,7 @@ func init() { cmd.BatchPerform("enable-memclean", new(options.ServerIdsOptions)) cmd.Perform("qga-set-password", &options.ServerQgaSetPassword{}) cmd.Perform("qga-command", &options.ServerQgaCommand{}) + cmd.Perform("set-password", &options.ServerSetPasswordOptions{}) cmd.Get("vnc", new(options.ServerIdOptions)) cmd.Get("desc", new(options.ServerIdOptions)) diff --git a/pkg/apis/compute/guests.go b/pkg/apis/compute/guests.go index 7a73d8e400..634746287f 100644 --- a/pkg/apis/compute/guests.go +++ b/pkg/apis/compute/guests.go @@ -906,3 +906,12 @@ type ServerQgaSetPasswordInput struct { type ServerQgaCommandInput struct { Command string } + +type ServerSetPasswordInput struct { + Username string + Password string + + // deploy params + ResetPassword bool + AutoStart bool +} diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index 76ebe1e95d..fbceb2108e 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -32,6 +32,7 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/pkg/tristate" "yunion.io/x/pkg/util/fileutils" + "yunion.io/x/pkg/util/osprofile" "yunion.io/x/pkg/util/regutils" "yunion.io/x/pkg/util/sets" "yunion.io/x/pkg/utils" @@ -665,6 +666,36 @@ func (self *SGuest) GetDetailsCreateParams(ctx context.Context, userCred mcclien return input.JSON(input), nil } +func (self *SGuest) PerformSetPassword(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ServerSetPasswordInput) (jsonutils.JSONObject, error) { + switch self.Status { + case api.VM_RUNNING: + inputQga := &api.ServerQgaSetPasswordInput{ + Username: input.Username, + Password: input.Password, + } + if inputQga.Username == "" { + if self.OsType == osprofile.OS_TYPE_WINDOWS { + inputQga.Username = api.VM_DEFAULT_WINDOWS_LOGIN_USER + } else { + inputQga.Username = api.VM_DEFAULT_LINUX_LOGIN_USER + } + } + if inputQga.Password == "" && input.ResetPassword { + inputQga.Password = seclib2.RandomPassword2(12) + } + return self.PerformQgaSetPassword(ctx, userCred, query, inputQga) + case api.VM_READY: + inputDeploy := api.ServerDeployInput{ + Password: input.Password, + ResetPassword: input.ResetPassword, + AutoStart: input.AutoStart, + } + return self.PerformDeploy(ctx, userCred, query, inputDeploy) + default: + return nil, httperrors.NewServerStatusError("Cannot deploy in status %s", self.Status) + } +} + func (self *SGuest) saveOldPassword(ctx context.Context, userCred mcclient.TokenCredential) { loginKey := self.GetMetadata(ctx, api.VM_METADATA_LOGIN_KEY, userCred) if len(loginKey) > 0 { diff --git a/pkg/compute/tasks/guest_qga_reset_password_task.go b/pkg/compute/tasks/guest_qga_reset_password_task.go index 75c38fb1bf..40ed5456fd 100644 --- a/pkg/compute/tasks/guest_qga_reset_password_task.go +++ b/pkg/compute/tasks/guest_qga_reset_password_task.go @@ -59,7 +59,7 @@ func (self *GuestQgaSetPasswordTask) OnInit(ctx context.Context, obj db.IStandal guest := obj.(*models.SGuest) self.SetStage("OnQgaGuestPing", nil) if err := self.guestPing(ctx, guest); err != nil { - self.OnQgaGuestPingFailed(ctx, guest, nil) + self.taskFailed(ctx, guest, err.Error()) } } diff --git a/pkg/hostman/guestman/guest-agent.go b/pkg/hostman/guestman/guest-agent.go index 49b3f2352b..7c81d345c9 100644 --- a/pkg/hostman/guestman/guest-agent.go +++ b/pkg/hostman/guestman/guest-agent.go @@ -26,8 +26,8 @@ import ( ) const ( - QGA_LOCK_TIMEOUT = time.Second * 10 - QGA_EXEC_TIMEOUT = time.Second * 5 + QGA_LOCK_TIMEOUT = time.Second * 5 + QGA_EXEC_TIMEOUT = time.Second * 10 ) func qgaExec(timeout time.Duration, qgaFunc func(chan error)) error { @@ -64,11 +64,6 @@ func (m *SGuestManager) QgaGuestSetPassword(ctx context.Context, params interfac return nil, err } - if guest.guestAgent.TryLock(QGA_LOCK_TIMEOUT) { - defer guest.guestAgent.Unlock() - } else { - return nil, errors.Wrap(err, "qga unfinished last cmd, is qga unavailable?") - } f := func(c chan error) { if guest.guestAgent.TryLock(QGA_LOCK_TIMEOUT) { defer guest.guestAgent.Unlock() diff --git a/pkg/mcclient/options/compute/servers.go b/pkg/mcclient/options/compute/servers.go index 389fef9bc6..d117844211 100644 --- a/pkg/mcclient/options/compute/servers.go +++ b/pkg/mcclient/options/compute/servers.go @@ -820,6 +820,19 @@ func (o *ServerQgaCommand) Params() (jsonutils.JSONObject, error) { return options.StructToParams(o) } +type ServerSetPasswordOptions struct { + ServerIdOptions + + Username string `help:"Which user to set password" json:"username"` + Password string `help:"Password content" json:"password"` + ResetPassword bool `help:"Force reset password"` + AutoStart bool `help:"Auto start server after reset password"` +} + +func (o *ServerSetPasswordOptions) Params() (jsonutils.JSONObject, error) { + return options.StructToParams(o) +} + type ServerSaveImageOptions struct { ServerIdOptions IMAGE string `help:"Image name" json:"name"`