diff --git a/cmd/climc/climc.go b/cmd/climc/climc.go index 6f22d18d32..037cab5e46 100644 --- a/cmd/climc/climc.go +++ b/cmd/climc/climc.go @@ -4,8 +4,9 @@ import ( "fmt" "os" "strings" + "time" - "github.com/c-bata/go-prompt" + prompt "github.com/c-bata/go-prompt" "github.com/yunionio/log" "github.com/yunionio/pkg/util/version" "github.com/yunionio/structarg" @@ -34,6 +35,9 @@ type BaseOptions struct { SUBCOMMAND string `help:"climc subcommand" subcommand:"true"` } +var CacheToken mcclient.TokenCredential +var CacheTime time.Time + func getSubcommandsParser() (*structarg.ArgumentParser, error) { parse, e := structarg.NewArgumentParser(&BaseOptions{}, "climc", @@ -116,18 +120,23 @@ func newClientSession(options *BaseOptions) (*mcclient.ClientSession, error) { options.Timeout, options.Debug, options.Secure) - token, err := client.Authenticate(options.OsUsername, - options.OsPassword, - options.OsDomainName, - options.OsProjectName) - if err != nil { - return nil, err + + if CacheToken == nil || { + token, err := client.Authenticate(options.OsUsername, + options.OsPassword, + options.OsDomainName, + options.OsProjectName) + if err != nil { + return nil, err + } + CacheToken = token + CacheTime = time.Now() } session := client.NewSession(options.OsRegionName, options.OsZoneName, options.OsEndpointType, - token, + CacheToken, options.ApiVersion) return session, nil } @@ -144,7 +153,7 @@ func main() { fmt.Print(parser.HelpString()) } else if options.Version { fmt.Printf("Yunion API client version:\n %s\n", version.GetJsonString()) - } else if len(os.Args) <= 1 { + } else if len(os.Args) <= 1 || (options.ApiVersion == "v2" && len(os.Args) <= 3) { session, e := newClientSession(options) if e != nil { showErrorAndExit(e) diff --git a/pkg/compute/guestdrivers/base.go b/pkg/compute/guestdrivers/base.go index 948bbd0c38..dbb56293a8 100644 --- a/pkg/compute/guestdrivers/base.go +++ b/pkg/compute/guestdrivers/base.go @@ -54,13 +54,13 @@ func (self *SBaseGuestDriver) StartGuestCreateTask(guest *models.SGuest, ctx con } func (self *SBaseGuestDriver) OnGuestCreateTaskComplete(ctx context.Context, guest *models.SGuest, task taskman.ITask) error { - //if jsonutils.QueryBoolean(task.GetParams(), "auto_start", false) { - // task.SetStage("on_auto_start_guest", nil) - // return guest.StartGueststartTask(ctx, task.GetUserCred(), nil, task.GetTaskId()) - //} else { - task.SetStage("on_sync_status_complete", nil) - return guest.StartSyncstatus(ctx, task.GetUserCred(), task.GetTaskId()) - //} + if jsonutils.QueryBoolean(task.GetParams(), "auto_start", false) { + task.SetStage("on_auto_start_guest", nil) + return guest.StartGueststartTask(ctx, task.GetUserCred(), nil, task.GetTaskId()) + } else { + task.SetStage("on_sync_status_complete", nil) + return guest.StartSyncstatus(ctx, task.GetUserCred(), task.GetTaskId()) + } } func (self *SBaseGuestDriver) StartDeleteGuestTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error { @@ -113,3 +113,7 @@ func (self *SBaseGuestDriver) DoGuestCreateDisksTask(ctx context.Context, guest func (self *SBaseGuestDriver) RequestChangeVmConfig(ctx context.Context, guest *models.SGuest, task taskman.ITask, vcpuCount, vmemSize int64) error { return fmt.Errorf("Not Implement") } + +func (self *SBaseGuestDriver) RequestGuestHotAddIso(ctx context.Context, guest *models.SGuest, path string, task taskman.ITask) error { + return fmt.Errorf("Not Implement") +} diff --git a/pkg/compute/guestdrivers/esxi.go b/pkg/compute/guestdrivers/esxi.go index e516d0c266..b0b36feb24 100644 --- a/pkg/compute/guestdrivers/esxi.go +++ b/pkg/compute/guestdrivers/esxi.go @@ -3,11 +3,8 @@ package guestdrivers import ( "context" - "github.com/yunionio/jsonutils" - "github.com/yunionio/onecloud/pkg/cloudcommon/db/taskman" "github.com/yunionio/onecloud/pkg/compute/models" - "github.com/yunionio/onecloud/pkg/mcclient" ) type SESXiGuestDriver struct { @@ -44,3 +41,8 @@ func (self *SESXiGuestDriver) RequestDeleteDetachedDisk(ctx context.Context, dis task.ScheduleRun(nil) return nil } + +func (self *SESXiGuestDriver) RequestGuestHotAddIso(ctx context.Context, guest *models.SGuest, path string, task taskman.ITask) error { + task.ScheduleRun(nil) + return nil +} diff --git a/pkg/compute/guestdrivers/kvm.go b/pkg/compute/guestdrivers/kvm.go index 73a6439786..b638298b15 100644 --- a/pkg/compute/guestdrivers/kvm.go +++ b/pkg/compute/guestdrivers/kvm.go @@ -243,3 +243,11 @@ func (self *SKVMGuestDriver) RqeuestSuspendOnHost(ctx context.Context, guest *mo _, _, err := httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, header, nil, false) return err } + +func (self *SKVMGuestDriver) RequestGuestCreateAllDisks(ctx context.Context, guest *models.SGuest, task taskman.ITask) error { + return guest.StartGuestCreateDiskTask(ctx, task.GetUserCred(), task.GetParams(), task.GetTaskId()) +} + +func (self *SKVMGuestDriver) RequestGuestHotAddIso(ctx context.Context, guest *models.SGuest, path string, task taskman.ITask) error { + return guest.StartSyncstatus(ctx, task.GetUserCred(), task.GetTaskId()) +} diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index 5b50f79363..93569d45f3 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -607,6 +607,11 @@ func parseDiskInfo(ctx context.Context, userCred mcclient.TokenCredential, info } return &diskConfig, nil } + + // default backend + diskConfig.Backend = STORAGE_LOCAL + // diskConfig.Medium = DISK_TYPE_HYBRID + diskStr, err := info.GetString() if err != nil { log.Errorf("invalid diskinfo format %s", err) diff --git a/pkg/compute/models/guestdrivers.go b/pkg/compute/models/guestdrivers.go index 3370ef5529..bd0f21ede6 100644 --- a/pkg/compute/models/guestdrivers.go +++ b/pkg/compute/models/guestdrivers.go @@ -85,6 +85,8 @@ type IGuestDriver interface { AllowReconfigGuest() bool DoGuestCreateDisksTask(ctx context.Context, guest *SGuest, task taskman.ITask) error RequestChangeVmConfig(ctx context.Context, guest *SGuest, task taskman.ITask, vcpuCount, vmemSize int64) error + + RequestGuestHotAddIso(ctx context.Context, guest *SGuest, path string, task taskman.ITask) error } var guestDrivers map[string]IGuestDriver diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 7a228421b8..0186d7644b 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -521,6 +521,7 @@ func (manager *SGuestManager) ValidateCreateData(ctx context.Context, userCred m hypervisor = HYPERVISOR_BAREMETAL } + // base validate_create_data if data.Contains("prefer_baremetal") || data.Contains("prefer_host") { if !userCred.IsSystemAdmin() { return nil, httperrors.NewNotSufficientPrivilegeError("Only system admin can specify preferred host") @@ -558,7 +559,6 @@ func (manager *SGuestManager) ValidateCreateData(ctx context.Context, userCred m if err != nil { return nil, err } - } else { schedtags := make(map[string]string) if data.Contains("aggregate_strategy") { @@ -613,12 +613,16 @@ func (manager *SGuestManager) ValidateCreateData(ctx context.Context, userCred m } } + // default hypervisor + if len(hypervisor) == 0 { + hypervisor = HYPERVISOR_KVM + } + if !utils.IsInStringArray(hypervisor, HYPERVISORS) { return nil, httperrors.NewInputParameterError("Hypervisor %s not supported", hypervisor) } data.Add(jsonutils.NewString(hypervisor), "hypervisor") - for idx := 1; data.Contains(fmt.Sprintf("disk.%d", idx)); idx += 1 { diskJson, err := data.Get(fmt.Sprintf("disk.%d", idx)) if err != nil { @@ -789,13 +793,27 @@ func getGuestResourceRequirements(ctx context.Context, userCred mcclient.TokenCr func (guest *SGuest) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerProjId string, query jsonutils.JSONObject, data jsonutils.JSONObject) { guest.SVirtualResourceBase.PostCreate(ctx, userCred, ownerProjId, query, data) - + tags := []string{"cpu_bound", "io_bound", "io_hardlimit"} + appTags := make([]string, 0) + for _, tag := range tags { + if data.Contains(tag) { + appTags = append(appTags, tag) + } + } + guest.setApptags(ctx, appTags, userCred) osProfileJson, _ := data.Get("__os_profile__") if osProfileJson != nil { guest.setOSProfile(ctx, userCred, osProfileJson) } } +func (guest *SGuest) setApptags(ctx context.Context, appTags []string, userCred mcclient.TokenCredential) { + err := guest.SetMetadata(ctx, "app_tags", strings.Join(appTags, ","), userCred) + if err != nil { + log.Errorln(err) + } +} + func (manager *SGuestManager) OnCreateComplete(ctx context.Context, items []db.IModel, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) { pendingUsage := getGuestResourceRequirements(ctx, userCred, data, len(items)) @@ -2002,11 +2020,26 @@ func (self *SGuest) insertIso(imageId string) bool { return cdrom.insertIso(imageId) } -func (self *SGuest) insertIsoSucc(imageId string, path string, size int, name string) bool { +func (self *SGuest) InsertIsoSucc(imageId string, path string, size int, name string) bool { cdrom := self.getCdrom() return cdrom.insertIsoSucc(imageId, path, size, name) } +func (self *SGuest) GetDetailsIso(userCred mcclient.TokenCredential) jsonutils.JSONObject { + cdrom := self.getCdrom() + desc := jsonutils.NewDict() + if len(cdrom.ImageId) > 0 { + desc.Set("image_id", jsonutils.NewString(cdrom.ImageId)) + desc.Set("status", jsonutils.NewString("inserting")) + } + if len(cdrom.Path) > 0 { + desc.Set("name", jsonutils.NewString(cdrom.Name)) + desc.Set("size", jsonutils.NewInt(int64(cdrom.Size))) + desc.Set("status", jsonutils.NewString("ready")) + } + return desc +} + func (self *SGuest) StartInsertIsoTask(ctx context.Context, imageId string, hostId string, userCred mcclient.TokenCredential, parentTaskId string) error { self.insertIso(imageId) @@ -2014,7 +2047,7 @@ func (self *SGuest) StartInsertIsoTask(ctx context.Context, imageId string, host data.Add(jsonutils.NewString(imageId), "image_id") data.Add(jsonutils.NewString(hostId), "host_id") - task, err := taskman.TaskManager.NewTask(ctx, "GuestInsertISOTask", self, userCred, data, parentTaskId, "", nil) + task, err := taskman.TaskManager.NewTask(ctx, "GuestInsertIsoTask", self, userCred, data, parentTaskId, "", nil) if err != nil { return err } diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index 7e4f837e3e..86b3f207bd 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -18,6 +18,7 @@ import ( "github.com/yunionio/sqlchemy" "github.com/yunionio/onecloud/pkg/cloudcommon/db" + "github.com/yunionio/onecloud/pkg/cloudcommon/db/taskman" "github.com/yunionio/onecloud/pkg/cloudprovider" "github.com/yunionio/onecloud/pkg/compute/options" "github.com/yunionio/onecloud/pkg/httperrors" @@ -1517,6 +1518,22 @@ func (manager *SHostManager) GetHostsByManagerAndRegion(managerId string, region return ret } +func (self *SHost) StartImageCacheTask(ctx context.Context, userCred mcclient.TokenCredential, imageId, parentTaskId string, isForce bool) error { + //Todo + // HostcachedimagesManager.Register(userCred, self, imageId) + data := jsonutils.NewDict() + data.Set("image_id", jsonutils.NewString(imageId)) + if isForce { + data.Set("is_force", jsonutils.JSONTrue) + } + task, err := taskman.TaskManager.NewTask(ctx, "StorageCacheImageTask", self, userCred, data, parentTaskId, "", nil) + if err != nil { + return err + } + task.ScheduleRun(nil) + return nil +} + func (self *SHost) Request(userCred mcclient.TokenCredential, method string, url string, headers http.Header, body jsonutils.JSONObject) (jsonutils.JSONObject, error) { s := auth.GetSession(userCred, "", "") _, ret, err := s.JSONRequest(self.ManagerUri, "", method, url, headers, body) diff --git a/pkg/compute/tasks/guest_create_disk_task.go b/pkg/compute/tasks/guest_create_disk_task.go index 4ba43f712a..a477d42ded 100644 --- a/pkg/compute/tasks/guest_create_disk_task.go +++ b/pkg/compute/tasks/guest_create_disk_task.go @@ -28,6 +28,10 @@ func (self *GuestCreateDiskTask) OnDiskPrepared(ctx context.Context, obj db.ISta self.SetStageComplete(ctx, nil) } +func (self *GuestCreateDiskTask) OnDiskPreparedFailed(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + self.SetStageFailed(ctx, data.String()) +} + /* --------------------------------------------- */ /* -----------KVMGuestCreateDiskTask------------ */ /* --------------------------------------------- */ diff --git a/pkg/compute/tasks/guest_insert_iso_task.go b/pkg/compute/tasks/guest_insert_iso_task.go index 59926cfd73..fa60fcd032 100644 --- a/pkg/compute/tasks/guest_insert_iso_task.go +++ b/pkg/compute/tasks/guest_insert_iso_task.go @@ -4,8 +4,10 @@ import ( "context" "github.com/yunionio/jsonutils" + "github.com/yunionio/onecloud/pkg/cloudcommon/db" "github.com/yunionio/onecloud/pkg/cloudcommon/db/taskman" + "github.com/yunionio/onecloud/pkg/compute/models" ) type GuestInsertIsoTask struct { @@ -17,5 +19,59 @@ func init() { } func (self *GuestInsertIsoTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { - // TODO + self.prepareIsoImage(ctx, obj) +} + +func (self *GuestInsertIsoTask) prepareIsoImage(ctx context.Context, obj db.IStandaloneModel) { + imageId, _ := self.Params.GetString("image_id") + db.OpsLog.LogEvent(obj, db.ACT_ISO_PREPARING, imageId, self.UserCred) + var host *models.SHost + if self.Params.Contains("host_id") { + hostId, _ := self.Params.GetString("host_id") + iHost, _ := models.HostManager.FetchById(hostId) + host = iHost.(*models.SHost) + } else { + guest := obj.(*models.SGuest) + host = guest.GetHost() + } + self.SetStage("OnIsoPrepareComplete", nil) + host.StartImageCacheTask(ctx, self.UserCred, imageId, self.GetTaskId(), false) +} + +func (self *GuestInsertIsoTask) OnIsoPrepareCompleteFailed(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + imageId, _ := self.Params.GetString("image_id") + db.OpsLog.LogEvent(obj, db.ACT_ISO_PREPARE_FAIL, imageId, self.UserCred) + guest := obj.(*models.SGuest) + guest.EjectIso(self.UserCred) + self.SetStageFailed(ctx, "OnIsoPrepareCompleteFailed") +} + +func (self *GuestInsertIsoTask) OnIsoPrepareComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + imageId, _ := data.GetString("image_id") + jSize, err := data.Get("size") + if err != nil { + self.SetStageFailed(ctx, err.Error()) + } + size, err := jSize.Int() + if err != nil { + self.SetStageFailed(ctx, err.Error()) + } + name, _ := data.GetString("name") + path, _ := data.GetString("path") + guest := obj.(*models.SGuest) + if guest.InsertIsoSucc(imageId, path, int(size), name) { + db.OpsLog.LogEvent(guest, db.ACT_ISO_ATTACH, guest.GetDetailsIso(self.UserCred), self.UserCred) + if guest.Status == models.VM_RUNNING { + self.SetStage("OnConfigSyncComplete", nil) + guest.GetDriver().RequestGuestHotAddIso(ctx, guest, path, self) + } else { + self.SetStageComplete(ctx, nil) + } + } else { + self.SetStageComplete(ctx, nil) + } +} + +func (self *GuestInsertIsoTask) OnConfigSyncComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + self.SetStageComplete(ctx, nil) } diff --git a/pkg/util/esxi/storage.go b/pkg/util/esxi/storage.go index e1c89478bf..bf8f918ccf 100644 --- a/pkg/util/esxi/storage.go +++ b/pkg/util/esxi/storage.go @@ -54,6 +54,10 @@ func (self *SDatastore) GetIZone() cloudprovider.ICloudZone { return nil } +func (self *SDatastore) GetIDisk(idStr string) (cloudprovider.ICloudDisk, error) { + return nil, cloudprovider.ErrNotImplemented +} + func (self *SDatastore) GetIDisks() ([]cloudprovider.ICloudDisk, error) { return nil, cloudprovider.ErrNotImplemented }