Merge pull request #11772 from rainzm/webapp/azure

Webapp in azure
This commit is contained in:
Zexi Li
2021-08-02 12:09:13 +08:00
committed by GitHub
20 changed files with 1743 additions and 4 deletions
+53
View File
@@ -0,0 +1,53 @@
// 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 compute
import "yunion.io/x/onecloud/pkg/apis"
const (
APP_TYPE_WEB = "web"
APP_STATUS_READY = "ready"
APP_STATUS_UNKNOWN = "unknown"
)
type AppListInput struct {
apis.VirtualResourceListInput
apis.ExternalizedResourceBaseListInput
apis.EnabledResourceBaseListInput
ManagedResourceListInput
RegionalFilterListInput
TechStack string `json:"tech_stack"`
}
type AppDetails struct {
apis.VirtualResourceDetails
ManagedResourceInfo
CloudregionResourceInfo
}
type AppEnvironmentListInput struct {
apis.VirtualResourceListInput
apis.ExternalizedResourceBaseListInput
AppId string
InstanceType string
}
type AppEnvironmentDetails struct {
apis.VirtualResourceDetails
}
+1
View File
@@ -60,6 +60,7 @@ const (
CLOUD_CAPABILITY_MONGO_DB = "mongodb" // MongoDB
CLOUD_CAPABILITY_ES = "es" // ElasticSearch
CLOUD_CAPABILITY_KAFKA = "kafka" // Kafka
CLOUD_CAPABILITY_APP = "app" //App
)
const (
+18
View File
@@ -183,6 +183,9 @@ type ICloudRegion interface {
GetICloudKafkas() ([]ICloudKafka, error)
GetICloudKafkaById(id string) (ICloudKafka, error)
GetICloudApps() ([]ICloudApp, error)
GetICloudAppById(id string) (ICloudApp, error)
}
type ICloudZone interface {
@@ -1443,3 +1446,18 @@ type ICloudKafka interface {
Delete() error
}
type ICloudApp interface {
IVirtualResource
GetEnvironments() ([]ICloudAppEnvironment, error)
GetTechStack() string
GetType() string
GetKind() string
GetOsType() string
}
type ICloudAppEnvironment interface {
IVirtualResource
GetInstanceType() (string, error)
GetInstanceNumber() (int, error)
}
+407
View File
@@ -0,0 +1,407 @@
// 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/pkg/errors"
"yunion.io/x/pkg/tristate"
"yunion.io/x/pkg/util/compare"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/compute"
"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/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SAppManager struct {
db.SVirtualResourceBaseManager
db.SExternalizedResourceBaseManager
db.SEnabledResourceBaseManager
SManagedResourceBaseManager
SCloudregionResourceBaseManager
}
type SApp struct {
db.SVirtualResourceBase
db.SExternalizedResourceBase
db.SEnabledResourceBase
SManagedResourceBase
SCloudregionResourceBase
Type string `width:"16" charset:"ascii" nullable:"false" get:"user" list:"user"`
TechStack string `width:"64" charset:"ascii" nullable:"false" get:"user" list:"user"`
Kind string `width:"64" charset:"ascii" nullable:"false" get:"user" list:"user"`
}
var AppManager *SAppManager
func init() {
AppManager = &SAppManager{
SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(
SApp{},
"apps_tbl",
"webapp",
"webapps",
),
}
AppManager.SetVirtualObject(AppManager)
}
func (am *SAppManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return true
}
func (am *SAppManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.AppListInput) (*sqlchemy.SQuery, error) {
q, err := am.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter")
}
q, err = am.SEnabledResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SEnabledResourceBaseManager.ListItemFilter")
}
q, err = am.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
}
q, err = am.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter")
}
q, err = am.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput)
if err != nil {
return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter")
}
if query.TechStack != "" {
q = q.Equals("tech_stack", query.TechStack)
}
return q, nil
}
func (am *SAppManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.AppListInput) (*sqlchemy.SQuery, error) {
var err error
q, err = am.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields")
}
q, err = am.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields")
}
q, err = am.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput)
if err != nil {
return nil, errors.Wrap(err, "CloudregionResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
func (am *SAppManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
var err error
q, err = am.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
q, err = am.SManagedResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
q, err = am.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
switch field {
case "tech_stack":
q = am.Query("tech_stack").Distinct()
}
return q, nil
}
func (am *SAppManager) ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, keys stringutils2.SSortedStrings) (*sqlchemy.SQuery, error) {
var err error
q, err = am.SVirtualResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemExportKeys")
}
if keys.ContainsAny(am.SManagedResourceBaseManager.GetExportKeys()...) {
q, err = am.SManagedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemExportKeys")
}
}
if keys.ContainsAny(am.SCloudregionResourceBaseManager.GetExportKeys()...) {
q, err = am.SCloudregionResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemExportKeys")
}
}
return q, nil
}
func (am *SAppManager) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.AppDetails, error) {
return api.AppDetails{}, nil
}
func (a *SApp) GetAppEnvironments() ([]SAppEnvironment, error) {
q := AppEnvironmentManager.Query().Equals("app_id", a.Id)
ret := []SAppEnvironment{}
err := db.FetchModelObjects(AppEnvironmentManager, q, &ret)
if err != nil {
return nil, errors.Wrap(err, "db.FetchModelObjects")
}
return ret, nil
}
func (am *SAppManager) GetApps(providerId string) ([]SApp, error) {
q := AppManager.Query().Equals("manager_id", providerId)
ret := []SApp{}
err := db.FetchModelObjects(AppManager, q, &ret)
if err != nil {
return nil, errors.Wrap(err, "db.FetchModelObjects")
}
return ret, nil
}
func (self *SCloudregion) GetApps(managerId string) ([]SApp, error) {
q := AppManager.Query().Equals("cloudregion_id", self.Id)
if len(managerId) > 0 {
q = q.Equals("manager_id", managerId)
}
ret := []SApp{}
err := db.FetchModelObjects(AppManager, q, &ret)
if err != nil {
return nil, errors.Wrap(err, "db.FetchModelObjects")
}
return ret, nil
}
func (self *SCloudregion) SyncApps(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, exts []cloudprovider.ICloudApp) compare.SyncResult {
lockman.LockRawObject(ctx, AppManager.KeywordPlural(), fmt.Sprintf("%s-%s", provider.Id, self.Id))
defer lockman.ReleaseRawObject(ctx, AppManager.KeywordPlural(), fmt.Sprintf("%s-%s", provider.Id, self.Id))
result := compare.SyncResult{}
apps, err := self.GetApps(provider.Id)
if err != nil {
result.Error(err)
return result
}
removed := make([]SApp, 0)
commondb := make([]SApp, 0)
commonext := make([]cloudprovider.ICloudApp, 0)
added := make([]cloudprovider.ICloudApp, 0)
// compare
err = compare.CompareSets(apps, exts, &removed, &commondb, &commonext, &added)
if err != nil {
result.Error(err)
return result
}
// remove
for i := 0; i < len(removed); i++ {
err := removed[i].syncRemoveCloudApp(ctx, userCred)
if err != nil {
result.DeleteError(err)
continue
}
result.Delete()
}
// sync with cloud app
for i := 0; i < len(commondb); i++ {
err := commondb[i].SyncWithCloudApp(ctx, userCred, provider, commonext[i])
if err != nil {
result.UpdateError(err)
continue
}
result.Update()
}
// new one
for i := 0; i < len(added); i++ {
_, err := self.newFromCloudApp(ctx, userCred, provider, added[i])
if err != nil {
result.AddError(err)
continue
}
result.Add()
}
return result
}
func (self *SCloudregion) newFromCloudApp(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, ext cloudprovider.ICloudApp) (*SApp, error) {
app := SApp{}
app.SetModelManager(AppManager, &app)
app.ExternalId = ext.GetGlobalId()
app.CloudregionId = self.Id
app.ManagerId = provider.Id
app.IsEmulated = ext.IsEmulated()
app.Status = ext.GetStatus()
app.Type = ext.GetType()
app.Kind = ext.GetKind()
app.TechStack = ext.GetTechStack()
app.Name = ext.GetName()
app.Enabled = tristate.True
err := AppManager.TableSpec().Insert(ctx, &app)
if err != nil {
return nil, errors.Wrap(err, "unable to insert app")
}
aes, err := ext.GetEnvironments()
if err != nil {
return &app, errors.Wrap(err, "unable to GetEnvironments")
}
result := app.SyncAppEnvironments(ctx, userCred, provider, aes)
if result.IsError() {
return &app, errors.Wrap(result.AllError(), "unable to SyncAppEnvironments")
}
SyncCloudProject(userCred, &app, provider.GetOwnerId(), ext, provider.Id)
db.OpsLog.LogEvent(&app, db.ACT_CREATE, app.GetShortDesc(ctx), userCred)
return &app, nil
}
func (am *SAppManager) purgeAll(ctx context.Context, userCred mcclient.TokenCredential, providerId string) error {
apps, err := am.GetApps(providerId)
if err != nil {
return errors.Wrapf(err, "unable to GetApps of provider id %s", providerId)
}
for i := range apps {
err = apps[i].purge(ctx, userCred)
if err != nil {
return err
}
}
return nil
}
func (a *SApp) purge(ctx context.Context, userCred mcclient.TokenCredential) error {
aes, err := a.GetAppEnvironments()
if err != nil {
return errors.Wrap(err, "unable to GetAppEnvironments")
}
for i := range aes {
err = aes[i].Delete(ctx, userCred)
if err != nil {
return errors.Wrapf(err, "unable to Delete AppEnvironment %s", aes[i].Id)
}
}
return a.Delete(ctx, userCred)
}
func (a *SApp) syncRemoveCloudApp(ctx context.Context, userCred mcclient.TokenCredential) error {
return a.purge(ctx, userCred)
}
func (a *SApp) SyncWithCloudApp(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, ext cloudprovider.ICloudApp) error {
_, err := db.UpdateWithLock(ctx, a, func() error {
a.ExternalId = ext.GetGlobalId()
a.Status = ext.GetStatus()
a.Type = ext.GetType()
a.Kind = ext.GetKind()
a.TechStack = ext.GetTechStack()
return nil
})
if err != nil {
return errors.Wrap(err, "db.Update")
}
aes, err := ext.GetEnvironments()
if err != nil {
return errors.Wrapf(err, "unable to GetAppEnvironments for ICloudApp %s", ext.GetGlobalId())
}
result := a.SyncAppEnvironments(ctx, userCred, provider, aes)
if result.IsError() {
return result.AllError()
}
return nil
}
func (am *SAppManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []interface{}, fields stringutils2.SSortedStrings, isList bool) []api.AppDetails {
rows := make([]api.AppDetails, len(objs))
virtRows := am.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
manRows := am.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
regRows := am.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i].VirtualResourceDetails = virtRows[i]
rows[i].ManagedResourceInfo = manRows[i]
rows[i].CloudregionResourceInfo = regRows[i]
}
return rows
}
func (a *SApp) AllowPerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return a.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, a, "syncstatus")
}
func (a *SApp) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
var openTask = true
count, err := taskman.TaskManager.QueryTasksOfObject(a, time.Now().Add(-3*time.Minute), &openTask).CountWithError()
if err != nil {
return nil, err
}
if count > 0 {
return nil, httperrors.NewBadRequestError("WebApp has %d task active, can't sync status", count)
}
return nil, StartResourceSyncStatusTask(ctx, userCred, a, "AppSyncstatusTask", "")
}
func (a *SApp) GetRegion() (*SCloudregion, error) {
region, err := CloudregionManager.FetchById(a.CloudregionId)
if err != nil {
return nil, errors.Wrapf(err, "CloudregionManager.FetchById(%s)", a.CloudregionId)
}
return region.(*SCloudregion), nil
}
func (a *SApp) GetIRegion() (cloudprovider.ICloudRegion, error) {
region, err := a.GetRegion()
if err != nil {
return nil, errors.Wrap(err, "GetRegion")
}
provider, err := a.GetDriver()
if err != nil {
return nil, errors.Wrap(err, "GetDriver")
}
return provider.GetIRegionById(region.GetExternalId())
}
func (a *SApp) GetIApp() (cloudprovider.ICloudApp, error) {
if len(a.ExternalId) == 0 {
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty externalId")
}
iRegion, err := a.GetIRegion()
if err != nil {
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "GetIRegion")
}
return iRegion.GetICloudAppById(a.ExternalId)
}
+220
View File
@@ -0,0 +1,220 @@
// 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"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/compare"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/compute"
"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/mcclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SAppEnvironmentManager struct {
db.SVirtualResourceBaseManager
db.SExternalizedResourceBaseManager
}
type SAppEnvironment struct {
db.SVirtualResourceBase
db.SExternalizedResourceBase
AppId string `width:"36" charset:"ascii" index:"true"`
InstanceType string `width:"16" charset:"ascii" index:"true" get:"user" list:"user"`
InstanceNumber int `get:"user" list:"user"`
}
var AppEnvironmentManager *SAppEnvironmentManager
func init() {
AppEnvironmentManager = &SAppEnvironmentManager{
SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(
SAppEnvironment{},
"appenvironments_tbl",
"webappenvironment",
"webappenvironments",
),
}
AppEnvironmentManager.SetVirtualObject(AppEnvironmentManager)
}
func (aem *SAppEnvironmentManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input api.AppEnvironmentListInput) (*sqlchemy.SQuery, error) {
var err error
q, err = aem.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.VirtualResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter")
}
q, err = aem.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, input.ExternalizedResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
}
if input.AppId != "" {
q = q.Equals("app_id", input.AppId)
}
if input.InstanceType != "" {
q = q.Equals("instance_type", input.InstanceType)
}
return q, nil
}
func (aem *SAppEnvironmentManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.AppEnvironmentListInput) (*sqlchemy.SQuery, error) {
return aem.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput)
}
func (aem *SAppEnvironmentManager) ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, keys stringutils2.SSortedStrings) (*sqlchemy.SQuery, error) {
var err error
q, err = aem.SVirtualResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemExportKeys")
}
return q, nil
}
func (aem *SAppEnvironmentManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
q, err := aem.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
switch field {
case "instance_type":
q = aem.Query("instance_type").Distinct()
}
return q, nil
}
func (a *SApp) SyncAppEnvironments(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, exts []cloudprovider.ICloudAppEnvironment) compare.SyncResult {
lockman.LockRawObject(ctx, AppEnvironmentManager.KeywordPlural(), a.Id)
defer lockman.LockRawObject(ctx, AppEnvironmentManager.KeywordPlural(), a.Id)
result := compare.SyncResult{}
aes, err := a.GetAppEnvironments()
if err != nil {
result.Error(err)
return result
}
removed := make([]SAppEnvironment, 0)
commondb := make([]SAppEnvironment, 0)
commonext := make([]cloudprovider.ICloudAppEnvironment, 0)
added := make([]cloudprovider.ICloudAppEnvironment, 0)
// compare
err = compare.CompareSets(aes, exts, &removed, &commondb, &commonext, &added)
if err != nil {
result.Error(err)
return result
}
// remove
for i := 0; i < len(removed); i++ {
err := removed[i].syncRemoveCloudAppEnvironment(ctx, userCred)
if err != nil {
result.DeleteError(err)
continue
}
result.Delete()
}
// sync with cloud
for i := 0; i < len(commondb); i++ {
err := commondb[i].SyncWithCloudAppEnvironment(ctx, userCred, commonext[i])
if err != nil {
result.UpdateError(err)
continue
}
result.Update()
}
// new one
for i := 0; i < len(added); i++ {
_, err := a.newFromCloudAppEnvironment(ctx, userCred, provider, added[i])
if err != nil {
result.AddError(err)
continue
}
result.Add()
}
return result
}
func (a *SApp) newFromCloudAppEnvironment(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, ext cloudprovider.ICloudAppEnvironment) (*SAppEnvironment, error) {
var err error
appEnvironment := SAppEnvironment{}
appEnvironment.SetModelManager(AppEnvironmentManager, &appEnvironment)
appEnvironment.ExternalId = ext.GetGlobalId()
appEnvironment.IsEmulated = ext.IsEmulated()
appEnvironment.Status = ext.GetStatus()
appEnvironment.InstanceType, err = ext.GetInstanceType()
if err != nil {
return nil, errors.Wrap(err, "unable to GetInsntaceType")
}
appEnvironment.InstanceNumber, err = ext.GetInstanceNumber()
if err != nil {
return nil, errors.Wrap(err, "unable to GetInstanceNumber")
}
appEnvironment.Name = ext.GetName()
appEnvironment.AppId = a.Id
err = AppEnvironmentManager.TableSpec().Insert(ctx, &appEnvironment)
if err != nil {
return nil, errors.Wrapf(err, "newFromCloudAppEnvironment.Insert")
}
SyncCloudProject(userCred, &appEnvironment, provider.GetOwnerId(), ext, provider.Id)
db.OpsLog.LogEvent(&appEnvironment, db.ACT_CREATE, appEnvironment.GetShortDesc(ctx), userCred)
return nil, nil
}
func (ae *SAppEnvironment) syncRemoveCloudAppEnvironment(ctx context.Context, userCred mcclient.TokenCredential) error {
return ae.Delete(ctx, userCred)
}
func (ae *SAppEnvironment) SyncWithCloudAppEnvironment(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudAppEnvironment) error {
_, err := db.UpdateWithLock(ctx, ae, func() error {
var err error
ae.ExternalId = ext.GetGlobalId()
ae.Status = ext.GetStatus()
ae.InstanceType, err = ext.GetInstanceType()
if err != nil {
return err
}
ae.InstanceNumber, err = ext.GetInstanceNumber()
if err != nil {
return err
}
return nil
})
if err != nil {
return errors.Wrap(err, "db.Update")
}
return nil
}
func (aem *SAppEnvironmentManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []interface{}, fields stringutils2.SSortedStrings, isList bool) []api.AppEnvironmentDetails {
rows := make([]api.AppEnvironmentDetails, len(objs))
virRows := aem.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i].VirtualResourceDetails = virRows[i]
}
return rows
}
+1
View File
@@ -1484,6 +1484,7 @@ func (self *SCloudprovider) RealDelete(ctx context.Context, userCred mcclient.To
WafIPSetCacheManager,
WafRegexSetCacheManager,
WafInstanceManager,
AppManager,
VpcManager,
ElasticipManager,
MongoDBManager,
+22
View File
@@ -1170,6 +1170,24 @@ func syncKafkas(ctx context.Context, userCred mcclient.TokenCredential, syncResu
return nil
}
func syncApps(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, provider *SCloudprovider, localRegion *SCloudregion, remoteRegion cloudprovider.ICloudRegion) error {
log.Infof("try to syncApps")
iApps, err := remoteRegion.GetICloudApps()
if err != nil {
msg := fmt.Sprintf("GetICloudApps for region %s failed %s", remoteRegion.GetName(), err)
log.Errorf(msg)
return err
}
result := localRegion.SyncApps(ctx, userCred, provider, iApps)
syncResults.Add(AppManager, result)
msg := result.Result()
log.Infof("SyncApps for region %s result: %s", localRegion.Name, msg)
if result.IsError() {
return result.AllError()
}
return nil
}
func syncWafInstances(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, provider *SCloudprovider, localRegion *SCloudregion, remoteRegion cloudprovider.ICloudRegion) error {
wafIns, err := remoteRegion.GetICloudWafInstances()
if err != nil {
@@ -1416,6 +1434,10 @@ func syncPublicCloudProviderInfo(
syncKafkas(ctx, userCred, syncResults, provider, localRegion, remoteRegion)
}
if utils.IsInStringArray(cloudprovider.CLOUD_CAPABILITY_APP, driver.GetCapabilities()) {
syncApps(ctx, userCred, syncResults, provider, localRegion, remoteRegion)
}
if cloudprovider.IsSupportCompute(driver) {
log.Debugf("storageCachePairs count %d", len(storageCachePairs))
for i := range storageCachePairs {
+3
View File
@@ -231,6 +231,9 @@ func InitHandlers(app *appsrv.Application) {
models.ElasticSearchManager,
models.KafkaManager,
models.AppManager,
models.AppEnvironmentManager,
} {
db.RegisterModelManager(manager)
handler := db.NewModelHandler(manager)
+55
View File
@@ -0,0 +1,55 @@
// 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 tasks
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"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/logclient"
)
type AppSyncstatusTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(AppSyncstatusTask{})
}
func (at *AppSyncstatusTask) taskFailed(ctx context.Context, app *models.SApp, err error) {
app.SetStatus(at.UserCred, api.APP_STATUS_UNKNOWN, err.Error())
db.OpsLog.LogEvent(app, db.ACT_SYNC_STATUS, err, at.GetUserCred())
logclient.AddActionLogWithStartable(at, app, logclient.ACT_SYNC_STATUS, err, at.UserCred, false)
at.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (at *AppSyncstatusTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
app := obj.(*models.SApp)
iApp, err := app.GetIApp()
if err != nil {
at.taskFailed(ctx, app, errors.Wrapf(err, "app.GetIApp"))
return
}
app.SyncWithCloudApp(ctx, at.UserCred, app.GetCloudprovider(), iApp)
at.SetStageComplete(ctx, nil)
}
+43
View File
@@ -0,0 +1,43 @@
// 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 modules
import "yunion.io/x/onecloud/pkg/mcclient/modulebase"
type AppManager struct {
modulebase.ResourceManager
}
type AppEnvironmentManager struct {
modulebase.ResourceManager
}
var (
Apps AppManager
AppEnvironments AppEnvironmentManager
)
func init() {
Apps = AppManager{NewComputeManager("webapp", "webapps",
[]string{},
[]string{},
)}
AppEnvironments = AppEnvironmentManager{NewComputeManager("webappenvironment", "webappenvironments",
[]string{},
[]string{},
)}
registerCompute(&Apps)
registerCompute(&AppEnvironments)
}
+64
View File
@@ -0,0 +1,64 @@
// 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 compute
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type AppListOptions struct {
options.BaseListOptions
TechStack string
}
func (opts *AppListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
type AppIdOptions struct {
ID string `help:"App Id"`
}
func (opts *AppIdOptions) GetId() string {
return opts.ID
}
func (opts *AppIdOptions) Params() (jsonutils.JSONObject, error) {
return nil, nil
}
type AppEnvironmentListOptions struct {
options.BaseListOptions
AppId string `help:"App Id"`
InstanceType string `help:"Instance Type"`
}
func (opts *AppEnvironmentListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
type AppEnvironmentIdOption struct {
ID string `help:"AppEnvironment ID"`
}
func (opts *AppEnvironmentIdOption) GetId() string {
return opts.ID
}
func (opts *AppEnvironmentIdOption) Params() (jsonutils.JSONObject, error) {
return nil, nil
}
+199
View File
@@ -0,0 +1,199 @@
// 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 azure
import (
"fmt"
"net/url"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/multicloud"
)
type SAppServicePlan struct {
multicloud.AzureTags
region *SRegion
Properties SAppServicePlanProperties
ID string
Kind string
Location string
Name string
Type string
Sku SSkuDescription
}
type SAppServicePlanProperties struct {
FreeOfferExpirationTime string
GeoRegion string
HostingEnvironmentProfile SHostingEnvironmentProfile
HyperV bool
IsSpot bool
MaximumElasticWorkerCount int
MaximumNumberOfWorkers int
NumberOfSites int
PerSiteScaling bool
// 应用服务环境的预配状态
ProvisioningState string
Reserved bool
ResourceGroup string
SpotExpirationTime string
// Creating Pending Ready
Status string
Subscription string
TargetWorkerCount int
TargetWorkerSizeId int
WorkerTierName string
}
type SHostingEnvironmentProfile struct {
ID string
Name string
Type string
}
type SSkuDescription struct {
Capabilities []SCapability
Capacity int
Family string
locations []string
Name string
Size string
SkuCapacity SSkuCapacity
Tier string
}
type SCapability struct {
Name string
Reason string
Value string
}
type SSkuCapacity struct {
Default int
Maximum int
Minimum int
ScaleType string
}
func (r *SRegion) GetAppServicePlanWithCache(id string) (*SAppServicePlan, error) {
if r.appServicePlans == nil {
plans, err := r.GetAppServicePlans()
if err != nil {
return nil, err
}
appServicePlans := make(map[string]*SAppServicePlan, len(plans))
for i := range plans {
appServicePlans[plans[i].ID] = &plans[i]
}
r.appServicePlans = appServicePlans
}
if ret, ok := r.appServicePlans[id]; ok {
return ret, nil
}
return r.GetAppServicePlan(id)
}
func (r *SRegion) GetAppServicePlans() ([]SAppServicePlan, error) {
result := []SAppServicePlan{}
resource := "Microsoft.Web/serverfarms"
err := r.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result)
if err != nil {
return nil, err
}
for i := range result {
result[i].region = r
}
return result, nil
}
func (r *SRegion) GetAppServicePlan(planId string) (*SAppServicePlan, error) {
asp := &SAppServicePlan{region: r}
params := url.Values{"api-version": []string{"2019-08-01"}}
return asp, r.get(planId, params, asp)
}
type SServerFarmSku struct {
ResourceType string
Sku SSkuSpec
Capacity SSkuCapacity
}
type SSkuSpec struct {
Name string
Tier string
}
func (asp *SAppServicePlan) GetSkus() ([]SServerFarmSku, error) {
result := []SServerFarmSku{}
resource := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/serverfarms/%s/skus", asp.region.client._subscriptionId(), asp.Properties.ResourceGroup, asp.Name)
err := asp.region.client.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result)
if err != nil {
return nil, err
}
return result, nil
}
type SAppServicePlanVnet struct {
Id string
Name string
Properties SASPVnetProperties
}
type SASPVnetProperties struct {
VnetResourceId string
}
func (asp *SAppServicePlan) GetNetworks() ([]SNetwork, error) {
vnets, err := asp.GetVnets()
if err != nil {
return nil, errors.Wrap(err, "unable to get Vnets")
}
networks := make([]SNetwork, 0, len(vnets))
for i := range vnets {
network, err := asp.region.GetNetwork(vnets[i].Properties.VnetResourceId)
if err != nil {
return nil, errors.Wrap(err, "unable to get Network")
}
networks = append(networks, *network)
}
return networks, nil
}
func (asp *SAppServicePlan) GetVnets() ([]SAppServicePlanVnet, error) {
result := []SAppServicePlanVnet{}
resource := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/serverfarms/%s/virtualNetworkConnections", asp.region.client._subscriptionId(), asp.Properties.ResourceGroup, asp.Name)
err := asp.region.client.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result)
if err != nil {
return nil, err
}
return result, nil
}
type SSkuInfos struct {
ResourceType string
Skus []SResourceSku
}
func (r *SRegion) GetAppServiceSkus() ([]SSkuInfos, error) {
result := []SSkuInfos{}
resource := "Microsoft.Web/skus"
err := r.client.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result)
if err != nil {
return nil, err
}
return result, err
}
+156
View File
@@ -0,0 +1,156 @@
// 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 azure
import (
"net/url"
"yunion.io/x/onecloud/pkg/multicloud"
)
type SAutoscaleSettingResource struct {
multicloud.AzureTags
region *SRegion
Properties SAutoscaleSettingProperties
ID string
Location string
Name string
Type string
}
type SAutoscaleSettingProperties struct {
Enabled bool
Name string
TargetResourceUri string
Profiles []SAutoscaleProfile
}
type SAutoscaleProfile struct {
Capacity SScaleCapacity
FixedDate STimeWindow
Name string
Recurrence SRecurrence
Rule []SScaleRule
}
type SRecurrence struct {
Frequency string
Schedule SRecurrentSchedule
}
type SRecurrentSchedule struct {
Days []string
Hours []int
Minutes []int
TimeZone string
}
type STimeWindow struct {
// 采用 ISO 8601 格式的配置文件的结束时间。
End string
// 采用 ISO 8601 格式的配置文件的开始时间。
Start string
TimeZone string
}
type SScaleAction struct {
Cooldown string
Direction string
Type string
Value string
}
// 可以在此配置文件期间使用的实例数。
type SScaleCapacity struct {
Default string
Maximum string
Minimum string
}
// Decrease string
// Increase string
// None string
// 为缩放操作提供触发器和参数的规则。
type SScaleRule struct {
MetricTrigger SMetricTrigger
ScaleAction SScaleAction
}
// 维度运算符。 仅支持"Equals"和"NotEquals"。 "Equals"等于任何值。 "NotEquals"不等于所有值
type SScaleRuleMetricDimensionOperationType struct {
Equals string
NotEquals string
}
//触发缩放规则时应发生的操作类型。
// ChangeCount string
// ExactCount string
// PercentChangeCount string
type SScaleRuleMetricDimension struct {
DimensionName string
Operator string
Values []string
}
type SMetricTrigger struct {
// 维度条件的列表。 例如: [{"DimensionName": "AppName"、"Operator": "Equals"、"Values": ["App1"]}、{"DimensionName": "Deployment"、"Operator": "Equals"、"Values": ["default"]}]。
Dimensions []SScaleRuleMetricDimension
// 一个值,该值指示度量值是否应除以每个实例。
DividePerInstance bool
// 定义规则监视内容的指标的名称。
MetricName string
// 定义规则监视内容的指标的命名空间。
MetricNamespace string
// 规则监视的资源的资源标识符。
MetricResourceUri string
// 用于比较指标数据和阈值的运算符。
// Equals GreaterThan GreaterThanOrEqual LessThan LessThanOrEqual NotEquals
Operator string
// 指标统计信息类型。 来自多个实例的指标进行组合的方式。
// Average Max Min Sum
Statistic string
// 触发缩放操作的度量值的阈值。
Threshold int
// 时间聚合类型。 随着时间推移,收集的数据应如何组合。 默认值为 Average。
// Average Count Last Maximum Minimum Total
TimeAggregation string
//规则监视的度量值的粒度。 必须是从指标的指标定义返回的预定义值之一。 必须介于 12 小时和 1 分钟之间。
TimeGrain string
//收集实例数据的时间范围。 此值必须大于指标集合中的延迟,可能会因资源而异。 必须介于 12 小时和 5 分钟之间。
TimeWindow string
}
func (r *SRegion) GetAutoscaleSettingResources() ([]SAutoscaleSettingResource, error) {
result := []SAutoscaleSettingResource{}
resource := "microsoft.insights/autoscalesettings"
err := r.client.list(resource, url.Values{"api-version": []string{"2015-04-01"}}, &result)
if err != nil {
return nil, err
}
return result, nil
}
+8 -3
View File
@@ -508,10 +508,14 @@ func (self *SAzureClient) _list(resource string, params url.Values) (jsonutils.J
path = fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/%s", subId, params.Get("resourceGroups"), resource)
params.Del("resourceGroups")
default:
if len(subId) == 0 {
return nil, fmt.Errorf("no avaiable subscriptions")
if strings.HasPrefix(resource, "subscriptions/") || strings.HasPrefix(resource, "/subscriptions/") {
path = resource
} else {
if len(subId) == 0 {
return nil, fmt.Errorf("no avaiable subscriptions")
}
path = fmt.Sprintf("subscriptions/%s/providers/%s", subId, resource)
}
path = fmt.Sprintf("subscriptions/%s/providers/%s", subId, resource)
}
params.Set("api-version", self._apiVersion(resource, params))
return self.jsonRequest("GET", path, nil, params, true)
@@ -976,6 +980,7 @@ func (self *SAzureClient) GetCapabilities() []string {
cloudprovider.CLOUD_CAPABILITY_SAML_AUTH,
cloudprovider.CLOUD_CAPABILITY_WAF,
cloudprovider.CLOUD_CAPABILITY_CACHE,
cloudprovider.CLOUD_CAPABILITY_APP,
}
return caps
}
+2 -1
View File
@@ -42,7 +42,8 @@ type SRegion struct {
multicloud.SRegion
client *SAzureClient
storageCache *SStoragecache
storageCache *SStoragecache
appServicePlans map[string]*SAppServicePlan
ID string
Name string
@@ -0,0 +1,81 @@
// 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 shell
import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/multicloud/azure"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type AppServicePlanListOptions struct {
}
shellutils.R(&AppServicePlanListOptions{}, "app-service-plan-list", "List app service plan", func(cli *azure.SRegion, args *AppServicePlanListOptions) error {
appServicePlans, err := cli.GetAppServicePlans()
if err != nil {
return err
}
fmt.Printf("sku: %s\n", jsonutils.Marshal(appServicePlans[0].Sku))
printList(appServicePlans, len(appServicePlans), 0, 0, []string{})
return nil
})
type AppServicePlanShowOptions struct {
ID string
}
shellutils.R(&AppServicePlanShowOptions{}, "app-service-plan-show", "Show app service plan", func(cli *azure.SRegion, args *AppServicePlanShowOptions) error {
appServicePlan, err := cli.GetAppServicePlan(args.ID)
if err != nil {
return err
}
printObject(appServicePlan)
return nil
})
shellutils.R(&AppServicePlanListOptions{}, "autoscale-setting-list", "List autoscale setting in app service plan", func(cli *azure.SRegion, args *AppServicePlanListOptions) error {
appServicePlans, err := cli.GetAutoscaleSettingResources()
if err != nil {
return err
}
printList(appServicePlans, len(appServicePlans), 0, 0, []string{})
return nil
})
shellutils.R(&AppServicePlanShowOptions{}, "app-service-sku-list", "List sku usable in app service plan", func(cli *azure.SRegion, args *AppServicePlanShowOptions) error {
appServicePlan, err := cli.GetAppServicePlan(args.ID)
if err != nil {
return err
}
skus, err := appServicePlan.GetSkus()
if err != nil {
return err
}
printList(skus, len(skus), 0, 0, []string{})
return nil
})
shellutils.R(&AppServicePlanShowOptions{}, "app-service-network-list", "List network connected with app service plan", func(cli *azure.SRegion, args *AppServicePlanShowOptions) error {
appServicePlan, err := cli.GetAppServicePlan(args.ID)
if err != nil {
return err
}
networks, err := appServicePlan.GetNetworks()
if err != nil {
return err
}
printList(networks, len(networks), 0, 0, []string{})
return nil
})
}
+68
View File
@@ -0,0 +1,68 @@
// 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 shell
import (
"yunion.io/x/onecloud/pkg/multicloud/azure"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type AppSiteListOptions struct {
}
shellutils.R(&AppSiteListOptions{}, "app-site-list", "List app service plan", func(cli *azure.SRegion, args *AppSiteListOptions) error {
ass, err := cli.GetAppSites()
if err != nil {
return err
}
printList(ass, len(ass), 0, 0, []string{})
return nil
})
type AppSiteShowOptions struct {
ID string
}
shellutils.R(&AppSiteShowOptions{}, "app-site-show", "Show app service plan", func(cli *azure.SRegion, args *AppSiteShowOptions) error {
as, err := cli.GetAppSite(args.ID)
if err != nil {
return err
}
printObject(as)
return nil
})
shellutils.R(&AppSiteShowOptions{}, "app-site-deployment-list", "List sku usable in app service plan", func(cli *azure.SRegion, args *AppSiteShowOptions) error {
as, err := cli.GetAppSite(args.ID)
if err != nil {
return err
}
deployments, err := as.GetDeployments()
if err != nil {
return err
}
printList(deployments, len(deployments), 0, 0, []string{})
return nil
})
shellutils.R(&AppSiteShowOptions{}, "app-site-slot-list", "List slots ofr App site", func(cli *azure.SRegion, args *AppSiteShowOptions) error {
as, err := cli.GetAppSite(args.ID)
if err != nil {
return err
}
slots, err := as.GetSlots()
if err != nil {
return err
}
printList(slots, len(slots), 0, 0, []string{})
return nil
})
}
+302
View File
@@ -0,0 +1,302 @@
// 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 azure
import (
"fmt"
"net/url"
"strings"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
type SAppSite struct {
multicloud.AzureTags
region *SRegion
appServicePlan *SAppServicePlan
Properties SAppSiteProperties
Id string
Name string
Kind string
Location string
Type string
stack *string
}
type SAppSiteProperties struct {
AvailabilityState string
DefaultHostName string
Enabled bool
EnabledHostNames []string
HostNameSslStates []SHostNameSslState
HostNames []string
HttpsOnly bool
OutboundIpAddresses string
ResourceGroup string
ServerFarmId string
SiteConfig SSiteConfig
State string
}
type SSiteConfig struct {
// TODO
}
type SHostNameSslState struct {
HostType string
Name string
SslState string
Thumbprint string
ToUpdate bool
VirtualIP string
}
func (r *SRegion) GetAppSites() ([]SAppSite, error) {
result := []SAppSite{}
resource := "Microsoft.Web/sites"
err := r.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result)
if err != nil {
return nil, err
}
for i := range result {
result[i].region = r
}
return result, nil
}
func (r *SRegion) GetICloudApps() ([]cloudprovider.ICloudApp, error) {
ass, err := r.GetAppSites()
if err != nil {
return nil, err
}
apps := make([]cloudprovider.ICloudApp, 0, len(ass))
for i := range ass {
apps = append(apps, &SApp{
SAppSite: ass[i],
})
}
return apps, nil
}
func (r *SRegion) GetICloudAppById(id string) (cloudprovider.ICloudApp, error) {
as, err := r.GetAppSite(id)
if err != nil {
return nil, err
}
return &SApp{
SAppSite: *as,
}, nil
}
func (as *SAppSite) GetSlots() ([]SAppSite, error) {
result := []SAppSite{}
resource := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/sites/%s/slots", as.region.client.subscriptionId, as.Properties.ResourceGroup, as.Name)
err := as.region.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result)
if err != nil {
return nil, err
}
return result, nil
}
func (r *SRegion) GetAppSite(siteId string) (*SAppSite, error) {
as := &SAppSite{region: r}
params := url.Values{"api-version": []string{"2019-08-01"}}
return as, r.get(siteId, params, as)
}
func (as *SAppSite) GetAppServicePlan() (*SAppServicePlan, error) {
if as.appServicePlan != nil {
return as.appServicePlan, nil
}
plan, err := as.region.GetAppServicePlanWithCache(as.Properties.ServerFarmId)
if err != nil {
return nil, errors.Wrap(err, "unable to get AppServicePlan")
}
as.appServicePlan = plan
return plan, nil
}
type SDeployment struct {
ID string
Name string
Kind string
Type string
Properties SDeploymentProperties
}
type SDeploymentProperties struct {
Active bool
Author string
AuthorEmail string
Deployer string
Details string
EndTime string
Message string
StartTime string
Status string
}
func (as *SAppSite) GetDeployments() ([]SDeployment, error) {
result := []SDeployment{}
resource := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/sites/%s/deployments", as.region.client._subscriptionId(), as.Properties.ResourceGroup, as.Name)
err := as.region.client.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result)
if err != nil {
return nil, err
}
return result, nil
}
type SStringDictionary struct {
Id string
Kind string
Name string
Type string
Properties map[string]string
}
func (as *SAppSite) GetStack() (string, error) {
if as.stack != nil {
return *as.stack, nil
}
// result := SStringDictionary{}
resource := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/sites/%s/config/metadata", as.region.client.subscriptionId, as.Properties.ResourceGroup, as.Name)
params := url.Values{}
params.Set("api-version", "2019-08-01")
path := resource + "/list"
response, err := as.region.client.jsonRequest("POST", path, nil, params, true)
if err != nil {
return "", err
}
stack, err := response.GetString("properties", "CURRENT_STACK")
if err != nil {
return "", errors.Wrapf(err, "unable to parse response correctly, response: %s", response)
}
as.stack = &stack
return stack, nil
}
func (as *SAppSite) GetId() string {
return as.Id
}
func (as *SAppSite) GetName() string {
return as.Name
}
func (as *SAppSite) GetGlobalId() string {
return strings.ToLower(as.Id)
}
func (as *SAppSite) GetStatus() string {
return "ready"
}
func (as *SAppSite) GetProjectId() string {
return strings.ToLower(as.Properties.ResourceGroup)
}
type SApp struct {
multicloud.SResourceBase
multicloud.AzureTags
SAppSite
}
type SAppEnvironment struct {
multicloud.SResourceBase
multicloud.AzureTags
SAppSite
}
func (ae *SAppEnvironment) GetInstanceType() (string, error) {
asp, err := ae.SAppSite.GetAppServicePlan()
if err != nil {
return "", err
}
return asp.Sku.Name, nil
}
func (ae *SAppEnvironment) GetInstanceNumber() (int, error) {
asp, err := ae.SAppSite.GetAppServicePlan()
if err != nil {
return 0, err
}
return asp.Sku.Capacity, nil
}
func (a *SApp) GetEnvironments() ([]cloudprovider.ICloudAppEnvironment, error) {
sites, err := a.SAppSite.GetSlots()
if err != nil {
return nil, err
}
aes := make([]cloudprovider.ICloudAppEnvironment, 0, len(sites)+1)
aes = append(aes, &SAppEnvironment{
SAppSite: a.SAppSite,
})
for i := range sites {
sites[i].region = a.region
aes = append(aes, &SAppEnvironment{
SAppSite: sites[i],
})
}
return aes, nil
}
var techStacks = map[string]string{
"dotnet": ".NET",
"dotnetcore": ".NET Core",
"aspdotnet": "ASP.NET",
"node": "Node",
"python": "Python",
"php": "PHP",
"ruby": "Ruby",
"java": "Java",
"javacontainers": "Jave Containers",
}
func (a *SApp) GetTechStack() string {
if strings.Contains(a.SAppSite.Kind, "container") {
return "Docker container"
}
stack, err := a.GetStack()
if err != nil {
log.Errorf("unable to GetStack: %v", err)
}
if s, ok := techStacks[stack]; ok {
return s
}
return stack
}
func (a *SApp) GetType() string {
return "web"
}
func (a *SApp) GetKind() string {
return a.Kind
}
func (a *SApp) GetOsType() string {
if strings.Contains(a.Kind, "linux") {
return "Linux"
}
return "Windows"
}
+8
View File
@@ -222,3 +222,11 @@ func (self *SRegion) GetICloudKafkas() ([]cloudprovider.ICloudKafka, error) {
func (self *SRegion) GetICloudKafkaById(id string) (cloudprovider.ICloudKafka, error) {
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetICloudKafkaById")
}
func (self *SRegion) GetICloudApps() ([]cloudprovider.ICloudApp, error) {
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetICloudApps")
}
func (self *SRegion) GetICloudAppById(id string) (cloudprovider.ICloudApp, error) {
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetICloudAppById")
}