Merge branch 'release/2.4.0' of ssh://git.yunion.io/~qiujian/onecloud into hotfix/qj-policy-cache

This commit is contained in:
Qiu Jian
2018-12-10 15:36:18 +08:00
160 changed files with 3324 additions and 759 deletions
Generated
+9 -8
View File
@@ -1312,11 +1312,11 @@
[[projects]]
branch = "master"
digest = "1:a2346cf0c965791c281a428a3e9bf522913941028e4c814a774af7f3cc2360b0"
digest = "1:3c2ee66e652654aae64107ab7e0087cfb05a959b2e22ff75880d0cd7b47e695d"
name = "yunion.io/x/jsonutils"
packages = ["."]
pruneopts = "UT"
revision = "814e036849815935e5957ebd03bd0f4fc992fe83"
revision = "0233c7b766f65b0ebbe6f72717f141405afbb496"
[[projects]]
branch = "master"
@@ -1331,7 +1331,7 @@
[[projects]]
branch = "master"
digest = "1:5293df1051bc3efc179027b9250533e5ece1da66ab03bbfb00384c18b9916282"
digest = "1:6d91d27a4867494b3fdaa177e519f13ee45dbb0c246c9b7ed05ea7a586ebb9a4"
name = "yunion.io/x/pkg"
packages = [
"gotypes",
@@ -1364,23 +1364,23 @@
"utils",
]
pruneopts = "UT"
revision = "9ea65d37be78406707a313fdecb17aa392199575"
revision = "a8af02b7adb621ab73bb094330e2c0c3adbfbf90"
[[projects]]
branch = "master"
digest = "1:5a3958d2f3c6c6510cc6b0e754cc45f6e98d8f8780ea04c1232a8f22fd6d91fc"
digest = "1:2fdf064ae928c1b311e67ec51e856ce655abc39e8eacf5e6b3f7bd0417fac0a6"
name = "yunion.io/x/sqlchemy"
packages = ["."]
pruneopts = "UT"
revision = "30271a36b97155505642d6d3709a37600aade302"
revision = "e22221d5efcc667e68b0fdeed19958e788c3ad63"
[[projects]]
branch = "master"
digest = "1:bbaf572e68e5dad4045e1e424af29838882c620df391fa1631dd8dc851c87a95"
digest = "1:97c47d46b272f535bc6760672a3dd4512bf66fb4463cb70547178e21cf9078f7"
name = "yunion.io/x/structarg"
packages = ["."]
pruneopts = "UT"
revision = "c95bf78846decd8dea379e925410f2895fb20076"
revision = "1a162c0cfa82905f20a795e9ac530bf27f9a0549"
[solve-meta]
analyzer-name = "dep"
@@ -1434,6 +1434,7 @@
"github.com/coredns/coredns/request",
"github.com/fatih/color",
"github.com/go-sql-driver/mysql",
"github.com/golang-plus/errors",
"github.com/golang-plus/uuid",
"github.com/googollee/go-socket.io",
"github.com/gorilla/mux",
+3 -1
View File
@@ -43,9 +43,11 @@ install: prepare_dir
done
build:
build: gendoc
$(MAKE) $(wildcard cmd/*)
gendoc:
@sh build/gendoc.sh
test:
@for PKG in $$( $(PKGS) | grep "$(filter-out $@,$(MAKECMDGOALS))" ); do \
+12
View File
@@ -0,0 +1,12 @@
for top in pkg
do
for d in $(find $top -type d)
do
if [ ! -f $d/doc.go ]; then
if ls $d/*.go > /dev/null 2>&1; then
echo $d/doc.go
echo "package $(basename $d) // import \"yunion.io/x/onecloud/$d\"" > $d/doc.go
fi
fi
done
done
+12 -31
View File
@@ -11,40 +11,21 @@ import (
func init() {
type DiskListOptions struct {
options.BaseListOptions
Unused bool `help:"Show unused disks"`
Share bool `help:"Show Share storage disks"`
Local bool `help:"Show Local storage disks"`
Guest string `help:"Guest ID or name"`
Storage string `help:"Storage ID or name"`
Unused *bool `help:"Show unused disks"`
Share *bool `help:"Show Share storage disks"`
Local *bool `help:"Show Local storage disks"`
Guest string `help:"Guest ID or name"`
Storage string `help:"Storage ID or name"`
Provider string `help:"Provider for disk" choices:"Aliyun|VMware|Azure"`
BillingType string `help:"billing type" choices:"postpaid|prepaid"`
}
R(&DiskListOptions{}, "disk-list", "List virtual disks", func(s *mcclient.ClientSession, suboptions *DiskListOptions) error {
var params *jsonutils.JSONDict
{
var err error
params, err = suboptions.BaseListOptions.Params()
if err != nil {
return err
}
}
if suboptions.Unused {
params.Add(jsonutils.JSONTrue, "unused")
}
if suboptions.Share {
params.Add(jsonutils.JSONTrue, "share")
}
if suboptions.Local {
params.Add(jsonutils.JSONTrue, "local")
}
if len(suboptions.Guest) > 0 {
params.Add(jsonutils.NewString(suboptions.Guest), "guest")
}
if len(suboptions.Storage) > 0 {
params.Add(jsonutils.NewString(suboptions.Storage), "storage")
}
if len(suboptions.Provider) > 0 {
params.Add(jsonutils.NewString(suboptions.Provider), "provider")
params, err := options.ListStructToParams(suboptions)
if err != nil {
return err
}
result, err := modules.Disks.List(s, params)
if err != nil {
+32 -3
View File
@@ -22,9 +22,11 @@ func init() {
Occupied bool `help:"show occupid host"`
Enabled bool `help:"Show enabled host only"`
Disabled bool `help:"Show disabled host only"`
HostType string `help:"Host type filter" choices:"baremetal|hypervisor|esxi|kubelet|hyperv"`
HostType string `help:"Host type filter" choices:"baremetal|hypervisor|esxi|kubelet|hyperv|aliyun|azure|qcloud|aws|huawei"`
AnyMac string `help:"Mac matches one of the host's interface"`
ResourceType string `help:"Resource type" choices:"shared|prepaid|dedicated"`
Manager string `help:"Show regions belongs to the cloud provider"`
Usable bool `help:"List all zones that is usable"`
@@ -64,6 +66,9 @@ func init() {
if len(args.HostType) > 0 {
params.Add(jsonutils.NewString(args.HostType), "host_type")
}
if len(args.ResourceType) > 0 {
params.Add(jsonutils.NewString(args.ResourceType), "resource_type")
}
if len(args.Manager) > 0 {
params.Add(jsonutils.NewString(args.Manager), "manager")
@@ -403,12 +408,24 @@ func init() {
})
type HostEnableNetIfOptions struct {
ID string `help:"ID or Name of host"`
MAC string `help:"MAC of NIC to enable"`
ID string `help:"ID or Name of host"`
MAC string `help:"MAC of NIC to enable"`
Ip string `help:"IP address"`
Network string `help:"network to connect"`
Reserved bool `help:"fetch IP from reserved pool"`
}
R(&HostEnableNetIfOptions{}, "host-enable-netif", "Enable a network interface for a host", func(s *mcclient.ClientSession, args *HostEnableNetIfOptions) error {
params := jsonutils.NewDict()
params.Add(jsonutils.NewString(args.MAC), "mac")
if len(args.Ip) > 0 {
params.Add(jsonutils.NewString(args.Ip), "ip_addr")
if args.Reserved {
params.Add(jsonutils.JSONTrue, "reserve")
}
}
if len(args.Network) > 0 {
params.Add(jsonutils.NewString(args.Network), "network")
}
result, err := modules.Hosts.PerformAction(s, args.ID, "enable-netif", params)
if err != nil {
return err
@@ -512,4 +529,16 @@ func init() {
return nil
})
type HostUndoPrepaidRecycleOptions struct {
ID string `help:"ID or name of host to undo recycle"`
}
R(&HostUndoPrepaidRecycleOptions{}, "host-undo-recycle", "Pull a prepaid server from recycle pool, so that it will not be shared any more", func(s *mcclient.ClientSession, args *HostUndoPrepaidRecycleOptions) error {
params := jsonutils.NewDict()
result, err := modules.Hosts.PerformAction(s, args.ID, "undo-prepaid-recycle", params)
if err != nil {
return err
}
printObject(result)
return nil
})
}
+51
View File
@@ -9,6 +9,7 @@ import (
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/pkg/util/regutils"
)
func init() {
@@ -57,6 +58,17 @@ func init() {
return err
}
if opts.GenerateName {
params.Add(jsonutils.NewString(opts.NAME), "generate_name")
} else {
params.Add(jsonutils.NewString(opts.NAME), "name")
}
if regutils.MatchSize(opts.MEMSPEC) {
params.Add(jsonutils.NewString(opts.MEMSPEC), "vmem_size")
} else {
params.Add(jsonutils.NewString(opts.MEMSPEC), "instance_type")
}
if opts.NoAccountInit != nil && *opts.NoAccountInit {
params.Add(jsonutils.JSONFalse, "reset_password")
}
@@ -592,4 +604,43 @@ func init() {
printObject(result)
return nil
})
type ServerRenewOptions struct {
ID string `help:"ID or name of server to renew"`
DURATION string `help:"Duration of renew, ADMIN only command"`
}
R(&ServerRenewOptions{}, "server-renew", "Renew a server", func(s *mcclient.ClientSession, args *ServerRenewOptions) error {
params := jsonutils.NewDict()
params.Add(jsonutils.NewString(args.DURATION), "duration")
result, err := modules.Servers.PerformAction(s, args.ID, "renew", params)
if err != nil {
return err
}
printObject(result)
return nil
})
type ServerPrepaidRecycleOptions struct {
ID string `help:"ID or name of server to recycle"`
}
R(&ServerPrepaidRecycleOptions{}, "server-enable-recycle", "Put a prepaid server into recycle pool, so that it can be shared", func(s *mcclient.ClientSession, args *ServerPrepaidRecycleOptions) error {
params := jsonutils.NewDict()
result, err := modules.Servers.PerformAction(s, args.ID, "prepaid-recycle", params)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&ServerPrepaidRecycleOptions{}, "server-disable-recycle", "Pull a prepaid server from recycle pool, so that it will not be shared anymore", func(s *mcclient.ClientSession, args *ServerPrepaidRecycleOptions) error {
params := jsonutils.NewDict()
result, err := modules.Servers.PerformAction(s, args.ID, "undo-prepaid-recycle", params)
if err != nil {
return err
}
printObject(result)
return nil
})
}
+17 -3
View File
@@ -1,6 +1,8 @@
package shell
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
@@ -9,12 +11,24 @@ import (
func init() {
type ServerSkusListOptions struct {
options.BaseListOptions
Provider string `help:"provider" choices:"all|kvm|esxi|xen|hyperv|aliyun|azure|aws|qcloud|huawei"`
Region string `help:"region Id or name"`
Zone string `help:"zone Id or name"`
Cpu int `help:"Cpu core count"`
Mem int `help:"Memory size in MB"`
Name string `help:"Name of Sku"`
}
R(&ServerSkusListOptions{}, "server-sku-list", "List all avaiable Server SKU", func(s *mcclient.ClientSession, args *ServerSkusListOptions) error {
params, err := options.ListStructToParams(args)
if err != nil {
return err
}
if args.Cpu > 0 {
params.Add(jsonutils.NewInt(int64(args.Cpu)), "cpu_core_count")
}
if args.Mem > 0 {
params.Add(jsonutils.NewInt(int64(args.Mem)), "memory_size_mb")
}
results, err := modules.ServerSkus.List(s, params)
if err != nil {
return err
@@ -39,6 +53,7 @@ func init() {
Name string `help:"Name ID of SKU" required:"true" positional:"true"`
CpuCoreCount int `help:"Cpu Count" required:"true" positional:"true"`
MemorySizeMB int `help:"Memory MB" required:"true" positional:"true"`
Provider string `help:"Provider name" choices:"kvm|esxi"`
OsName *string `help:"OS name/type" choices:"Linux|Windows|Any" default:"Any"`
SkuFamily *string `help:"sku family"`
@@ -61,9 +76,8 @@ func init() {
GPUCount *int `help:"GPU count"`
GPUAttachable *bool `help:"Allow attach GPU"`
Zone *string `help:"Zone ID or name"`
Region *string `help:"Region ID or name"`
Provider *string `help:"Provider name" choices:"kvm|esxi"`
Zone *string `help:"Zone ID or name"`
Region *string `help:"Region ID or name"`
}
R(&ServerSkusCreateOptions{}, "server-sku-create", "Create a server sku record", func(s *mcclient.ClientSession, args *ServerSkusCreateOptions) error {
params, err := options.StructToParams(args)
+18 -2
View File
@@ -8,6 +8,7 @@ import (
type GeneralUsageOptions struct {
HostType []string `help:"Host types" choices:"hypervisor|baremetal|esxi|xen|kubelet|hyperv|aliyun|azure|aws|huawei|qcloud"`
Provider []string `help:"Provider" choices:"VMware|Aliyun|Azure|Aws|Qcloud|Huawei"`
Project string
}
@@ -16,6 +17,9 @@ func fetchHostTypeOptions(args *GeneralUsageOptions) *jsonutils.JSONDict {
if len(args.HostType) > 0 {
params.Add(jsonutils.NewStringArray(args.HostType), "host_type")
}
if len(args.Provider) > 0 {
params.Add(jsonutils.NewStringArray(args.Provider), "provider")
}
return params
}
@@ -61,9 +65,21 @@ func init() {
return nil
})
R(&ResourceUsageOptions{}, "vcenter-usage", "Show general usage of vcenter", func(s *mcclient.ClientSession, args *ResourceUsageOptions) error {
R(&ResourceUsageOptions{}, "cloud-provider-usage", "Show general usage of vcenter", func(s *mcclient.ClientSession, args *ResourceUsageOptions) error {
params := fetchHostTypeOptions(&args.GeneralUsageOptions)
params.Add(jsonutils.NewString("vcenters"), "range_type")
params.Add(jsonutils.NewString("cloudproviders"), "range_type")
params.Add(jsonutils.NewString(args.ID), "range_id")
result, err := modules.Usages.GetGeneralUsage(s, params)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&ResourceUsageOptions{}, "cloud-account-usage", "Show general usage of vcenter", func(s *mcclient.ClientSession, args *ResourceUsageOptions) error {
params := fetchHostTypeOptions(&args.GeneralUsageOptions)
params.Add(jsonutils.NewString("cloudaccounts"), "range_type")
params.Add(jsonutils.NewString(args.ID), "range_id")
result, err := modules.Usages.GetGeneralUsage(s, params)
if err != nil {
+1
View File
@@ -0,0 +1 @@
package test // import "yunion.io/x/onecloud/pkg/appsrv/test"
+1
View File
@@ -0,0 +1 @@
package consts // import "yunion.io/x/onecloud/pkg/cloudcommon/consts"
+9 -7
View File
@@ -12,6 +12,8 @@ import (
"yunion.io/x/onecloud/pkg/mcclient/auth"
)
type TCronJobFunction func(ctx context.Context, userCred mcclient.TokenCredential, isStart bool)
var manager *SCronJobManager
func init() {
@@ -43,7 +45,7 @@ func (t *Timer2) Next(now time.Time) time.Time {
type SCronJob struct {
Name string
job func(ctx context.Context, userCred mcclient.TokenCredential)
job TCronJobFunction
Timer ICronTimer
Next time.Time
StartRun bool
@@ -92,7 +94,7 @@ func GetCronJobManager() *SCronJobManager {
return manager
}
func (self *SCronJobManager) AddJob1(name string, interval time.Duration, jobFunc func(ctx context.Context, userCred mcclient.TokenCredential)) {
func (self *SCronJobManager) AddJob1(name string, interval time.Duration, jobFunc TCronJobFunction) {
t := Timer1{
dur: interval,
}
@@ -108,7 +110,7 @@ func (self *SCronJobManager) AddJob1(name string, interval time.Duration, jobFun
}
}
func (self *SCronJobManager) AddJob2(name string, day, hour, min, sec int, jobFunc func(ctx context.Context, userCred mcclient.TokenCredential), startRun bool) {
func (self *SCronJobManager) AddJob2(name string, day, hour, min, sec int, jobFunc TCronJobFunction, startRun bool) {
t := Timer2{
day: day,
hour: hour,
@@ -160,7 +162,7 @@ func (self *SCronJobManager) run() {
for i := 0; i < len(self.jobs); i += 1 {
if self.jobs[i].StartRun {
self.jobs[i].StartRun = false
self.jobs[i].runJob()
self.jobs[i].runJob(true)
}
}
select {
@@ -169,7 +171,7 @@ func (self *SCronJobManager) run() {
if job.Next.After(now) || job.Next.IsZero() {
break
}
go job.runJob()
go job.runJob(false)
job.Next = job.Timer.Next(now)
heap.Fix(&self.jobs, i)
}
@@ -184,7 +186,7 @@ func (self *SCronJobManager) run() {
}
}
func (job *SCronJob) runJob() {
func (job *SCronJob) runJob(isStart bool) {
defer func() {
if r := recover(); r != nil {
log.Errorf("CronJob task %s run error: %s", job.Name, r)
@@ -196,5 +198,5 @@ func (job *SCronJob) runJob() {
ctx := context.Background()
ctx = context.WithValue(ctx, appctx.APP_CONTEXT_KEY_APPNAME, "Region-Corn-Service")
userCred := auth.AdminCredential()
job.job(ctx, userCred)
job.job(ctx, userCred, isStart)
}
@@ -0,0 +1 @@
package example // import "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman/example"
+7
View File
@@ -150,6 +150,13 @@ const (
ACT_GUEST_DETACH_ISOLATED_DEVICE_FAIL = "guest_detach_isolated_deivce_fail"
ACT_CHANGE_BANDWIDTH = "eip_change_bandwidth"
ACT_RENEW = "renew"
ACT_SCHEDULE = "schedule"
ACT_RECYCLE_PREPAID = "recycle_prepaid"
ACT_UNDO_RECYCLE_PREPAID = "undo_recycle_prepaid"
)
type SOpsLogManager struct {
+1 -1
View File
@@ -13,7 +13,7 @@ type ITask interface {
GetParams() *jsonutils.JSONDict
GetUserCred() mcclient.TokenCredential
GetTaskId() string
SetStage(stageName string, data *jsonutils.JSONDict)
SetStage(stageName string, data *jsonutils.JSONDict) error
GetTaskRequestHeader() http.Header
+22 -15
View File
@@ -398,8 +398,8 @@ func execITask(taskValue reflect.Value, task *STask, odata jsonutils.JSONObject,
}
task.taskObjects = objs
// lockman.LockClass(ctx, objResManager, task.UserCred.GetProjectId())
// defer lockman.ReleaseClass(ctx, objResManager, task.UserCred.GetProjectId())
lockman.LockClass(ctx, objResManager, task.UserCred.GetProjectId())
defer lockman.ReleaseClass(ctx, objResManager, task.UserCred.GetProjectId())
params[1] = reflect.ValueOf(objs)
} else {
@@ -413,8 +413,8 @@ func execITask(taskValue reflect.Value, task *STask, odata jsonutils.JSONObject,
}
task.taskObject = obj
// lockman.LockObject(ctx, obj)
// defer lockman.ReleaseObject(ctx, obj)
lockman.LockObject(ctx, obj)
defer lockman.ReleaseObject(ctx, obj)
params[1] = reflect.ValueOf(obj)
}
@@ -470,30 +470,37 @@ func (self *STask) SaveRequestContext(data *appctx.AppContextData) {
}
}
func (self *STask) SetStage(stageName string, data *jsonutils.JSONDict) {
func (self *STask) SaveParams(data *jsonutils.JSONDict) error {
return self.SetStage("", data)
}
func (self *STask) SetStage(stageName string, data *jsonutils.JSONDict) error {
_, err := self.GetModelManager().TableSpec().Update(self, func() error {
params := jsonutils.NewDict()
params.Update(self.Params)
if data != nil {
params.Update(data)
}
stages, _ := params.Get("__stages")
if stages == nil {
stages = jsonutils.NewArray()
params.Add(stages, "__stages")
if len(stageName) > 0 {
stages, _ := params.Get("__stages")
if stages == nil {
stages = jsonutils.NewArray()
params.Add(stages, "__stages")
}
stageList := stages.(*jsonutils.JSONArray)
stageData := jsonutils.NewDict()
stageData.Add(jsonutils.NewString(self.Stage), "name")
stageData.Add(jsonutils.NewTimeString(time.Now()), "complete_at")
stageList.Add(stageData)
self.Stage = stageName
}
stageList := stages.(*jsonutils.JSONArray)
stageData := jsonutils.NewDict()
stageData.Add(jsonutils.NewString(self.Stage), "name")
stageData.Add(jsonutils.NewTimeString(time.Now()), "complete_at")
stageList.Add(stageData)
self.Stage = stageName
self.Params = params
return nil
})
if err != nil {
log.Errorf("set_stage fail %s", err)
}
return err
}
func (self *STask) GetObjectIdStr() string {
+1
View File
@@ -0,0 +1 @@
package policy // import "yunion.io/x/onecloud/pkg/cloudcommon/policy"
+12
View File
@@ -99,6 +99,18 @@ var (
Action: PolicyActionGet,
Result: rbacutils.OwnerAllow,
},
{
Service: "compute",
Resource: "serverskus",
Action: PolicyActionList,
Result: rbacutils.UserAllow,
},
{
Service: "compute",
Resource: "serverskus",
Action: PolicyActionGet,
Result: rbacutils.UserAllow,
},
{
Service: "yunionagent",
Resource: "notices",
+1 -3
View File
@@ -1,8 +1,6 @@
package policy
import (
"yunion.io/x/log"
"yunion.io/x/pkg/gotypes"
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
@@ -32,7 +30,7 @@ func (self *SPolicyTokenCredential) IsAdminAllow(service string, resource string
func init() {
gotypes.RegisterSerializableTransformer(mcclient.TokenCredentialType, func(input gotypes.ISerializable) gotypes.ISerializable {
log.Debugf("do TokenCredential transform for %#v", input)
// log.Debugf("do TokenCredential transform for %#v", input)
switch val := input.(type) {
case *mcclient.SSimpleToken:
return &SPolicyTokenCredential{val}
+7 -2
View File
@@ -9,6 +9,7 @@ import (
"yunion.io/x/pkg/util/secrules"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/billing"
)
type ICloudResource interface {
@@ -151,10 +152,10 @@ type ICloudHost interface {
GetManagerId() string
CreateVM(name string, imgId string, sysDiskSize int, cpu int, memMB int, vswitchId string, ipAddr string, desc string,
passwd string, storageType string, diskSizes []int, publicKey string, extSecGrpId string, userData string) (ICloudVM, error)
passwd string, storageType string, diskSizes []int, publicKey string, extSecGrpId string, userData string, billingCycle *billing.SBillingCycle) (ICloudVM, error)
// 使用instanceType创建实例。
CreateVM2(name string, imgId string, sysDiskSize int, instanceType string, vswitchId string, ipAddr string, desc string,
passwd string, storageType string, diskSizes []int, publicKey string, extSecGrpId string, userData string) (ICloudVM, error)
passwd string, storageType string, diskSizes []int, publicKey string, extSecGrpId string, userData string, billingCycle *billing.SBillingCycle) (ICloudVM, error)
GetIHostNics() ([]ICloudHostNetInterface, error)
}
@@ -212,6 +213,8 @@ type ICloudVM interface {
DetachDisk(ctx context.Context, diskId string) error
CreateDisk(ctx context.Context, sizeMb int, uuid string, driver string) error
Renew(bc billing.SBillingCycle) error
}
type ICloudNic interface {
@@ -297,6 +300,8 @@ type ICloudDisk interface {
Resize(ctx context.Context, newSizeMB int64) error
Reset(ctx context.Context, snapshotId string) error
Rebuild(ctx context.Context) error
}
type ICloudSnapshot interface {
+1
View File
@@ -0,0 +1 @@
package consts
+1
View File
@@ -0,0 +1 @@
package consts // import "yunion.io/x/onecloud/pkg/compute/consts"
+22 -3
View File
@@ -14,6 +14,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/billing"
"yunion.io/x/onecloud/pkg/util/seclib2"
)
@@ -156,12 +157,18 @@ func (self *SAliyunGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu
var createErr error
var iVM cloudprovider.ICloudVM
var bc *billing.SBillingCycle
if desc.BillingCycle.IsValid() {
bc = &desc.BillingCycle
}
if len(desc.InstanceType) > 0 {
iVM, createErr = ihost.CreateVM2(desc.Name, desc.ExternalImageId, desc.SysDiskSize, desc.InstanceType, desc.ExternalNetworkId,
desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData)
desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData, bc)
} else {
iVM, createErr = ihost.CreateVM(desc.Name, desc.ExternalImageId, desc.SysDiskSize, desc.Cpu, desc.Memory, desc.ExternalNetworkId,
desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData)
desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData, bc)
}
if createErr != nil {
@@ -275,7 +282,7 @@ func (self *SAliyunGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu
if len(idisks) < len(desc.DataDisks)+1 {
log.Debugf("inconsistent disk number???? %d != %d", len(idisks), len(desc.DataDisks)+1)
}
if idisks[0].GetGlobalId() != diskId {
if len(idisks) > 0 && idisks[0].GetGlobalId() != diskId {
log.Errorf("system disk id inconsistent %s != %s", idisks[0].GetGlobalId(), diskId)
}
time.Sleep(time.Second * 5)
@@ -301,3 +308,15 @@ func (self *SAliyunGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu
func (self *SAliyunGuestDriver) AllowReconfigGuest() bool {
return true
}
func (self *SAliyunGuestDriver) IsSupportedBillingCycle(bc billing.SBillingCycle) bool {
weeks := bc.GetWeeks()
if weeks >= 1 && weeks <= 4 {
return true
}
months := bc.GetMonths()
if (months >= 1 && months <= 10) || (months == 12) || (months == 24) || (months == 36) || (months == 48) || (months == 60) {
return true
}
return false
}
+7 -2
View File
@@ -13,6 +13,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/billing"
)
type SAwsGuestDriver struct {
@@ -132,10 +133,10 @@ func (self *SAwsGuestDriver) RequestDeployGuestOnHost(ctx context.Context, guest
var iVM cloudprovider.ICloudVM
if len(desc.InstanceType) > 0 {
iVM, createErr = ihost.CreateVM2(desc.Name, desc.ExternalImageId, desc.SysDiskSize, desc.InstanceType, desc.ExternalNetworkId,
desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData)
desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData, nil)
} else {
iVM, createErr = ihost.CreateVM(desc.Name, desc.ExternalImageId, desc.SysDiskSize, desc.Cpu, desc.Memory, desc.ExternalNetworkId,
desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData)
desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData, nil)
}
if createErr != nil {
@@ -242,3 +243,7 @@ func (self *SAwsGuestDriver) RequestDeployGuestOnHost(ctx context.Context, guest
return nil
}
func (self *SAwsGuestDriver) IsSupportedBillingCycle(bc billing.SBillingCycle) bool {
return false
}
+7 -2
View File
@@ -19,6 +19,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/billing"
)
type SAzureGuestDriver struct {
@@ -180,10 +181,10 @@ func (self *SAzureGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gue
var iVM cloudprovider.ICloudVM
if len(desc.InstanceType) > 0 {
iVM, createErr = ihost.CreateVM2(desc.Name, desc.ExternalImageId, desc.SysDiskSize, desc.InstanceType, desc.ExternalNetworkId,
desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData)
desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData, nil)
} else {
iVM, createErr = ihost.CreateVM(desc.Name, desc.ExternalImageId, desc.SysDiskSize, desc.Cpu, desc.Memory, desc.ExternalNetworkId,
desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData)
desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData, nil)
}
if createErr != nil {
@@ -319,3 +320,7 @@ func (self *SAzureGuestDriver) RequestSyncConfigOnHost(ctx context.Context, gues
})
return nil
}
func (self *SAzureGuestDriver) IsSupportedBillingCycle(bc billing.SBillingCycle) bool {
return false
}
+6 -4
View File
@@ -247,12 +247,14 @@ func (self *SBaremetalGuestDriver) StartGuestSyncstatusTask(guest *models.SGuest
func (self *SBaremetalGuestDriver) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
var confs = make([]baremetal.BaremetalDiskConfig, 0)
for data.Contains(fmt.Sprintf("baremetal_disk_config.%d", len(confs))) {
desc, _ := data.GetString(fmt.Sprintf("baremetal_disk_config.%d", len(confs)))
data.Remove(fmt.Sprintf("baremetal_disk_config.%d", len(confs)))
jsonArray := jsonutils.GetArrayOfPrefix(data, "baremetal_disk_config")
for i := 0; i < len(jsonArray); i += 1 {
// for data.Contains(fmt.Sprintf("baremetal_disk_config.%d", len(confs))) {
desc, _ := jsonArray[i].GetString() // data.GetString(fmt.Sprintf("baremetal_disk_config.%d", len(confs)))
data.Remove(fmt.Sprintf("baremetal_disk_config.%d", i))
bmConf, err := baremetal.ParseDiskConfig(desc)
if err != nil {
return nil, httperrors.NewInputParameterError("baremetal_disk_config.%d", len(confs))
return nil, httperrors.NewInputParameterError("baremetal_disk_config.%d", i)
}
confs = append(confs, bmConf)
}
+17
View File
@@ -8,10 +8,12 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"time"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/billing"
)
type SBaseGuestDriver struct {
@@ -55,6 +57,13 @@ func (self *SBaseGuestDriver) StartGuestCreateTask(guest *models.SGuest, ctx con
}
func (self *SBaseGuestDriver) OnGuestCreateTaskComplete(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
duration, _ := task.GetParams().GetString("duration")
if len(duration) > 0 {
bc, err := billing.ParseBillingCycle(duration)
if err == nil && guest.ExpiredAt.IsZero() {
guest.SaveRenewInfo(task.GetUserCred(), &bc, nil)
}
}
if jsonutils.QueryBoolean(task.GetParams(), "auto_start", false) {
task.SetStage("on_auto_start_guest", nil)
return guest.StartGueststartTask(ctx, task.GetUserCred(), nil, task.GetTaskId())
@@ -195,3 +204,11 @@ func (self *SBaseGuestDriver) GetMaxSecurityGroupCount() int {
func (self *SBaseGuestDriver) getTaskRequestHeader(task taskman.ITask) http.Header {
return task.GetTaskRequestHeader()
}
func (self *SBaseGuestDriver) IsSupportedBillingCycle(bc billing.SBillingCycle) bool {
return true
}
func (self *SBaseGuestDriver) RequestRenewInstance(guest *models.SGuest, bc billing.SBillingCycle) (time.Time, error) {
return time.Time{}, nil
}
+7 -1
View File
@@ -9,8 +9,10 @@ import (
"yunion.io/x/log"
"yunion.io/x/pkg/utils"
"time"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/billing"
)
type SESXiGuestDriver struct {
@@ -150,7 +152,7 @@ func (self *SESXiGuestDriver) OnGuestDeployTaskDataReceived(ctx context.Context,
if host.Id != guest.HostId {
models.HostManager.ClearSchedDescCache(host.Id)
models.HostManager.ClearSchedDescCache(guest.HostId)
guest.SetHostId(host.Id)
guest.OnScheduleToHost(ctx, task.GetUserCred(), host.Id)
}
}
@@ -169,3 +171,7 @@ func (self *SESXiGuestDriver) DoGuestCreateDisksTask(ctx context.Context, guest
subtask.ScheduleRun(nil)
return nil
}
func (self *SESXiGuestDriver) RequestRenewInstance(guest *models.SGuest, bc billing.SBillingCycle) (time.Time, error) {
return time.Time{}, nil
}
+43 -11
View File
@@ -10,11 +10,13 @@ import (
"yunion.io/x/pkg/util/compare"
"yunion.io/x/pkg/util/secrules"
"time"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/billing"
)
type SManagedVirtualizedGuestDriver struct {
@@ -39,6 +41,8 @@ type SManagedVMCreateConfig struct {
SecGroupId string
SecGroupName string
SecRules []secrules.SecurityRule
BillingCycle billing.SBillingCycle
}
func (self *SManagedVirtualizedGuestDriver) GetJsonDescAtHost(ctx context.Context, guest *models.SGuest, host *models.SHost) jsonutils.JSONObject {
@@ -48,14 +52,7 @@ func (self *SManagedVirtualizedGuestDriver) GetJsonDescAtHost(ctx context.Contex
config.Memory = guest.VmemSize
config.Description = guest.Description
if len(guest.SkuId) > 0 {
isku, err := models.ServerSkuManager.FetchById(guest.SkuId)
if err != nil {
log.Errorf("GetJsonDescAtHost sku id %s not found", guest.SkuId)
}
config.InstanceType = isku.GetName()
}
config.InstanceType = guest.InstanceType
if len(guest.KeypairId) > 0 {
config.PublicKey = guest.GetKeypairPublicKey()
@@ -92,6 +89,15 @@ func (self *SManagedVirtualizedGuestDriver) GetJsonDescAtHost(ctx context.Contex
config.DataDisks[i-1] = disk.DiskSize / 1024 // MB => GB
}
}
if guest.BillingType == models.BILLING_TYPE_PREPAID {
bc, err := billing.ParseBillingCycle(guest.BillingCycle)
if err != nil {
log.Errorf("fail to parse billing cycle %s: %s", guest.BillingCycle, err)
}
config.BillingCycle = bc
}
return jsonutils.Marshal(&config)
}
@@ -347,6 +353,11 @@ func (self *SManagedVirtualizedGuestDriver) RequestDiskSnapshot(ctx context.Cont
func (self *SManagedVirtualizedGuestDriver) OnGuestDeployTaskDataReceived(ctx context.Context, guest *models.SGuest, task taskman.ITask, data jsonutils.JSONObject) error {
recycle := false
if guest.IsPrepaidRecycle() {
recycle = true
}
if data.Contains("disks") {
diskInfo := make([]SDiskInfo, 0)
err := data.Unmarshal(&diskInfo, "disks")
@@ -367,15 +378,19 @@ func (self *SManagedVirtualizedGuestDriver) OnGuestDeployTaskDataReceived(ctx co
disk.ExternalId = diskInfo[i].Uuid
disk.DiskType = diskInfo[i].DiskType
disk.Status = models.DISK_READY
disk.BillingType = diskInfo[i].BillingType
disk.FsFormat = diskInfo[i].FsFromat
if diskInfo[i].AutoDelete {
disk.AutoDelete = true
}
// disk.TemplateId = diskInfo[i].TemplateId
disk.AccessPath = diskInfo[i].Path
disk.DiskFormat = diskInfo[i].DiskFormat
disk.ExpiredAt = diskInfo[i].ExpiredAt
if !recycle {
disk.BillingType = diskInfo[i].BillingType
disk.ExpiredAt = diskInfo[i].ExpiredAt
}
if len(diskInfo[i].Metadata) > 0 {
for key, value := range diskInfo[i].Metadata {
if err := disk.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil {
@@ -422,6 +437,11 @@ func (self *SManagedVirtualizedGuestDriver) OnGuestDeployTaskDataReceived(ctx co
}
}
exp, err := data.GetTime("expired_at")
if err == nil && !guest.IsPrepaidRecycle() {
guest.SaveRenewInfo(task.GetUserCred(), nil, &exp)
}
guest.SaveDeployInfo(ctx, task.GetUserCred(), data)
return nil
}
@@ -550,3 +570,15 @@ func (self *SManagedVirtualizedGuestDriver) RequestSyncConfigOnHost(ctx context.
})
return nil
}*/
func (self *SManagedVirtualizedGuestDriver) RequestRenewInstance(guest *models.SGuest, bc billing.SBillingCycle) (time.Time, error) {
iVM, err := guest.GetIVM()
if err != nil {
return time.Time{}, err
}
err = iVM.Renew(bc)
if err != nil {
return time.Time{}, err
}
return iVM.GetExpiredAt(), nil
}
+15 -2
View File
@@ -16,6 +16,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/billing"
"yunion.io/x/onecloud/pkg/util/seclib2"
)
@@ -182,12 +183,16 @@ func (self *SQcloudGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu
var createErr error
var iVM cloudprovider.ICloudVM
var bc *billing.SBillingCycle
if desc.BillingCycle.IsValid() {
bc = &desc.BillingCycle
}
if len(desc.InstanceType) > 0 {
iVM, createErr = ihost.CreateVM2(desc.Name, desc.ExternalImageId, desc.SysDiskSize, desc.InstanceType, desc.ExternalNetworkId,
desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData)
desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData, bc)
} else {
iVM, createErr = ihost.CreateVM(desc.Name, desc.ExternalImageId, desc.SysDiskSize, desc.Cpu, desc.Memory, desc.ExternalNetworkId,
desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData)
desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData, bc)
}
if createErr != nil {
@@ -387,3 +392,11 @@ func (self *SQcloudGuestDriver) RequestSyncConfigOnHost(ctx context.Context, gue
func (self *SQcloudGuestDriver) AllowReconfigGuest() bool {
return true
}
func (self *SQcloudGuestDriver) IsSupportedBillingCycle(bc billing.SBillingCycle) bool {
months := bc.GetMonths()
if (months >= 1 && months <= 12) || (months == 24) || (months == 36) {
return true
}
return false
}
+5
View File
@@ -8,6 +8,7 @@ import (
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
)
type SDiskInfo struct {
@@ -85,5 +86,9 @@ func fetchIVMinfo(desc SManagedVMCreateConfig, iVM cloudprovider.ICloudVM, guest
data.Add(jsonutils.NewString(iVM.GetGlobalId()), "uuid")
data.Add(iVM.GetMetadata(), "metadata")
if iVM.GetBillingType() == models.BILLING_TYPE_PREPAID {
data.Add(jsonutils.NewTimeString(iVM.GetExpiredAt()), "expired_at")
}
return data
}
@@ -190,6 +190,14 @@ func (self *SVirtualizedGuestDriver) ValidateCreateHostData(ctx context.Context,
return nil, httperrors.NewInvalidStatusError("Host %s is not online", bmName)
}
data.Add(jsonutils.NewString(host.Id), "prefer_host_id")
if host.IsPrepaidRecycle() {
data.Set("vmem_size", jsonutils.NewInt(int64(host.MemSize)))
data.Set("vcpu_count", jsonutils.NewInt(int64(host.CpuCount)))
if host.GetGuestCount() >= 1 {
return nil, httperrors.NewInsufficientResourceError("host has been occupied")
}
}
return data, nil
}
+17 -10
View File
@@ -128,6 +128,11 @@ func (self *SKVMHostDriver) RequestAllocateDiskOnStorage(ctx context.Context, ho
return err
}
func (self *SKVMHostDriver) RequestRebuildDiskOnStorage(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask, content *jsonutils.JSONDict) error {
content.Add(jsonutils.JSONTrue, "rebuild")
return self.RequestAllocateDiskOnStorage(ctx, host, storage, disk, task, content)
}
func (self *SKVMHostDriver) RequestDeallocateDiskOnHost(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask) error {
log.Infof("Deallocating disk on host %s", host.GetName())
header := task.GetTaskRequestHeader()
@@ -228,11 +233,11 @@ func (self *SKVMHostDriver) PrepareConvert(host *models.SHost, image, raid strin
return nil, err
}
var sysSize = "60g"
log.Infof("%v", data)
if data.Contains("baremetal_disk_config.0") {
for i := 0; data.Contains(fmt.Sprintf("baremetal_disk_config.%d", i)); i++ {
v, _ := data.Get(fmt.Sprintf("baremetal_disk_config.%d", i))
params.Set(fmt.Sprintf("baremetal_disk_config.%d", i), v)
jsonArray := jsonutils.GetArrayOfPrefix(data, "baremetal_disk_config")
for i := 0; i < len(jsonArray); i += 1 { // } .Contains(fmt.Sprintf("baremetal_disk_config.%d", i)); i++ {
// v, _ := data.Get(fmt.Sprintf("baremetal_disk_config.%d", i))
params.Set(fmt.Sprintf("baremetal_disk_config.%d", i), jsonArray[i])
}
} else {
raid, err = self.GetRaidScheme(host, raid)
@@ -244,9 +249,10 @@ func (self *SKVMHostDriver) PrepareConvert(host *models.SHost, image, raid strin
}
}
if data.Contains("disk.0") {
for i := 0; data.Contains(fmt.Sprintf("disk.%d", i)); i++ {
v, _ := data.Get(fmt.Sprintf("disk.%d", i))
params.Set(fmt.Sprintf("disk.%d", i), v)
jsonArray := jsonutils.GetArrayOfPrefix(data, "disk")
for i := 0; i < len(jsonArray); i += 1 { // } data.Contains(fmt.Sprintf("disk.%d", i)); i++ {
// v, _ := data.Get(fmt.Sprintf("disk.%d", i))
params.Set(fmt.Sprintf("disk.%d", i), jsonArray[i])
}
} else {
if len(image) == 0 {
@@ -265,9 +271,10 @@ func (self *SKVMHostDriver) PrepareConvert(host *models.SHost, image, raid strin
params.Set("disk.1", jsonutils.NewString("ext4:autoextend:/opt/cloud/workspace"))
}
if data.Contains("net.0") {
for i := 0; data.Contains(fmt.Sprintf("net.%d", i)); i++ {
v, _ := data.Get(fmt.Sprintf("net.%d", i))
params.Set(fmt.Sprintf("net.%d", i), v)
jsonArray := jsonutils.GetArrayOfPrefix(data, "net")
for i := 0; i < len(jsonArray); i += 1 { // } data.Contains(fmt.Sprintf("net.%d", i)); i++ {
// v, _ := data.Get(fmt.Sprintf("net.%d", i))
params.Set(fmt.Sprintf("net.%d", i), jsonArray[i])
}
} else {
wire := host.GetMasterWire()
+23
View File
@@ -241,6 +241,7 @@ func (self *SManagedVirtualizationHostDriver) RequestAllocateDiskOnStorage(ctx c
data := jsonutils.NewDict()
data.Add(jsonutils.NewInt(int64(iDisk.GetDiskSizeMB())), "disk_size")
data.Add(jsonutils.NewString(iDisk.GetDiskFormat()), "disk_format")
data.Add(jsonutils.NewString(iDisk.GetAccessPath()), "disk_path")
return data, nil
})
@@ -288,3 +289,25 @@ func (self *SManagedVirtualizationHostDriver) RequestResetDisk(ctx context.Conte
})
return nil
}
func (self *SManagedVirtualizationHostDriver) RequestRebuildDiskOnStorage(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask, content *jsonutils.JSONDict) error {
iDisk, err := disk.GetIDisk()
if err != nil {
return err
}
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
err := iDisk.Rebuild(ctx)
if err != nil {
return nil, err
}
data := jsonutils.NewDict()
data.Add(jsonutils.NewInt(int64(iDisk.GetDiskSizeMB())), "disk_size")
data.Add(jsonutils.NewString(iDisk.GetDiskFormat()), "disk_format")
data.Add(jsonutils.NewString(iDisk.GetAccessPath()), "disk_path")
return data, nil
})
return nil
}
+23 -2
View File
@@ -13,8 +13,9 @@ const (
)
type SBillingResourceBase struct {
BillingType string `width:"36" charset:"ascii" nullable:"true" default:"postpaid" list:"user" create:"optional"`
ExpiredAt time.Time `nullable:"true" list:"user" create:"optional"`
BillingType string `width:"36" charset:"ascii" nullable:"true" default:"postpaid" list:"user" create:"admin_optional"`
ExpiredAt time.Time `nullable:"true" list:"user" create:"admin_optional"`
BillingCycle string `width:"10" charset:"ascii" nullable:"true" list:"user" create:"admin_optional"`
}
func (self *SBillingResourceBase) GetChargeType() string {
@@ -25,6 +26,24 @@ func (self *SBillingResourceBase) GetChargeType() string {
}
}
func (self *SBillingResourceBase) FetchCloudBillingInfo(info *SCloudBillingInfo) {
info.ChargeType = self.GetChargeType()
if self.GetChargeType() == BILLING_TYPE_PREPAID {
info.ExpiredAt = self.ExpiredAt
info.BillingCycle = self.BillingCycle
}
}
func (self *SBillingResourceBase) IsValidPrePaid() bool {
if self.BillingType == BILLING_TYPE_PREPAID {
now := time.Now().UTC()
if self.ExpiredAt.After(now) {
return true
}
}
return false
}
type SCloudBillingInfo struct {
Provider string
Account string
@@ -42,6 +61,8 @@ type SCloudBillingInfo struct {
PriceKey string
ChargeType string
InternetChargeType string
ExpiredAt time.Time
BillingCycle string
}
func MakeCloudBillingInfo(region *SCloudregion, zone *SZone, provider *SCloudprovider) SCloudBillingInfo {
+2 -2
View File
@@ -4,6 +4,8 @@ import (
"context"
"database/sql"
"fmt"
"net/url"
"strconv"
"strings"
"time"
@@ -13,8 +15,6 @@ import (
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
"net/url"
"strconv"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
+60 -13
View File
@@ -28,6 +28,7 @@ import (
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/auth"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/util/billing"
)
const (
@@ -113,14 +114,31 @@ func (manager *SDiskManager) GetContextManager() []db.IModelManager {
}
func (manager *SDiskManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) {
queryDict, ok := query.(*jsonutils.JSONDict)
if !ok {
return nil, fmt.Errorf("invalid querystring format")
}
billingTypeStr, _ := queryDict.GetString("billing_type")
if len(billingTypeStr) > 0 {
if billingTypeStr == BILLING_TYPE_POSTPAID {
q = q.Filter(
sqlchemy.OR(
sqlchemy.IsNullOrEmpty(q.Field("billing_type")),
sqlchemy.Equals(q.Field("billing_type"), billingTypeStr),
),
)
} else {
q = q.Equals("billing_type", billingTypeStr)
}
queryDict.Remove("billing_type")
}
q, err := manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query)
if err != nil {
return nil, err
}
queryDict, ok := query.(*jsonutils.JSONDict)
if !ok {
return nil, fmt.Errorf("Invalid querystring formst: %v", query)
}
if query.Contains("unused") {
guestdisks := GuestdiskManager.Query().SubQuery()
sq := guestdisks.Query(guestdisks.Field("disk_id"))
@@ -435,9 +453,10 @@ func (self *SDisk) StartAllocate(ctx context.Context, host *SHost, storage *SSto
}
}
if rebuild {
content.Add(jsonutils.JSONTrue, "rebuild")
return host.GetHostDriver().RequestRebuildDiskOnStorage(ctx, host, storage, self, task, content)
} else {
return host.GetHostDriver().RequestAllocateDiskOnStorage(ctx, host, storage, self, task, content)
}
return host.GetHostDriver().RequestAllocateDiskOnStorage(ctx, host, storage, self, task, content)
}
func (self *SDisk) AllowGetDetailsConvertSnapshot(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
@@ -843,9 +862,14 @@ func (manager *SDiskManager) SyncDisks(ctx context.Context, userCred mcclient.To
}
func (self *SDisk) syncWithCloudDisk(ctx context.Context, userCred mcclient.TokenCredential, extDisk cloudprovider.ICloudDisk, index int, projectId string, projectSync bool) error {
recycle := false
guests := self.GetGuests()
if len(guests) == 1 && guests[0].IsPrepaidRecycle() {
recycle = true
}
_, err := self.GetModelManager().TableSpec().Update(self, func() error {
extDisk.Refresh()
self.Name = extDisk.GetName()
// self.Name = extDisk.GetName()
self.Status = extDisk.GetStatus()
self.DiskFormat = extDisk.GetDiskFormat()
self.DiskSize = extDisk.GetDiskSizeMB()
@@ -863,10 +887,12 @@ func (self *SDisk) syncWithCloudDisk(ctx context.Context, userCred mcclient.Toke
self.IsEmulated = extDisk.IsEmulated()
self.BillingType = extDisk.GetBillingType()
self.ExpiredAt = extDisk.GetExpiredAt()
if !recycle {
self.BillingType = extDisk.GetBillingType()
self.ExpiredAt = extDisk.GetExpiredAt()
}
self.ProjectId = userCred.GetProjectId()
// self.ProjectId = userCred.GetProjectId()
if projectSync && len(projectId) > 0 {
self.ProjectId = projectId
}
@@ -1325,7 +1351,7 @@ func (self *SDisk) GetShortDesc() *jsonutils.JSONDict {
billingInfo.PriceKey = priceKey
}
billingInfo.ChargeType = self.GetChargeType()
self.FetchCloudBillingInfo(&billingInfo)
desc.Update(jsonutils.Marshal(billingInfo))
@@ -1376,7 +1402,7 @@ func (manager *SDiskManager) getExpiredPendingDeleteDisks() []SDisk {
return disks
}
func (manager *SDiskManager) CleanPendingDeleteDisks(ctx context.Context, userCred mcclient.TokenCredential) {
func (manager *SDiskManager) CleanPendingDeleteDisks(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
disks := manager.getExpiredPendingDeleteDisks()
if disks == nil {
return
@@ -1396,7 +1422,7 @@ func (manager *SDiskManager) getAutoSnapshotDisks() []SDisk {
return dest
}
func (manager *SDiskManager) AutoDiskSnapshot(ctx context.Context, userCred mcclient.TokenCredential) {
func (manager *SDiskManager) AutoDiskSnapshot(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
disks := manager.getAutoSnapshotDisks()
if disks == nil {
return
@@ -1435,3 +1461,24 @@ func (disk *SDisk) StratCreateBackupTask(ctx context.Context, userCred mcclient.
}
return nil
}
func (self *SDisk) SaveRenewInfo(userCred mcclient.TokenCredential, bc *billing.SBillingCycle, expireAt *time.Time) error {
_, err := self.GetModelManager().TableSpec().Update(self, func() error {
if self.BillingType != BILLING_TYPE_PREPAID {
self.BillingType = BILLING_TYPE_PREPAID
}
if expireAt != nil && !expireAt.IsZero() {
self.ExpiredAt = *expireAt
} else if bc != nil {
self.BillingCycle = bc.String()
self.ExpiredAt = bc.EndAt(self.ExpiredAt)
}
return nil
})
if err != nil {
log.Errorf("Update error %s", err)
return err
}
db.OpsLog.LogEvent(self, db.ACT_RENEW, self.GetShortDesc(), userCred)
return nil
}
+47 -15
View File
@@ -827,30 +827,62 @@ func (u EipUsage) Total() int {
return u.PublicIPCount + u.EIPCount
}
func (manager *SElasticipManager) usageQ(q *sqlchemy.SQuery, rangeObj db.IStandaloneModel, hostTypes []string) *sqlchemy.SQuery {
if rangeObj == nil {
func (manager *SElasticipManager) usageQByProvider(q *sqlchemy.SQuery, providers []string) *sqlchemy.SQuery {
if len(providers) == 0 {
return q
}
zones := ZoneManager.Query().SubQuery()
hosts := HostManager.Query().SubQuery()
sq := zones.Query(zones.Field("cloudregion_id")).
Join(hosts, sqlchemy.AND(
sqlchemy.IsFalse(hosts.Field("deleted")),
sqlchemy.IsTrue(hosts.Field("enabled")),
sqlchemy.Equals(hosts.Field("zone_id"), zones.Field("id"))))
sq = AttachUsageQuery(sq, hosts, hosts.Field("id"), hostTypes, rangeObj)
q = q.Filter(sqlchemy.In(q.Field("cloudregion_id"), sq.Distinct()))
cloudproviders := CloudproviderManager.Query().SubQuery()
subq := cloudproviders.Query(cloudproviders.Field("id")).In("provider", providers).SubQuery()
q = q.Filter(sqlchemy.In(q.Field("manager_id"), subq))
return q
}
func (manager *SElasticipManager) TotalCount(projectId string, rangeObj db.IStandaloneModel, hostTypes []string) EipUsage {
func (manager *SElasticipManager) usageQByRange(q *sqlchemy.SQuery, rangeObj db.IStandaloneModel) *sqlchemy.SQuery {
if rangeObj == nil {
return q
}
kw := rangeObj.Keyword()
// log.Debugf("rangeObj keyword: %s", kw)
switch kw {
case "zone":
zone := rangeObj.(*SZone)
q = q.Filter(sqlchemy.Equals(q.Field("cloudregion_id"), zone.CloudregionId))
case "wire":
wire := rangeObj.(*SWire)
zone := wire.GetZone()
q = q.Filter(sqlchemy.Equals(q.Field("cloudregion_id"), zone.CloudregionId))
case "host":
host := rangeObj.(*SHost)
zone := host.GetZone()
q = q.Filter(sqlchemy.Equals(q.Field("cloudregion_id"), zone.CloudregionId))
case "cloudprovider":
q = q.Filter(sqlchemy.Equals(q.Field("manager_id"), rangeObj.GetId()))
case "cloudaccount":
cloudproviders := CloudproviderManager.Query().SubQuery()
subq := cloudproviders.Query(cloudproviders.Field("id")).Equals("cloudaccount_id", rangeObj.GetId()).SubQuery()
q = q.Filter(sqlchemy.In(q.Field("manager_id"), subq))
case "cloudregion":
q = q.Filter(sqlchemy.Equals(q.Field("cloudregion_id"), rangeObj.GetId()))
}
return q
}
func (manager *SElasticipManager) usageQ(q *sqlchemy.SQuery, rangeObj db.IStandaloneModel, providers []string) *sqlchemy.SQuery {
q = manager.usageQByRange(q, rangeObj)
q = manager.usageQByProvider(q, providers)
return q
}
func (manager *SElasticipManager) TotalCount(projectId string, rangeObj db.IStandaloneModel, providers []string) EipUsage {
usage := EipUsage{}
q1 := manager.Query().Equals("mode", EIP_MODE_INSTANCE_PUBLICIP)
q1 = manager.usageQ(q1, rangeObj, hostTypes)
q1 = manager.usageQ(q1, rangeObj, providers)
q2 := manager.Query().Equals("mode", EIP_MODE_STANDALONE_EIP)
q2 = manager.usageQ(q2, rangeObj, hostTypes)
q2 = manager.usageQ(q2, rangeObj, providers)
q3 := manager.Query().Equals("mode", EIP_MODE_STANDALONE_EIP).IsNotEmpty("associate_id")
q3 = manager.usageQ(q3, rangeObj, hostTypes)
q3 = manager.usageQ(q3, rangeObj, providers)
if len(projectId) > 0 {
q1 = q1.Equals("tenant_id", projectId)
q2 = q2.Equals("tenant_id", projectId)
+149 -44
View File
@@ -22,8 +22,10 @@ import (
"yunion.io/x/onecloud/pkg/util/logclient"
"yunion.io/x/onecloud/pkg/util/seclib2"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/util/billing"
"yunion.io/x/pkg/util/fileutils"
"yunion.io/x/pkg/util/regutils"
"yunion.io/x/pkg/utils"
@@ -776,23 +778,19 @@ func (self *SGuest) AllowPerformRebuildRoot(ctx context.Context, userCred mcclie
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 len(imageId) == 0 {
gdc := self.CategorizeDisks()
imageId = gdc.Root.GetTemplateId()
if len(imageId) == 0 {
return nil, httperrors.NewBadRequestError("No template for root disk")
if len(imageId) > 0 {
img, err := CachedimageManager.getImageInfo(ctx, userCred, imageId, false)
if err != nil {
return nil, httperrors.NewNotFoundError("failed to find %s", imageId)
}
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)
}
imageId = img.Id
}
img, err := CachedimageManager.getImageInfo(ctx, userCred, imageId, false)
if err != nil {
return nil, httperrors.NewNotFoundError("failed to find %s", imageId)
}
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)
}
imageId = img.Id
rebuildStatus, err := self.GetDriver().GetRebuildRootStatus()
if err != nil {
@@ -834,11 +832,20 @@ func (self *SGuest) PerformRebuildRoot(ctx context.Context, userCred mcclient.To
}
}
return nil, self.StartRebuildRootTask(ctx, userCred, imageId, needStop, autoStart, passwd, resetPasswd)
allDisks := jsonutils.QueryBoolean(data, "all_disks", false)
return nil, self.StartRebuildRootTask(ctx, userCred, imageId, needStop, autoStart, passwd, resetPasswd, allDisks)
}
func (self *SGuest) StartRebuildRootTask(ctx context.Context, userCred mcclient.TokenCredential, imageId string, needStop, autoStart bool, passwd string, resetPasswd bool) error {
func (self *SGuest) StartRebuildRootTask(ctx context.Context, userCred mcclient.TokenCredential, imageId string, needStop, autoStart bool, passwd string, resetPasswd bool, allDisk bool) error {
data := jsonutils.NewDict()
if len(imageId) == 0 {
gdc := self.CategorizeDisks()
imageId = gdc.Root.GetTemplateId()
if len(imageId) == 0 {
return httperrors.NewBadRequestError("No template for root disk")
}
}
data.Set("image_id", jsonutils.NewString(imageId))
if needStop {
data.Set("need_stop", jsonutils.JSONTrue)
@@ -854,6 +861,12 @@ func (self *SGuest) StartRebuildRootTask(ctx context.Context, userCred mcclient.
if len(passwd) > 0 {
data.Set("password", jsonutils.NewString(passwd))
}
if allDisk {
data.Set("all_disks", jsonutils.JSONTrue)
} else {
data.Set("all_disks", jsonutils.JSONFalse)
}
if self.GetHypervisor() == HYPERVISOR_BAREMETAL {
task, err := taskman.TaskManager.NewTask(ctx, "BaremetalServerRebuildRootTask", self, userCred, data, "", "", nil)
if err != nil {
@@ -882,13 +895,18 @@ func (self *SGuest) AllowPerformCreatedisk(ctx context.Context, userCred mcclien
}
func (self *SGuest) PerformCreatedisk(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
var diskIdx, diskSize = 0, 0
diskSize := 0
disksConf := jsonutils.NewDict()
diskSizes := make(map[string]int, 0)
diskSeq := fmt.Sprintf("disk.%d", diskIdx)
for data.Contains(diskSeq) {
diskDef, _ := data.Get(diskSeq)
diskInfo, err := parseDiskInfo(ctx, userCred, diskDef)
diskDefArray := jsonutils.GetArrayOfPrefix(data, "disk")
if len(diskDefArray) == 0 {
logclient.AddActionLog(self, logclient.ACT_CREATE, "No Disk Info Provided", userCred, false)
return nil, httperrors.NewBadRequestError("No Disk Info Provided")
}
for diskIdx := 0; diskIdx < len(diskDefArray); diskIdx += 1 {
diskInfo, err := parseDiskInfo(ctx, userCred, diskDefArray[diskIdx])
if err != nil {
logclient.AddActionLog(self, logclient.ACT_CREATE, err.Error(), userCred, false)
return nil, httperrors.NewBadRequestError(err.Error())
@@ -896,19 +914,13 @@ func (self *SGuest) PerformCreatedisk(ctx context.Context, userCred mcclient.Tok
if len(diskInfo.Backend) == 0 {
diskInfo.Backend = self.getDefaultStorageType()
}
disksConf.Set(diskSeq, jsonutils.Marshal(diskInfo))
disksConf.Set(fmt.Sprintf("disk.%d", diskIdx), jsonutils.Marshal(diskInfo))
if _, ok := diskSizes[diskInfo.Backend]; !ok {
diskSizes[diskInfo.Backend] = diskInfo.SizeMb
} else {
diskSizes[diskInfo.Backend] += diskInfo.SizeMb
}
diskSize += diskInfo.SizeMb
diskIdx += 1
diskSeq = fmt.Sprintf("disk.%d", diskIdx)
}
if diskIdx == 0 {
logclient.AddActionLog(self, logclient.ACT_CREATE, "No Disk Info Provided", userCred, false)
return nil, httperrors.NewBadRequestError("No Disk Info Provided")
}
host := self.GetHost()
if host == nil {
@@ -938,7 +950,7 @@ func (self *SGuest) PerformCreatedisk(ctx context.Context, userCred mcclient.Tok
lockman.LockObject(ctx, host)
defer lockman.ReleaseObject(ctx, host)
err = self.CreateDisksOnHost(ctx, userCred, host, disksConf, pendingUsage)
err = self.CreateDisksOnHost(ctx, userCred, host, disksConf, pendingUsage, false)
if err != nil {
QuotaManager.CancelPendingUsage(ctx, userCred, self.ProjectId, nil, pendingUsage)
logclient.AddActionLog(self, logclient.ACT_CREATE, err.Error(), userCred, false)
@@ -1220,14 +1232,12 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
var addCpu, addMem int
confs := jsonutils.NewDict()
skuId, _ := data.GetString("sku_id")
if len(skuId) > 0 && self.SkuId != skuId {
isku, err := ServerSkuManager.FetchById(skuId)
skuId := jsonutils.GetAnyString(data, []string{"instance_type", "sku", "flavor"})
if len(skuId) > 0 {
sku, err := ServerSkuManager.FetchSkuByNameAndHypervisor(skuId, self.GetHypervisor(), true)
if err != nil {
return nil, httperrors.NewNotFoundError("sku_id %s not found", skuId)
return nil, err
}
sku := isku.(*SServerSku)
addCpu = sku.CpuCoreCount - int(self.VcpuCount)
addMem = sku.MemorySizeMB - self.VmemSize
confs.Add(jsonutils.NewString(sku.ExternalId), "sku_id")
@@ -1245,6 +1255,9 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
return nil, httperrors.NewBadRequestError("Params vcpu_count parse error")
}
addCpu = int(nVcpu - int64(self.VcpuCount))
if addCpu < 0 {
addCpu = 0
}
}
vmemSize, err := data.GetString("vmem_size")
if err == nil {
@@ -1260,6 +1273,9 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
return nil, httperrors.NewBadRequestError("Params vmem_size parse error")
}
addMem = nVmem - self.VmemSize
if addMem < 0 {
addMem = 0
}
}
}
@@ -1273,7 +1289,7 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
for {
diskNum := fmt.Sprintf("disk.%d", diskIdx)
diskDesc, err := data.Get(diskNum)
if err != nil {
if err != nil || diskDesc == jsonutils.JSONNull {
break
}
diskConf, err := parseDiskInfo(ctx, userCred, diskDesc)
@@ -1319,11 +1335,6 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
}
provider, e := self.GetHost().GetDriver()
/*if e != nil {
log.Errorf("Get Provider Error: %s", e)
return nil, httperrors.NewInsufficientResourceError("Provider Not Found")
}*/
if e != nil || !provider.IsPublicCloud() {
for storageId, needSize := range diskSizes {
iStorage, err := StorageManager.FetchById(storageId)
@@ -1368,7 +1379,7 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
}
}
if newDisks.Length() > 0 {
err := self.CreateDisksOnHost(ctx, userCred, host, newDisks, pendingUsage)
err := self.CreateDisksOnHost(ctx, userCred, host, newDisks, pendingUsage, false)
if err != nil {
QuotaManager.CancelPendingUsage(ctx, userCred, self.ProjectId, nil, pendingUsage)
return nil, httperrors.NewBadRequestError("Create disk on host error: %s", err)
@@ -1389,15 +1400,31 @@ func (self *SGuest) StartChangeConfigTask(ctx context.Context, userCred mcclient
return nil
}
func (self *SGuest) revokeAllSecgroups(ctx context.Context, userCred mcclient.TokenCredential) error {
err := self.revokeSecgroup(ctx, userCred, self.getSecgroup())
if err != nil {
return err
}
err = GuestsecgroupManager.DeleteGuestSecgroup(ctx, userCred, self, nil)
if err != nil {
return err
}
return nil
}
func (self *SGuest) DoPendingDelete(ctx context.Context, userCred mcclient.TokenCredential) {
eip, _ := self.GetEip()
if eip != nil {
eip.DoPendingDelete(ctx, userCred)
}
// revoke all secgroups
// TODO: sync revoked secgroups to remote cloud
self.revokeAllSecgroups(ctx, userCred)
// remove detachable disks
for _, guestdisk := range self.GetDisks() {
disk := guestdisk.GetDisk()
storage := disk.GetStorage()
if utils.IsInStringArray(storage.StorageType, STORAGE_LOCAL_TYPES) || utils.IsInStringArray(disk.DiskType, []string{DISK_TYPE_SYS, DISK_TYPE_SWAP}) || (utils.IsInStringArray(self.Hypervisor, PUBLIC_CLOUD_HYPERVISORS) && disk.AutoDelete) {
if storage.IsLocal() || disk.BillingType == BILLING_TYPE_PREPAID || utils.IsInStringArray(disk.DiskType, []string{DISK_TYPE_SYS, DISK_TYPE_SWAP}) || (utils.IsInStringArray(self.Hypervisor, PUBLIC_CLOUD_HYPERVISORS) && disk.AutoDelete) {
disk.DoPendingDelete(ctx, userCred)
} else {
self.DetachDisk(ctx, disk, userCred)
@@ -2007,3 +2034,81 @@ func (self *SGuest) PerformDelExtraOption(ctx context.Context, userCred mcclient
extraOptions.Remove(key)
return nil, self.SetExtraOptions(ctx, userCred, extraOptions)
}
func (self *SGuest) AllowPerformRenew(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return db.IsAdminAllowPerform(userCred, self, "renew")
}
func (self *SGuest) PerformRenew(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
durationStr := jsonutils.GetAnyString(data, []string{"duration"})
if len(durationStr) == 0 {
return nil, httperrors.NewInputParameterError("missong duration")
}
bc, err := billing.ParseBillingCycle(durationStr)
if err != nil {
return nil, httperrors.NewInputParameterError("invalid duration %s: %s", durationStr, err)
}
if !self.GetDriver().IsSupportedBillingCycle(bc) {
return nil, httperrors.NewInputParameterError("unsupported duration %s", durationStr)
}
err = self.startGuestRenewTask(ctx, userCred, durationStr, "")
if err != nil {
return nil, err
}
return nil, nil
}
func (self *SGuest) startGuestRenewTask(ctx context.Context, userCred mcclient.TokenCredential, duration string, parentTaskId string) error {
data := jsonutils.NewDict()
data.Add(jsonutils.NewString(duration), "duration")
task, err := taskman.TaskManager.NewTask(ctx, "GuestRenewTask", self, userCred, data, parentTaskId, "", nil)
if err != nil {
log.Errorf("fail to crate GuestRenewTask %s", err)
return err
}
task.ScheduleRun(nil)
return nil
}
func (self *SGuest) SaveRenewInfo(userCred mcclient.TokenCredential, bc *billing.SBillingCycle, expireAt *time.Time) error {
err := self.doSaveRenewInfo(userCred, bc, expireAt)
if err != nil {
return err
}
guestdisks := self.GetDisks()
for i := 0; i < len(guestdisks); i += 1 {
disk := guestdisks[i].GetDisk()
if disk.BillingType == BILLING_TYPE_PREPAID {
err = disk.SaveRenewInfo(userCred, bc, expireAt)
if err != nil {
return err
}
}
}
return nil
}
func (self *SGuest) doSaveRenewInfo(userCred mcclient.TokenCredential, bc *billing.SBillingCycle, expireAt *time.Time) error {
_, err := self.GetModelManager().TableSpec().Update(self, func() error {
if self.BillingType != BILLING_TYPE_PREPAID {
self.BillingType = BILLING_TYPE_PREPAID
}
if expireAt != nil && !expireAt.IsZero() {
self.ExpiredAt = *expireAt
} else {
self.BillingCycle = bc.String()
self.ExpiredAt = bc.EndAt(self.ExpiredAt)
}
return nil
})
if err != nil {
log.Errorf("Update error %s", err)
return err
}
db.OpsLog.LogEvent(self, db.ACT_RENEW, self.GetShortDesc(), userCred)
return nil
}
+6
View File
@@ -3,11 +3,13 @@ package models
import (
"context"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/billing"
)
type IGuestDriver interface {
@@ -17,6 +19,10 @@ type IGuestDriver interface {
GetMaxVMemSizeGB() int
GetMaxSecurityGroupCount() int
IsSupportedBillingCycle(bc billing.SBillingCycle) bool
RequestRenewInstance(guest *SGuest, bc billing.SBillingCycle) (time.Time, error)
GetJsonDescAtHost(ctx context.Context, guest *SGuest, host *SHost) jsonutils.JSONObject
ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error)
+364 -182
View File
@@ -22,6 +22,7 @@ import (
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
@@ -31,6 +32,7 @@ import (
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/auth"
"yunion.io/x/onecloud/pkg/util/billing"
"yunion.io/x/onecloud/pkg/util/seclib2"
)
@@ -125,21 +127,36 @@ const (
HYPERVISOR_BAREMETAL = "baremetal"
HYPERVISOR_ESXI = "esxi"
HYPERVISOR_HYPERV = "hyperv"
HYPERVISOR_ALIYUN = "aliyun"
HYPERVISOR_QCLOUD = "qcloud"
HYPERVISOR_AZURE = "azure"
HYPERVISOR_AWS = "aws"
HYPERVISOR_XEN = "xen"
HYPERVISOR_ALIYUN = "aliyun"
HYPERVISOR_QCLOUD = "qcloud"
HYPERVISOR_AZURE = "azure"
HYPERVISOR_AWS = "aws"
// HYPERVISOR_DEFAULT = HYPERVISOR_KVM
HYPERVISOR_DEFAULT = HYPERVISOR_ALIYUN
HYPERVISOR_DEFAULT = HYPERVISOR_KVM
)
var VM_RUNNING_STATUS = []string{VM_START_START, VM_STARTING, VM_RUNNING, VM_BLOCK_STREAM}
var VM_CREATING_STATUS = []string{VM_CREATE_NETWORK, VM_CREATE_DISK, VM_START_DEPLOY, VM_DEPLOYING}
var HYPERVISORS = []string{HYPERVISOR_KVM, HYPERVISOR_BAREMETAL, HYPERVISOR_ESXI, HYPERVISOR_CONTAINER, HYPERVISOR_ALIYUN, HYPERVISOR_AZURE, HYPERVISOR_AWS, HYPERVISOR_QCLOUD}
var HYPERVISORS = []string{HYPERVISOR_KVM,
HYPERVISOR_BAREMETAL,
HYPERVISOR_ESXI,
HYPERVISOR_CONTAINER,
HYPERVISOR_ALIYUN,
HYPERVISOR_AZURE,
HYPERVISOR_AWS,
HYPERVISOR_QCLOUD,
}
var PUBLIC_CLOUD_HYPERVISORS = []string{HYPERVISOR_ALIYUN, HYPERVISOR_AWS, HYPERVISOR_AZURE, HYPERVISOR_QCLOUD}
var PUBLIC_CLOUD_HYPERVISORS = []string{
HYPERVISOR_ALIYUN,
HYPERVISOR_AWS,
HYPERVISOR_AZURE,
HYPERVISOR_QCLOUD,
}
// var HYPERVISORS = []string{HYPERVISOR_ALIYUN}
@@ -214,7 +231,7 @@ type SGuest struct {
Hypervisor string `width:"16" charset:"ascii" nullable:"false" default:"kvm" list:"user" create:"required"` // Column(VARCHAR(16, charset='ascii'), nullable=False, default=HYPERVISOR_DEFAULT)
SkuId string `width:"64" charset:"ascii" nullable:"true" list:"user" create:"optional"`
InstanceType string `width:"64" charset:"ascii" nullable:"true" list:"user" create:"optional"`
}
func (manager *SGuestManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
@@ -227,14 +244,30 @@ func (manager *SGuestManager) AllowListItems(ctx context.Context, userCred mccli
}
func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) {
q, err := manager.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query)
if err != nil {
return nil, err
}
queryDict, ok := query.(*jsonutils.JSONDict)
if !ok {
return nil, fmt.Errorf("invalid querystring format")
}
billingTypeStr, _ := queryDict.GetString("billing_type")
if len(billingTypeStr) > 0 {
if billingTypeStr == BILLING_TYPE_POSTPAID {
q = q.Filter(
sqlchemy.OR(
sqlchemy.IsNullOrEmpty(q.Field("billing_type")),
sqlchemy.Equals(q.Field("billing_type"), billingTypeStr),
),
)
} else {
q = q.Equals("billing_type", billingTypeStr)
}
queryDict.Remove("billing_type")
}
q, err := manager.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query)
if err != nil {
return nil, err
}
isBMstr, _ := queryDict.GetString("baremetal")
if len(isBMstr) > 0 && utils.ToBool(isBMstr) {
queryDict.Add(jsonutils.NewString(HYPERVISOR_BAREMETAL), "hypervisor")
@@ -245,6 +278,25 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ
q = q.Equals("hypervisor", hypervisor)
}
resourceTypeStr := jsonutils.GetAnyString(queryDict, []string{"resource_type"})
if len(resourceTypeStr) > 0 {
hosts := HostManager.Query().SubQuery()
subq := hosts.Query(hosts.Field("id"))
switch resourceTypeStr {
case HostResourceTypeShared:
subq = subq.Filter(
sqlchemy.OR(
sqlchemy.IsNullOrEmpty(hosts.Field("resource_type")),
sqlchemy.Equals(hosts.Field("resource_type"), resourceTypeStr),
),
)
default:
subq = subq.Equals("resource_type", resourceTypeStr)
}
q = q.In("host_id", subq.SubQuery())
}
hostFilter, _ := queryDict.GetString("host")
if len(hostFilter) > 0 {
host, _ := HostManager.FetchByIdOrName(nil, hostFilter)
@@ -320,26 +372,17 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ
}
disk := diskI.(*SDisk)
guestdisks := GuestdiskManager.Query().SubQuery()
count := guestdisks.Query().Filter(sqlchemy.AND(
sqlchemy.Equals(guestdisks.Field("disk_id"), disk.Id),
sqlchemy.IsFalse(guestdisks.Field("deleted")))).Count()
count := guestdisks.Query().Equals("disk_id", disk.Id).Count()
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"))))
sgq := guestdisks.Query(guestdisks.Field("guest_id")).Equals("disk_id", disk.Id).SubQuery()
q = q.Filter(sqlchemy.In(q.Field("id"), sgq))
} else {
hosts := HostManager.Query().SubQuery()
hoststorages := HoststorageManager.Query().SubQuery()
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")))).
Join(storages, sqlchemy.AND(
sqlchemy.Equals(storages.Field("id"), hoststorages.Field("storage_id")),
sqlchemy.IsFalse(storages.Field("deleted")))).
Join(hoststorages, sqlchemy.Equals(hoststorages.Field("host_id"), hosts.Field("id"))).
Join(storages, sqlchemy.Equals(storages.Field("id"), hoststorages.Field("storage_id"))).
Filter(sqlchemy.Equals(storages.Field("id"), disk.StorageId)).SubQuery()
q = q.In("host_id", sq)
}
@@ -440,7 +483,10 @@ func (guest *SGuest) GetDriver() IGuestDriver {
func (guest *SGuest) ValidateDeleteCondition(ctx context.Context) error {
if guest.DisableDelete.IsTrue() {
return fmt.Errorf("Virtual server is locked, cannot delete")
return httperrors.NewInvalidStatusError("Virtual server is locked, cannot delete")
}
if guest.IsValidPrePaid() {
return httperrors.NewForbiddenError("not allow to delete prepaid server in valid status")
}
return guest.SVirtualResourceBase.ValidateDeleteCondition(ctx)
}
@@ -579,16 +625,6 @@ func validateMemCpuData(data jsonutils.JSONObject) (int, int, error) {
return vmemSize, vcpuCount, nil
}
func validateSkuData(sku_id string) (string, int, int, error) {
isku, err := ServerSkuManager.FetchById(sku_id)
if err != nil {
return "", 0, 0, err
}
sku := isku.(*SServerSku)
return sku.GetId(), sku.CpuCoreCount, sku.MemorySizeMB, nil
}
func (self *SGuest) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
vmemSize, vcpuCount, err := validateMemCpuData(data)
if err != nil {
@@ -644,8 +680,9 @@ func (manager *SGuestManager) ValidateCreateData(ctx context.Context, userCred m
var osProf osprofile.SOSProfile
hypervisor, _ = data.GetString("hypervisor")
if hypervisor != HYPERVISOR_CONTAINER {
disk0Json, _ := data.Get("disk.0")
if disk0Json == nil {
if disk0Json == nil || disk0Json == jsonutils.JSONNull {
return nil, httperrors.NewInputParameterError("No disk information provided")
}
diskConfig, err := parseDiskInfo(ctx, userCred, disk0Json)
@@ -681,14 +718,62 @@ func (manager *SGuestManager) ValidateCreateData(ctx context.Context, userCred m
data.Add(jsonutils.NewString(osProf.OSType), "os_type")
}
data.Add(jsonutils.Marshal(osProf), "__os_profile__")
}
data, err = ValidateScheduleCreateData(ctx, userCred, data, hypervisor)
if err != nil {
return nil, err
}
hypervisor, _ = data.GetString("hypervisor")
if hypervisor != HYPERVISOR_CONTAINER {
// support sku here
var sku *SServerSku
skuId := jsonutils.GetAnyString(data, []string{"sku", "flavor", "instance_type"})
if len(skuId) > 0 {
sku, err := ServerSkuManager.FetchSkuByNameAndHypervisor(skuId, hypervisor, true)
if err != nil {
return nil, err
}
data.Add(jsonutils.NewString(sku.Id), "instance_type")
data.Add(jsonutils.NewInt(int64(sku.MemorySizeMB)), "vmem_size")
data.Add(jsonutils.NewInt(int64(sku.CpuCoreCount)), "vcpu_count")
} else {
vmemSize, vcpuCount, err := validateMemCpuData(data)
if err != nil {
return nil, err
}
if vmemSize == 0 {
return nil, httperrors.NewInputParameterError("Missing memory size")
}
if vcpuCount == 0 {
vcpuCount = 1
}
data.Add(jsonutils.NewInt(int64(vmemSize)), "vmem_size")
data.Add(jsonutils.NewInt(int64(vcpuCount)), "vcpu_count")
}
dataDiskDefs := make([]string, 0)
if sku != nil && sku.AttachedDiskCount > 0 {
for i := 0; i < sku.AttachedDiskCount; i += 1 {
dataDiskDefs = append(dataDiskDefs, fmt.Sprintf("%dgb:%s", sku.AttachedDiskSizeGB, sku.AttachedDiskType))
}
}
// start from data disk
for idx := 1; data.Contains(fmt.Sprintf("disk.%d", idx)); idx += 1 {
diskJson, err := data.Get(fmt.Sprintf("disk.%d", idx))
jsonArray := jsonutils.GetArrayOfPrefix(data, "disk")
for idx := 1; idx < len(jsonArray); idx += 1 { // data.Contains(fmt.Sprintf("disk.%d", idx))
diskJson, err := jsonArray[idx].GetString() // data.GetString(fmt.Sprintf("disk.%d", idx))
if err != nil {
return nil, httperrors.NewInputParameterError("invalid disk description %s", err)
}
diskConfig, err := parseDiskInfo(ctx, userCred, diskJson)
dataDiskDefs = append(dataDiskDefs, diskJson)
}
for i := 0; i < len(dataDiskDefs); i += 1 {
diskConfig, err := parseDiskInfo(ctx, userCred, jsonutils.NewString(dataDiskDefs[i]))
if err != nil {
return nil, httperrors.NewInputParameterError("parse disk description error %s", err)
}
@@ -698,22 +783,43 @@ func (manager *SGuestManager) ValidateCreateData(ctx context.Context, userCred m
if len(diskConfig.Driver) == 0 {
diskConfig.Driver = osProf.DiskDriver
}
data.Add(jsonutils.Marshal(diskConfig), fmt.Sprintf("disk.%d", idx))
data.Add(jsonutils.Marshal(diskConfig), fmt.Sprintf("disk.%d", i+1))
}
resourceTypeStr := jsonutils.GetAnyString(data, []string{"resource_type"})
durationStr := jsonutils.GetAnyString(data, []string{"duration"})
if len(durationStr) > 0 {
if !userCred.IsAdminAllow(consts.GetServiceType(), manager.KeywordPlural(), "renew") {
return nil, httperrors.NewForbiddenError("only admin can create prepaid resource")
}
if resourceTypeStr == HostResourceTypePrepaidRecycle {
return nil, httperrors.NewConflictError("cannot create prepaid server on prepaid resource type")
}
billingCycle, err := billing.ParseBillingCycle(durationStr)
if err != nil {
return nil, httperrors.NewInputParameterError("invalid duration %s", durationStr)
}
if !GetDriver(hypervisor).IsSupportedBillingCycle(billingCycle) {
return nil, httperrors.NewInputParameterError("unsupported duration %s", durationStr)
}
data.Add(jsonutils.NewString(BILLING_TYPE_PREPAID), "billing_type")
data.Add(jsonutils.NewString(billingCycle.String()), "billing_cycle")
// expired_at will be set later by callback
// data.Add(jsonutils.NewTimeString(billingCycle.EndAt(time.Time{})), "expired_at")
data.Set("duration", jsonutils.NewString(billingCycle.String()))
}
}
data, err = ValidateScheduleCreateData(ctx, userCred, data, hypervisor)
if err != nil {
return nil, err
}
hypervisor, _ = data.GetString("hypervisor")
for idx := 0; data.Contains(fmt.Sprintf("net.%d", idx)); idx += 1 {
netJson, err := data.Get(fmt.Sprintf("net.%d", idx))
if err != nil {
return nil, httperrors.NewInputParameterError("invalid network description %s", err)
}
netConfig, err := parseNetworkInfo(userCred, netJson)
netJsonArray := jsonutils.GetArrayOfPrefix(data, "net")
for idx := 0; idx < len(netJsonArray); idx += 1 { // .Contains(fmt.Sprintf("net.%d", idx)); idx += 1 {
netConfig, err := parseNetworkInfo(userCred, netJsonArray[idx])
if err != nil {
return nil, httperrors.NewInputParameterError("parse network description error %s", err)
}
@@ -724,18 +830,15 @@ func (manager *SGuestManager) ValidateCreateData(ctx context.Context, userCred m
if len(netConfig.Driver) == 0 {
netConfig.Driver = osProf.NetDriver
}
data.Add(jsonutils.Marshal(netConfig), fmt.Sprintf("net.%d", idx))
data.Set(fmt.Sprintf("net.%d", idx), jsonutils.Marshal(netConfig))
}
for idx := 0; data.Contains(fmt.Sprintf("isolated_device.%d", idx)); idx += 1 {
isoDevArray := jsonutils.GetArrayOfPrefix(data, "isolated_device")
for idx := 0; idx < len(isoDevArray); idx += 1 { // .Contains(fmt.Sprintf("isolated_device.%d", idx)); idx += 1 {
if jsonutils.QueryBoolean(data, "backup", false) {
return nil, httperrors.NewBadRequestError("Cannot create backup with isolated device")
}
devJson, err := data.Get(fmt.Sprintf("isolated_device.%d", idx))
if err != nil {
return nil, httperrors.NewInputParameterError("invalid isolated device description %s", err)
}
devConfig, err := IsolatedDeviceManager.parseDeviceInfo(userCred, devJson)
devConfig, err := IsolatedDeviceManager.parseDeviceInfo(userCred, isoDevArray[idx])
if err != nil {
return nil, httperrors.NewInputParameterError("parse isolated device description error %s", err)
}
@@ -743,7 +846,7 @@ func (manager *SGuestManager) ValidateCreateData(ctx context.Context, userCred m
if err != nil {
return nil, err
}
data.Add(jsonutils.Marshal(devConfig), fmt.Sprintf("isolated_device.%d", idx))
data.Set(fmt.Sprintf("isolated_device.%d", idx), jsonutils.Marshal(devConfig))
}
if data.Contains("cdrom") {
@@ -800,35 +903,6 @@ func (manager *SGuestManager) ValidateCreateData(ctx context.Context, userCred m
return nil, err
}
// support sku here
sku_id, _ := data.GetString("sku_id")
if len(sku_id) > 0 {
sku_id, vcpuCount, vmemSize, err := validateSkuData(sku_id)
if err == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError2(ServerSkuManager.Keyword(), sku_id)
} else if err != nil {
return nil, err
}
data.Add(jsonutils.NewString(sku_id), "sku_id")
data.Add(jsonutils.NewInt(int64(vmemSize)), "vmem_size")
data.Add(jsonutils.NewInt(int64(vcpuCount)), "vcpu_count")
} else {
vmemSize, vcpuCount, err := validateMemCpuData(data)
if err != nil {
return nil, err
}
if vmemSize == 0 {
return nil, httperrors.NewInputParameterError("Missing memory size")
}
if vcpuCount == 0 {
vcpuCount = 1
}
data.Add(jsonutils.NewInt(int64(vmemSize)), "vmem_size")
data.Add(jsonutils.NewInt(int64(vcpuCount)), "vcpu_count")
}
if !jsonutils.QueryBoolean(data, "is_system", false) {
err = manager.checkCreateQuota(ctx, userCred, ownerProjId, data,
jsonutils.QueryBoolean(data, "backup", false))
@@ -877,24 +951,25 @@ func getGuestResourceRequirements(ctx context.Context, userCred mcclient.TokenCr
diskSize := 0
for idx := 0; data.Contains(fmt.Sprintf("disk.%d", idx)); idx += 1 {
dataJson, _ := data.Get(fmt.Sprintf("disk.%d", idx))
diskConfig, _ := parseDiskInfo(ctx, userCred, dataJson)
diskJsonArray := jsonutils.GetArrayOfPrefix(data, "disk")
for idx := 0; idx < len(diskJsonArray); idx += 1 { // data.Contains(fmt.Sprintf("disk.%d", idx)); idx += 1 {
diskConfig, _ := parseDiskInfo(ctx, userCred, diskJsonArray[idx])
diskSize += diskConfig.SizeMb
}
devCount := 0
for idx := 0; data.Contains(fmt.Sprintf("isolated_device.%d", idx)); idx += 1 {
devCount += 1
}
isoDevArray := jsonutils.GetArrayOfPrefix(data, "isolated_device")
devCount := len(isoDevArray)
// for idx := 0; data.Contains(fmt.Sprintf("isolated_device.%d", idx)); idx += 1 {
// devCount += 1
//}
eNicCnt := 0
iNicCnt := 0
eBw := 0
iBw := 0
for idx := 0; data.Contains(fmt.Sprintf("net.%d", idx)); idx += 1 {
netJson, _ := data.Get(fmt.Sprintf("net.%d", idx))
netConfig, _ := parseNetworkInfo(userCred, netJson)
netJsonArray := jsonutils.GetArrayOfPrefix(data, "net")
for idx := 0; idx < len(netJsonArray); idx += 1 { // .Contains(fmt.Sprintf("net.%d", idx)); idx += 1 {
netConfig, _ := parseNetworkInfo(userCred, netJsonArray[idx])
if isExitNetworkInfo(netConfig) {
eNicCnt += 1
eBw += netConfig.BwLimit
@@ -1065,6 +1140,14 @@ func (self *SGuest) moreExtraInfo(extra *jsonutils.JSONDict) *jsonutils.JSONDict
}
}
}
err := self.CanPerformPrepaidRecycle()
if err != nil {
extra.Add(jsonutils.JSONFalse, "can_recycle")
} else {
extra.Add(jsonutils.JSONTrue, "can_recycle")
}
return extra
}
@@ -1115,6 +1198,12 @@ func (self *SGuest) GetExtraDetails(ctx context.Context, userCred mcclient.Token
}
extra.Add(isGpu, "is_gpu")
if self.IsPrepaidRecycle() {
extra.Add(jsonutils.JSONTrue, "is_prepaid_recycle")
} else {
extra.Add(jsonutils.JSONFalse, "is_prepaid_recycle")
}
return self.moreExtraInfo(extra)
}
@@ -1499,10 +1588,16 @@ func (self *SGuest) GetIsolatedDevices() []SIsolatedDevice {
}
func (self *SGuest) syncWithCloudVM(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, extVM cloudprovider.ICloudVM, projectId string, projectSync bool) error {
recycle := false
if self.IsPrepaidRecycle() {
recycle = true
}
metaData := extVM.GetMetadata()
diff, err := GuestManager.TableSpec().Update(self, func() error {
extVM.Refresh()
self.Name = extVM.GetName()
// self.Name = extVM.GetName()
self.Status = extVM.GetStatus()
self.VcpuCount = extVM.GetVcpuCount()
self.BootOrder = extVM.GetBootOrder()
@@ -1511,25 +1606,24 @@ func (self *SGuest) syncWithCloudVM(ctx context.Context, userCred mcclient.Token
self.OsType = extVM.GetOSType()
self.Bios = extVM.GetBios()
self.Machine = extVM.GetMachine()
self.HostId = host.Id
self.ProjectId = userCred.GetProjectId()
if !recycle {
self.HostId = host.Id
}
metaData := extVM.GetMetadata()
instanceType := extVM.GetInstanceType()
zoneExtId, err := metaData.GetString("zone_ext_id")
if err != nil {
log.Errorf("get zone external id fail %s", err)
if len(instanceType) > 0 {
self.InstanceType = instanceType
}
isku, err := ServerSkuManager.FetchByZoneExtId(zoneExtId, instanceType)
if err != nil {
log.Errorf("get sku fail %s", err)
} else {
self.SkuId = isku.GetId()
}
if extVM.GetHypervisor() == HYPERVISOR_AWS && isku != nil {
self.VmemSize = isku.(*SServerSku).MemorySizeMB
if extVM.GetHypervisor() == HYPERVISOR_AWS {
sku, err := ServerSkuManager.FetchSkuByNameAndHypervisor(instanceType, extVM.GetHypervisor(), false)
if err == nil {
self.VmemSize = sku.MemorySizeMB
} else {
self.VmemSize = extVM.GetVmemSizeMB()
}
} else {
self.VmemSize = extVM.GetVmemSizeMB()
}
@@ -1542,8 +1636,10 @@ func (self *SGuest) syncWithCloudVM(ctx context.Context, userCred mcclient.Token
self.IsEmulated = extVM.IsEmulated()
self.BillingType = extVM.GetBillingType()
self.ExpiredAt = extVM.GetExpiredAt()
if !recycle {
self.BillingType = extVM.GetBillingType()
self.ExpiredAt = extVM.GetExpiredAt()
}
if metaData != nil && metaData.Contains("secgroupIds") {
secgroupIds := []string{}
@@ -1589,6 +1685,15 @@ func (self *SGuest) syncWithCloudVM(ctx context.Context, userCred mcclient.Token
}
}
}
if recycle {
vhost := self.GetHost()
err = vhost.syncWithCloudPrepaidVM(extVM, host, projectSync)
if err != nil {
return err
}
}
return nil
}
@@ -1618,7 +1723,8 @@ func (manager *SGuestManager) newCloudVM(ctx context.Context, userCred mcclient.
metaData := extVM.GetMetadata()
instanceType := extVM.GetInstanceType()
zoneExtId, err := metaData.GetString("zone_ext_id")
/*zoneExtId, err := metaData.GetString("zone_ext_id")
if err != nil {
log.Errorf("get zone external id fail %s", err)
}
@@ -1628,10 +1734,19 @@ func (manager *SGuestManager) newCloudVM(ctx context.Context, userCred mcclient.
log.Errorf("get sku zone %s instance type %s fail %s", zoneExtId, instanceType, err)
} else {
guest.SkuId = isku.GetId()
}*/
if len(instanceType) > 0 {
guest.InstanceType = instanceType
}
if extVM.GetHypervisor() == HYPERVISOR_AWS && isku != nil {
guest.VmemSize = isku.(*SServerSku).MemorySizeMB
if extVM.GetHypervisor() == HYPERVISOR_AWS {
sku, err := ServerSkuManager.FetchSkuByNameAndHypervisor(instanceType, extVM.GetHypervisor(), false)
if err == nil {
guest.VmemSize = sku.MemorySizeMB
} else {
guest.VmemSize = extVM.GetVmemSizeMB()
}
} else {
guest.VmemSize = extVM.GetVmemSizeMB()
}
@@ -1661,9 +1776,10 @@ func (manager *SGuestManager) newCloudVM(ctx context.Context, userCred mcclient.
}
}
err = manager.TableSpec().Insert(&guest)
err := manager.TableSpec().Insert(&guest)
if err != nil {
log.Errorf("Insert fail %s", err)
return nil, err
}
for _, secgroup := range extraSecgroups {
@@ -1692,9 +1808,10 @@ func (manager *SGuestManager) newCloudVM(ctx context.Context, userCred mcclient.
func (manager *SGuestManager) TotalCount(
projectId string, rangeObj db.IStandaloneModel,
status []string, hypervisors []string,
includeSystem bool, pendingDelete bool, hostType string,
includeSystem bool, pendingDelete bool,
hostTypes []string, resourceTypes []string, providers []string,
) SGuestCountStat {
return totalGuestResourceCount(projectId, rangeObj, status, hypervisors, includeSystem, pendingDelete, hostType)
return totalGuestResourceCount(projectId, rangeObj, status, hypervisors, includeSystem, pendingDelete, hostTypes, resourceTypes, providers)
}
func (self *SGuest) detachNetwork(ctx context.Context, userCred mcclient.TokenCredential, network *SNetwork, reserve bool, deploy bool) error {
@@ -2022,30 +2139,27 @@ func (self *SGuest) SyncVMDisks(ctx context.Context, userCred mcclient.TokenCred
return result
}
func filterGuestByRange(q *sqlchemy.SQuery, rangeObj db.IStandaloneModel, hostType string) *sqlchemy.SQuery {
func filterGuestByRange(q *sqlchemy.SQuery, rangeObj db.IStandaloneModel, hostTypes []string, resourceTypes []string, providers []string) *sqlchemy.SQuery {
hosts := HostManager.Query().SubQuery()
q = q.Join(hosts, sqlchemy.AND(
sqlchemy.Equals(hosts.Field("id"), q.Field("host_id")),
sqlchemy.IsFalse(hosts.Field("deleted")),
sqlchemy.IsTrue(hosts.Field("enabled")),
sqlchemy.Equals(hosts.Field("host_status"), HOST_ONLINE)))
hostTypes := []string{}
if len(hostType) != 0 {
hostTypes = append(hostTypes, hostType)
}
q = AttachUsageQuery(q, hosts, hosts.Field("id"), hostTypes, rangeObj)
q = q.Join(hosts, sqlchemy.Equals(hosts.Field("id"), q.Field("host_id")))
q = q.Filter(sqlchemy.IsTrue(hosts.Field("enabled")))
// q = q.Filter(sqlchemy.Equals(hosts.Field("host_status"), HOST_ONLINE))
q = AttachUsageQuery(q, hosts, hostTypes, resourceTypes, providers, rangeObj)
return q
}
type SGuestCountStat struct {
TotalGuestCount int
TotalCpuCount int
TotalMemSize int
TotalDiskSize int
TotalIsolatedCount int
TotalBackupCpuCount int
TotalBackupMemSize int
TotalBackupDiskSize int
TotalGuestCount int
TotalCpuCount int
TotalMemSize int
TotalDiskSize int
TotalIsolatedCount int
TotalBackupGuestCount int
TotalBackupCpuCount int
TotalBackupMemSize int
TotalBackupDiskSize int
}
func totalGuestResourceCount(
@@ -2055,19 +2169,26 @@ func totalGuestResourceCount(
hypervisors []string,
includeSystem bool,
pendingDelete bool,
hostType string,
hostTypes []string,
resourceTypes []string,
providers []string,
) SGuestCountStat {
guestdisks := GuestdiskManager.Query().SubQuery()
disks := DiskManager.Query().SubQuery()
diskQuery := guestdisks.Query(guestdisks.Field("guest_id"), sqlchemy.SUM("guest_disk_size", disks.Field("disk_size")))
diskQuery = diskQuery.Join(disks, sqlchemy.AND(sqlchemy.Equals(guestdisks.Field("disk_id"), disks.Field("id")),
sqlchemy.IsFalse(disks.Field("deleted"))))
diskQuery = diskQuery.Join(disks, sqlchemy.Equals(guestdisks.Field("disk_id"), disks.Field("id")))
diskQuery = diskQuery.GroupBy(guestdisks.Field("guest_id"))
diskSubQuery := diskQuery.SubQuery()
diskBackupSubQuery := diskQuery.IsNotEmpty("backup_storage_id").SubQuery()
backupDiskQuery := guestdisks.Query(guestdisks.Field("guest_id"), sqlchemy.SUM("guest_disk_size", disks.Field("disk_size")))
backupDiskQuery = backupDiskQuery.LeftJoin(disks, sqlchemy.Equals(guestdisks.Field("disk_id"), disks.Field("id")))
backupDiskQuery = backupDiskQuery.Filter(sqlchemy.IsNotEmpty(disks.Field("backup_storage_id")))
backupDiskQuery = backupDiskQuery.GroupBy(guestdisks.Field("guest_id"))
diskBackupSubQuery := backupDiskQuery.SubQuery()
// diskBackupSubQuery := diskQuery.IsNotEmpty("backup_storage_id").SubQuery()
isolated := IsolatedDeviceManager.Query().SubQuery()
@@ -2078,7 +2199,11 @@ func totalGuestResourceCount(
isoDevSubQuery := isoDevQuery.SubQuery()
guests := GuestManager.Query().SubQuery()
guestBackupSubQuery := GuestManager.Query("id", "vcpu_count", "vmem_size").IsNotEmpty("backup_host_id").SubQuery()
guestBackupSubQuery := GuestManager.Query(
"id",
"vcpu_count",
"vmem_size",
).IsNotEmpty("backup_host_id").SubQuery()
q := guests.Query(sqlchemy.COUNT("total_guest_count"),
sqlchemy.SUM("total_cpu_count", guests.Field("vcpu_count")),
@@ -2087,15 +2212,18 @@ func totalGuestResourceCount(
sqlchemy.SUM("total_isolated_count", isoDevSubQuery.Field("device_sum")),
sqlchemy.SUM("total_backup_disk_size", diskBackupSubQuery.Field("guest_disk_size")),
sqlchemy.SUM("total_backup_cpu_count", guestBackupSubQuery.Field("vcpu_count")),
sqlchemy.SUM("total_backup_mem_size", guestBackupSubQuery.Field("vmem_size")))
sqlchemy.SUM("total_backup_mem_size", guestBackupSubQuery.Field("vmem_size")),
sqlchemy.COUNT("total_backup_guest_count", guestBackupSubQuery.Field("id")),
)
q = q.LeftJoin(guestBackupSubQuery, sqlchemy.Equals(guestBackupSubQuery.Field("id"), guests.Field("id")))
q = q.LeftJoin(diskSubQuery, sqlchemy.Equals(diskSubQuery.Field("guest_id"), guests.Field("id")))
q = q.LeftJoin(guestBackupSubQuery, sqlchemy.Equals(guestBackupSubQuery.Field("id"), q.Field("id")))
q = q.LeftJoin(diskBackupSubQuery, sqlchemy.Equals(diskBackupSubQuery.Field("guest_id"), guests.Field("id")))
q = q.LeftJoin(isoDevSubQuery, sqlchemy.Equals(isoDevSubQuery.Field("guest_id"), guests.Field("id")))
q = filterGuestByRange(q, rangeObj, hostType)
q = filterGuestByRange(q, rangeObj, hostTypes, resourceTypes, providers)
if len(projectId) > 0 {
q = q.Filter(sqlchemy.Equals(guests.Field("tenant_id"), projectId))
@@ -2135,13 +2263,24 @@ func (self *SGuest) getDefaultNetworkConfig() *SNetworkConfig {
}
func (self *SGuest) CreateNetworksOnHost(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, data *jsonutils.JSONDict, pendingUsage quotas.IQuota) error {
idx := 0
netJsonArray := jsonutils.GetArrayOfPrefix(data, "net")
/* idx := 0
for idx = 0; data.Contains(fmt.Sprintf("net.%d", idx)); idx += 1 {
netJson, err := data.Get(fmt.Sprintf("net.%d", idx))
if err != nil {
return err
}
netConfig, err := parseNetworkInfo(userCred, netJson)
if netJson == jsonutils.JSONNull {
break
}
}*/
if len(netJsonArray) == 0 {
netConfig := self.getDefaultNetworkConfig()
return self.attach2RandomNetwork(ctx, userCred, host, netConfig, pendingUsage)
}
for idx := 0; idx < len(netJsonArray); idx += 1 {
netConfig, err := parseNetworkInfo(userCred, netJsonArray[idx])
if err != nil {
return err
}
@@ -2150,10 +2289,6 @@ func (self *SGuest) CreateNetworksOnHost(ctx context.Context, userCred mcclient.
return err
}
}
if idx == 0 {
netConfig := self.getDefaultNetworkConfig()
return self.attach2RandomNetwork(ctx, userCred, host, netConfig, pendingUsage)
}
return nil
}
@@ -2196,17 +2331,15 @@ func (self *SGuest) attach2RandomNetwork(ctx context.Context, userCred mcclient.
return driver.Attach2RandomNetwork(self, ctx, userCred, host, netConfig, pendingUsage)
}
func (self *SGuest) CreateDisksOnHost(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, data *jsonutils.JSONDict, pendingUsage quotas.IQuota) error {
for idx := 0; data.Contains(fmt.Sprintf("disk.%d", idx)); idx += 1 {
diskJson, err := data.Get(fmt.Sprintf("disk.%d", idx))
func (self *SGuest) CreateDisksOnHost(ctx context.Context, userCred mcclient.TokenCredential, host *SHost,
data *jsonutils.JSONDict, pendingUsage quotas.IQuota, inheritBilling bool) error {
diskJsonArray := jsonutils.GetArrayOfPrefix(data, "disk")
for idx := 0; idx < len(diskJsonArray); idx += 1 { // .Contains(fmt.Sprintf("disk.%d", idx)); idx += 1 {
diskConfig, err := parseDiskInfo(ctx, userCred, diskJsonArray[idx])
if err != nil {
return err
}
diskConfig, err := parseDiskInfo(ctx, userCred, diskJson)
if err != nil {
return err
}
disk, err := self.createDiskOnHost(ctx, userCred, host, diskConfig, pendingUsage)
disk, err := self.createDiskOnHost(ctx, userCred, host, diskConfig, pendingUsage, inheritBilling)
if err != nil {
return err
}
@@ -2215,7 +2348,8 @@ func (self *SGuest) CreateDisksOnHost(ctx context.Context, userCred mcclient.Tok
return nil
}
func (self *SGuest) createDiskOnStorage(ctx context.Context, userCred mcclient.TokenCredential, storage *SStorage, diskConfig *SDiskConfig, pendingUsage quotas.IQuota) (*SDisk, error) {
func (self *SGuest) createDiskOnStorage(ctx context.Context, userCred mcclient.TokenCredential, storage *SStorage,
diskConfig *SDiskConfig, pendingUsage quotas.IQuota, inheritBilling bool) (*SDisk, error) {
lockman.LockObject(ctx, storage)
defer lockman.ReleaseObject(ctx, storage)
@@ -2223,7 +2357,20 @@ func (self *SGuest) createDiskOnStorage(ctx context.Context, userCred mcclient.T
defer lockman.ReleaseClass(ctx, QuotaManager, self.ProjectId)
diskName := fmt.Sprintf("vdisk_%s_%d", self.Name, time.Now().UnixNano())
disk, err := storage.createDisk(diskName, diskConfig, userCred, self.ProjectId, true, self.IsSystem)
billingType := BILLING_TYPE_POSTPAID
billingCycle := ""
if inheritBilling {
billingType = self.BillingType
billingCycle = self.BillingCycle
}
autoDelete := false
if storage.IsLocal() || billingType == BILLING_TYPE_PREPAID {
autoDelete = true
}
disk, err := storage.createDisk(diskName, diskConfig, userCred, self.ProjectId, autoDelete, self.IsSystem,
billingType, billingCycle)
if err != nil {
return nil, err
@@ -2236,12 +2383,13 @@ func (self *SGuest) createDiskOnStorage(ctx context.Context, userCred mcclient.T
return disk, nil
}
func (self *SGuest) createDiskOnHost(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, diskConfig *SDiskConfig, pendingUsage quotas.IQuota) (*SDisk, error) {
func (self *SGuest) createDiskOnHost(ctx context.Context, userCred mcclient.TokenCredential, host *SHost,
diskConfig *SDiskConfig, pendingUsage quotas.IQuota, inheritBilling bool) (*SDisk, error) {
storage := self.GetDriver().ChooseHostStorage(host, diskConfig.Backend)
if storage == nil {
return nil, fmt.Errorf("No storage to create disk")
}
disk, err := self.createDiskOnStorage(ctx, userCred, storage, diskConfig, pendingUsage)
disk, err := self.createDiskOnStorage(ctx, userCred, storage, diskConfig, pendingUsage, inheritBilling)
if err != nil {
return nil, err
}
@@ -2262,12 +2410,9 @@ func (self *SGuest) createDiskOnHost(ctx context.Context, userCred mcclient.Toke
}
func (self *SGuest) CreateIsolatedDeviceOnHost(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, data *jsonutils.JSONDict, pendingUsage quotas.IQuota) error {
for idx := 0; data.Contains(fmt.Sprintf("isolated_device.%d", idx)); idx += 1 {
devJson, err := data.Get(fmt.Sprintf("isolated_device.%d", idx))
if err != nil {
return err
}
devConfig, err := IsolatedDeviceManager.parseDeviceInfo(userCred, devJson)
devJsonArray := jsonutils.GetArrayOfPrefix(data, "isolated_device")
for idx := 0; idx < len(devJsonArray); idx += 1 { // .Contains(fmt.Sprintf("isolated_device.%d", idx)); idx += 1 {
devConfig, err := IsolatedDeviceManager.parseDeviceInfo(userCred, devJsonArray[idx])
if err != nil {
return err
}
@@ -3033,7 +3178,7 @@ func (self *SGuest) GetShortDesc() *jsonutils.JSONDict {
billingInfo.PriceKey = priceKey
}
billingInfo.ChargeType = self.GetChargeType()
self.FetchCloudBillingInfo(&billingInfo)
desc.Update(jsonutils.Marshal(billingInfo))
@@ -3119,10 +3264,8 @@ func (manager *SGuestManager) GetIpInProjectWithName(projectId, name string, isE
sqlchemy.AND(
sqlchemy.Equals(guests.Field("id"), guestnics.Field("guest_id")),
sqlchemy.OR(sqlchemy.IsNull(guests.Field("pending_deleted")),
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(guests.Field("pending_deleted"))))).
Join(networks, sqlchemy.Equals(networks.Field("id"), guestnics.Field("network_id"))).
Filter(sqlchemy.Equals(guests.Field("name"), name)).
Filter(sqlchemy.NotEquals(guestnics.Field("ip_addr"), "")).
Filter(sqlchemy.IsNotNull(guestnics.Field("ip_addr"))).
@@ -3168,7 +3311,7 @@ func (manager *SGuestManager) getExpiredPendingDeleteGuests() []SGuest {
deadline := time.Now().Add(time.Duration(options.Options.PendingDeleteExpireSeconds*-1) * time.Second)
q := manager.Query()
q = q.IsTrue("pending_deleted").LT("pending_deleted_at", deadline).In("hypervisor", []string{"aliyun"}).Limit(options.Options.PendingDeleteMaxCleanBatchSize)
q = q.IsTrue("pending_deleted").LT("pending_deleted_at", deadline).Limit(options.Options.PendingDeleteMaxCleanBatchSize)
guests := make([]SGuest, 0)
err := db.FetchModelObjects(GuestManager, q, &guests)
@@ -3180,7 +3323,7 @@ func (manager *SGuestManager) getExpiredPendingDeleteGuests() []SGuest {
return guests
}
func (manager *SGuestManager) CleanPendingDeleteServers(ctx context.Context, userCred mcclient.TokenCredential) {
func (manager *SGuestManager) CleanPendingDeleteServers(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
guests := manager.getExpiredPendingDeleteGuests()
if guests == nil {
return
@@ -3190,6 +3333,32 @@ func (manager *SGuestManager) CleanPendingDeleteServers(ctx context.Context, use
}
}
func (manager *SGuestManager) getExpiredPrepaidGuests() []SGuest {
deadline := time.Now().Add(time.Duration(options.Options.PrepaidExpireCheckSeconds*-1) * time.Second)
q := manager.Query()
q = q.Equals("billing_type", BILLING_TYPE_PREPAID).LT("expired_at", deadline).Limit(options.Options.ExpiredPrepaidMaxCleanBatchSize)
guests := make([]SGuest, 0)
err := db.FetchModelObjects(GuestManager, q, &guests)
if err != nil {
log.Errorf("fetch guests error %s", err)
return nil
}
return guests
}
func (manager *SGuestManager) DeleteExpiredPrepaidServers(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
guests := manager.getExpiredPrepaidGuests()
if guests == nil {
return
}
for i := 0; i < len(guests); i += 1 {
guests[i].StartDeleteGuestTask(ctx, userCred, "", false, true)
}
}
func (self *SGuest) GetEip() (*SElasticip, error) {
return ElasticipManager.getEipForInstance("server", self.Id)
}
@@ -3446,3 +3615,16 @@ func (self *SGuest) GuestDisksHasSnapshot() bool {
}
return false
}
func (self *SGuest) OnScheduleToHost(ctx context.Context, userCred mcclient.TokenCredential, hostId string) error {
err := self.SetHostId(hostId)
if err != nil {
return err
}
notes := jsonutils.NewDict()
notes.Add(jsonutils.NewString(hostId), "host_id")
db.OpsLog.LogEvent(self, db.ACT_SCHEDULE, notes, userCred)
return nil
}
+6 -1
View File
@@ -67,7 +67,12 @@ func (manager *SGuestsecgroupManager) newGuestSecgroup(ctx context.Context, user
func (manager *SGuestsecgroupManager) DeleteGuestSecgroup(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, secgroup *SSecurityGroup) error {
gss := []SGuestsecgroup{}
q := manager.Query()
q = q.Equals("guest_id", guest.Id).Equals("secgroup_id", secgroup.Id)
if guest != nil {
q = q.Equals("guest_id", guest.Id)
}
if secgroup != nil {
q = q.Equals("secgroup_id", secgroup.Id)
}
if err := db.FetchModelObjects(manager, q, &gss); err != nil {
return err
}
+3 -3
View File
@@ -3,7 +3,6 @@ package models
import (
"context"
"database/sql"
"fmt"
"strings"
"yunion.io/x/jsonutils"
@@ -93,8 +92,9 @@ func ValidateScheduleCreateData(ctx context.Context, userCred mcclient.TokenCred
return nil, httperrors.NewInputParameterError("invalid aggregate_strategy")
}
}
for idx := 0; data.Contains(fmt.Sprintf("schedtag.%d", idx)); idx += 1 {
aggStr, _ := data.GetString(fmt.Sprintf("schedtag.%d", idx))
aggArray := jsonutils.GetArrayOfPrefix(data, "schedtag")
for idx := 0; idx < len(aggArray); idx += 1 { // data.Contains(fmt.Sprintf("schedtag.%d", idx)); idx += 1 {
aggStr, _ := aggArray[idx].GetString() // .GetString(fmt.Sprintf("schedtag.%d", idx))
if len(aggStr) > 0 {
parts := strings.Split(aggStr, ":")
if len(parts) >= 2 && len(parts[0]) > 0 && len(parts[1]) > 0 {
+645
View File
@@ -0,0 +1,645 @@
package models
import (
"context"
"fmt"
"strings"
"time"
"github.com/golang-plus/errors"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/tristate"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/baremetal"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/logclient"
)
func (self *SHost) GetResourceType() string {
if len(self.ResourceType) > 0 {
return self.ResourceType
}
return HostResourceTypeDefault
}
func (self *SGuest) AllowPerformPrepaidRecycle(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return db.IsAdminAllowPerform(userCred, self, "prepaid-recycle")
}
func (self *SGuest) CanPerformPrepaidRecycle() error {
if self.BillingType != BILLING_TYPE_PREPAID {
return fmt.Errorf("recycle prepaid server only")
}
if self.ExpiredAt.Before(time.Now()) {
return fmt.Errorf("prepaid expired")
}
host := self.GetHost()
if host == nil {
return fmt.Errorf("no host")
}
if !host.IsManaged() {
return fmt.Errorf("only managed prepaid server can be pooled")
}
return nil
}
func (self *SGuest) PerformPrepaidRecycle(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
err := self.CanPerformPrepaidRecycle()
if err != nil {
return nil, httperrors.NewInvalidStatusError(err.Error())
}
err = self.doPrepaidRecycle(ctx, userCred)
if err != nil {
logclient.AddActionLog(self, logclient.ACT_RECYCLE_PREPAID, self.GetShortDesc(), userCred, false)
return nil, httperrors.NewGeneralError(err)
}
db.OpsLog.LogEvent(self, db.ACT_RECYCLE_PREPAID, self.GetShortDesc(), userCred)
logclient.AddActionLog(self, logclient.ACT_RECYCLE_PREPAID, self.GetShortDesc(), userCred, true)
return nil, nil
}
func (self *SGuest) doPrepaidRecycle(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockClass(ctx, HostManager, userCred.GetProjectId())
defer lockman.ReleaseClass(ctx, HostManager, userCred.GetProjectId())
return self.doPrepaidRecycleNoLock(ctx, userCred)
}
func (self *SGuest) doPrepaidRecycleNoLock(ctx context.Context, userCred mcclient.TokenCredential) error {
oHost := self.GetHost()
fakeHost := SHost{}
fakeHost.SetModelManager(HostManager)
fakeHost.Name = fmt.Sprintf("%s-host", self.Name)
fakeHost.CpuCount = self.VcpuCount
fakeHost.NodeCount = 1
fakeHost.CpuCmtbound = 1.0
fakeHost.MemCmtbound = 1.0
fakeHost.MemReserved = 0
fakeHost.MemSize = self.VmemSize
guestdisks := self.GetDisks()
storageInfo := make([]baremetal.BaremetalStorage, 0)
totalSize := 0
for i := 0; i < len(guestdisks); i += 1 {
disk := guestdisks[i].GetDisk()
storage := disk.GetStorage()
totalSize += disk.DiskSize
if len(fakeHost.StorageType) == 0 {
fakeHost.StorageType = storage.StorageType
}
info := baremetal.BaremetalStorage{}
info.Size = int64(disk.DiskSize)
info.Index = int64(i)
info.Slot = i
info.Driver = storage.StorageType
info.Rotate = (storage.MediumType != DISK_TYPE_SSD)
storageInfo = append(storageInfo, info)
}
fakeHost.StorageDriver = baremetal.DISK_DRIVER_LINUX
fakeHost.StorageSize = totalSize
fakeHost.StorageInfo = jsonutils.Marshal(&storageInfo)
fakeHost.ZoneId = self.getZone().GetId()
fakeHost.IsBaremetal = false
fakeHost.IsMaintenance = false
fakeHost.ResourceType = HostResourceTypePrepaidRecycle
guestnics := self.GetNetworks()
if len(guestnics) == 0 {
msg := "no network info on guest????"
log.Errorf(msg)
return fmt.Errorf(msg)
}
fakeHost.AccessIp = guestnics[0].IpAddr
fakeHost.AccessMac = guestnics[0].MacAddr
fakeHost.BillingType = BILLING_TYPE_PREPAID
fakeHost.BillingCycle = self.BillingCycle
fakeHost.ExpiredAt = self.ExpiredAt
fakeHost.Status = HOST_STATUS_RUNNING
fakeHost.HostStatus = HOST_ONLINE
fakeHost.Enabled = true
fakeHost.HostType = oHost.HostType
fakeHost.ExternalId = oHost.ExternalId
fakeHost.RealExternalId = self.ExternalId
fakeHost.ManagerId = oHost.ManagerId
fakeHost.IsEmulated = true
fakeHost.Description = "fake host for prepaid vm recycling"
err := HostManager.TableSpec().Insert(&fakeHost)
if err != nil {
log.Errorf("fail to insert fake host %s", err)
return err
}
for i := 0; i < len(guestnics); i += 1 {
var nicType string
if i == 0 {
nicType = NIC_TYPE_ADMIN
}
err = fakeHost.addNetif(ctx, userCred,
guestnics[i].MacAddr,
guestnics[i].GetNetwork().WireId,
"",
1000,
nicType,
int8(i),
tristate.True,
1500,
false,
fmt.Sprintf("eth%d", i),
fmt.Sprintf("br%d", i),
false,
false)
if err != nil {
log.Errorf("fail to addNetInterface %d: %s", i, err)
fakeHost.RealDelete(ctx, userCred)
return err
}
}
storageSize := 0
var externalId string
for i := 0; i < len(guestdisks); i += 1 {
disk := guestdisks[i].GetDisk()
storage := disk.GetStorage()
if disk.BillingType == BILLING_TYPE_PREPAID {
storageSize += disk.DiskSize
if len(externalId) == 0 {
externalId = storage.ExternalId
} else {
if externalId != storage.ExternalId {
msg := "inconsistent storage !!!!"
log.Errorf(msg)
return errors.New(msg)
}
}
}
}
sysStorage := guestdisks[0].GetDisk().GetStorage()
fakeStorage := SStorage{}
fakeStorage.SetModelManager(StorageManager)
fakeStorage.Name = fmt.Sprintf("%s-storage", self.Name)
fakeStorage.Capacity = storageSize
fakeStorage.StorageType = STORAGE_LOCAL
fakeStorage.MediumType = sysStorage.MediumType
fakeStorage.Cmtbound = 1.0
fakeStorage.ZoneId = fakeHost.ZoneId
fakeStorage.StoragecacheId = sysStorage.StoragecacheId
fakeStorage.Enabled = true
fakeStorage.Status = STORAGE_ONLINE
fakeStorage.Description = "fake storage for prepaid vm recycling"
fakeStorage.IsEmulated = true
fakeStorage.ManagerId = sysStorage.ManagerId
fakeStorage.ExternalId = externalId
err = StorageManager.TableSpec().Insert(&fakeStorage)
if err != nil {
log.Errorf("fail to insert fake storage %s", err)
return err
}
err = fakeHost.Attach2Storage(ctx, userCred, &fakeStorage, "")
if err != nil {
log.Errorf("fail to add fake storage: %s", err)
fakeHost.RealDelete(ctx, userCred)
return err
}
_, err = self.GetModelManager().TableSpec().Update(self, func() error {
// clear billing information
self.BillingType = BILLING_TYPE_POSTPAID
self.BillingCycle = ""
self.ExpiredAt = time.Time{}
// switch to fakeHost
self.HostId = fakeHost.Id
return nil
})
if err != nil {
log.Errorf("clear billing information fail: %s", err)
fakeHost.RealDelete(ctx, userCred)
return err
}
for i := 0; i < len(guestdisks); i += 1 {
disk := guestdisks[i].GetDisk()
if disk.BillingType == BILLING_TYPE_PREPAID {
_, err = disk.GetModelManager().TableSpec().Update(disk, func() error {
disk.BillingType = BILLING_TYPE_POSTPAID
disk.BillingCycle = ""
disk.ExpiredAt = time.Time{}
disk.StorageId = fakeStorage.Id
return nil
})
if err != nil {
log.Errorf("clear billing information for %d %s disk fail: %s", i, disk.DiskType, err)
fakeHost.RealDelete(ctx, userCred)
return err
}
}
}
return nil
}
func (self *SGuest) AllowPerformUndoPrepaidRecycle(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return db.IsAdminAllowPerform(userCred, self, "undo-prepaid-recycle")
}
func (self *SGuest) PerformUndoPrepaidRecycle(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
host := self.GetHost()
if host == nil {
return nil, httperrors.NewInvalidStatusError("no valid host")
}
if host.Enabled {
return nil, httperrors.NewInvalidStatusError("host should be disabled")
}
if host.ResourceType != HostResourceTypePrepaidRecycle || host.BillingType != BILLING_TYPE_PREPAID {
return nil, httperrors.NewInvalidStatusError("host is not a prepaid recycle host")
}
err := doUndoPrepaidRecycle(ctx, userCred, host, self)
if err != nil {
logclient.AddActionLog(self, logclient.ACT_UNDO_RECYCLE_PREPAID, self.GetShortDesc(), userCred, false)
return nil, httperrors.NewGeneralError(err)
}
db.OpsLog.LogEvent(self, db.ACT_UNDO_RECYCLE_PREPAID, self.GetShortDesc(), userCred)
logclient.AddActionLog(self, logclient.ACT_UNDO_RECYCLE_PREPAID, self.GetShortDesc(), userCred, true)
return nil, nil
}
func (self *SHost) AllowPerformUndoPrepaidRecycle(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return db.IsAdminAllowPerform(userCred, self, "undo-prepaid-recycle")
}
func (self *SHost) PerformUndoPrepaidRecycle(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
if self.Enabled {
return nil, httperrors.NewInvalidStatusError("host should be disabled")
}
if self.ResourceType != HostResourceTypePrepaidRecycle || self.BillingType != BILLING_TYPE_PREPAID {
return nil, httperrors.NewInvalidStatusError("host is not a prepaid recycle host")
}
guests := self.GetGuests()
if len(guests) == 0 {
return nil, httperrors.NewInvalidStatusError("cannot delete a recycle host without active instance")
}
if len(guests) > 1 {
return nil, httperrors.NewInvalidStatusError("a recycle host shoud not allocate more than 1 guest")
}
err := doUndoPrepaidRecycle(ctx, userCred, self, &guests[0])
if err != nil {
logclient.AddActionLog(self, logclient.ACT_UNDO_RECYCLE_PREPAID, self.GetShortDesc(), userCred, false)
return nil, httperrors.NewGeneralError(err)
}
db.OpsLog.LogEvent(self, db.ACT_UNDO_RECYCLE_PREPAID, self.GetShortDesc(), userCred)
logclient.AddActionLog(self, logclient.ACT_UNDO_RECYCLE_PREPAID, self.GetShortDesc(), userCred, true)
return nil, nil
}
func findIdiskById(idisks []cloudprovider.ICloudDisk, uuid string) cloudprovider.ICloudDisk {
for i := 0; i < len(idisks); i += 1 {
if idisks[i].GetGlobalId() == uuid {
return idisks[i]
}
}
return nil
}
func doUndoPrepaidRecycle(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, server *SGuest) error {
if host.RealExternalId != server.ExternalId {
msg := "host and server external id not match!!!!"
log.Errorf(msg)
return errors.New(msg)
}
q := HostManager.Query()
q = q.Equals("external_id", host.ExternalId)
q = q.Equals("host_type", host.HostType)
q = q.IsNullOrEmpty("resource_type")
oHostCnt := q.Count()
if oHostCnt == 0 {
msg := "orthordox host not found???"
log.Errorf(msg)
return errors.New(msg)
}
if oHostCnt > 1 {
msg := fmt.Sprintf("more than 1 (%d) orthordox host found???", oHostCnt)
log.Errorf(msg)
return errors.New(msg)
}
oHost := SHost{}
oHost.SetModelManager(HostManager)
err := q.First(&oHost)
if err != nil {
msg := fmt.Sprintf("fail to query orthordox host %s", err)
log.Errorf(msg)
return errors.New(msg)
}
iHost, err := oHost.GetIHost()
if err != nil {
msg := fmt.Sprint("fail to find ihost %s", err)
log.Errorf(msg)
return errors.New(msg)
}
iVM, err := iHost.GetIVMById(server.ExternalId)
if err != nil {
msg := fmt.Sprintf("fail to GetIVMById %s", err)
log.Errorf(msg)
return errors.New(msg)
}
idisks, err := iVM.GetIDisks()
if err != nil {
msg := fmt.Sprintf("iVM.GetIDisks fail %s", err)
log.Errorf(msg)
return errors.New(msg)
}
_, err = server.GetModelManager().TableSpec().Update(server, func() error {
// recover billing information
server.BillingType = BILLING_TYPE_PREPAID
server.BillingCycle = host.BillingCycle
server.ExpiredAt = host.ExpiredAt
// switch to original Host
server.HostId = oHost.Id
return nil
})
if err != nil {
log.Errorf("fail to recover vm hostId %s", err)
return err
}
guestdisks := server.GetDisks()
for i := 0; i < len(guestdisks); i += 1 {
disk := guestdisks[i].GetDisk()
storage := disk.GetStorage()
idisk := findIdiskById(idisks, disk.ExternalId)
if idisk == nil {
msg := fmt.Sprintf("fail to find idisk by ID %s: %s", disk.ExternalId, err)
log.Errorf(msg)
return errors.New(msg)
}
istorage, err := idisk.GetIStorage()
if err != nil {
log.Errorf("idisk.GetIStorage fail %s", err)
return err
}
oStorageObj, err := StorageManager.FetchByExternalId(istorage.GetGlobalId())
if err != nil {
log.Errorf("StorageManager.FetchByExternalId fail %s", err)
return err
}
oStorage := oStorageObj.(*SStorage)
if storage.StorageType == STORAGE_LOCAL {
_, err = disk.GetModelManager().TableSpec().Update(disk, func() error {
disk.BillingType = BILLING_TYPE_PREPAID
disk.BillingCycle = host.BillingCycle
disk.ExpiredAt = host.ExpiredAt
disk.StorageId = oStorage.Id
return nil
})
if err != nil {
log.Errorf("fail to recover prepaid disk info %s", err)
return err
}
}
}
err = host.RealDelete(ctx, userCred)
if err != nil {
log.Errorf("fail to delete fake host")
return err
}
return nil
}
func (self *SGuest) IsPrepaidRecycle() bool {
host := self.GetHost()
if host == nil {
return false
}
return host.IsPrepaidRecycle()
}
func (host *SHost) IsPrepaidRecycle() bool {
if host.ResourceType != HostResourceTypePrepaidRecycle {
return false
}
if host.BillingType != BILLING_TYPE_PREPAID {
return false
}
return true
}
func (self *SHost) BorrowIpAddrsFromGuest(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest) error {
guestnics := guest.GetNetworks()
for i := 0; i < len(guestnics); i += 1 {
err := guestnics[i].Detach(ctx, userCred)
if err != nil {
log.Errorf("fail to detach guest network %s", err)
return err
}
netif := self.GetNetInterface(guestnics[i].MacAddr)
if netif == nil {
msg := fmt.Sprintf("fail to find netinterface for mac %s", guestnics[i].MacAddr)
log.Errorf(msg)
return fmt.Errorf(msg)
}
err = self.EnableNetif(ctx, userCred, netif, "", guestnics[i].IpAddr, "", false, false)
if err != nil {
log.Errorf("fail to enable netif %s %s", guestnics[i].IpAddr, err)
return err
}
}
return nil
}
func (host *SHost) SetGuestCreateNetworkAndDiskParams(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
ihost, err := host.GetIHost()
if err != nil {
log.Errorf("host.GetIHost fail %s", err)
return nil, err
}
ivm, err := ihost.GetIVMById(host.RealExternalId)
if err != nil {
log.Errorf("ihost.GetIVMById(host.RealExternalId) fail %s", err)
return nil, err
}
idisks, err := ivm.GetIDisks()
if err != nil {
log.Errorf("ivm.GetIDisks fail %s", err)
return nil, err
}
netifs := host.GetNetInterfaces()
netIdx := 0
for i := 0; i < len(netifs); i += 1 {
hn := netifs[i].GetBaremetalNetwork()
if hn != nil {
err := host.DisableNetif(ctx, userCred, &netifs[i], true)
if err != nil {
return nil, err
}
packedMac := strings.Replace(netifs[i].Mac, ":", "", -1)
netDesc := fmt.Sprintf("%s:%s:%s:[reserved]", packedMac, hn.IpAddr, hn.NetworkId)
params.Set(fmt.Sprintf("net.%d", netIdx), jsonutils.NewString(netDesc))
netIdx += 1
}
}
params.Set(fmt.Sprintf("net.%d", netIdx), jsonutils.JSONNull)
for i := 0; i < len(idisks); i += 1 {
/*istorage, err := idisks[i].GetIStorage()
if err != nil {
log.Errorf("idisks[i].GetIStorage fail %s", err)
return nil, err
}*/
key := fmt.Sprintf("disk.%d", i)
jsonConf, _ := params.Get(key)
if jsonConf != nil && jsonConf != jsonutils.JSONNull {
conf, err := parseDiskInfo(ctx, userCred, jsonConf)
if err != nil {
log.Debugf("parseDiskInfo %s fail %s", jsonConf, err)
return nil, err
}
conf.SizeMb = idisks[i].GetDiskSizeMB()
conf.Backend = STORAGE_LOCAL
params.Set(key, jsonutils.Marshal(conf))
} else {
strConf := fmt.Sprintf("%s:%d", STORAGE_LOCAL, idisks[i].GetDiskSizeMB())
conf, err := parseDiskInfo(ctx, userCred, jsonutils.NewString(strConf))
if err != nil {
return nil, err
}
params.Set(key, jsonutils.Marshal(conf))
}
}
params.Set(fmt.Sprintf("disk.%d", len(idisks)), jsonutils.JSONNull)
// log.Debugf("params after rebuid: %s", params.String())
return params, nil
}
func (host *SHost) RebuildRecycledGuest(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest) error {
oHost := SHost{}
oHost.SetModelManager(HostManager)
q := HostManager.Query()
q = q.Equals("external_id", host.ExternalId)
q = q.IsNullOrEmpty("resource_type")
err := q.First(&oHost)
if err != nil {
log.Errorf("query oHost fail %s", err)
return err
}
err = guest.SetExternalId(host.RealExternalId)
if err != nil {
log.Errorf("guest.SetExternalId fail %s", err)
return err
}
extVM, err := guest.GetIVM()
if err != nil {
log.Errorf("guest.GetIVM fail %s", err)
return err
}
err = guest.syncWithCloudVM(ctx, userCred, &oHost, extVM, "", false)
if err != nil {
log.Errorf("guest.syncWithCloudVM fail %s", err)
return err
}
idisks, err := extVM.GetIDisks()
if err != nil {
log.Errorf("extVM.GetIDisks fail %s", err)
return err
}
guestdisks := guest.GetDisks()
for i := 0; i < len(guestdisks); i += 1 {
disk := guestdisks[i].GetDisk()
err = disk.SetExternalId(idisks[i].GetGlobalId())
if err != nil {
log.Errorf("disk.SetExternalId fail %s", err)
return err
}
err = disk.syncWithCloudDisk(ctx, userCred, idisks[i], i, "", false)
if err != nil {
log.Errorf("disk.syncWithCloudDisk fail %s", err)
return err
}
}
return nil
}
func (manager *SHostManager) GetHostByRealExternalId(eid string) *SHost {
q := manager.Query()
q = q.Equals("real_external_id", eid)
host := SHost{}
host.SetModelManager(manager)
err := q.First(&host)
if err != nil {
return nil
}
return &host
}
+3
View File
@@ -20,7 +20,10 @@ type IHostDriver interface {
ValidateDiskSize(storage *SStorage, sizeGb int) error
RequestPrepareSaveDiskOnHost(ctx context.Context, host *SHost, disk *SDisk, imageId string, task taskman.ITask) error
RequestSaveUploadImageOnHost(ctx context.Context, host *SHost, disk *SDisk, imageId string, task taskman.ITask, data jsonutils.JSONObject) error
RequestAllocateDiskOnStorage(ctx context.Context, host *SHost, storage *SStorage, disk *SDisk, task taskman.ITask, content *jsonutils.JSONDict) error
RequestRebuildDiskOnStorage(ctx context.Context, host *SHost, storage *SStorage, disk *SDisk, task taskman.ITask, content *jsonutils.JSONDict) error
RequestDeallocateDiskOnHost(ctx context.Context, host *SHost, storage *SStorage, disk *SDisk, task taskman.ITask) error
RequestResizeDiskOnHostOnline(ctx context.Context, host *SHost, storage *SStorage, disk *SDisk, size int64, task taskman.ITask) error
RequestResizeDiskOnHost(ctx context.Context, host *SHost, storage *SStorage, disk *SDisk, size int64, task taskman.ITask) error
+99 -21
View File
@@ -40,14 +40,16 @@ import (
const (
HOST_TYPE_BAREMETAL = "baremetal"
HOST_TYPE_HYPERVISOR = "hypervisor" // KVM
HOST_TYPE_ESXI = "esxi" // # VMWare vSphere ESXi
HOST_TYPE_KUBELET = "kubelet" // # Kubernetes Kubelet
HOST_TYPE_HYPERV = "hyperv" // # Microsoft Hyper-V
HOST_TYPE_XEN = "xen" // # XenServer
HOST_TYPE_ALIYUN = "aliyun"
HOST_TYPE_AWS = "aws"
HOST_TYPE_QCLOUD = "qcloud"
HOST_TYPE_AZURE = "azure"
HOST_TYPE_KVM = "kvm"
HOST_TYPE_ESXI = "esxi" // # VMWare vSphere ESXi
HOST_TYPE_KUBELET = "kubelet" // # Kubernetes Kubelet
HOST_TYPE_HYPERV = "hyperv" // # Microsoft Hyper-V
HOST_TYPE_XEN = "xen" // # XenServer
HOST_TYPE_ALIYUN = "aliyun"
HOST_TYPE_AWS = "aws"
HOST_TYPE_QCLOUD = "qcloud"
HOST_TYPE_AZURE = "azure"
HOST_TYPE_DEFAULT = HOST_TYPE_HYPERVISOR
@@ -85,6 +87,13 @@ const (
HOST_STATUS_UNKNOWN = BAREMETAL_UNKNOWN
)
const (
HostResourceTypeShared = "shared"
HostResourceTypeDefault = HostResourceTypeShared
HostResourceTypePrepaidRecycle = "prepaid"
HostResourceTypeDedicated = "dedicated"
)
var HOST_TYPES = []string{HOST_TYPE_BAREMETAL, HOST_TYPE_HYPERVISOR, HOST_TYPE_ESXI, HOST_TYPE_KUBELET, HOST_TYPE_XEN, HOST_TYPE_ALIYUN, HOST_TYPE_AZURE, HOST_TYPE_AWS, HOST_TYPE_QCLOUD}
var NIC_TYPES = []string{NIC_TYPE_IPMI, NIC_TYPE_ADMIN}
@@ -110,6 +119,7 @@ func init() {
type SHost struct {
db.SEnabledStatusStandaloneResourceBase
SManagedResourceBase
SBillingResourceBase
Rack string `width:"16" charset:"ascii" nullable:"true" get:"admin" update:"admin" create:"admin_optional"` // Column(VARCHAR(16, charset='ascii'), nullable=True)
Slots string `width:"16" charset:"ascii" nullable:"true" get:"admin" update:"admin" create:"admin_optional"` // Column(VARCHAR(16, charset='ascii'), nullable=True)
@@ -154,6 +164,10 @@ type SHost struct {
IsMaintenance bool `nullable:"true" default:"false" list:"admin"` // Column(Boolean, nullable=True, default=False)
LastPingAt time.Time ``
ResourceType string `width:"36" charset:"ascii" nullable:"false" list:"admin" update:"admin" create:"admin_required"` // Column(VARCHAR(36, charset='ascii'), nullable=False)
RealExternalId string `width:"256" charset:"utf8" get:"admin"`
}
func (manager *SHostManager) GetContextManager() []db.IModelManager {
@@ -181,6 +195,24 @@ func (self *SHost) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenC
}
func (manager *SHostManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) {
resType, _ := query.GetString("resource_type")
if len(resType) > 0 {
queryDict := query.(*jsonutils.JSONDict)
queryDict.Remove("resource_type")
switch resType {
case HostResourceTypeShared:
q = q.Filter(
sqlchemy.OR(
sqlchemy.IsNullOrEmpty(q.Field("resource_type")),
sqlchemy.Equals(q.Field("resource_type"), HostResourceTypeShared),
),
)
default:
q = q.Equals("resource_type", resType)
}
}
q, err := manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query)
if err != nil {
return nil, err
@@ -1059,6 +1091,9 @@ func (manager *SHostManager) getHostsByZoneProvider(zone *SZone, provider *SClou
if provider != nil {
q = q.Equals("manager_id", provider.Id)
}
// exclude prepaid_recycle fake hosts
q = q.NotEquals("resource_type", HostResourceTypePrepaidRecycle)
err := db.FetchModelObjects(manager, q, &hosts)
if err != nil {
log.Errorf("%s", err)
@@ -1175,6 +1210,32 @@ func (self *SHost) syncWithCloudHost(extHost cloudprovider.ICloudHost, projectSy
return err
}
func (self *SHost) syncWithCloudPrepaidVM(extVM cloudprovider.ICloudVM, host *SHost, projectSync bool) error {
_, err := self.SaveUpdates(func() error {
self.CpuCount = extVM.GetVcpuCount()
self.MemSize = extVM.GetVmemSizeMB()
self.BillingType = extVM.GetBillingType()
self.ExpiredAt = extVM.GetExpiredAt()
self.ExternalId = host.ExternalId
return nil
})
if err != nil {
log.Errorf("syncWithCloudZone error %s", err)
}
if projectSync {
if err := HostManager.ClearSchedDescCache(self.Id); err != nil {
log.Errorf("ClearSchedDescCache for host %s error %v", self.Name, err)
}
}
return err
}
func (manager *SHostManager) newFromCloudHost(extHost cloudprovider.ICloudHost, izone *SZone) (*SHost, error) {
host := SHost{}
host.SetModelManager(manager)
@@ -1303,7 +1364,16 @@ func (self *SHost) syncWithCloudHostStorage(localStorage *SStorage, extStorage c
return hs.syncWithCloudHostStorage(extStorage)
}
func (self *SHost) isAttach2Storage(storage *SStorage) bool {
hs := self.GetHoststorageOfId(storage.Id)
return hs != nil
}
func (self *SHost) Attach2Storage(ctx context.Context, userCred mcclient.TokenCredential, storage *SStorage, mountPoint string) error {
if self.isAttach2Storage(storage) {
return nil
}
hs := SHoststorage{}
hs.SetModelManager(HoststorageManager)
@@ -1314,6 +1384,7 @@ func (self *SHost) Attach2Storage(ctx context.Context, userCred mcclient.TokenCr
if err != nil {
return err
}
db.OpsLog.LogAttachEvent(self, storage, userCred, nil)
return nil
@@ -1471,6 +1542,13 @@ func (self *SHost) SyncHostVMs(ctx context.Context, userCred mcclient.TokenCrede
}
for i := 0; i < len(added); i += 1 {
if added[i].GetBillingType() == BILLING_TYPE_PREPAID {
vhost := HostManager.GetHostByRealExternalId(added[i].GetGlobalId())
if vhost != nil {
// this recycle vm is not build yet, skip synchronize
continue
}
}
new, err := GuestManager.newCloudVM(ctx, userCred, self, added[i], projectId)
if err != nil {
syncResult.AddError(err)
@@ -1607,6 +1685,8 @@ func (manager *SHostManager) totalCountQ(
rangeObj db.IStandaloneModel,
hostStatus, status string,
hostTypes []string,
resourceTypes []string,
providers []string,
enabled, isBaremetal tristate.TriState,
) *sqlchemy.SQuery {
hosts := manager.Query().SubQuery()
@@ -1631,7 +1711,7 @@ func (manager *SHostManager) totalCountQ(
}
q = q.Filter(cond(hosts.Field("is_baremetal")))
}
q = AttachUsageQuery(q, hosts, hosts.Field("id"), hostTypes, rangeObj)
q = AttachUsageQuery(q, hosts, hostTypes, resourceTypes, providers, rangeObj)
return q
}
@@ -1708,25 +1788,16 @@ func (manager *SHostManager) calculateCount(q *sqlchemy.SQuery) HostsCountStat {
}
}
func (manager *SHostManager) totalCount(
userCred mcclient.TokenCredential,
rangeObj db.IStandaloneModel,
hostStatus, status string,
hostTypes []string,
enabled, isBaremetal tristate.TriState,
) HostsCountStat {
return manager.calculateCount(manager.totalCountQ(userCred, rangeObj, hostStatus, status, hostTypes, enabled, isBaremetal))
}
func (manager *SHostManager) TotalCount(
userCred mcclient.TokenCredential,
rangeObj db.IStandaloneModel,
hostStatus, status string,
hostTypes []string,
resourceTypes []string,
providers []string,
enabled, isBaremetal tristate.TriState,
) HostsCountStat {
stat1 := manager.totalCount(userCred, rangeObj, hostStatus, status, hostTypes, enabled, isBaremetal)
return stat1
return manager.calculateCount(manager.totalCountQ(userCred, rangeObj, hostStatus, status, hostTypes, resourceTypes, providers, enabled, isBaremetal))
}
/*
@@ -1930,6 +2001,13 @@ func (self *SHost) getMoreDetails(ctx context.Context, extra *jsonutils.JSONDict
extra.Add(jsonutils.NewFloat(memCommitRate), "mem_commit_rate")
extra.Add(self.GetHardwareSpecification(), "spec")
extra = self.SManagedResourceBase.getExtraDetails(ctx, extra)
if self.IsPrepaidRecycle() {
extra.Add(jsonutils.JSONTrue, "is_prepaid_recycle")
} else {
extra.Add(jsonutils.JSONFalse, "is_prepaid_recycle")
}
return extra
}
+13 -15
View File
@@ -385,20 +385,18 @@ func (manager *SIsolatedDeviceManager) ReleaseDevicesOfGuest(guest *SGuest, user
}
func (manager *SIsolatedDeviceManager) totalCountQ(
devType, hostTypes []string,
devType []string, hostTypes []string,
resourceTypes []string, providers []string,
rangeObj db.IStandaloneModel,
) *sqlchemy.SQuery {
hosts := HostManager.Query().SubQuery()
q := manager.Query().Join(hosts, sqlchemy.AND(
sqlchemy.IsFalse(hosts.Field("deleted")),
sqlchemy.IsTrue(hosts.Field("enabled")),
))
q = q.Filter(sqlchemy.Equals(hosts.Field("id"), q.Field("host_id")))
if len(devType) != 0 {
q.In("dev_type", devType)
}
devs := manager.Query().SubQuery()
return AttachUsageQuery(q, hosts, devs.Field("host_id"), hostTypes, rangeObj)
q := devs.Query().Join(hosts, sqlchemy.Equals(devs.Field("host_id"), hosts.Field("id")))
q = q.Filter(sqlchemy.IsTrue(hosts.Field("enabled")))
if len(devType) != 0 {
q = q.Filter(sqlchemy.In(devs.Field("dev_type"), devType))
}
return AttachUsageQuery(q, hosts, hostTypes, resourceTypes, providers, rangeObj)
}
type IsolatedDeviceCountStat struct {
@@ -406,14 +404,14 @@ type IsolatedDeviceCountStat struct {
Gpus int
}
func (manager *SIsolatedDeviceManager) totalCount(devType, hostTypes []string, rangeObj db.IStandaloneModel) int {
return manager.totalCountQ(devType, hostTypes, rangeObj).Count()
func (manager *SIsolatedDeviceManager) totalCount(devType, hostTypes []string, resourceTypes []string, providers []string, rangeObj db.IStandaloneModel) int {
return manager.totalCountQ(devType, hostTypes, resourceTypes, providers, rangeObj).Count()
}
func (manager *SIsolatedDeviceManager) TotalCount(hostType []string, rangeObj db.IStandaloneModel) IsolatedDeviceCountStat {
func (manager *SIsolatedDeviceManager) TotalCount(hostType []string, resourceTypes []string, providers []string, rangeObj db.IStandaloneModel) IsolatedDeviceCountStat {
return IsolatedDeviceCountStat{
Devices: manager.totalCount(nil, hostType, rangeObj),
Gpus: manager.totalCount(VALID_GPU_TYPES, hostType, rangeObj),
Devices: manager.totalCount(nil, hostType, resourceTypes, providers, rangeObj),
Gpus: manager.totalCount(VALID_GPU_TYPES, hostType, resourceTypes, providers, rangeObj),
}
}
+1 -1
View File
@@ -270,7 +270,7 @@ func (man *SLoadbalancerAgentManager) ValidateCreateData(ctx context.Context, us
return man.SStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerProjId, query, data)
}
func (man *SLoadbalancerAgentManager) CleanPendingDeleteLoadbalancers(ctx context.Context, userCred mcclient.TokenCredential) {
func (man *SLoadbalancerAgentManager) CleanPendingDeleteLoadbalancers(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
agents := []SLoadbalancerAgent{}
{
// find active agents
+8
View File
@@ -35,6 +35,14 @@ func (self *SManagedResourceBase) GetDriver() (cloudprovider.ICloudProvider, err
return provider.GetDriver()
}
func (self *SManagedResourceBase) GetProviderName() string {
driver := self.GetCloudprovider()
if driver != nil {
return driver.Provider
}
return ""
}
func (self *SManagedResourceBase) IsManaged() bool {
return len(self.ManagerId) > 0
}
-3
View File
@@ -189,9 +189,6 @@ func (self *SNetInterface) getServerJsonDesc() *jsonutils.JSONDict {
func (self *SNetInterface) getBaremetalJsonDesc() *jsonutils.JSONDict {
bn := self.GetBaremetalNetwork()
if bn == nil {
return nil
}
return self.hostNetworkToJson(bn)
}
+13 -17
View File
@@ -606,26 +606,22 @@ func (manager *SNetworkManager) GetNetworkOfIP(ipAddr string, serverType string,
return nil, sql.ErrNoRows
}
func (manager *SNetworkManager) allNetworksQ(rangeObj db.IStandaloneModel) *sqlchemy.SQuery {
func (manager *SNetworkManager) allNetworksQ(providers []string, rangeObj db.IStandaloneModel) *sqlchemy.SQuery {
networks := manager.Query().SubQuery()
hostwires := HostwireManager.Query().SubQuery()
hosts := HostManager.Query().SubQuery()
q := networks.Query().
Join(hostwires, sqlchemy.AND(
sqlchemy.Equals(hostwires.Field("wire_id"), networks.Field("wire_id")),
sqlchemy.IsFalse(hostwires.Field("deleted")))).
Join(hosts, sqlchemy.AND(
sqlchemy.Equals(hosts.Field("id"), hostwires.Field("host_id")),
sqlchemy.IsFalse(hosts.Field("deleted")),
sqlchemy.IsTrue(hosts.Field("enabled")),
sqlchemy.OR(
sqlchemy.Equals(hosts.Field("host_type"), HOST_TYPE_BAREMETAL),
sqlchemy.Equals(hosts.Field("host_status"), HOST_ONLINE))))
return AttachUsageQuery(q, hosts, hostwires.Field("host_id"), nil, rangeObj)
q := networks.Query()
q = q.Join(hostwires, sqlchemy.Equals(hostwires.Field("wire_id"), networks.Field("wire_id")))
q = q.Join(hosts, sqlchemy.Equals(hosts.Field("id"), hostwires.Field("host_id")))
q = q.Filter(sqlchemy.IsTrue(hosts.Field("enabled")))
q = q.Filter(sqlchemy.OR(
sqlchemy.Equals(hosts.Field("host_type"), HOST_TYPE_BAREMETAL),
sqlchemy.Equals(hosts.Field("host_status"), HOST_ONLINE)))
return AttachUsageQuery(q, hosts, nil, nil, providers, rangeObj)
}
func (manager *SNetworkManager) totalPortCountQ(userCred mcclient.TokenCredential, rangeObj db.IStandaloneModel) *sqlchemy.SQuery {
q := manager.allNetworksQ(rangeObj)
func (manager *SNetworkManager) totalPortCountQ(userCred mcclient.TokenCredential, providers []string, rangeObj db.IStandaloneModel) *sqlchemy.SQuery {
q := manager.allNetworksQ(providers, rangeObj)
networks := manager.Query().SubQuery()
if userCred != nil && !db.IsAdminAllowList(userCred, manager) {
q = q.Filter(sqlchemy.OR(
@@ -640,9 +636,9 @@ type NetworkPortStat struct {
CountExt int
}
func (manager *SNetworkManager) TotalPortCount(userCred mcclient.TokenCredential, rangeObj db.IStandaloneModel) NetworkPortStat {
func (manager *SNetworkManager) TotalPortCount(userCred mcclient.TokenCredential, providers []string, rangeObj db.IStandaloneModel) NetworkPortStat {
nets := make([]SNetwork, 0)
err := manager.totalPortCountQ(userCred, rangeObj).All(&nets)
err := manager.totalPortCountQ(userCred, providers, rangeObj).All(&nets)
if err != nil {
log.Errorf("TotalPortCount: %v", err)
}
+2 -2
View File
@@ -75,9 +75,9 @@ func (self *SQuota) FetchSystemQuota() {
func (self *SQuota) FetchUsage(projectId string) error {
diskSize := totalDiskSize(projectId, tristate.None, tristate.None, false)
net := totalGuestNicCount(projectId, nil, false)
guest := totalGuestResourceCount(projectId, nil, nil, nil, false, false, "")
guest := totalGuestResourceCount(projectId, nil, nil, nil, false, false, nil, nil, nil)
eipUsage := ElasticipManager.TotalCount(projectId, nil, nil)
snapshotCount := totalSnapshotCount(projectId)
snapshotCount := TotalSnapshotCount(projectId, nil, nil)
// XXX
// keypair belongs to user
// keypair := totalKeypairCount(projectId)
+132 -21
View File
@@ -78,11 +78,14 @@ type SServerSku struct {
CloudregionId string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"admin_required" update:"admin"`
ZoneId string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
Provider string `width:"64" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
Provider string `width:"64" charset:"ascii" nullable:"true" list:"user" create:"admin_optional" update:"admin"`
}
func inWhiteList(provider string) bool {
// 只有为true的hypervisor才进行创建和更新操作
if len(provider) == 0 {
return true
}
switch provider {
case HYPERVISOR_ESXI, HYPERVISOR_KVM:
return true
@@ -99,19 +102,21 @@ func (self *SServerSku) AllowGetDetails(ctx context.Context, userCred mcclient.T
return true
}
func (manager *SServerSkuManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return db.IsAdminAllowCreate(userCred, manager)
}
func (self *SServerSkuManager) ValidateCreateData(ctx context.Context,
userCred mcclient.TokenCredential,
ownerProjId string,
query jsonutils.JSONObject,
data *jsonutils.JSONDict,
) (*jsonutils.JSONDict, error) {
provider, err := data.GetString("provider")
if err != nil || len(provider) == 0 {
return nil, httperrors.NewMissingParameterError("provider")
}
provider, _ := data.GetString("provider")
if !inWhiteList(provider) {
return nil, httperrors.NewInputParameterError("can not create with provider %s", provider)
return nil, httperrors.NewForbiddenError("can not create instance_type for public cloud %s", provider)
}
regionStr := jsonutils.GetAnyString(data, []string{"region", "region_id", "cloudregion", "cloudregion_id"})
@@ -179,7 +184,7 @@ func (self *SServerSkuManager) GetPropertyInstanceSpecs(ctx context.Context, use
q := self.Query()
zone, err := query.GetString("zone")
if err == nil && len(zone) > 0 {
q = q.Equals("zone", zone)
q = q.Equals("zone_id", zone)
} else {
return nil, httperrors.NewMissingParameterError("zone")
}
@@ -240,11 +245,7 @@ func (self *SServerSkuManager) GetPropertyInstanceSpecs(ctx context.Context, use
}
func (self *SServerSku) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool {
if self.SStandaloneResourceBase.AllowUpdateItem(ctx, userCred) == false {
return false
}
return inWhiteList(self.Provider)
return inWhiteList(self.Provider) && db.IsAdminAllowUpdate(userCred, self)
}
func (self *SServerSku) ValidateUpdateData(
@@ -252,9 +253,14 @@ func (self *SServerSku) ValidateUpdateData(
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
if !inWhiteList(self.Provider) {
return nil, httperrors.NewForbiddenError("can not create instance_type for public cloud %s", self.Provider)
}
provider, err := data.GetString("provider")
if err == nil && !inWhiteList(provider) {
return nil, httperrors.NewInputParameterError("can not create with provider %s", provider)
return nil, httperrors.NewForbiddenError("can not create instance_type for public cloud %s", provider)
}
zoneStr := jsonutils.GetAnyString(data, []string{"zone", "zone_id"})
@@ -272,16 +278,18 @@ func (self *SServerSku) ValidateUpdateData(
}
func (self *SServerSku) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
if !inWhiteList(self.Provider) {
return false
}
return inWhiteList(self.Provider) && db.IsAdminAllowDelete(userCred, self)
}
count := GuestManager.Query().Equals("sku_id", self.Id).Count()
if count == 0 {
return self.SStandaloneResourceBase.AllowDeleteItem(ctx, userCred, query, data)
} else {
return false
func (self *SServerSku) ValidateDeleteCondition(ctx context.Context) error {
if !inWhiteList(self.Provider) {
return httperrors.NewForbiddenError("not allow to delete public cloud instance_type: %s", self.Name)
}
count := GuestManager.Query().Equals("instance_type", self.Name).Count()
if count > 0 {
return httperrors.NewNotEmptyError("instance_type used by servers")
}
return nil
}
func (self *SServerSku) GetZoneExternalId() (string, error) {
@@ -293,3 +301,106 @@ func (self *SServerSku) GetZoneExternalId() (string, error) {
zone := zoneObj.(*SZone)
return zone.GetExternalId(), nil
}
func (manager *SServerSkuManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) {
queryDict := query.(*jsonutils.JSONDict)
provider := jsonutils.GetAnyString(query, []string{"provider"})
if len(provider) > 0 {
if provider != "all" {
q = q.Equals("provider", provider)
}
queryDict.Remove("provider")
} else {
q = q.Filter(sqlchemy.OR(
sqlchemy.IsNull(q.Field("provider")),
sqlchemy.IsEmpty(q.Field("provider")),
))
}
q, err := manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query)
if err != nil {
return nil, err
}
regionStr := jsonutils.GetAnyString(query, []string{"region", "cloudregion", "region_id", "cloudregion_id"})
if len(regionStr) > 0 {
regionObj, err := CloudregionManager.FetchByIdOrName(nil, regionStr)
if err != nil {
if err == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError2(CloudregionManager.Keyword(), regionStr)
}
return nil, httperrors.NewGeneralError(err)
}
q = q.Equals("cloudregion_id", regionObj.GetId())
}
zoneStr := jsonutils.GetAnyString(query, []string{"zone", "zone_id"})
if len(zoneStr) > 0 {
zoneObj, err := ZoneManager.FetchByIdOrName(nil, zoneStr)
if err != nil {
if err == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError2(ZoneManager.Keyword(), zoneStr)
}
return nil, httperrors.NewGeneralError(err)
}
q = q.Equals("zone_id", zoneObj.GetId())
}
return q, err
}
func (manager *SServerSkuManager) FetchSkuByNameAndHypervisor(name string, hypervisor string, checkConsistency bool) (*SServerSku, error) {
q := manager.Query()
q = q.Equals("name", name)
if len(hypervisor) > 0 {
switch hypervisor {
case HYPERVISOR_BAREMETAL, HYPERVISOR_CONTAINER:
return nil, httperrors.NewNotImplementedError("%s not supported", hypervisor)
case HYPERVISOR_KVM, HYPERVISOR_ESXI, HYPERVISOR_XEN, HOST_TYPE_HYPERV:
q = q.Filter(sqlchemy.OR(
sqlchemy.IsEmpty(q.Field("provider")),
sqlchemy.IsNull(q.Field("provider")),
sqlchemy.Equals(q.Field("provider"), hypervisor),
))
default:
q = q.Equals("provider", hypervisor)
}
} else {
q = q.IsEmpty("provider")
}
skus := make([]SServerSku, 0)
err := db.FetchModelObjects(manager, q, &skus)
if err != nil {
log.Errorf("fetch sku fail %s", err)
return nil, err
}
if len(skus) == 0 {
log.Errorf("no sku found for %s %s", name, hypervisor)
return nil, httperrors.NewResourceNotFoundError2(manager.Keyword(), name)
}
if len(skus) == 1 {
return &skus[0], nil
}
if checkConsistency {
for i := 1; i < len(skus); i += 1 {
if skus[i].CpuCoreCount != skus[0].CpuCoreCount || skus[i].MemorySizeMB != skus[0].MemorySizeMB {
log.Errorf("inconsistent sku %s %s", jsonutils.Marshal(&skus[0]), jsonutils.Marshal(&skus[i]))
return nil, httperrors.NewDuplicateResourceError("duplicate instanceType %s", name)
}
}
}
return &skus[0], nil
}
func (manager *SServerSkuManager) GetSkuCountByProvider(provider string) int {
q := manager.Query()
if len(provider) == 0 {
q = q.IsNotEmpty("provider")
} else {
q = q.Equals("provider", provider)
}
return q.Count()
}
+24 -3
View File
@@ -456,10 +456,31 @@ func (self *SSnapshot) Delete(ctx context.Context, userCred mcclient.TokenCreden
return nil
}
func totalSnapshotCount(projectId string) int {
func TotalSnapshotCount(projectId string, rangeObj db.IStandaloneModel, providers []string) int {
q := SnapshotManager.Query()
count := q.Equals("tenant_id", projectId).Equals("fake_deleted", false).Count()
return count
if len(projectId) > 0 {
q = q.Equals("tenant_id", projectId)
}
if rangeObj != nil {
switch rangeObj.Keyword() {
case "cloudprovider":
q = q.Filter(sqlchemy.Equals(q.Field("manager_id"), rangeObj.GetId()))
case "cloudaccount":
cloudproviders := CloudproviderManager.Query().SubQuery()
subq := cloudproviders.Query(cloudproviders.Field("id")).Equals("cloudaccount_id", rangeObj.GetId()).SubQuery()
q = q.Filter(sqlchemy.In(q.Field("manager_id"), subq))
case "cloudregion":
q = q.Filter(sqlchemy.Equals(q.Field("cloudregion_id"), rangeObj.GetId()))
}
}
if len(providers) > 0 {
cloudproviders := CloudproviderManager.Query().SubQuery()
subq := cloudproviders.Query(cloudproviders.Field("id"))
subq = subq.In("provider", providers)
q = q.In("manager_id", subq.SubQuery())
}
q = q.Equals("fake_deleted", false)
return q.Count()
}
// Only sync snapshot status
+35 -22
View File
@@ -800,6 +800,7 @@ func (manager *SStorageManager) disksFailedQ() *sqlchemy.SSubQuery {
func (manager *SStorageManager) totalCapacityQ(
rangeObj db.IStandaloneModel, hostTypes []string,
resourceTypes []string, providers []string,
) *sqlchemy.SQuery {
stmt := manager.disksReadyQ()
stmt2 := manager.disksFailedQ()
@@ -814,26 +815,32 @@ func (manager *SStorageManager) totalCapacityQ(
stmt2.Field("failed_capacity"),
attachedDisks.Field("attached_used_capacity"),
detachedDisks.Field("detached_used_capacity"),
).
LeftJoin(stmt, sqlchemy.Equals(stmt.Field("storage_id"), storages.Field("id"))).
LeftJoin(stmt2, sqlchemy.Equals(stmt2.Field("storage_id"), storages.Field("id"))).
LeftJoin(attachedDisks, sqlchemy.Equals(attachedDisks.Field("storage_id"), storages.Field("id"))).
LeftJoin(detachedDisks, sqlchemy.Equals(detachedDisks.Field("storage_id"), storages.Field("id")))
)
q = q.LeftJoin(stmt, sqlchemy.Equals(stmt.Field("storage_id"), storages.Field("id")))
q = q.LeftJoin(stmt2, sqlchemy.Equals(stmt2.Field("storage_id"), storages.Field("id")))
q = q.LeftJoin(attachedDisks, sqlchemy.Equals(attachedDisks.Field("storage_id"), storages.Field("id")))
q = q.LeftJoin(detachedDisks, sqlchemy.Equals(detachedDisks.Field("storage_id"), storages.Field("id")))
hosts := HostManager.Query().SubQuery()
hostStorages := HoststorageManager.Query().SubQuery()
if len(hostTypes) > 0 || len(resourceTypes) > 0 || rangeObj != nil {
hosts := HostManager.Query().SubQuery()
hostStorages := HoststorageManager.Query().SubQuery()
q = q.Join(hostStorages, sqlchemy.AND(
sqlchemy.Equals(hostStorages.Field("storage_id"), storages.Field("id")),
sqlchemy.IsFalse(hostStorages.Field("deleted")),
)).Join(
hosts, sqlchemy.AND(
sqlchemy.Equals(hosts.Field("id"), hostStorages.Field("host_id")),
sqlchemy.IsFalse(hosts.Field("deleted")),
sqlchemy.IsTrue(hosts.Field("enabled")),
sqlchemy.Equals(hosts.Field("host_status"), HOST_ONLINE)))
q = q.Join(hostStorages, sqlchemy.Equals(hostStorages.Field("storage_id"), storages.Field("id")))
q = q.Join(hosts, sqlchemy.Equals(hosts.Field("id"), hostStorages.Field("host_id")))
q = q.Filter(sqlchemy.IsTrue(hosts.Field("enabled")))
q = q.Filter(sqlchemy.Equals(hosts.Field("host_status"), HOST_ONLINE))
return AttachUsageQuery(q, hosts, hostStorages.Field("host_id"), hostTypes, rangeObj)
q = AttachUsageQuery(q, hosts, hostTypes, resourceTypes, nil, rangeObj)
}
if len(providers) > 0 {
cloudproviders := CloudproviderManager.Query().SubQuery()
subq := cloudproviders.Query(cloudproviders.Field("id"))
subq = subq.Filter(sqlchemy.In(cloudproviders.Field("provider"), providers))
q = q.Filter(sqlchemy.In(storages.Field("manager_id"), subq.SubQuery()))
}
return q
}
type StorageStat struct {
@@ -850,7 +857,7 @@ type StoragesCapacityStat struct {
Capacity int64
CapacityVirtual float64
CapacityUsed int64
CapacityUnread int64
CapacityUnready int64
AttachedCapacity int64
DetachedCapacity int64
}
@@ -884,18 +891,21 @@ func (manager *SStorageManager) calculateCapacity(q *sqlchemy.SQuery) StoragesCa
Capacity: tCapa,
CapacityVirtual: tVCapa,
CapacityUsed: tUsed,
CapacityUnread: tFailed,
CapacityUnready: tFailed,
AttachedCapacity: atCapa,
DetachedCapacity: dtCapa,
}
}
func (manager *SStorageManager) TotalCapacity(rangeObj db.IStandaloneModel, hostTypes []string) StoragesCapacityStat {
res1 := manager.calculateCapacity(manager.totalCapacityQ(rangeObj, hostTypes))
func (manager *SStorageManager) TotalCapacity(rangeObj db.IStandaloneModel, hostTypes []string, resourceTypes []string, providers []string) StoragesCapacityStat {
res1 := manager.calculateCapacity(manager.totalCapacityQ(rangeObj, hostTypes, resourceTypes, providers))
return res1
}
func (self *SStorage) createDisk(name string, diskConfig *SDiskConfig, userCred mcclient.TokenCredential, ownerProjId string, autoDelete bool, isSystem bool) (*SDisk, error) {
func (self *SStorage) createDisk(name string, diskConfig *SDiskConfig, userCred mcclient.TokenCredential,
ownerProjId string, autoDelete bool, isSystem bool,
billingType string, billingCycle string,
) (*SDisk, error) {
disk := SDisk{}
disk.SetModelManager(DiskManager)
@@ -907,6 +917,9 @@ func (self *SStorage) createDisk(name string, diskConfig *SDiskConfig, userCred
disk.ProjectId = ownerProjId
disk.IsSystem = isSystem
disk.BillingType = billingType
disk.BillingCycle = billingCycle
err := disk.GetModelManager().TableSpec().Insert(&disk)
if err != nil {
return nil, err
+35 -15
View File
@@ -1,51 +1,71 @@
package models
import (
"yunion.io/x/log"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/pkg/utils"
)
func AttachUsageQuery(
q *sqlchemy.SQuery,
hosts *sqlchemy.SSubQuery,
hostIdField sqlchemy.IQueryField,
hostTypes []string,
resourceTypes []string,
providers []string,
rangeObj db.IStandaloneModel,
) *sqlchemy.SQuery {
if len(hostTypes) != 0 {
if len(hostTypes) > 0 {
q = q.Filter(sqlchemy.In(hosts.Field("host_type"), hostTypes))
}
if len(resourceTypes) > 0 {
if utils.IsInStringArray(HostResourceTypeShared, resourceTypes) {
q = q.Filter(sqlchemy.OR(
sqlchemy.IsNullOrEmpty(hosts.Field("resource_type")),
sqlchemy.In(hosts.Field("resource_type"), resourceTypes),
))
} else {
q = q.Filter(sqlchemy.In(hosts.Field("resource_type"), resourceTypes))
}
}
if len(providers) > 0 {
cloudproviders := CloudproviderManager.Query().SubQuery()
subq := cloudproviders.Query(cloudproviders.Field("id")).In("provider", providers).SubQuery()
q = q.Filter(sqlchemy.In(hosts.Field("manager_id"), subq))
}
if rangeObj == nil {
return q
}
rangeObjId := rangeObj.GetId()
//rangeObjId := rangeObj.GetId()
kw := rangeObj.Keyword()
log.Debugf("rangeObj keyword: %s", kw)
// log.Debugf("rangeObj keyword: %s", kw)
switch kw {
case "zone":
q = q.Filter(sqlchemy.Equals(hosts.Field("zone_id"), rangeObjId))
zone := rangeObj.(*SZone)
q = q.Filter(sqlchemy.Equals(hosts.Field("zone_id"), zone.Id))
case "wire":
wire := rangeObj.(*SWire)
hostWires := HostwireManager.Query().SubQuery()
q = q.Join(hostWires, sqlchemy.AND(
sqlchemy.Equals(hosts.Field("id"), hostWires.Field("host_id")),
sqlchemy.IsFalse(hostWires.Field("deleted")))).
Filter(sqlchemy.Equals(hostWires.Field("wire_id"), rangeObjId))
subq := hostWires.Query(hostWires.Field("host_id")).Equals("wire_id", wire.Id).SubQuery()
q = q.Filter(sqlchemy.In(hosts.Field("id"), subq))
case "host":
q = q.Filter(sqlchemy.Equals(hostIdField, rangeObjId))
case "vcenter":
q = q.Filter(sqlchemy.Equals(hosts.Field("manager_id"), rangeObjId))
q = q.Filter(sqlchemy.Equals(hosts.Field("id"), rangeObj.GetId()))
case "cloudprovider":
q = q.Filter(sqlchemy.Equals(hosts.Field("manager_id"), rangeObj.GetId()))
case "cloudaccount":
cloudproviders := CloudproviderManager.Query().SubQuery()
subq := cloudproviders.Query(cloudproviders.Field("id")).Equals("cloudaccount_id", rangeObj.GetId()).SubQuery()
q = q.Filter(sqlchemy.In(hosts.Field("manager_id"), subq))
case "schedtag":
aggHosts := HostschedtagManager.Query().SubQuery()
q = q.Join(aggHosts, sqlchemy.AND(
sqlchemy.Equals(hosts.Field("id"), aggHosts.Field("host_id")),
sqlchemy.IsFalse(aggHosts.Field("deleted")))).
Filter(sqlchemy.Equals(aggHosts.Field("schedtag_id"), rangeObjId))
Filter(sqlchemy.Equals(aggHosts.Field("schedtag_id"), rangeObj.GetId()))
case "cloudregion":
zones := ZoneManager.Query().SubQuery()
q = q.Join(zones, sqlchemy.Equals(hosts.Field("zone_id"), zones.Field("id")))
q = q.Filter(sqlchemy.Equals(zones.Field("cloudregion_id"), rangeObjId))
q = q.Filter(sqlchemy.Equals(zones.Field("cloudregion_id"), rangeObj.GetId()))
}
return q
}
+43 -36
View File
@@ -275,30 +275,26 @@ func (manager *SWireManager) newFromCloudWire(extWire cloudprovider.ICloudWire,
return &wire, nil
}
func (manager *SWireManager) totalCountQ(rangeObj db.IStandaloneModel, hostTypes []string) *sqlchemy.SQuery {
func (manager *SWireManager) totalCountQ(rangeObj db.IStandaloneModel, hostTypes []string, providers []string) *sqlchemy.SQuery {
guests := GuestManager.Query().SubQuery()
hosts := HostManager.Query().SubQuery()
gNics := GuestnetworkManager.Query().SubQuery()
gNicQ := gNics.Query(
gNics.Field("network_id"),
sqlchemy.COUNT("id").Label("gnic_count")).
Join(guests, sqlchemy.AND(
sqlchemy.IsFalse(guests.Field("deleted")),
sqlchemy.Equals(guests.Field("id"), gNics.Field("guest_id")),
)).
Join(hosts, sqlchemy.AND(
sqlchemy.Equals(guests.Field("host_id"), hosts.Field("id")),
sqlchemy.IsFalse(hosts.Field("deleted")),
sqlchemy.IsTrue(hosts.Field("enabled"))))
sqlchemy.COUNT("id").Label("gnic_count"),
)
gNicQ = gNicQ.Join(guests, sqlchemy.Equals(guests.Field("id"), gNics.Field("guest_id")))
gNicQ = gNicQ.Join(hosts, sqlchemy.Equals(guests.Field("host_id"), hosts.Field("id")))
gNicQ = gNicQ.Filter(sqlchemy.IsTrue(hosts.Field("enabled")))
hNics := HostnetworkManager.Query().SubQuery()
hNicQ := hNics.Query(
hNics.Field("network_id"),
sqlchemy.COUNT("id").Label("hnic_count")).
Join(hosts, sqlchemy.AND(
sqlchemy.Equals(hNics.Field("baremetal_id"), hosts.Field("id")),
sqlchemy.IsFalse(hosts.Field("deleted")),
sqlchemy.IsTrue(hosts.Field("enabled"))))
sqlchemy.COUNT("id").Label("hnic_count"),
)
hNicQ = hNicQ.Join(hosts, sqlchemy.Equals(hNics.Field("baremetal_id"), hosts.Field("id")))
hNicQ = hNicQ.Filter(sqlchemy.IsTrue(hosts.Field("enabled")))
revIps := ReservedipManager.Query().SubQuery()
revQ := revIps.Query(revIps.Field("network_id"), sqlchemy.COUNT("id").Label("rnic_count"))
@@ -313,30 +309,41 @@ func (manager *SWireManager) totalCountQ(rangeObj db.IStandaloneModel, hostTypes
sqlchemy.COUNT("id").Label("net_count"),
sqlchemy.SUM("gnic_count", gNicQ.Field("gnic_count")),
sqlchemy.SUM("hnic_count", hNicQ.Field("hnic_count")),
sqlchemy.SUM("rev_count", revQ.Field("rnic_count"))).
LeftJoin(gNicSQ, sqlchemy.Equals(gNicSQ.Field("network_id"), networks.Field("id"))).
LeftJoin(hNicSQ, sqlchemy.Equals(hNicSQ.Field("network_id"), networks.Field("id"))).
LeftJoin(revSQ, sqlchemy.Equals(revSQ.Field("network_id"), networks.Field("id"))).
GroupBy(networks.Field("wire_id")).SubQuery()
sqlchemy.SUM("rev_count", revQ.Field("rnic_count")))
netQ = netQ.LeftJoin(gNicSQ, sqlchemy.Equals(gNicSQ.Field("network_id"), networks.Field("id")))
netQ = netQ.LeftJoin(hNicSQ, sqlchemy.Equals(hNicSQ.Field("network_id"), networks.Field("id")))
netQ = netQ.LeftJoin(revSQ, sqlchemy.Equals(revSQ.Field("network_id"), networks.Field("id")))
netQ = netQ.GroupBy(networks.Field("wire_id"))
netSQ := netQ.SubQuery()
wires := WireManager.Query().SubQuery()
q := wires.Query(
sqlchemy.COUNT("id").Label("wires_count"),
sqlchemy.SUM("net_count", netQ.Field("net_count")),
sqlchemy.SUM("guest_nic_count", netQ.Field("gnic_count")),
sqlchemy.SUM("host_nic_count", netQ.Field("hnic_count")),
sqlchemy.SUM("reserved_count", netQ.Field("rev_count")),
).
LeftJoin(netQ, sqlchemy.Equals(wires.Field("id"), netQ.Field("wire_id")))
hostwires := HostwireManager.Query().SubQuery()
sq := hostwires.Query(hostwires.Field("wire_id")).
Join(hosts, sqlchemy.AND(
sqlchemy.Equals(hosts.Field("id"), hostwires.Field("host_id")),
sqlchemy.IsFalse(hosts.Field("deleted")),
sqlchemy.IsTrue(hosts.Field("enabled"))))
sq = AttachUsageQuery(sq, hosts, hosts.Field("id"), hostTypes, rangeObj)
sqlchemy.SUM("net_count", netSQ.Field("net_count")),
sqlchemy.SUM("guest_nic_count", netSQ.Field("gnic_count")),
sqlchemy.SUM("host_nic_count", netSQ.Field("hnic_count")),
sqlchemy.SUM("reserved_count", netSQ.Field("rev_count")),
)
q = q.LeftJoin(netSQ, sqlchemy.Equals(wires.Field("id"), netSQ.Field("wire_id")))
if rangeObj != nil || len(hostTypes) > 0 {
hostwires := HostwireManager.Query().SubQuery()
sq := hostwires.Query(hostwires.Field("wire_id"))
sq = sq.Join(hosts, sqlchemy.Equals(hosts.Field("id"), hostwires.Field("host_id")))
sq = sq.Filter(sqlchemy.IsTrue(hosts.Field("enabled")))
sq = AttachUsageQuery(sq, hosts, hostTypes, nil, nil, rangeObj)
q = q.Filter(sqlchemy.In(wires.Field("id"), sq.Distinct()))
}
if len(providers) > 0 {
vpcs := VpcManager.Query().SubQuery()
cloudproviders := CloudproviderManager.Query().SubQuery()
subq := vpcs.Query(vpcs.Field("id"))
subq = subq.Join(cloudproviders, sqlchemy.Equals(vpcs.Field("manager_id"), cloudproviders.Field("id")))
subq = subq.Filter(sqlchemy.In(cloudproviders.Field("provider"), providers))
q = q.Filter(sqlchemy.In(wires.Field("vpc_id"), subq.SubQuery()))
}
q = q.Filter(sqlchemy.In(wires.Field("id"), sq.Distinct()))
return q
}
@@ -348,9 +355,9 @@ type WiresCountStat struct {
ReservedCount int
}
func (manager *SWireManager) TotalCount(rangeObj db.IStandaloneModel, hostTypes []string) WiresCountStat {
func (manager *SWireManager) TotalCount(rangeObj db.IStandaloneModel, hostTypes []string, providers []string) WiresCountStat {
stat := WiresCountStat{}
err := manager.totalCountQ(rangeObj, hostTypes).First(&stat)
err := manager.totalCountQ(rangeObj, hostTypes, providers).First(&stat)
if err != nil {
log.Errorf("Wire total count: %v", err)
}
+3
View File
@@ -26,6 +26,9 @@ type ComputeOptions struct {
PendingDeleteExpireSeconds int `default:"259200" help:"How long a pending delete VM/disks cleaned automatically, default 3 days"`
PendingDeleteMaxCleanBatchSize int `default:"50" help:"How many pending delete servers can be clean in a batch"`
PrepaidExpireCheckSeconds int `default:"600" help:"How long to wait to scan expired prepaid VM or disks, default is 10 minutes"`
ExpiredPrepaidMaxCleanBatchSize int `default:"50" help:"How many expired prepaid servers can be deleted in a batch"`
LoadbalancerPendingDeleteCheckInterval int `default:"3600" help:"Interval between checks of pending deleted loadbalancer objects, defaults to 1h"`
ImageCacheStoragePolicy string `default:"least_used" choices:"best_fit|least_used" help:"Policy to choose storage for image cache, best_fit or least_used"`
+2
View File
@@ -59,6 +59,8 @@ func StartService() {
cron.AddJob1("CleanPendingDeleteServers", time.Duration(options.Options.PendingDeleteCheckSeconds)*time.Second, models.GuestManager.CleanPendingDeleteServers)
cron.AddJob1("CleanPendingDeleteDisks", time.Duration(options.Options.PendingDeleteCheckSeconds)*time.Second, models.DiskManager.CleanPendingDeleteDisks)
cron.AddJob1("CleanPendingDeleteLoadbalancers", time.Duration(options.Options.LoadbalancerPendingDeleteCheckInterval)*time.Second, models.LoadbalancerAgentManager.CleanPendingDeleteLoadbalancers)
cron.AddJob1("CleanPendingDeleteServers", time.Duration(options.Options.PrepaidExpireCheckSeconds)*time.Second, models.GuestManager.DeleteExpiredPrepaidServers)
cron.AddJob2("AutoDiskSnapshot", options.Options.AutoSnapshotDay, options.Options.AutoSnapshotHour, 0, 0, models.DiskManager.AutoDiskSnapshot, false)
cron.AddJob2("SyncSkus", options.Options.SyncSkusDay, options.Options.SyncSkusHour, 0, 0, skus.SyncSkus, true)
+1
View File
@@ -0,0 +1 @@
package skus // import "yunion.io/x/onecloud/pkg/compute/skus"
+6 -1
View File
@@ -306,7 +306,12 @@ func (self *SkusZoneList) SyncToLocalDB() error {
return err
}
func SyncSkus(ctx context.Context, userCred mcclient.TokenCredential) {
func SyncSkus(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
if isStart {
if models.ServerSkuManager.GetSkuCountByProvider("") > 0 {
return
}
}
skus := SkusZoneList{}
if e := skus.Refresh(nil); e != nil {
log.Errorf("SyncSkus refresh failed, %s", e.Error())
+1
View File
@@ -0,0 +1 @@
package specs // import "yunion.io/x/onecloud/pkg/compute/specs"
+11 -3
View File
@@ -84,10 +84,18 @@ func (self *CloudAccountSyncInfoTask) OnCloudaccountSyncComplete(ctx context.Con
account.SetStatus(self.UserCred, models.CLOUD_PROVIDER_CONNECTED, "")
}
// sync skus
if err := skus.SyncSkusByProviderIds([]string{cloudprovider.Provider}); err != nil {
self.SetStageFailed(ctx, err.Error())
if models.ServerSkuManager.GetSkuCountByProvider(cloudprovider.Provider) == 0 {
// sync skus
self.SetStage("OnSyncServerSkuComplete", nil)
taskman.LocalTaskRun(self, func() (jsonutils.JSONObject, error) {
err := skus.SyncSkusByProviderIds([]string{cloudprovider.Provider})
return nil, err
})
}
}
self.SetStageComplete(ctx, nil)
}
func (self *CloudAccountSyncInfoTask) OnSyncServerSkuComplete(ctx context.Context, items []db.IStandaloneModel, data jsonutils.JSONObject) {
self.SetStageComplete(ctx, nil)
}
+42 -3
View File
@@ -47,7 +47,7 @@ func (self *GuestBatchCreateTask) SaveScheduleResult(ctx context.Context, obj IS
log.Errorf("GetPendingUsage fail %s", err)
}
if len(guest.HostId) == 0 {
guest.SetHostId(hostId)
guest.OnScheduleToHost(ctx, self.UserCred, hostId)
}
quotaCpuMem := models.SQuota{Cpu: int(guest.VcpuCount), Memory: guest.VmemSize}
@@ -56,6 +56,20 @@ func (self *GuestBatchCreateTask) SaveScheduleResult(ctx context.Context, obj IS
host := guest.GetHost()
if host.IsPrepaidRecycle() {
params, err := host.SetGuestCreateNetworkAndDiskParams(ctx, self.UserCred, self.Params)
if err != nil {
log.Errorf("host.SetGuestCreateNetworkAndDiskParams fail %s", err)
guest.SetStatus(self.UserCred, models.VM_CREATE_FAILED, err.Error())
self.SetStageFailed(ctx, err.Error())
db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, err, self.UserCred)
notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_CREATE_FAILED, err.Error())
return
}
self.Params = params
self.SaveParams(params)
}
err = guest.CreateNetworksOnHost(ctx, self.UserCred, host, self.Params, &pendingUsage)
self.SetPendingUsage(&pendingUsage)
@@ -69,7 +83,7 @@ func (self *GuestBatchCreateTask) SaveScheduleResult(ctx context.Context, obj IS
}
guest.GetDriver().PrepareDiskRaidConfig(host, self.Params)
err = guest.CreateDisksOnHost(ctx, self.UserCred, host, self.Params, &pendingUsage)
err = guest.CreateDisksOnHost(ctx, self.UserCred, host, self.Params, &pendingUsage, true)
self.SetPendingUsage(&pendingUsage)
if err != nil {
@@ -95,13 +109,38 @@ func (self *GuestBatchCreateTask) SaveScheduleResult(ctx context.Context, obj IS
guest.JoinGroups(self.UserCred, self.Params)
if guest.IsPrepaidRecycle() {
err := host.RebuildRecycledGuest(ctx, self.UserCred, guest)
if err != nil {
log.Errorf("start guest create task fail %s", err)
guest.SetStatus(self.UserCred, models.VM_CREATE_FAILED, err.Error())
self.SetStageFailed(ctx, err.Error())
db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, err, self.UserCred)
notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_CREATE_FAILED, err.Error())
return
}
autoStart := jsonutils.QueryBoolean(self.Params, "auto_start", false)
resetPassword := jsonutils.QueryBoolean(self.Params, "reset_password", true)
passwd, _ := self.Params.GetString("password")
err = guest.StartRebuildRootTask(ctx, self.UserCred, "", false, autoStart, passwd, resetPassword, true)
if err != nil {
log.Errorf("start guest create task fail %s", err)
guest.SetStatus(self.UserCred, models.VM_CREATE_FAILED, err.Error())
self.SetStageFailed(ctx, err.Error())
db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, err, self.UserCred)
notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_CREATE_FAILED, err.Error())
return
}
return
}
err = guest.StartGuestCreateTask(ctx, self.UserCred, self.Params, nil, self.GetId())
if err != nil {
log.Errorf("start guest create task fail %s", err)
guest.SetStatus(self.UserCred, models.VM_CREATE_FAILED, err.Error())
self.SetStageFailed(ctx, err.Error())
db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, err, self.UserCred)
notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_DEVICE_FAILED, err.Error())
notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_CREATE_FAILED, err.Error())
}
}
+11 -1
View File
@@ -2,6 +2,7 @@ package tasks
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
@@ -155,7 +156,16 @@ func (self *GuestDeleteTask) OnGuestDetachDisksCompleteFailed(ctx context.Contex
func (self *GuestDeleteTask) DoDeleteGuest(ctx context.Context, guest *models.SGuest) {
models.IsolatedDeviceManager.ReleaseDevicesOfGuest(guest, self.UserCred)
host := guest.GetHost()
if (host == nil || !host.Enabled) && jsonutils.QueryBoolean(self.Params, "purge", false) {
if guest.IsPrepaidRecycle() {
err := host.BorrowIpAddrsFromGuest(ctx, self.UserCred, guest)
if err != nil {
msg := fmt.Sprintf("host.BorrowIpAddrsFromGuest fail %s", err)
log.Errorf(msg)
self.OnGuestDeleteFailed(ctx, guest, jsonutils.NewString(msg))
return
}
self.OnGuestDeleteComplete(ctx, guest, nil)
} else if (host == nil || !host.Enabled) && jsonutils.QueryBoolean(self.Params, "purge", false) {
self.OnGuestDeleteComplete(ctx, guest, nil)
} else {
self.SetStage("on_guest_delete_complete", nil)
+1 -1
View File
@@ -301,7 +301,7 @@ func (self *GuestMigrateTask) setGuest(ctx context.Context, guest *models.SGuest
}
oldHost := guest.GetHost()
oldHost.ClearSchedDescCache()
err := guest.SetHostId(targetHostId)
err := guest.OnScheduleToHost(ctx, self.UserCred, targetHostId)
if err != nil {
return err
}
+43 -2
View File
@@ -71,6 +71,48 @@ func (self *GuestRebuildRootTask) StartRebuildRootDisk(ctx context.Context, gues
}
func (self *GuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
allDisks := jsonutils.QueryBoolean(self.Params, "all_disks", false)
if allDisks {
guestdisks := guest.GetDisks()
for i := 1; i < len(guestdisks); i += 1 {
disk := guestdisks[i].GetDisk()
if disk != nil {
disk.SetStatus(self.UserCred, models.DISK_INIT, "rebuild data disks")
}
}
self.SetStage("OnRebuildingDataDisksComplete", nil)
self.OnRebuildingDataDisksComplete(ctx, guest, data)
} else {
self.OnRebuildAllDisksComplete(ctx, guest, data)
}
}
func (self *GuestRebuildRootTask) OnRebuildingDataDisksComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
diskReady := true
guestdisks := guest.GetDisks()
if len(guestdisks) > 0 {
guest.SetStatus(self.UserCred, models.VM_REBUILD_ROOT, "rebuild data disks")
}
for i := 1; i < len(guestdisks); i += 1 {
disk := guestdisks[i].GetDisk()
if disk.Status == models.DISK_INIT {
diskReady = false
disk.StartDiskCreateTask(ctx, self.UserCred, true, "", self.GetTaskId())
}
}
if diskReady {
self.OnRebuildAllDisksComplete(ctx, guest, data)
}
}
func (self *GuestRebuildRootTask) OnRebuildingDataDisksCompleteFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
db.OpsLog.LogEvent(guest, db.ACT_REBUILD_ROOT_FAIL, data, self.UserCred)
guest.SetStatus(self.UserCred, models.VM_REBUILD_ROOT_FAIL, "OnRebuildingDataDisksCompleteFailed")
logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, data, self.UserCred, false)
self.SetStageFailed(ctx, data.String())
}
func (self *GuestRebuildRootTask) OnRebuildAllDisksComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
imgId, _ := self.Params.GetString("image_id")
imginfo, err := models.CachedimageManager.GetImageById(ctx, self.UserCred, imgId, false)
if err != nil {
@@ -109,7 +151,7 @@ func (self *GuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Context,
func (self *GuestRebuildRootTask) OnRebuildRootDiskCompleteFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
db.OpsLog.LogEvent(guest, db.ACT_REBUILD_ROOT_FAIL, data, self.UserCred)
guest.SetStatus(self.UserCred, models.VM_REBUILD_ROOT_FAIL, "")
guest.SetStatus(self.UserCred, models.VM_REBUILD_ROOT_FAIL, "OnRebuildRootDiskCompleteFailed")
logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, data, self.UserCred, false)
self.SetStageFailed(ctx, data.String())
}
@@ -162,7 +204,6 @@ func (self *KVMGuestRebuildRootTask) OnRebuildRootDiskCompleteFailed(ctx context
func (self *KVMGuestRebuildRootTask) OnGuestDeployComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
guest := obj.(*models.SGuest)
self.SetStageComplete(ctx, nil)
logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, nil, self.UserCred, true)
}
+47
View File
@@ -0,0 +1,47 @@
package tasks
import (
"context"
"yunion.io/x/jsonutils"
"fmt"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/billing"
)
type GuestRenewTask struct {
SGuestBaseTask
}
func init() {
taskman.RegisterTask(GuestRenewTask{})
}
func (self *GuestRenewTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
guest := obj.(*models.SGuest)
durationStr, _ := self.GetParams().GetString("duration")
bc, _ := billing.ParseBillingCycle(durationStr)
exp, err := guest.GetDriver().RequestRenewInstance(guest, bc)
if err != nil {
msg := fmt.Sprintf("RequestRenewInstance failed %s", err)
log.Errorf(msg)
self.SetStageFailed(ctx, msg)
return
}
err = guest.SaveRenewInfo(self.UserCred, &bc, &exp)
if err != nil {
msg := fmt.Sprintf("SaveRenewInfo fail %s", err)
log.Errorf(msg)
self.SetStageFailed(ctx, msg)
return
}
self.SetStageComplete(ctx, nil)
}
+3 -3
View File
@@ -34,7 +34,7 @@ type IScheduleTask interface {
GetUserCred() mcclient.TokenCredential
GetSchedParams() *jsonutils.JSONDict
GetPendingUsage(quota quotas.IQuota) error
SetStage(stageName string, data *jsonutils.JSONDict)
SetStage(stageName string, data *jsonutils.JSONDict) error
SetStageFailed(ctx context.Context, reason string)
OnStartSchedule(obj IScheduleModel)
@@ -212,8 +212,8 @@ func onScheduleSucc(
obj IScheduleModel,
hostId string,
) {
lockman.LockObject(ctx, obj)
defer lockman.ReleaseObject(ctx, obj)
lockman.LockRawObject(ctx, models.HostManager.KeywordPlural(), hostId)
defer lockman.ReleaseRawObject(ctx, models.HostManager.KeywordPlural(), hostId)
task.SaveScheduleResult(ctx, obj, hostId)
models.HostManager.ClearSchedDescCache(hostId)
+225 -106
View File
@@ -48,7 +48,7 @@ func (u Usage) Include(nus ...Usage) Usage {
return u
}
type objUsageFunc func(mcclient.TokenCredential, db.IStandaloneModel, []string) (Usage, error)
type objUsageFunc func(mcclient.TokenCredential, db.IStandaloneModel, []string, []string) (Usage, error)
func getRangeObjId(ctx context.Context) (string, error) {
params := appctx.AppContextParams(ctx)
@@ -81,7 +81,7 @@ func rangeObjHandler(
httperrors.NotFoundError(w, err.Error())
return
}
projectName, _ := getQuery(r).GetString("project")
projectName := json.GetAnyString(getQuery(r), []string{"project", "tenant"})
if projectName != "" {
userCred, err = generateProjectUserCred(ctx, userCred, projectName)
if err != nil {
@@ -89,7 +89,11 @@ func rangeObjHandler(
return
}
}
usage, err := reporter(userCred, obj, getHostTypes(r))
query := getQuery(r)
hostTypes := json.GetQueryStringArray(query, "host_type")
// resourceTypes := json.GetQueryStringArray(query, "resource_type")
providers := json.GetQueryStringArray(query, "provider")
usage, err := reporter(userCred, obj, hostTypes, providers)
if err != nil {
httperrors.GeneralServerError(w, err)
return
@@ -124,13 +128,14 @@ func addHandler(prefix, rangeObjKey string, hf appsrv.FilterHandler, app *appsrv
func AddUsageHandler(prefix string, app *appsrv.Application) {
prefix = fmt.Sprintf("%s/usages", prefix)
for key, f := range map[string]appsrv.FilterHandler{
"": rangeObjHandler(nil, ReportGeneralUsage),
"zone": rangeObjHandler(models.ZoneManager, ReportZoneUsage),
"wire": rangeObjHandler(models.WireManager, ReportWireUsage),
"schedtag": rangeObjHandler(models.SchedtagManager, ReportSchedtagUsage),
"host": rangeObjHandler(models.HostManager, ReportHostUsage),
"vcenter": rangeObjHandler(models.VCenterManager, ReportVCenterUsage),
"cloudregion": rangeObjHandler(models.CloudregionManager, ReportCloudRegionUsage),
"": rangeObjHandler(nil, ReportGeneralUsage),
"zone": rangeObjHandler(models.ZoneManager, ReportZoneUsage),
"wire": rangeObjHandler(models.WireManager, ReportWireUsage),
"schedtag": rangeObjHandler(models.SchedtagManager, ReportSchedtagUsage),
"host": rangeObjHandler(models.HostManager, ReportHostUsage),
"cloudaccount": rangeObjHandler(models.CloudaccountManager, ReportCloudAccountUsage),
"cloudprovider": rangeObjHandler(models.CloudproviderManager, ReportCloudProviderUsage),
"cloudregion": rangeObjHandler(models.CloudregionManager, ReportCloudRegionUsage),
} {
addHandler(prefix, key, f, app)
}
@@ -151,47 +156,45 @@ func getQuery(r *http.Request) json.JSONObject {
return query
}
func getHostTypes(r *http.Request) []string {
types := make([]string, 0)
t, _ := getQuery(r).GetString("host_type")
if len(t) != 0 {
types = append(types, t)
}
return types
func ReportHostUsage(userCred mcclient.TokenCredential, host db.IStandaloneModel, hostTypes []string, providers []string) (Usage, error) {
return ReportGeneralUsage(userCred, host, hostTypes, providers)
}
func ReportHostUsage(userCred mcclient.TokenCredential, host db.IStandaloneModel, hostTypes []string) (Usage, error) {
return ReportGeneralUsage(userCred, host, hostTypes)
func ReportWireUsage(userCred mcclient.TokenCredential, wire db.IStandaloneModel, hostTypes []string, providers []string) (Usage, error) {
return ReportGeneralUsage(userCred, wire, hostTypes, providers)
}
func ReportWireUsage(userCred mcclient.TokenCredential, wire db.IStandaloneModel, hostTypes []string) (Usage, error) {
return ReportGeneralUsage(userCred, wire, hostTypes)
func ReportCloudAccountUsage(userCred mcclient.TokenCredential, account db.IStandaloneModel, hostTypes []string, providers []string) (Usage, error) {
return ReportGeneralUsage(userCred, account, hostTypes, providers)
}
func ReportVCenterUsage(userCred mcclient.TokenCredential, vcenter db.IStandaloneModel, hostTypes []string) (Usage, error) {
return ReportGeneralUsage(userCred, vcenter, hostTypes)
func ReportCloudProviderUsage(userCred mcclient.TokenCredential, provider db.IStandaloneModel, hostTypes []string, providers []string) (Usage, error) {
return ReportGeneralUsage(userCred, provider, hostTypes, providers)
}
func ReportSchedtagUsage(userCred mcclient.TokenCredential, schedtag db.IStandaloneModel, hostTypes []string) (Usage, error) {
return ReportGeneralUsage(userCred, schedtag, hostTypes)
func ReportSchedtagUsage(userCred mcclient.TokenCredential, schedtag db.IStandaloneModel, hostTypes []string, providers []string) (Usage, error) {
return ReportGeneralUsage(userCred, schedtag, hostTypes, providers)
}
func ReportZoneUsage(userCred mcclient.TokenCredential, zone db.IStandaloneModel, hostTypes []string) (Usage, error) {
return ReportGeneralUsage(userCred, zone, hostTypes)
func ReportZoneUsage(userCred mcclient.TokenCredential, zone db.IStandaloneModel, hostTypes []string, providers []string) (Usage, error) {
return ReportGeneralUsage(userCred, zone, hostTypes, providers)
}
func ReportCloudRegionUsage(userCred mcclient.TokenCredential, cloudRegion db.IStandaloneModel, hostTypes []string) (Usage, error) {
return ReportGeneralUsage(userCred, cloudRegion, hostTypes)
func ReportCloudRegionUsage(userCred mcclient.TokenCredential, cloudRegion db.IStandaloneModel, hostTypes []string, providers []string) (Usage, error) {
return ReportGeneralUsage(userCred, cloudRegion, hostTypes, providers)
}
//func ReportGuestUsage()
func getAdminGeneralUsage(userCred mcclient.TokenCredential, rangeObj db.IStandaloneModel, hostTypes []string, providers []string) (count Usage, err error) {
count = RegionUsage(providers)
zone := ZoneUsage(providers)
count.Include(zone)
vpc := VpcUsage(providers)
count.Include(vpc)
func getAdminGeneralUsage(userCred mcclient.TokenCredential, rangeObj db.IStandaloneModel, hostTypes []string) (count Usage, err error) {
count = ZoneUsage()
var pmemTotal float64
var pcpuTotal float64
hostEnabledUsage := HostEnabledUsage(userCred, rangeObj, hostTypes)
hostEnabledUsage := HostEnabledUsage("", userCred, rangeObj, hostTypes, []string{models.HostResourceTypeShared}, providers)
pmemTotal = float64(hostEnabledUsage.Get("enabled_hosts.memory").(int64))
pcpuTotal = float64(hostEnabledUsage.Get("enabled_hosts.cpu").(int64))
if rangeObj != nil && rangeObj.Keyword() == "host" {
@@ -203,10 +206,12 @@ func getAdminGeneralUsage(userCred mcclient.TokenCredential, rangeObj db.IStanda
count.Add("memory.virtual", host.GetVirtualMemorySize())
count.Add("cpu.virtual", host.GetVirtualCPUCount())
}
guestRunningUsage := GuestRunningUsage("all.running_servers", nil, rangeObj, hostTypes)
guestRunningUsage := GuestRunningUsage("all.running_servers", nil, rangeObj, hostTypes, []string{models.HostResourceTypeShared}, providers)
runningMem := guestRunningUsage.Get("all.running_servers.memory").(int)
runningCpu := guestRunningUsage.Get("all.running_servers.cpu").(int)
containerRunningUsage := containerUsage("all.containers", nil, rangeObj)
containerRunningUsage := containerUsage("all.containers", nil, rangeObj, hostTypes, nil, providers)
containerRunningMem := containerRunningUsage.Get("all.containers.memory").(int)
containerRunningCpu := containerRunningUsage.Get("all.containers.cpu").(int)
runningMem += containerRunningMem
@@ -222,50 +227,92 @@ func getAdminGeneralUsage(userCred mcclient.TokenCredential, rangeObj db.IStanda
count.Add("all.memory_commit_rate.running", runningMemCmtRate)
count.Add("all.cpu_commit_rate.running", runningCpuCmtRate)
storageUsage := StorageUsage(rangeObj, hostTypes)
storageCmtRate := 0.0
disksSize := storageUsage.Get("all.disks").(int64)
storageSize := storageUsage.Get("storages").(int64)
if storageSize > 0 {
storageCmtRate = utils.FloatRound(float64(disksSize)/float64(storageSize), 2)
}
count.Add("storages_commit_rate", storageCmtRate)
storageUsage := StorageUsage("", rangeObj, hostTypes, []string{models.HostResourceTypeShared}, providers)
count.Include(
HostAllUsage(userCred, rangeObj, hostTypes),
HostAllUsage("", userCred, rangeObj, hostTypes, []string{models.HostResourceTypeShared}, providers),
HostAllUsage("prepaid_pool", userCred, rangeObj, hostTypes, []string{models.HostResourceTypePrepaidRecycle}, providers),
HostAllUsage("any_pool", userCred, rangeObj, hostTypes, nil, providers),
hostEnabledUsage,
BaremetalUsage(userCred, rangeObj, hostTypes),
HostEnabledUsage("prepaid_pool", userCred, rangeObj, hostTypes, []string{models.HostResourceTypePrepaidRecycle}, providers),
HostEnabledUsage("any_pool", userCred, rangeObj, hostTypes, nil, providers),
BaremetalUsage(userCred, rangeObj, hostTypes, providers),
storageUsage,
GuestNormalUsage("all.servers", nil, rangeObj, hostTypes),
GuestPendingDeleteUsage("all.pending_delete_servers", nil, rangeObj, hostTypes),
GuestReadyUsage("all.ready_servers", nil, rangeObj, hostTypes),
StorageUsage("prepaid_pool", rangeObj, hostTypes, []string{models.HostResourceTypePrepaidRecycle}, providers),
StorageUsage("any_pool", rangeObj, hostTypes, nil, providers),
GuestNormalUsage("all.servers", nil, rangeObj, hostTypes, []string{models.HostResourceTypeShared}, providers),
GuestNormalUsage("all.servers.prepaid_pool", nil, rangeObj, hostTypes, []string{models.HostResourceTypePrepaidRecycle}, providers),
GuestNormalUsage("all.servers.any_pool", nil, rangeObj, hostTypes, nil, providers),
GuestPendingDeleteUsage("all.pending_delete_servers", nil, rangeObj, hostTypes, []string{models.HostResourceTypeShared}, providers),
GuestPendingDeleteUsage("all.pending_delete_servers.prepaid_pool", nil, rangeObj, hostTypes, []string{models.HostResourceTypePrepaidRecycle}, providers),
GuestPendingDeleteUsage("all.pending_delete_servers.any_pool", nil, rangeObj, hostTypes, nil, providers),
GuestReadyUsage("all.ready_servers", nil, rangeObj, hostTypes, []string{models.HostResourceTypeShared}, providers),
GuestReadyUsage("all.ready_servers.prepaid_pool", nil, rangeObj, hostTypes, []string{models.HostResourceTypePrepaidRecycle}, providers),
GuestReadyUsage("all.ready_servers.any_pool", nil, rangeObj, hostTypes, nil, providers),
guestRunningUsage,
GuestRunningUsage("all.running_servers.prepaid_pool", nil, rangeObj, hostTypes, []string{models.HostResourceTypePrepaidRecycle}, providers),
GuestRunningUsage("all.running_servers.any_pool", nil, rangeObj, hostTypes, nil, providers),
containerRunningUsage,
IsolatedDeviceUsage(rangeObj, hostTypes),
WireUsage(rangeObj, hostTypes),
EipUsage(rangeObj, hostTypes),
IsolatedDeviceUsage("", rangeObj, hostTypes, []string{models.HostResourceTypeShared}, providers),
IsolatedDeviceUsage("prepaid_pool", rangeObj, hostTypes, []string{models.HostResourceTypePrepaidRecycle}, providers),
IsolatedDeviceUsage("any_pool", rangeObj, hostTypes, nil, providers),
WireUsage(rangeObj, hostTypes, providers),
EipUsage("", rangeObj, providers),
SnapshotUsage("", rangeObj, providers),
)
return
}
func getCommonGeneralUsage(cred mcclient.TokenCredential, rangeObj db.IStandaloneModel, hostTypes []string) (count Usage, err error) {
guestNormalUsage := GuestNormalUsage("servers", cred, rangeObj, hostTypes)
guestRunningUsage := GuestRunningUsage("running_servers", cred, rangeObj, hostTypes)
guestPendingDeleteUsage := GuestPendingDeleteUsage("pending_delete_servers", cred, rangeObj, hostTypes)
guestReadyUsage := GuestReadyUsage("ready_servers", cred, rangeObj, hostTypes)
containerUsage := containerUsage("containers", cred, rangeObj)
func getCommonGeneralUsage(cred mcclient.TokenCredential, rangeObj db.IStandaloneModel, hostTypes []string, providers []string) (count Usage, err error) {
guestNormalUsage := GuestNormalUsage("servers", cred, rangeObj, hostTypes, []string{models.HostResourceTypeShared}, providers)
containerUsage := containerUsage("containers", cred, rangeObj, hostTypes, nil, providers)
eipUsage := EipUsage(cred.GetProjectId(), rangeObj, providers)
snapshotUsage := SnapshotUsage(cred.GetProjectId(), rangeObj, providers)
count = guestNormalUsage.Include(
guestRunningUsage,
guestPendingDeleteUsage,
guestReadyUsage,
GuestNormalUsage("servers.prepaid_pool", cred, rangeObj, hostTypes, []string{models.HostResourceTypePrepaidRecycle}, providers),
GuestNormalUsage("servers.any_pool", cred, rangeObj, hostTypes, nil, providers),
GuestRunningUsage("running_servers", cred, rangeObj, hostTypes, []string{models.HostResourceTypeShared}, providers),
GuestRunningUsage("running_servers.prepaid_pool", cred, rangeObj, hostTypes, []string{models.HostResourceTypePrepaidRecycle}, providers),
GuestRunningUsage("running_servers.any_pool", cred, rangeObj, hostTypes, nil, providers),
GuestPendingDeleteUsage("pending_delete_servers", cred, rangeObj, hostTypes, []string{models.HostResourceTypeShared}, providers),
GuestPendingDeleteUsage("pending_delete_servers.prepaid_pool", cred, rangeObj, hostTypes, []string{models.HostResourceTypePrepaidRecycle}, providers),
GuestPendingDeleteUsage("pending_delete_servers.any_pool", cred, rangeObj, hostTypes, nil, providers),
GuestReadyUsage("ready_servers", cred, rangeObj, hostTypes, []string{models.HostResourceTypeShared}, providers),
GuestReadyUsage("ready_servers.prepaid_pool", cred, rangeObj, hostTypes, []string{models.HostResourceTypePrepaidRecycle}, providers),
GuestReadyUsage("ready_servers.any_pool", cred, rangeObj, hostTypes, nil, providers),
containerUsage,
NetworkUsage(cred, rangeObj),
NetworkUsage(cred, providers, rangeObj),
eipUsage,
snapshotUsage,
)
return
}
func ReportGeneralUsage(userCred mcclient.TokenCredential, rangeObj db.IStandaloneModel, hostTypes []string) (count Usage, err error) {
func ReportGeneralUsage(userCred mcclient.TokenCredential, rangeObj db.IStandaloneModel, hostTypes []string, providers []string) (count Usage, err error) {
count = make(map[string]interface{})
isAdmin := false
@@ -280,7 +327,7 @@ func ReportGeneralUsage(userCred mcclient.TokenCredential, rangeObj db.IStandalo
}
if isAdmin {
count, err = getAdminGeneralUsage(userCred, rangeObj, hostTypes)
count, err = getAdminGeneralUsage(userCred, rangeObj, hostTypes, providers)
if err != nil {
return
}
@@ -303,7 +350,7 @@ func ReportGeneralUsage(userCred mcclient.TokenCredential, rangeObj db.IStandalo
if includeCommon {
var commonUsage map[string]interface{}
commonUsage, err = getCommonGeneralUsage(userCred, rangeObj, hostTypes)
commonUsage, err = getCommonGeneralUsage(userCred, rangeObj, hostTypes, providers)
if err != nil {
return
}
@@ -312,29 +359,68 @@ func ReportGeneralUsage(userCred mcclient.TokenCredential, rangeObj db.IStandalo
return
}
func ZoneUsage() Usage {
func RegionUsage(providers []string) Usage {
q := models.CloudregionManager.Query()
if len(providers) > 0 {
q = q.In("provider", providers)
}
count := make(map[string]interface{})
count["zones"] = models.ZoneManager.Count()
count["regions"] = q.Count()
return count
}
func StorageUsage(rangeObj db.IStandaloneModel, hostTypes []string) Usage {
func ZoneUsage(providers []string) Usage {
regions := models.CloudregionManager.Query().SubQuery()
subq := regions.Query(regions.Field("id"))
if len(providers) > 0 {
subq = subq.In("provider", providers)
}
q := models.ZoneManager.Query().In("cloudregion_id", subq.SubQuery())
count := make(map[string]interface{})
count["zones"] = q.Count()
return count
}
func VpcUsage(providers []string) Usage {
regions := models.CloudregionManager.Query().SubQuery()
subq := regions.Query(regions.Field("id"))
if len(providers) > 0 {
subq = subq.In("provider", providers)
}
q := models.VpcManager.Query().In("cloudregion_id", subq.SubQuery())
count := make(map[string]interface{})
count["vpcs"] = q.Count()
return count
}
func StorageUsage(prefix string, rangeObj db.IStandaloneModel, hostTypes []string, resourceTypes []string, providers []string) Usage {
sPrefix := "storages"
dPrefix := "all.disks"
if len(prefix) > 0 {
sPrefix = fmt.Sprintf("%s.%s", sPrefix, prefix)
dPrefix = fmt.Sprintf("%s.%s", dPrefix, prefix)
}
count := make(map[string]interface{})
result := models.StorageManager.TotalCapacity(rangeObj, hostTypes)
result := models.StorageManager.TotalCapacity(rangeObj, hostTypes, resourceTypes, providers)
count[sPrefix] = result.Capacity
count[fmt.Sprintf("%s.virtual", sPrefix)] = result.CapacityVirtual
count[dPrefix] = result.CapacityUsed
count[fmt.Sprintf("%s.unready", dPrefix)] = result.CapacityUnread
count[fmt.Sprintf("%s.unready", dPrefix)] = result.CapacityUnready
count[fmt.Sprintf("%s.attached", dPrefix)] = result.AttachedCapacity
count[fmt.Sprintf("%s.detached", dPrefix)] = result.DetachedCapacity
storageCmtRate := 0.0
if result.Capacity > 0 {
storageCmtRate = utils.FloatRound(float64(result.CapacityUsed)/float64(result.Capacity), 2)
}
count[fmt.Sprintf("%s.commit_rate", sPrefix)] = storageCmtRate
return count
}
func WireUsage(rangeObj db.IStandaloneModel, hostTypes []string) Usage {
func WireUsage(rangeObj db.IStandaloneModel, hostTypes []string, providers []string) Usage {
count := make(map[string]interface{})
result := models.WireManager.TotalCount(rangeObj, hostTypes)
result := models.WireManager.TotalCount(rangeObj, hostTypes, providers)
count["wires"] = result.WiresCount
count["networks"] = result.NetCount
count["all.nics.guest"] = result.GuestNicCount
@@ -343,27 +429,36 @@ func WireUsage(rangeObj db.IStandaloneModel, hostTypes []string) Usage {
return count
}
func NetworkUsage(userCred mcclient.TokenCredential, rangeObj db.IStandaloneModel) Usage {
func NetworkUsage(userCred mcclient.TokenCredential, providers []string, rangeObj db.IStandaloneModel) Usage {
count := make(map[string]interface{})
ret := models.NetworkManager.TotalPortCount(userCred, rangeObj)
ret := models.NetworkManager.TotalPortCount(userCred, providers, rangeObj)
count["ports"] = ret.Count
count["ports_exit"] = ret.CountExt
return count
}
func HostAllUsage(userCred mcclient.TokenCredential, rangeObj db.IStandaloneModel, hostTypes []string) Usage {
func HostAllUsage(pref string, userCred mcclient.TokenCredential, rangeObj db.IStandaloneModel,
hostTypes []string, resourceTypes []string, providers []string) Usage {
prefix := "hosts"
return hostUsage(userCred, prefix, rangeObj, hostTypes, tristate.None, tristate.None)
if len(pref) > 0 {
prefix = fmt.Sprintf("%s.%s", prefix, pref)
}
return hostUsage(userCred, prefix, rangeObj, hostTypes, resourceTypes, providers, tristate.None, tristate.None)
}
func HostEnabledUsage(userCred mcclient.TokenCredential, rangeObj db.IStandaloneModel, hostTypes []string) Usage {
func HostEnabledUsage(pref string, userCred mcclient.TokenCredential, rangeObj db.IStandaloneModel,
hostTypes []string, resourceTypes []string, providers []string) Usage {
prefix := "enabled_hosts"
return hostUsage(userCred, prefix, rangeObj, hostTypes, tristate.True, tristate.None)
if len(pref) > 0 {
prefix = fmt.Sprintf("%s.%s", prefix, pref)
}
return hostUsage(userCred, prefix, rangeObj, hostTypes, resourceTypes, providers, tristate.True, tristate.None)
}
func BaremetalUsage(userCred mcclient.TokenCredential, rangeObj db.IStandaloneModel, hostTypes []string) Usage {
func BaremetalUsage(userCred mcclient.TokenCredential, rangeObj db.IStandaloneModel,
hostTypes []string, providers []string) Usage {
prefix := "baremetals"
count := hostUsage(userCred, prefix, rangeObj, hostTypes, tristate.None, tristate.True)
count := hostUsage(userCred, prefix, rangeObj, hostTypes, nil, providers, tristate.None, tristate.True)
delete(count, fmt.Sprintf("%s.memory.virtual", prefix))
delete(count, fmt.Sprintf("%s.cpu.virtual", prefix))
return count
@@ -372,11 +467,12 @@ func BaremetalUsage(userCred mcclient.TokenCredential, rangeObj db.IStandaloneMo
func hostUsage(
userCred mcclient.TokenCredential, prefix string,
rangeObj db.IStandaloneModel, hostTypes []string,
resourceTypes []string, providers []string,
enabled, isBaremetal tristate.TriState,
) Usage {
count := make(map[string]interface{})
result := models.HostManager.TotalCount(userCred, rangeObj, "", "", hostTypes, enabled, isBaremetal)
result := models.HostManager.TotalCount(userCred, rangeObj, "", "", hostTypes, resourceTypes, providers, enabled, isBaremetal)
count[prefix] = result.Count
count[fmt.Sprintf("%s.memory", prefix)] = result.Memory
count[fmt.Sprintf("%s.cpu", prefix)] = result.CPU
@@ -386,38 +482,35 @@ func hostUsage(
return count
}
func GuestNormalUsage(prefix string, cred mcclient.TokenCredential, rangeObj db.IStandaloneModel, hostTypes []string) Usage {
return guestUsage(prefix, cred, rangeObj, hostTypes, nil, false)
func GuestNormalUsage(prefix string, cred mcclient.TokenCredential, rangeObj db.IStandaloneModel, hostTypes []string, resourceTypes []string, providers []string) Usage {
return guestUsage(prefix, cred, rangeObj, hostTypes, resourceTypes, providers, nil, false)
}
func GuestPendingDeleteUsage(prefix string, cred mcclient.TokenCredential, rangeObj db.IStandaloneModel, hostTypes []string) Usage {
return guestUsage(prefix, cred, rangeObj, hostTypes, nil, true)
func GuestPendingDeleteUsage(prefix string, cred mcclient.TokenCredential, rangeObj db.IStandaloneModel, hostTypes []string, resourceTypes []string, providers []string) Usage {
return guestUsage(prefix, cred, rangeObj, hostTypes, resourceTypes, providers, nil, true)
}
func GuestRunningUsage(prefix string, cred mcclient.TokenCredential, rangeObj db.IStandaloneModel, hostTypes []string) Usage {
return guestUsage(prefix, cred, rangeObj, hostTypes, []string{models.VM_RUNNING}, false)
func GuestRunningUsage(prefix string, cred mcclient.TokenCredential, rangeObj db.IStandaloneModel, hostTypes []string, resourceTypes []string, providers []string) Usage {
return guestUsage(prefix, cred, rangeObj, hostTypes, resourceTypes, providers, []string{models.VM_RUNNING}, false)
}
func GuestReadyUsage(prefix string, cred mcclient.TokenCredential, rangeObj db.IStandaloneModel, hostTypes []string) Usage {
return guestUsage(prefix, cred, rangeObj, hostTypes, []string{models.VM_READY}, false)
func GuestReadyUsage(prefix string, cred mcclient.TokenCredential, rangeObj db.IStandaloneModel, hostTypes []string, resourceTypes []string, providers []string) Usage {
return guestUsage(prefix, cred, rangeObj, hostTypes, resourceTypes, providers, []string{models.VM_READY}, false)
}
func guestHypervisorsUsage(
prefix string,
userCred mcclient.TokenCredential,
rangeObj db.IStandaloneModel,
hostTypes, status, hypervisors []string,
hostTypes []string, resourceTypes []string, providers []string,
status, hypervisors []string,
pendingDelete bool,
) Usage {
hostType := ""
if len(hostTypes) != 0 {
hostType = hostTypes[0]
}
projectId := ""
if userCred != nil {
projectId = userCred.GetProjectId()
}
guest := models.GuestManager.TotalCount(projectId, rangeObj, status, hypervisors, true, pendingDelete, hostType)
guest := models.GuestManager.TotalCount(projectId, rangeObj, status, hypervisors, true, pendingDelete, hostTypes, resourceTypes, providers)
count := make(map[string]interface{})
count[prefix] = guest.TotalGuestCount
count[fmt.Sprintf("%s.cpu", prefix)] = guest.TotalCpuCount
@@ -430,34 +523,60 @@ func guestHypervisorsUsage(
count[fmt.Sprintf("%s.disk", prefix)] = guest.TotalDiskSize
count[fmt.Sprintf("%s.isolated_devices", prefix)] = guest.TotalIsolatedCount
count[fmt.Sprintf("%s.ha", prefix)] = guest.TotalBackupGuestCount
count[fmt.Sprintf("%s.ha.cpu", prefix)] = guest.TotalBackupCpuCount
count[fmt.Sprintf("%s.ha.memory", prefix)] = guest.TotalBackupMemSize
count[fmt.Sprintf("%s.ha.disk", prefix)] = guest.TotalBackupDiskSize
return count
}
func guestUsage(prefix string, userCred mcclient.TokenCredential, rangeObj db.IStandaloneModel, hostTypes, status []string, pendingDelete bool) Usage {
func guestUsage(prefix string, userCred mcclient.TokenCredential, rangeObj db.IStandaloneModel,
hostTypes []string, resourceTypes []string, providers []string,
status []string, pendingDelete bool) Usage {
hypervisors := sets.NewString(models.HYPERVISORS...)
hypervisors.Delete(models.HYPERVISOR_CONTAINER)
return guestHypervisorsUsage(prefix, userCred, rangeObj, hostTypes, status, hypervisors.List(), pendingDelete)
return guestHypervisorsUsage(prefix, userCred, rangeObj, hostTypes, resourceTypes, providers, status, hypervisors.List(), pendingDelete)
}
func containerUsage(prefix string, userCred mcclient.TokenCredential, rangeObj db.IStandaloneModel) Usage {
func containerUsage(prefix string, userCred mcclient.TokenCredential, rangeObj db.IStandaloneModel,
hostTypes []string, resourceTypes []string, providers []string) Usage {
hypervisors := []string{models.HYPERVISOR_CONTAINER}
return guestHypervisorsUsage(prefix, userCred, rangeObj, nil, nil, hypervisors, false)
return guestHypervisorsUsage(prefix, userCred, rangeObj, hostTypes, resourceTypes, providers, nil, hypervisors, false)
}
func IsolatedDeviceUsage(rangeObj db.IStandaloneModel, hostType []string) Usage {
func IsolatedDeviceUsage(pref string, rangeObj db.IStandaloneModel, hostType []string, resourceTypes []string, providers []string) Usage {
prefix := "isolated_devices"
ret := models.IsolatedDeviceManager.TotalCount(hostType, rangeObj)
if len(pref) > 0 {
prefix = fmt.Sprintf("%s.%s", prefix, pref)
}
ret := models.IsolatedDeviceManager.TotalCount(hostType, resourceTypes, providers, rangeObj)
count := make(map[string]interface{})
count[prefix] = ret.Devices
return count
}
func EipUsage(rangeObj db.IStandaloneModel, hostTypes []string) Usage {
eipUsage := models.ElasticipManager.TotalCount("", rangeObj, hostTypes)
func getKey(projectId, key string) string {
if len(projectId) > 0 {
return key
} else {
return fmt.Sprintf("all.%s", key)
}
}
func EipUsage(projectId string, rangeObj db.IStandaloneModel, providers []string) Usage {
eipUsage := models.ElasticipManager.TotalCount(projectId, rangeObj, providers)
count := make(map[string]interface{})
count["eip.all"] = eipUsage.Total()
count["eip.public_ip"] = eipUsage.PublicIPCount
count["eip.floating_ip"] = eipUsage.EIPCount
count["eip.floating_ip.used"] = eipUsage.EIPUsedCount
count[getKey(projectId, "eip")] = eipUsage.Total()
count[getKey(projectId, "eip.public_ip")] = eipUsage.PublicIPCount
count[getKey(projectId, "eip.floating_ip")] = eipUsage.EIPCount
count[getKey(projectId, "eip.floating_ip.used")] = eipUsage.EIPUsedCount
return count
}
func SnapshotUsage(projectId string, rangeObj db.IStandaloneModel, providers []string) Usage {
cnt := models.TotalSnapshotCount(projectId, rangeObj, providers)
count := make(map[string]interface{})
count[getKey(projectId, "snapshot")] = cnt
return count
}
+1
View File
@@ -0,0 +1 @@
package lbagent // import "yunion.io/x/onecloud/pkg/lbagent"
+1
View File
@@ -0,0 +1 @@
package gobetween // import "yunion.io/x/onecloud/pkg/lbagent/gobetween"
+1
View File
@@ -0,0 +1 @@
package models // import "yunion.io/x/onecloud/pkg/lbagent/models"
+1
View File
@@ -0,0 +1 @@
package utils // import "yunion.io/x/onecloud/pkg/lbagent/utils"
+1
View File
@@ -0,0 +1 @@
package models // import "yunion.io/x/onecloud/pkg/mcclient/models"
+1 -1
View File
@@ -30,7 +30,7 @@ func init() {
"Memory_size_mb", "Os_name", "Sys_disk_resizable", "Sys_disk_type",
"Sys_disk_min_size_mb", "Sys_disk_max_size_mb", "Attached_disk_type",
"Attached_disk_size_gb", "Attached_disk_count", "Data_disk_types",
"Data_disk_max_count", "Nic_max_count", "Cloudregion_id", "Zone_id"},
"Data_disk_max_count", "Nic_max_count", "Cloudregion_id", "Zone_id", "Provider"},
[]string{})}
register(&CloudmetaSkus)
+1
View File
@@ -0,0 +1 @@
package options // import "yunion.io/x/onecloud/pkg/mcclient/options"
+1
View File
@@ -0,0 +1 @@
package k8s // import "yunion.io/x/onecloud/pkg/mcclient/options/k8s"
+5 -4
View File
@@ -3,10 +3,11 @@ package options
import "yunion.io/x/jsonutils"
type ScheduleOptions struct {
Zone string `help:"Preferred zone where virtual server should be created" json:"prefer_zone"`
Host string `help:"Preferred host where virtual server should be created" json:"prefer_host"`
Schedtag []string `help:"Schedule policy, key = aggregate name, value = require|exclude|prefer|avoid" metavar:"<KEY:VALUE>"`
Hypervisor string `help:"Hypervisor type" choices:"kvm|esxi|baremetal|container|aliyun|azure|qcloud|aws"`
Zone string `help:"Preferred zone where virtual server should be created" json:"prefer_zone"`
Host string `help:"Preferred host where virtual server should be created" json:"prefer_host"`
Schedtag []string `help:"Schedule policy, key = aggregate name, value = require|exclude|prefer|avoid" metavar:"<KEY:VALUE>"`
Hypervisor string `help:"Hypervisor type" choices:"kvm|esxi|baremetal|container|aliyun|azure|qcloud|aws|huawei"`
ResourceType string `help:"Resource type" choices:"shared|prepaid|dedicated"`
}
func (opts *ScheduleOptions) Params() (*jsonutils.JSONDict, error) {
+14 -2
View File
@@ -24,6 +24,10 @@ type ServerListOptions struct {
WithEip *bool `help:"Show Servers with EIP"`
WithoutEip *bool `help:"Show Servers without EIP"`
ResourceType string `help:"Resource type" choices:"shared|prepaid|dedicated"`
BillingType string `help:"billing type" choices:"postpaid|prepaid"`
BaseListOptions
}
@@ -90,8 +94,9 @@ func ParseServerDeployInfoList(list []string) (*jsonutils.JSONDict, error) {
type ServerCreateOptions struct {
ScheduleOptions
NAME string `help:"Name of server"`
MEM string `help:"Memory size" metavar:"MEMORY" json:"vmem_size"`
NAME string `help:"Name of server" json:"-"`
MEMSPEC string `help:"Memory size Or Instance Type" metavar:"MEMSPEC" json:"-"`
Disk []string `help:"Disk descriptions" nargs:"+"`
Net []string `help:"Network descriptions" metavar:"NETWORK"`
IsolatedDevice []string `help:"Isolated device model or ID" metavar:"ISOLATED_DEVICE"`
@@ -120,6 +125,10 @@ type ServerCreateOptions struct {
DryRun *bool `help:"Dry run to test scheduler" json:"-"`
RaidConfig []string `help:"Baremetal raid config" json:"-"`
UserDataFile string `help:"user_data file path" json:"-"`
Duration string `help:"valid duration of the server, e.g. 1H, 1D, 1W, 1M, 1Y, ADMIN ONLY option"`
GenerateName bool `help:"name is generated by pattern" json:"-"`
}
func (opts *ServerCreateOptions) Params() (*jsonutils.JSONDict, error) {
@@ -283,6 +292,7 @@ type ServerRebuildRootOptions struct {
Password string `help:"Default user password"`
NoAccountInit *bool `help:"Not reset account password"`
AutoStart *bool `help:"Auto start server after it is created"`
AllDisks *bool `help:"Rebuild all disks including data disks"`
}
type ServerChangeConfigOptions struct {
@@ -290,6 +300,8 @@ type ServerChangeConfigOptions struct {
Ncpu *int `help:"New number of Virtual CPU cores" json:"vcpu_count"`
Vmem string `help:"New memory size" json:"vmem_size"`
Disk []string `help:"Data disk description, from the 1st data disk to the last one, empty string if no change for this data disk"`
InstanceType string `help:"Instance Type, e.g. S2.SMALL2 for qcloud"`
}
type ServerResetOptions struct {
@@ -24,6 +24,7 @@ const (
ErrNoMoreSpaceForUnspecificSplit = `no more space for an unspecific split`
ErrSubtotalOfSplitExceedsDiskSize = `subtotal of split exceeds disk size`
ErrBaremetalHasAlreadyBeenOccupied = `baremetal has already been occupied`
ErrPrepaidHostOccupied = `prepaid host occupied`
ErrUnknown = `unknown error`
)
@@ -0,0 +1 @@
package k8s // import "yunion.io/x/onecloud/pkg/scheduler/algorithm/predicates/k8s"
@@ -0,0 +1,48 @@
package predicates
import (
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/scheduler/core"
)
type ResourceTypePredicate struct {
BasePredicate
}
func (p *ResourceTypePredicate) Name() string {
return "resource_type"
}
func (p *ResourceTypePredicate) Clone() core.FitPredicate {
return &ResourceTypePredicate{}
}
func (p *ResourceTypePredicate) PreExecute(u *core.Unit, cs []core.Candidater) (bool, error) {
if u.SchedData().ResourceType == "" {
return false, nil
}
return true, nil
}
func (p *ResourceTypePredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core.PredicateFailureReason, error) {
h := NewPredicateHelper(p, u, c)
d := u.SchedData()
hostResType := c.GetResourceType()
reqResType := d.ResourceType
if hostResType != reqResType {
h.Exclude2("resource_type", hostResType, reqResType)
}
if hostResType == models.HostResourceTypePrepaidRecycle {
if c.GetGuestCount() == 0 {
h.SetCapacity(1)
} else {
h.Exclude(ErrPrepaidHostOccupied)
}
}
// TODO: support HostResourceTypeDedicated
return h.GetResult()
}
@@ -20,5 +20,6 @@ func baremetalPredicates() sets.String {
factory.RegisterFitPredicate("d-BaremetalMemoryFilter", &predicatebm.MemoryPredicate{}),
factory.RegisterFitPredicate("e-BaremetalStorageFilter", &predicatebm.StoragePredicate{}),
factory.RegisterFitPredicate("f-BaremetalNetFilter", &predicatebm.NetworkPredicate{}),
factory.RegisterFitPredicate("g-BaremetalResourceTypeFilter", &predicates.ResourceTypePredicate{}),
)
}
@@ -25,6 +25,7 @@ func defaultPredicates() sets.String {
factory.RegisterFitPredicate("i-GuestStorageFilter", &predicateguest.StoragePredicate{}),
factory.RegisterFitPredicate("j-GuestNetworkFilter", &predicateguest.NetworkPredicate{}),
factory.RegisterFitPredicate("k-GuestIsolatedDeviceFilter", &predicateguest.IsolatedDevicePredicate{}),
factory.RegisterFitPredicate("l-GuestResourceTypeFilter", &predicates.ResourceTypePredicate{}),
)
}
+8 -1
View File
@@ -13,6 +13,7 @@ import (
o "yunion.io/x/onecloud/cmd/scheduler/options"
"yunion.io/x/onecloud/pkg/compute/baremetal"
"yunion.io/x/onecloud/pkg/compute/models"
)
type Meta map[string]string
@@ -94,6 +95,7 @@ type SchedData struct {
ForGuests []*ForGuest `json:"for_guests"`
GuestStatus string `json:"guest_status"`
Hypervisor string `json:"hypervisor"`
ResourceType string `json:"resource_type"`
// VM
Groups []string `json:"group"`
@@ -168,6 +170,10 @@ func NewSchedData(sjson *simplejson.Json, count int64, byTest bool) (*SchedData,
}
}
if resourceType, ok := sjson.CheckGet("resource_type"); ok {
data.ResourceType = resourceType.MustString()
}
data.Candidates = candidates
err := data.reviseSchedType(sjson)
@@ -263,7 +269,8 @@ func (s *SchedData) reviseSchedType(sjson *simplejson.Json) error {
}
func (d *SchedData) SkipDirtyMarkHost() bool {
skipByHypervisor := d.IsPublicCloudProvider() || d.IsContainer || d.Hypervisor == SchedTypeContainer
isSharePublicCloudProvider := d.IsPublicCloudProvider() && (d.ResourceType == "" || d.ResourceType == models.HostResourceTypeShared)
skipByHypervisor := isSharePublicCloudProvider || d.IsContainer || d.Hypervisor == SchedTypeContainer
skipByBackup := d.Backup
return skipByHypervisor || skipByBackup
}
+3 -10
View File
@@ -4,6 +4,8 @@ import (
"fmt"
"yunion.io/x/pkg/util/sets"
"yunion.io/x/onecloud/pkg/compute/models"
)
const (
@@ -16,10 +18,6 @@ const (
SchedTypeHyperV = "hyperv"
SchedTypeKvm = "kvm"
HostHypervisorForKvm = "hypervisor"
HostTypeAliyun = "aliyun"
HostTypeAzure = "azure"
HostTypeAws = "aws"
HostTypeQcloud = "qcloud"
HostTypeKubelet = "kubelet"
AggregateStrategyRequire = "require"
@@ -49,12 +47,7 @@ var (
AggregateStrategyAvoid,
)
PublicCloudProviders = sets.NewString(
HostTypeAliyun,
HostTypeAzure,
HostTypeAws,
HostTypeQcloud,
)
PublicCloudProviders = sets.NewString(models.PUBLIC_CLOUD_HYPERVISORS...)
ValidGpuTypes = sets.NewString(
GPU_HPC_TYPE,
+7
View File
@@ -104,6 +104,13 @@ func (bd *BaremetalDesc) Get(key string) interface{} {
}
}
func (bd *BaremetalDesc) GetGuestCount() int64 {
if bd.ServerID == "" {
return 0
}
return 1
}
func (bd *BaremetalDesc) XGet(key string, kind core.Kind) interface{} {
return core.XGetCalculator(bd, key, kind)
}
+29 -10
View File
@@ -8,6 +8,7 @@ import (
"yunion.io/x/log"
"yunion.io/x/pkg/utils"
cloudmodels "yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/scheduler/api"
"yunion.io/x/onecloud/pkg/scheduler/db/models"
)
@@ -24,6 +25,7 @@ func (b *baseDesc) UUID() string {
type baseHostDesc struct {
baseDesc
models.BillingResourceBase
ManagerID *string `json:"manager_id"`
Status string `json:"status"`
@@ -44,6 +46,15 @@ type baseHostDesc struct {
Aggregates []*models.Aggregate `json:"aggregates"`
HostAggregates []*models.Aggregate `json:"host_aggregates"`
Cloudprovider *models.Cloudprovider `json:"cloudprovider"`
ResourceType string `json:"resource_type"`
RealExternalId string `json:"real_external_id"`
}
func reviseResourceType(resType string) string {
if resType == "" {
return cloudmodels.HostResourceTypeDefault
}
return resType
}
func newBaseHostDesc(host *models.Host) (*baseHostDesc, error) {
@@ -53,16 +64,19 @@ func newBaseHostDesc(host *models.Host) (*baseHostDesc, error) {
Name: host.Name,
UpdatedAt: host.UpdatedAt,
},
ManagerID: host.ManagerID,
Status: host.Status,
CPUCount: host.CPUCount,
MemSize: host.MemSize,
HostStatus: host.HostStatus,
Enabled: host.Enabled,
HostType: host.HostType,
IsBaremetal: host.IsBaremetal,
NodeCount: host.NodeCount,
IsMaintenance: host.IsMaintenance,
BillingResourceBase: host.BillingResourceBase,
ManagerID: host.ManagerID,
Status: host.Status,
CPUCount: host.CPUCount,
MemSize: host.MemSize,
HostStatus: host.HostStatus,
Enabled: host.Enabled,
HostType: host.HostType,
IsBaremetal: host.IsBaremetal,
NodeCount: host.NodeCount,
IsMaintenance: host.IsMaintenance,
ResourceType: reviseResourceType(host.ResourceType),
RealExternalId: host.RealExternalId,
}
if err := desc.fillCloudProvider(host); err != nil {
@@ -97,6 +111,7 @@ func (b baseHostDesc) GetSchedDesc() *jsonutils.JSONDict {
desc.Add(jsonutils.NewString(b.HostType), "host_type")
desc.Add(jsonutils.NewString(b.ZoneID), "zone_id")
desc.Add(jsonutils.NewString(b.Zone), "zone")
desc.Add(jsonutils.NewString(b.ResourceType), "resource_type")
if b.Cloudprovider != nil {
p := b.Cloudprovider
@@ -109,6 +124,10 @@ func (b baseHostDesc) GetSchedDesc() *jsonutils.JSONDict {
return desc
}
func (b baseHostDesc) GetResourceType() string {
return b.ResourceType
}
func (b *baseHostDesc) fillCloudProvider(host *models.Host) error {
if host.ManagerID == nil {
log.Debugf("Host %q manager id is empty, no cloud provider", host.Name)
+5 -1
View File
@@ -224,6 +224,10 @@ func (h *HostDesc) Type() int {
return 0
}
func (h *HostDesc) GetGuestCount() int64 {
return h.GuestCount
}
func (h *HostDesc) Get(key string) interface{} {
switch key {
case "ID":
@@ -953,7 +957,7 @@ func (b *HostBuilder) build() ([]interface{}, error) {
if len(errs) > 0 {
//return nil, errors.NewAggregate(errs)
err := errors.NewAggregate(errs)
log.Warningf("Build schedule descs error: %s", err)
log.V(4).Warningf("Build schedule descs error: %s", err)
}
return schedDescs, nil
+1
View File
@@ -7,6 +7,7 @@ import (
"sync"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/scheduler/api"
)
+2
View File
@@ -49,6 +49,8 @@ type Candidater interface {
GetHostAggregates() []*models.Aggregate
GetSchedDesc() *jsonutils.JSONDict
GetGuestCount() int64
GetResourceType() string
}
// HostPriority represents the priority of scheduling to particular host, higher priority is better.
+11
View File
@@ -0,0 +1,11 @@
package models
import (
"time"
)
type BillingResourceBase struct {
BillingType string `json:"billing_type" gorm:"column:billing_type"`
ExpiredAt time.Time `json:"expired_at" gorm:"column:expired_at;type:datetime"`
BillingCycle string `json:"billing_cycle" gorm:"column:billing_cycle"`
}
+4
View File
@@ -20,6 +20,7 @@ var (
type Host struct {
StandaloneModel
BillingResourceBase
Rack string `json:"rack,omitempty" gorm:"column:rack"`
Slots string `json:"slots,omitempty" gorm:"column:slots"`
@@ -57,6 +58,9 @@ type Host struct {
ManagerID *string `json:"manager_id" gorm:"column:manager_id"`
IsMaintenance bool `json:"is_maintenance" gorm:"column:is_maintenance"`
ResourceType string `json:"resource_type" gorm:"column:resource_type"`
RealExternalId string `json:"real_external_id" gorm:"column:real_external_id;type:varchar(256) CHARACTER SET utf8"`
// DECAPITATE
ClusterID string `json:"cluster_id" gorm:"column:cluster_id"`
PoolID string `json:"pool_id,omitempty" gorm:"column:pool_id"`
+23
View File
@@ -389,3 +389,26 @@ func (self *SDisk) GetExpiredAt() time.Time {
func (self *SDisk) GetAccessPath() string {
return ""
}
func (self *SDisk) Rebuild(ctx context.Context) error {
err := self.storage.zone.region.rebuildDisk(self.DiskId)
if err != nil {
if isError(err, "IncorrectInstanceStatus") {
return nil
}
log.Errorf("rebuild disk fail %s", err)
return err
}
return nil
}
func (self *SRegion) rebuildDisk(diskId string) error {
params := make(map[string]string)
params["DiskId"] = diskId
_, err := self.ecsRequest("ReInitDisk", params)
if err != nil {
log.Errorf("ReInitDisk %s fail %s", diskId, err)
return err
}
return nil
}
+11 -9
View File
@@ -7,6 +7,7 @@ import (
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/billing"
)
type SHost struct {
@@ -166,8 +167,9 @@ func (self *SHost) GetInstanceById(instanceId string) (*SInstance, error) {
func (self *SHost) CreateVM(name string, imgId string, sysDiskSize int, cpu int, memMB int,
vswitchId string, ipAddr string, desc string, passwd string,
storageType string, diskSizes []int, publicKey string, secgroupId string, userData string) (cloudprovider.ICloudVM, error) {
vmId, err := self._createVM(name, imgId, sysDiskSize, cpu, memMB, "", vswitchId, ipAddr, desc, passwd, storageType, diskSizes, publicKey, secgroupId, userData)
storageType string, diskSizes []int, publicKey string, secgroupId string, userData string,
bc *billing.SBillingCycle) (cloudprovider.ICloudVM, error) {
vmId, err := self._createVM(name, imgId, sysDiskSize, cpu, memMB, "", vswitchId, ipAddr, desc, passwd, storageType, diskSizes, publicKey, secgroupId, userData, bc)
if err != nil {
return nil, err
}
@@ -181,8 +183,9 @@ func (self *SHost) CreateVM(name string, imgId string, sysDiskSize int, cpu int,
func (self *SHost) CreateVM2(name string, imgId string, sysDiskSize int, instanceType string,
vswitchId string, ipAddr string, desc string, passwd string,
storageType string, diskSizes []int, publicKey string, secgroupId string, userData string) (cloudprovider.ICloudVM, error) {
vmId, err := self._createVM(name, imgId, sysDiskSize, 0, 0, instanceType, vswitchId, ipAddr, desc, passwd, storageType, diskSizes, publicKey, secgroupId, userData)
storageType string, diskSizes []int, publicKey string, secgroupId string,
userData string, bc *billing.SBillingCycle) (cloudprovider.ICloudVM, error) {
vmId, err := self._createVM(name, imgId, sysDiskSize, 0, 0, instanceType, vswitchId, ipAddr, desc, passwd, storageType, diskSizes, publicKey, secgroupId, userData, bc)
if err != nil {
return nil, err
}
@@ -197,7 +200,7 @@ func (self *SHost) CreateVM2(name string, imgId string, sysDiskSize int, instanc
func (self *SHost) _createVM(name string, imgId string, sysDiskSize int, cpu int, memMB int, instanceType string,
vswitchId string, ipAddr string, desc string, passwd string,
storageType string, diskSizes []int, publicKey string, secgroupId string,
userData string) (string, error) {
userData string, bc *billing.SBillingCycle) (string, error) {
net := self.zone.getNetworkById(vswitchId)
if net == nil {
return "", fmt.Errorf("invalid switch ID %s", vswitchId)
@@ -249,13 +252,12 @@ func (self *SHost) _createVM(name string, imgId string, sysDiskSize int, cpu int
if len(instanceType) > 0 {
log.Debugf("Try instancetype : %s", instanceType)
vmId, err := self.zone.region.CreateInstance(name, imgId, instanceType, secgroupId, self.zone.ZoneId, desc, passwd, disks, vswitchId, ipAddr, keypair, userData)
vmId, err := self.zone.region.CreateInstance(name, imgId, instanceType, secgroupId, self.zone.ZoneId, desc, passwd, disks, vswitchId, ipAddr, keypair, userData, bc)
if err != nil {
log.Errorf("Failed for %s: %s", instanceType, err)
return "", fmt.Errorf("Failed to create, specification %s not supported", instanceType)
} else {
return vmId, nil
}
return vmId, nil
}
instanceTypes, err := self.zone.region.GetMatchInstanceTypes(cpu, memMB, 0, self.zone.ZoneId)
@@ -269,7 +271,7 @@ func (self *SHost) _createVM(name string, imgId string, sysDiskSize int, cpu int
for _, instType := range instanceTypes {
instanceTypeId := instType.InstanceTypeId
log.Debugf("Try instancetype : %s", instanceTypeId)
vmId, err := self.zone.region.CreateInstance(name, imgId, instanceTypeId, secgroupId, self.zone.ZoneId, desc, passwd, disks, vswitchId, ipAddr, keypair, userData)
vmId, err := self.zone.region.CreateInstance(name, imgId, instanceTypeId, secgroupId, self.zone.ZoneId, desc, passwd, disks, vswitchId, ipAddr, keypair, userData, bc)
if err != nil {
log.Errorf("Failed for %s: %s", instanceTypeId, err)
} else {
+73 -3
View File
@@ -12,8 +12,10 @@ import (
"context"
"sort"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/billing"
)
const (
@@ -268,6 +270,29 @@ func (self *SInstance) getVpc() (*SVpc, error) {
return self.host.zone.region.getVpc(self.VpcAttributes.VpcId)
}
type byAttachedTime []SDisk
func (a byAttachedTime) Len() int { return len(a) }
func (a byAttachedTime) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byAttachedTime) Less(i, j int) bool {
switch a[i].GetDiskType() {
case models.DISK_TYPE_SYS:
return true
case models.DISK_TYPE_SWAP:
switch a[j].GetDiskType() {
case models.DISK_TYPE_SYS:
return false
case models.DISK_TYPE_DATA:
return true
}
case models.DISK_TYPE_DATA:
if a[j].GetDiskType() != models.DISK_TYPE_DATA {
return false
}
}
return a[i].AttachedTime.Before(a[j].AttachedTime)
}
func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
disks, total, err := self.host.zone.region.GetDisks(self.InstanceId, "", "", nil, 0, 50)
if err != nil {
@@ -277,6 +302,11 @@ func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
if total > len(disks) {
disks, _, err = self.host.zone.region.GetDisks(self.InstanceId, "", "", nil, 0, total)
}
sort.Sort(byAttachedTime(disks))
log.Debugf("%s", jsonutils.Marshal(&disks))
idisks := make([]cloudprovider.ICloudDisk, len(disks))
for i := 0; i < len(disks); i += 1 {
store, err := self.host.zone.getStorageByCategory(disks[i].Category)
@@ -499,7 +529,7 @@ func (self *SRegion) GetInstance(instanceId string) (*SInstance, error) {
func (self *SRegion) CreateInstance(name string, imageId string, instanceType string, securityGroupId string,
zoneId string, desc string, passwd string, disks []SDisk, vSwitchId string, ipAddr string,
keypair string, userData string) (string, error) {
keypair string, userData string, bc *billing.SBillingCycle) (string, error) {
params := make(map[string]string)
params["RegionId"] = self.RegionId
params["ImageId"] = imageId
@@ -535,8 +565,7 @@ func (self *SRegion) CreateInstance(name string, imageId string, instanceType st
}
params["VSwitchId"] = vSwitchId
params["PrivateIpAddress"] = ipAddr
params["InstanceChargeType"] = "PostPaid"
params["SpotStrategy"] = "NoSpot"
if len(keypair) > 0 {
params["KeyPairName"] = keypair
}
@@ -545,6 +574,21 @@ func (self *SRegion) CreateInstance(name string, imageId string, instanceType st
params["UserData"] = userData
}
if bc != nil {
params["InstanceChargeType"] = "PrePaid"
if bc.GetWeeks() <= 4 {
params["PeriodUnit"] = "Week"
params["Period"] = fmt.Sprintf("%d", bc.GetWeeks())
} else {
params["PeriodUnit"] = "Month"
params["Period"] = fmt.Sprintf("%d", bc.GetMonths())
}
params["AutoRenew"] = "False"
} else {
params["InstanceChargeType"] = "PostPaid"
params["SpotStrategy"] = "NoSpot"
}
params["ClientToken"] = utils.GenRequestId(20)
body, err := self.ecsRequest("CreateInstance", params)
@@ -620,6 +664,9 @@ func (self *SRegion) StopVM(instanceId string, isForce bool) error {
log.Errorf("Fail to get instance status on StopVM: %s", err)
return err
}
if status == InstanceStatusStopped {
return nil
}
if status != InstanceStatusRunning {
log.Errorf("StopVM: vm status is %s expect %s", status, InstanceStatusRunning)
return cloudprovider.ErrInvalidStatus
@@ -869,3 +916,26 @@ func (self *SInstance) UpdateUserData(userData string) error {
func (self *SInstance) CreateDisk(ctx context.Context, sizeMb int, uuid string, driver string) error {
return cloudprovider.ErrNotSupported
}
func (self *SInstance) Renew(bc billing.SBillingCycle) error {
return self.host.zone.region.RenewInstance(self.InstanceId, bc)
}
func (region *SRegion) RenewInstance(instanceId string, bc billing.SBillingCycle) error {
params := make(map[string]string)
params["InstanceId"] = instanceId
if bc.GetWeeks() <= 4 {
params["PeriodUnit"] = "Week"
params["Period"] = fmt.Sprintf("%s", bc.GetWeeks())
} else {
params["PeriodUnit"] = "Month"
params["Period"] = fmt.Sprintf("%s", bc.GetMonths())
}
params["ClientToken"] = utils.GenRequestId(20)
_, err := region.ecsRequest("RenewInstance", params)
if err != nil {
log.Errorf("RenewInstance fail %s", err)
return err
}
return nil
}
+1 -1
View File
@@ -433,7 +433,7 @@ func (self *SRegion) CreateInstanceSimple(name string, imgId string, cpu int, me
log.Debugf("Search in zone %s", z.LocalName)
net := z.getNetworkById(vswitchId)
if net != nil {
inst, err := z.getHost().CreateVM(name, imgId, 0, cpu, memGB*1024, vswitchId, "", "", passwd, storageType, dataDiskSizesGB, publicKey, "", "")
inst, err := z.getHost().CreateVM(name, imgId, 0, cpu, memGB*1024, vswitchId, "", "", passwd, storageType, dataDiskSizesGB, publicKey, "", "", nil)
if err != nil {
return nil, err
}
+7 -1
View File
@@ -396,7 +396,9 @@ func (self *SRegion) resetDisk(diskId, snapshotId string) error {
}
params := &ec2.CreateVolumeInput{}
params.SetSnapshotId(snapshotId)
if len(snapshotId) > 0 {
params.SetSnapshotId(snapshotId)
}
params.SetSize(int64(disk.Size))
params.SetVolumeType(disk.Category)
params.SetAvailabilityZone(disk.ZoneId)
@@ -465,3 +467,7 @@ func (self *SRegion) CreateDisk(zoneId string, category string, name string, siz
func (disk *SDisk) GetAccessPath() string {
return ""
}
func (self *SDisk) Rebuild(ctx context.Context) error {
return self.storage.zone.region.resetDisk(self.DiskId, "")
}
+1
View File
@@ -0,0 +1 @@
package aws // import "yunion.io/x/onecloud/pkg/util/aws"
+9 -3
View File
@@ -6,6 +6,7 @@ import (
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/billing"
)
type SHost struct {
@@ -56,7 +57,11 @@ func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) {
}
func (self *SHost) GetIVMById(gid string) (cloudprovider.ICloudVM, error) {
log.Debugf("GetIVMById %s", gid)
if len(gid) == 0 {
log.Errorf("GetIVMById guest id is empty")
return nil, cloudprovider.ErrNotFound
}
ivms, _, err := self.zone.region.GetInstances(self.zone.ZoneId, []string{gid}, 0, 1)
if err != nil {
return nil, err
@@ -155,7 +160,8 @@ func (self *SHost) GetInstanceById(instanceId string) (*SInstance, error) {
}
func (self *SHost) CreateVM(name, imgId string, sysDiskSize, cpu, memMB int, networkId, ipAddr, desc,
passwd, storageType string, diskSizes []int, publicKey string, secgroupId string, userData string) (cloudprovider.ICloudVM, error) {
passwd, storageType string, diskSizes []int, publicKey string, secgroupId string, userData string,
bc *billing.SBillingCycle) (cloudprovider.ICloudVM, error) {
vmId, err := self._createVM(name, imgId, sysDiskSize, cpu, memMB, "", networkId, ipAddr, desc, passwd, storageType, diskSizes, publicKey, secgroupId, userData)
if err != nil {
return nil, err
@@ -170,7 +176,7 @@ func (self *SHost) CreateVM(name, imgId string, sysDiskSize, cpu, memMB int, net
}
func (self *SHost) CreateVM2(name, imgId string, sysDiskSize int, instanceType string, networkId, ipAddr, desc,
passwd, storageType string, diskSizes []int, publicKey string, secgroupId string, userData string) (cloudprovider.ICloudVM, error) {
passwd, storageType string, diskSizes []int, publicKey string, secgroupId string, userData string, bc *billing.SBillingCycle) (cloudprovider.ICloudVM, error) {
vmId, err := self._createVM(name, imgId, sysDiskSize, 0, 0, instanceType, networkId, ipAddr, desc, passwd, storageType, diskSizes, publicKey, secgroupId, userData)
if err != nil {
return nil, err

Some files were not shown because too many files have changed in this diff Show More