| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package models
- import (
- "context"
- "fmt"
- "time"
- "yunion.io/x/jsonutils"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/util/rbacscope"
- "yunion.io/x/pkg/util/sets"
- "yunion.io/x/pkg/utils"
- "yunion.io/x/sqlchemy"
- "yunion.io/x/onecloud/pkg/apis"
- api "yunion.io/x/onecloud/pkg/apis/compute"
- computeapis "yunion.io/x/onecloud/pkg/apis/compute"
- "yunion.io/x/onecloud/pkg/cloudcommon/cmdline"
- "yunion.io/x/onecloud/pkg/cloudcommon/db"
- "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
- "yunion.io/x/onecloud/pkg/compute/options"
- "yunion.io/x/onecloud/pkg/httperrors"
- "yunion.io/x/onecloud/pkg/mcclient"
- "yunion.io/x/onecloud/pkg/mcclient/auth"
- "yunion.io/x/onecloud/pkg/mcclient/modules/image"
- "yunion.io/x/onecloud/pkg/util/logclient"
- "yunion.io/x/onecloud/pkg/util/stringutils2"
- )
- const (
- IMAGE_TYPE_NORMAL = "normal"
- IMAGE_TYPE_GUEST = "guest"
- )
- type SGuestTemplateManager struct {
- db.SSharableVirtualResourceBaseManager
- SCloudregionResourceBaseManager
- SVpcResourceBaseManager
- }
- type SGuestTemplate struct {
- db.SSharableVirtualResourceBase
- SCloudregionResourceBase
- SVpcResourceBase
- // 虚拟机CPU数量
- VcpuCount int `nullable:"false" default:"1" create:"optional" json:"vcpu_count"`
- // 虚拟机内存大小(MB)
- VmemSize int `nullable:"false" create:"optional" json:"vmem_size"`
- // 虚拟机操作系统类型
- // pattern:Linux|Windows|VMWare
- OsType string `width:"36" charset:"ascii" nullable:"true" create:"optional" json:"os_type" list:"user" get:"user"`
- // 镜像类型
- ImageType string `width:"10" charset:"ascii" nullabel:"true" default:"normal" create:"optional" json:"image_type"`
- // 镜像ID
- ImageId string `width:"128" charset:"ascii" create:"optional" json:"image_id"`
- // 虚拟机技术
- Hypervisor string `width:"16" charset:"ascii" default:"kvm" create:"optional" json:"hypervisor"`
- // 计费方式
- BillingType string `width:"16" charset:"ascii" default:"postpaid" create:"optional" list:"user" get:"user" json:"billing_type"`
- // 其他配置信息
- Content jsonutils.JSONObject `nullable:"false" list:"user" update:"user" create:"optional" json:"content"`
- LastCheckTime time.Time
- }
- var GuestTemplateManager *SGuestTemplateManager
- func init() {
- GuestTemplateManager = &SGuestTemplateManager{
- SSharableVirtualResourceBaseManager: db.NewSharableVirtualResourceBaseManager(
- SGuestTemplate{},
- "guesttemplates_tbl",
- "servertemplate",
- "servertemplates",
- ),
- }
- GuestTemplateManager.SetVirtualObject(GuestTemplateManager)
- }
- func (gtm *SGuestTemplateManager) ValidateCreateData(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- ownerId mcclient.IIdentityProvider,
- query jsonutils.JSONObject,
- input computeapis.GuestTemplateCreateInput,
- ) (computeapis.GuestTemplateCreateInput, error) {
- var err error
- if input.Content == nil {
- return input, httperrors.NewMissingParameterError("content")
- }
- if !input.Content.Contains("name") && !input.Content.Contains("generate_name") {
- input.Content.Set("generate_name", jsonutils.NewString(input.Name))
- }
- input.GuestTemplateInput, err = gtm.validateData(ctx, userCred, ownerId, query, input.GuestTemplateInput)
- if err != nil {
- return input, errors.Wrap(err, "gtm.validateData")
- }
- input.SharableVirtualResourceCreateInput, err = gtm.SSharableVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.SharableVirtualResourceCreateInput)
- if err != nil {
- return input, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ValidateCreateData")
- }
- return input, nil
- }
- func (gt *SGuestTemplate) PostCreate(ctx context.Context, userCred mcclient.TokenCredential,
- ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
- gt.SetStatus(ctx, userCred, computeapis.GT_READY, "")
- gt.updateCheckTime()
- logclient.AddActionLogWithContext(ctx, gt, logclient.ACT_CREATE, nil, userCred, true)
- }
- func (gt *SGuestTemplate) updateCheckTime() error {
- _, err := db.Update(gt, func() error {
- gt.LastCheckTime = time.Now()
- return nil
- })
- return err
- }
- func (gt *SGuestTemplate) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential,
- query jsonutils.JSONObject, data jsonutils.JSONObject) {
- logclient.AddActionLogWithContext(ctx, gt, logclient.ACT_UPDATE, nil, userCred, true)
- }
- var HypervisorBrandMap = map[string]string{
- computeapis.HYPERVISOR_KVM: computeapis.CLOUD_PROVIDER_ONECLOUD,
- computeapis.HYPERVISOR_ESXI: computeapis.CLOUD_PROVIDER_VMWARE,
- computeapis.HYPERVISOR_ALIYUN: computeapis.CLOUD_PROVIDER_ALIYUN,
- computeapis.HYPERVISOR_QCLOUD: computeapis.CLOUD_PROVIDER_QCLOUD,
- computeapis.HYPERVISOR_AZURE: computeapis.CLOUD_PROVIDER_AZURE,
- computeapis.HYPERVISOR_AWS: computeapis.CLOUD_PROVIDER_AWS,
- computeapis.HYPERVISOR_HUAWEI: computeapis.CLOUD_PROVIDER_HUAWEI,
- computeapis.HYPERVISOR_OPENSTACK: computeapis.CLOUD_PROVIDER_OPENSTACK,
- computeapis.HYPERVISOR_UCLOUD: computeapis.CLOUD_PROVIDER_UCLOUD,
- computeapis.HYPERVISOR_ZSTACK: computeapis.CLOUD_PROVIDER_ZSTACK,
- computeapis.HYPERVISOR_GOOGLE: computeapis.CLOUD_PROVIDER_GOOGLE,
- computeapis.HYPERVISOR_CTYUN: computeapis.CLOUD_PROVIDER_CTYUN,
- computeapis.HYPERVISOR_CNWARE: computeapis.CLOUD_PROVIDER_CNWARE,
- }
- var BrandHypervisorMap = map[string]string{
- computeapis.CLOUD_PROVIDER_ONECLOUD: computeapis.HYPERVISOR_KVM,
- computeapis.CLOUD_PROVIDER_VMWARE: computeapis.HYPERVISOR_ESXI,
- computeapis.CLOUD_PROVIDER_ALIYUN: computeapis.HYPERVISOR_ALIYUN,
- computeapis.CLOUD_PROVIDER_QCLOUD: computeapis.HYPERVISOR_QCLOUD,
- computeapis.CLOUD_PROVIDER_AZURE: computeapis.HYPERVISOR_AZURE,
- computeapis.CLOUD_PROVIDER_AWS: computeapis.HYPERVISOR_AWS,
- computeapis.CLOUD_PROVIDER_HUAWEI: computeapis.HYPERVISOR_HUAWEI,
- computeapis.CLOUD_PROVIDER_OPENSTACK: computeapis.HYPERVISOR_OPENSTACK,
- computeapis.CLOUD_PROVIDER_UCLOUD: computeapis.HYPERVISOR_UCLOUD,
- computeapis.CLOUD_PROVIDER_ZSTACK: computeapis.HYPERVISOR_ZSTACK,
- computeapis.CLOUD_PROVIDER_GOOGLE: computeapis.HYPERVISOR_GOOGLE,
- computeapis.CLOUD_PROVIDER_CTYUN: computeapis.HYPERVISOR_CTYUN,
- computeapis.CLOUD_PROVIDER_CNWARE: computeapis.HYPERVISOR_CNWARE,
- }
- func Hypervisor2Brand(hypervisor string) string {
- brand, ok := HypervisorBrandMap[hypervisor]
- if !ok {
- return "unkown"
- }
- return brand
- }
- func Brand2Hypervisor(brand string) string {
- hypervisor, ok := BrandHypervisorMap[brand]
- if !ok {
- return "unkown"
- }
- return hypervisor
- }
- func (gtm *SGuestTemplateManager) validateContent(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, content *jsonutils.JSONDict) (*computeapis.ServerCreateInput, error) {
- // hack
- if !content.Contains("name") && !content.Contains("generate_name") {
- content.Set("generate_name", jsonutils.NewString("fake_name"))
- }
- input, err := GuestManager.validateCreateData(ctx, userCred, ownerId, query, content)
- if err != nil {
- return nil, httperrors.NewInputParameterError("%v", err)
- }
- // check Image
- imageId := input.Disks[0].ImageId
- image, err := CachedimageManager.getImageInfo(ctx, userCred, imageId, false)
- if err != nil {
- return nil, errors.Wrapf(err, "getImageInfo of '%s'", imageId)
- }
- if image == nil {
- return nil, fmt.Errorf("no such image %s", imageId)
- }
- return input, nil
- }
- func (gtm *SGuestTemplateManager) validateData(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- ownerId mcclient.IIdentityProvider,
- query jsonutils.JSONObject,
- cinput computeapis.GuestTemplateInput,
- ) (computeapis.GuestTemplateInput, error) {
- if cinput.Content == nil {
- return cinput, nil
- }
- content := cinput.Content
- // data := cinput.JSON(cinput)
- // not support guest image and guest snapshot for now
- if content.Contains("instance_snapshot_id") {
- return cinput, httperrors.NewInputParameterError(
- "no support for instance snapshot in guest template for now")
- }
- // I don't hope cinput.Content same with data["content"] will change in GuestManager.validateCreateData
- copy := jsonutils.DeepCopy(content).(*jsonutils.JSONDict)
- input, err := gtm.validateContent(ctx, userCred, ownerId, query, copy)
- if err != nil {
- return cinput, httperrors.NewInputParameterError("%v", err)
- }
- log.Debugf("data: %#v", input)
- // fill field
- cinput.VmemSize = input.VmemSize
- // data.Add(jsonutils.NewInt(int64(input.VmemSize)), "vmem_size")
- cinput.VcpuCount = input.VcpuCount
- // data.Add(jsonutils.NewInt(int64(input.VcpuCount)), "vcpu_count")
- cinput.OsType = input.OsType
- // data.Add(jsonutils.NewString(input.OsType), "os_type")
- cinput.Hypervisor = input.Hypervisor
- // data.Add(jsonutils.NewString(input.Hypervisor), "hypervisor")
- cinput.InstanceType = input.InstanceType
- cinput.CloudregionId = input.PreferRegion
- cinput.BillingType = input.BillingType
- // fill vpc
- if len(input.Networks) != 0 && len(input.Networks[0].Network) != 0 {
- model, err := NetworkManager.FetchById(input.Networks[0].Network)
- if err != nil {
- return cinput, errors.Wrap(err, "NetworkManager.FetchById")
- }
- net := model.(*SNetwork)
- vpc, _ := net.GetVpc()
- if vpc != nil {
- cinput.VpcId = vpc.Id
- }
- }
- if len(input.GuestImageID) > 0 {
- cinput.ImageType = IMAGE_TYPE_GUEST
- cinput.ImageId = input.GuestImageID
- // data.Add(jsonutils.NewString(IMAGE_TYPE_GUEST), "image_type")
- // data.Add(jsonutils.NewString(input.GuestImageID), "image_id")
- } else {
- cinput.ImageType = input.GuestImageID
- cinput.ImageId = input.Disks[0].ImageId // if input.Didks is empty???
- // data.Add(jsonutils.NewString(input.Disks[0].ImageId), "image_id")
- // data.Add(jsonutils.NewString(IMAGE_TYPE_NORMAL), "image_type")
- }
- // hide some properties
- content.Remove("name")
- content.Remove("generate_name")
- // "__count__" was converted to "count" by apigateway
- content.Remove("count")
- content.Remove("project_id")
- content.Remove("__count__")
- cinput.Content = content
- // data.Add(contentDict, "content")
- return cinput, nil
- }
- func (gt *SGuestTemplate) ValidateUpdateData(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- input computeapis.GuestTemplateUpdateInput,
- ) (computeapis.GuestTemplateUpdateInput, error) {
- var err error
- input.GuestTemplateInput, err = GuestTemplateManager.validateData(ctx, userCred, gt.GetOwnerId(), query, input.GuestTemplateInput)
- if err != nil {
- return input, errors.Wrap(err, "GuestTemplateManager.validateData")
- }
- input.SharableVirtualResourceBaseUpdateInput, err = gt.SSharableVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, input.SharableVirtualResourceBaseUpdateInput)
- if err != nil {
- return input, errors.Wrap(err, "SSharableVirtualResourceBase.ValidateUpdateData")
- }
- return input, nil
- }
- func (manager *SGuestTemplateManager) FetchCustomizeColumns(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- objs []interface{},
- fields stringutils2.SSortedStrings,
- isList bool,
- ) []computeapis.GuestTemplateDetails {
- rows := make([]computeapis.GuestTemplateDetails, len(objs))
- virtRows := manager.SSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
- crRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
- vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
- for i := range rows {
- rows[i] = computeapis.GuestTemplateDetails{
- SharableVirtualResourceDetails: virtRows[i],
- CloudregionResourceInfo: crRows[i],
- VpcResourceInfo: vpcRows[i],
- }
- rows[i], _ = objs[i].(*SGuestTemplate).getMoreDetails(ctx, userCred, rows[i])
- }
- return rows
- }
- func (gt *SGuestTemplate) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential,
- out computeapis.GuestTemplateDetails) (computeapis.GuestTemplateDetails, error) {
- input, err := cmdline.FetchServerCreateInputByJSON(gt.Content)
- if err != nil {
- return out, err
- }
- configInfo := computeapis.GuestTemplateConfigInfo{}
- if len(input.PreferZone) != 0 {
- zone := ZoneManager.FetchZoneById(input.PreferZone)
- if zone != nil {
- input.PreferZone = zone.GetName()
- out.ZoneId = zone.GetId()
- }
- out.Zone = input.PreferZone
- }
- out.Brand = Hypervisor2Brand(gt.Hypervisor)
- // metadata
- configInfo.Metadata = input.Metadata
- // sku deal
- if len(input.InstanceType) > 0 {
- skuOutput := computeapis.GuestTemplateSku{}
- sku, err := ServerSkuManager.FetchSkuByNameAndProvider(input.InstanceType, out.Provider, true)
- if err != nil {
- skuOutput.Name = input.InstanceType
- skuOutput.MemorySizeMb = gt.VmemSize
- skuOutput.CpuCoreCount = gt.VcpuCount
- } else {
- skuOutput.Name = sku.Name
- skuOutput.MemorySizeMb = sku.MemorySizeMB
- skuOutput.CpuCoreCount = sku.CpuCoreCount
- skuOutput.InstanceTypeCategory = sku.InstanceTypeCategory
- skuOutput.InstanceTypeFamily = sku.InstanceTypeFamily
- }
- configInfo.Sku = skuOutput
- }
- // disk deal
- disks := make([]computeapis.GuestTemplateDisk, len(input.Disks))
- for i := range input.Disks {
- disks[i] = computeapis.GuestTemplateDisk{
- Backend: input.Disks[i].Backend,
- DiskType: input.Disks[i].DiskType,
- Index: input.Disks[i].Index,
- SizeMb: input.Disks[i].SizeMb,
- }
- }
- configInfo.Disks = disks
- // keypair
- if len(input.KeypairId) > 0 {
- model, err := KeypairManager.FetchByIdOrName(ctx, userCred, input.KeypairId)
- if err == nil {
- keypair := model.(*SKeypair)
- configInfo.Keypair = keypair.GetName()
- }
- }
- // network
- if len(input.Networks) > 0 {
- networkList := make([]computeapis.GuestTemplateNetwork, 0, len(input.Networks))
- networkIdList := make([]string, len(input.Networks))
- for i := range input.Networks {
- networkIdList[i] = input.Networks[i].Network
- }
- networkSet := sets.NewString(networkIdList...)
- wireQuery := WireManager.Query("id", "vpc_id").SubQuery()
- vpcQuery := VpcManager.Query("id", "name").SubQuery()
- q := NetworkManager.Query("id", "name", "wire_id", "guest_ip_start", "guest_ip_end", "vlan_id")
- if len(networkIdList) == 1 {
- q = q.Equals("id", networkIdList[0])
- } else {
- q = q.In("id", networkIdList)
- }
- q = q.LeftJoin(wireQuery, sqlchemy.Equals(q.Field("wire_id"), wireQuery.Field("id")))
- q = q.LeftJoin(vpcQuery, sqlchemy.Equals(wireQuery.Field("vpc_id"), vpcQuery.Field("id")))
- q = q.AppendField(vpcQuery.Field("id", "vpc_id"), vpcQuery.Field("name", "vpc_name"))
- q.All(&networkList)
- for _, p := range networkList {
- if networkSet.Has(p.ID) {
- networkSet.Delete(p.ID)
- }
- }
- // some specified network
- for _, id := range networkSet.UnsortedList() {
- networkList = append(networkList, computeapis.GuestTemplateNetwork{ID: id})
- }
- configInfo.Nets = networkList
- }
- if len(input.Secgroups) > 0 {
- q := SecurityGroupManager.Query("id", "name").In("id", input.Secgroups)
- rows, err := q.Rows()
- if err != nil {
- return out, errors.Wrap(err, "SQuery.Rows")
- }
- names := make([]string, 0, len(input.Secgroups))
- for rows.Next() {
- var id, name string
- rows.Scan(&id, &name)
- names = append(names, name)
- }
- rows.Close()
- out.Secgroups = names
- }
- // isolatedDevices
- if input.IsolatedDevices != nil && len(input.IsolatedDevices) != 0 {
- configInfo.IsolatedDeviceConfig = make([]computeapis.IsolatedDeviceConfig, len(input.IsolatedDevices))
- for i := range configInfo.IsolatedDeviceConfig {
- configInfo.IsolatedDeviceConfig[i] = *input.IsolatedDevices[i]
- }
- }
- // fill image info
- switch gt.ImageType {
- case IMAGE_TYPE_NORMAL:
- image, err := CachedimageManager.getImageInfo(ctx, userCred, gt.ImageId, false)
- if err == nil {
- configInfo.Image = image.Name
- } else {
- configInfo.Image = gt.ImageId
- }
- case IMAGE_TYPE_GUEST:
- s := auth.GetSession(ctx, userCred, options.Options.Region)
- ret, err := image.GuestImages.Get(s, gt.ImageId, jsonutils.JSONNull)
- if err != nil || !ret.Contains("id") {
- configInfo.Image = gt.ImageId
- } else {
- name, _ := ret.GetString("id")
- configInfo.Image = name
- }
- default:
- // no arrivals
- }
- // reset_password
- if input.ResetPassword == nil {
- configInfo.ResetPassword = true
- } else {
- configInfo.ResetPassword = *input.ResetPassword
- }
- out.ConfigInfo = configInfo
- return out, nil
- }
- func (gt *SGuestTemplate) PerformPublic(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- data apis.PerformPublicProjectInput,
- ) (jsonutils.JSONObject, error) {
- // image, network, secgroup, instancegroup
- input, err := cmdline.FetchServerCreateInputByJSON(gt.Content)
- if err != nil {
- return nil, errors.Wrap(err, "fail to convert content of guest template to ServerCreateInput")
- }
- // check for below private resource in the guest template
- privateResource := map[string]int{
- "keypair": len(input.KeypairId),
- "instance group": len(input.InstanceGroupIds),
- "instance snapshot": len(input.InstanceSnapshotId),
- }
- for k, v := range privateResource {
- if v > 0 {
- return nil, gt.genForbiddenError(k, "", "")
- }
- }
- targetScopeStr := data.Scope
- targetScope := rbacscope.String2ScopeDefault(targetScopeStr, rbacscope.ScopeSystem)
- // check if secgroup is public
- if len(input.SecgroupId) > 0 {
- model, err := SecurityGroupManager.FetchByIdOrName(ctx, userCred, input.SecgroupId)
- if err != nil {
- return nil, httperrors.NewResourceNotFoundError("there is no such secgroup %s descripted by guest template",
- input.SecgroupId)
- }
- secgroup := model.(*SSecurityGroup)
- sgScope := rbacscope.String2Scope(secgroup.PublicScope)
- if !secgroup.IsPublic || !sgScope.HigherEqual(targetScope) {
- return nil, gt.genForbiddenError("security group", input.SecgroupId, string(targetScope))
- }
- }
- // check if networks is public
- if len(input.Networks) > 0 {
- for i := range input.Networks {
- str := input.Networks[i].Network
- model, err := NetworkManager.FetchByIdOrName(ctx, userCred, str)
- if err != nil {
- return nil, httperrors.NewResourceNotFoundError(
- "there is no such secgroup %s descripted by guest template", str)
- }
- network := model.(*SNetwork)
- netScope := rbacscope.String2Scope(network.PublicScope)
- if !network.IsPublic || !netScope.HigherEqual(targetScope) {
- return nil, gt.genForbiddenError("network", str, string(targetScope))
- }
- }
- }
- // check if image is public
- var (
- isPublic bool
- publicScope string
- )
- switch gt.ImageType {
- case IMAGE_TYPE_NORMAL:
- image, err := CachedimageManager.GetImageById(ctx, userCred, gt.ImageId, false)
- if err != nil {
- return nil, errors.Wrapf(err, "fail to fetch image %s descripted by guest template", gt.ImageId)
- }
- isPublic, publicScope = image.IsPublic, image.PublicScope
- case IMAGE_TYPE_GUEST:
- s := auth.GetSession(ctx, userCred, options.Options.Region)
- ret, err := image.GuestImages.Get(s, gt.ImageId, jsonutils.JSONNull)
- if err != nil {
- return nil, errors.Wrapf(err, "fail to fetch guest image %s descripted by guest template", gt.ImageId)
- }
- isPublic = jsonutils.QueryBoolean(ret, "is_public", false)
- publicScope, _ = ret.GetString("public_scope")
- default:
- //no arrivals
- }
- igScope := rbacscope.String2Scope(publicScope)
- if !isPublic || !igScope.HigherEqual(targetScope) {
- return nil, gt.genForbiddenError("image", "", string(targetScope))
- }
- return gt.SSharableVirtualResourceBase.PerformPublic(ctx, userCred, query, data)
- }
- func (gt *SGuestTemplate) genForbiddenError(resourceName, resourceStr, scope string) error {
- var (
- msgFmt string
- msgArgs []interface{}
- )
- if resourceStr == "" {
- msgFmt = "the %s in guest template is not a public resource"
- msgArgs = []interface{}{resourceName}
- } else {
- msgFmt = "the %s %q in guest template is not a public resource"
- msgArgs = []interface{}{resourceName, resourceStr}
- }
- if scope != "" {
- msgFmt += " in %s scope"
- msgArgs = append(msgArgs, scope)
- }
- return httperrors.NewForbiddenError(msgFmt, msgArgs...)
- }
- func (gt *SGuestTemplate) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
- // check service catelog
- q := ServiceCatalogManager.Query("name").Equals("guest_template_id", gt.Id)
- names := make([]struct{ Name string }, 0, 1)
- err := q.All(&names)
- if err != nil {
- return errors.Wrap(err, "SQuery.All")
- }
- if len(names) > 0 {
- return httperrors.NewForbiddenError("guest template %s used by service catalog %s", gt.Id, names[0].Name)
- }
- // check scaling group
- q = ScalingGroupManager.Query("name").Equals("guest_template_id", gt.Id)
- names = make([]struct{ Name string }, 0, 1)
- err = q.All(&names)
- if err != nil {
- return errors.Wrap(err, "SQuery.All")
- }
- if len(names) > 0 {
- return httperrors.NewForbiddenError("guest template %s used by scalig group %s", gt.Id, names[0].Name)
- }
- return nil
- }
- // 主机模板列表
- func (manager *SGuestTemplateManager) ListItemFilter(
- ctx context.Context,
- q *sqlchemy.SQuery,
- userCred mcclient.TokenCredential,
- input computeapis.GuestTemplateListInput,
- ) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.SharableVirtualResourceListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemFilter")
- }
- q, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, input.RegionalFilterListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter")
- }
- if len(input.VpcId) > 0 {
- q, err = manager.SVpcResourceBaseManager.ListItemFilter(ctx, q, userCred, input.VpcFilterListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter")
- }
- }
- if len(input.CloudEnv) > 0 {
- cloudregions := CloudregionManager.Query().SubQuery()
- q = q.Join(cloudregions, sqlchemy.Equals(q.Field("cloudregion_id"), cloudregions.Field("id")))
- switch input.CloudEnv {
- case api.CLOUD_ENV_PUBLIC_CLOUD:
- q = q.Filter(sqlchemy.In(cloudregions.Field("provider"), CloudproviderManager.GetPublicProviderProvidersQuery()))
- case api.CLOUD_ENV_PRIVATE_CLOUD:
- q = q.Filter(sqlchemy.In(cloudregions.Field("provider"), CloudproviderManager.GetPrivateProviderProvidersQuery()))
- case api.CLOUD_ENV_ON_PREMISE:
- q = q.Filter(sqlchemy.Equals(cloudregions.Field("provider"), api.CLOUD_PROVIDER_ONECLOUD))
- case api.CLOUD_ENV_PRIVATE_ON_PREMISE:
- q = q.Filter(sqlchemy.OR(
- sqlchemy.Equals(cloudregions.Field("provider"), api.CLOUD_PROVIDER_ONECLOUD),
- sqlchemy.In(cloudregions.Field("provider"), CloudproviderManager.GetPrivateProviderProvidersQuery()),
- ))
- }
- }
- if len(input.BillingType) > 0 {
- q = q.Equals("billing_type", input.BillingType)
- }
- if len(input.Brand) > 0 {
- q = q.Equals("hypervisor", Brand2Hypervisor(input.Brand))
- }
- return q, nil
- }
- func (manager *SGuestTemplateManager) OrderByExtraFields(
- ctx context.Context,
- q *sqlchemy.SQuery,
- userCred mcclient.TokenCredential,
- input computeapis.GuestTemplateListInput,
- ) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SSharableVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.SharableVirtualResourceListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.OrderByExtraFields")
- }
- q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.RegionalFilterListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields")
- }
- q, err = manager.SVpcResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.VpcFilterListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SVpcResourceBaseManager.OrderByExtraFields")
- }
- return q, nil
- }
- func (manager *SGuestTemplateManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SSharableVirtualResourceBaseManager.QueryDistinctExtraField(q, field)
- if err == nil {
- return q, nil
- }
- q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field)
- if err == nil {
- return q, nil
- }
- q, err = manager.SVpcResourceBaseManager.QueryDistinctExtraField(q, field)
- if err == nil {
- return q, nil
- }
- return q, httperrors.ErrNotFound
- }
- type SGuestTemplateValidate struct {
- Hypervisor string
- CloudregionId string
- VpcId string
- NetworkIds []string
- }
- func (gt *SGuestTemplate) Validate(ctx context.Context, userCred mcclient.TokenCredential,
- ownerId mcclient.IIdentityProvider, stv SGuestTemplateValidate) (bool, string) {
- if stv.Hypervisor != "" && gt.Hypervisor != stv.Hypervisor {
- return false, fmt.Sprintf("GuestTemplate has mismatched hypervisor, need %s but %s", stv.Hypervisor, gt.Hypervisor)
- }
- if stv.CloudregionId != "" && gt.CloudregionId != stv.CloudregionId {
- return false, fmt.Sprintf("GuestTemplate has mismatched cloudregion, need %s but %s", stv.CloudregionId, gt.CloudregionId)
- }
- if stv.VpcId != "" && gt.VpcId != "" && stv.VpcId != gt.VpcId {
- return false, fmt.Sprintf("GuestTemplate has mismatched vpc, need %s bu %s", stv.VpcId, gt.VpcId)
- }
- // check networks
- input, err := GuestTemplateManager.validateContent(ctx, userCred, ownerId, jsonutils.NewDict(), gt.Content.(*jsonutils.JSONDict))
- if err != nil {
- return false, err.Error()
- }
- if len(input.Networks) != 0 && len(input.Networks[0].Network) != 0 {
- for i := range input.Networks {
- if !utils.IsInStringArray(input.Networks[i].Network, stv.NetworkIds) {
- return false, fmt.Sprintf("GuestTemplate's network '%s' not in networks '%s'", input.Networks[i].Network, stv.NetworkIds)
- }
- }
- }
- return true, ""
- }
- func (manager *SGuestTemplateManager) ListItemExportKeys(ctx context.Context,
- q *sqlchemy.SQuery,
- userCred mcclient.TokenCredential,
- keys stringutils2.SSortedStrings,
- ) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SSharableVirtualResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
- if err != nil {
- return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemExportKeys")
- }
- if keys.ContainsAny(manager.SCloudregionResourceBaseManager.GetExportKeys()...) {
- q, err = manager.SCloudregionResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
- if err != nil {
- return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemExportKeys")
- }
- }
- if keys.ContainsAny(manager.SVpcResourceBaseManager.GetExportKeys()...) {
- q, err = manager.SVpcResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
- if err != nil {
- return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemExportKeys")
- }
- }
- return q, nil
- }
- func (g *SGuest) PerformSaveTemplate(ctx context.Context, userCred mcclient.TokenCredential,
- query jsonutils.JSONObject, input computeapis.GuestSaveToTemplateInput) (jsonutils.JSONObject, error) {
- g.SetStatus(ctx, userCred, computeapis.VM_TEMPLATE_SAVING, "save to template")
- if len(input.Name) == 0 && len(input.GenerateName) == 0 {
- input.GenerateName = fmt.Sprintf("%s-template", g.Name)
- }
- data := jsonutils.Marshal(input).(*jsonutils.JSONDict)
- if task, err := taskman.TaskManager.NewTask(ctx, "GuestSaveTemplateTask", g, userCred, data, "", "", nil); err != nil {
- return nil, errors.Wrap(err, "Unbale to init 'GuestSaveTemplateTask'")
- } else {
- task.ScheduleRun(nil)
- }
- return nil, nil
- }
- func (gt *SGuestTemplate) PerformInspect(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- return nil, gt.inspect(ctx, userCred)
- }
- func (gt *SGuestTemplate) inspect(ctx context.Context, userCred mcclient.TokenCredential) error {
- _, err := GuestTemplateManager.validateContent(ctx, userCred, gt.GetOwnerId(), jsonutils.NewDict(), gt.Content.(*jsonutils.JSONDict))
- if err == nil {
- gt.updateCheckTime()
- gt.SetStatus(ctx, userCred, computeapis.GT_READY, "inspect successfully")
- logclient.AddSimpleActionLog(gt, logclient.ACT_HEALTH_CHECK, "", userCred, true)
- return nil
- }
- // invalid
- gt.updateCheckTime()
- reason := fmt.Sprintf("During the inspection, the guest template is not available: %s", err.Error())
- gt.SetStatus(ctx, userCred, computeapis.GT_INVALID, reason)
- logclient.AddSimpleActionLog(gt, logclient.ACT_HEALTH_CHECK, reason, userCred, false)
- return nil
- }
- func (gm *SGuestTemplateManager) InspectAllTemplate(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
- lastCheckTime := time.Now().Add(time.Duration(-options.Options.GuestTemplateCheckInterval) * time.Hour)
- q := gm.Query()
- q = q.Filter(sqlchemy.OR(sqlchemy.IsNull(q.Field("last_check_time")), sqlchemy.LE(q.Field("last_check_time"),
- lastCheckTime)))
- gts := make([]SGuestTemplate, 0, 10)
- err := db.FetchModelObjects(gm, q, >s)
- if err != nil {
- log.Errorf("Unable to fetch all guest templates that need to check: %s", err.Error())
- return
- }
- for i := range gts {
- gts[i].inspect(ctx, userCred)
- }
- }
|