Merge pull request #5749 from ioito/feautre/qx-policy

fix: support azure policy
This commit is contained in:
Zexi Li
2020-04-13 09:50:13 +08:00
committed by GitHub
24 changed files with 1379 additions and 15 deletions

View File

@@ -0,0 +1,59 @@
// 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/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
func init() {
type PolicyListOptions struct {
options.BaseListOptions
Policydefinition string `help:"filter by policydefinition"`
}
R(&PolicyListOptions{}, "policy-assignment-list", "List policy assignments", func(s *mcclient.ClientSession, args *PolicyListOptions) error {
params, err := args.Params()
if err != nil {
return err
}
if len(args.Policydefinition) > 0 {
params.Add(jsonutils.NewString(args.Policydefinition), "policydefinition")
}
result, err := modules.PolicyAssignment.List(s, params)
if err != nil {
return err
}
printList(result, modules.PolicyAssignment.GetColumns(s))
return nil
})
type PolicyIdOptions struct {
ID string `help:"policy assignment id or name"`
}
R(&PolicyIdOptions{}, "policy-assignment-show", "Show policy assignment details", func(s *mcclient.ClientSession, args *PolicyIdOptions) error {
result, err := modules.PolicyAssignment.Get(s, args.ID, nil)
if err != nil {
return err
}
printObject(result)
return nil
})
}

View File

@@ -0,0 +1,62 @@
// 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/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
func init() {
type PolicyListOptions struct {
options.BaseListOptions
}
R(&PolicyListOptions{}, "policy-definition-list", "List policy definitions", func(s *mcclient.ClientSession, args *PolicyListOptions) error {
params, err := args.Params()
if err != nil {
return err
}
result, err := modules.PolicyDefinition.List(s, params)
if err != nil {
return err
}
printList(result, modules.PolicyDefinition.GetColumns(s))
return nil
})
type PolicyIdOptions struct {
ID string `help:"policy definition name or id"`
}
R(&PolicyIdOptions{}, "policy-definition-show", "Show policy definition", func(s *mcclient.ClientSession, args *PolicyIdOptions) error {
result, err := modules.PolicyDefinition.Get(s, args.ID, nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&PolicyIdOptions{}, "policy-definition-syncstatus", "Sync policy definition status", func(s *mcclient.ClientSession, args *PolicyIdOptions) error {
result, err := modules.PolicyDefinition.PerformAction(s, args.ID, "syncstatus", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
}

View File

@@ -0,0 +1,42 @@
// 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"
type PolicyDefinitionResourceListInput struct {
Policydefinition string
}
type PolicyAssignmentListInput struct {
apis.DomainLevelResourceListInput
ManagedResourceListInput
PolicyDefinitionResourceListInput
}
type PolicyAssignmentCreateInput struct {
SPolicyAssignment
}
type SPolicyDefinitionDetails struct {
}
type PolicyAssignmentDetails struct {
apis.DomainLevelResourceDetails
PolicyDefinitionResourceInfo
SPolicyAssignment
}

View File

@@ -0,0 +1,62 @@
// 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 (
POLICY_DEFINITION_STATUS_READY = "ready"
POLICY_DEFINITION_STATUS_UNKNOWN = "unknown"
POLICY_DEFINITION_CATEGORY_CLOUDREGION = "cloudregion"
POLICY_DEFINITION_CATEGORY_TAG = "tag"
POLICY_DEFINITION_CONDITION_IN = "in"
POLICY_DEFINITION_CONDITION_NOT_IN = "not_in"
POLICY_DEFINITION_CONDITION_CONTAINS = "contains"
POLICY_DEFINITION_CONDITION_EXCEPT = "except"
)
type PolicyDefinitionListInput struct {
apis.StatusStandaloneResourceListInput
ManagedResourceListInput
}
type PolicyDefinitionCreateInput struct {
apis.StatusStandaloneResourceCreateInput
SPolicyDefinition
}
type PolicyDefinitionDetails struct {
apis.StatusStandaloneResourceDetails
SPolicyDefinition
}
type PolicyDefinitionResourceInfo struct {
Policydefinition string
}
type SCloudregionPolicyDefinition struct {
Id string
Name string
}
type SCloudregionPolicyDefinitions struct {
Cloudregions []SCloudregionPolicyDefinition
}
type PolicyDefinitionSyncstatusInput struct {
}

View File

@@ -1580,6 +1580,31 @@ type SNetworkschedtag struct {
NetworkId string `json:"network_id"`
}
// SPolicyAssignment is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SPolicyAssignment.
type SPolicyAssignment struct {
apis.SDomainLevelResourceBase
SPolicyDefinitionResourceBase
}
// SPolicyDefinition is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SPolicyDefinition.
type SPolicyDefinition struct {
apis.SStatusStandaloneResourceBase
apis.SExternalizedResourceBase
SManagedResourceBase
// 参数
Parameters interface{} `json:"parameters"`
// 条件
Condition string `json:"condition"`
// 类别
Category string `json:"category"`
}
// SPolicyDefinitionResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SPolicyDefinitionResourceBase.
type SPolicyDefinitionResourceBase struct {
// 策略Id
PolicydefinitionId string `json:"policydefinition_id"`
}
// SQcloudCachedLb is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SQcloudCachedLb.
type SQcloudCachedLb struct {
apis.SVirtualResourceBase

View File

@@ -203,6 +203,7 @@ type ICloudProvider interface {
GetCapabilities() []string
GetICloudQuotas() ([]ICloudQuota, error)
GetICloudPolicyDefinitions() ([]ICloudPolicyDefinition, error)
}
func IsSupportProject(prod ICloudProvider) bool {
@@ -306,6 +307,10 @@ func (self *SBaseProvider) GetICloudQuotas() ([]ICloudQuota, error) {
return nil, ErrNotImplemented
}
func (self *SBaseProvider) GetICloudPolicyDefinitions() ([]ICloudPolicyDefinition, error) {
return nil, ErrNotImplemented
}
func (self *SBaseProvider) GetCloudRegionExternalIdPrefix() string {
return self.factory.GetId()
}

View File

@@ -950,3 +950,11 @@ type ICloudQuota interface {
GetMaxQuotaCount() int
GetCurrentQuotaUsedCount() int
}
type ICloudPolicyDefinition interface {
GetGlobalId() string
GetName() string
GetCategory() string
GetCondition() string
GetParameters() *jsonutils.JSONDict
}

View File

@@ -1340,11 +1340,82 @@ func (manager *SGuestManager) validateCreateData(
return nil, httperrors.NewInputParameterError("Invalid userdata: %v", err)
}
err = manager.ValidatePolicyDefinitions(ctx, userCred, ownerId, query, input)
if err != nil {
return nil, err
}
input.Project = ownerId.GetProjectId()
input.ProjectDomain = ownerId.GetProjectDomainId()
return input, nil
}
func (manager *SGuestManager) ValidatePolicyDefinitions(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input *api.ServerCreateInput) error {
definitions, err := PolicyDefinitionManager.GetAvailablePolicyDefinitions(ctx, userCred)
if err != nil {
return httperrors.NewGeneralError(err)
}
for i := range definitions {
switch definitions[i].Category {
case api.POLICY_DEFINITION_CATEGORY_CLOUDREGION:
if len(input.PreferRegion) == 0 {
return httperrors.NewMissingParameterError(fmt.Sprintf("policy definition %s require prefer_region_id parameter", definitions[i].Name))
}
if definitions[i].Parameters == nil {
return httperrors.NewPolicyDefinitionError("invalid parameters for policy definition %s", definitions[i].Name)
}
regionDefinitions := api.SCloudregionPolicyDefinitions{}
definitions[i].Parameters.Unmarshal(&regionDefinitions)
regions := []string{}
for _, region := range regionDefinitions.Cloudregions {
regions = append(regions, region.Id)
regions = append(regions, region.Name)
}
isIn := utils.IsInStringArray(input.PreferRegion, regions)
switch definitions[i].Condition {
case api.POLICY_DEFINITION_CONDITION_IN:
if !isIn {
return httperrors.NewPolicyDefinitionError("policy definition %s require cloudregion in %s", definitions[i].Name, definitions[i].Parameters)
}
case api.POLICY_DEFINITION_CONDITION_NOT_IN:
if isIn {
return httperrors.NewPolicyDefinitionError("policy definition %s require cloudregion not in %s", definitions[i].Name, definitions[i].Parameters)
}
default:
return httperrors.NewPolicyDefinitionError("invalid policy definition %s(%s) condition %s", definitions[i].Name, definitions[i].Id, definitions[i].Condition)
}
case api.POLICY_DEFINITION_CATEGORY_TAG:
tags := []string{}
if definitions[i].Parameters == nil {
return httperrors.NewPolicyDefinitionError("invalid parameters for policy definition %s", definitions[i].Name)
}
definitions[i].Parameters.Unmarshal(&tags, "tags")
metadataKeys := []string{}
for k, _ := range input.Metadata {
metadataKeys = append(metadataKeys, strings.TrimPrefix(k, db.USER_TAG_PREFIX))
}
for _, tag := range tags {
isIn := utils.IsInStringArray(tag, metadataKeys)
switch definitions[i].Condition {
case api.POLICY_DEFINITION_CONDITION_CONTAINS:
if !isIn {
return httperrors.NewPolicyDefinitionError("policy definition %s require must contains tag %s", definitions[i].Name, tag)
}
case api.POLICY_DEFINITION_CONDITION_EXCEPT:
if isIn {
return httperrors.NewPolicyDefinitionError("policy definition %s require except tag %s", definitions[i].Name, tag)
}
default:
return httperrors.NewPolicyDefinitionError("invalid policy definition %s(%s) condition %s", definitions[i].Name, definitions[i].Id, definitions[i].Condition)
}
}
default:
return httperrors.NewPolicyDefinitionError("invalid category %s for policy definition %s(%s)", definitions[i].Category, definitions[i].Name, definitions[i].Id)
}
}
return nil
}
func (manager *SGuestManager) BatchCreateValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
input, err := manager.validateCreateData(ctx, userCred, ownerId, query, data)
if err != nil {

View File

@@ -0,0 +1,130 @@
// 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"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SPolicyAssignmentManager struct {
db.SDomainLevelResourceBaseManager
SPolicyDefinitionResourceBaseManager
}
var PolicyAssignmentManager *SPolicyAssignmentManager
func init() {
PolicyAssignmentManager = &SPolicyAssignmentManager{
SDomainLevelResourceBaseManager: db.NewDomainLevelResourceBaseManager(
SPolicyAssignment{},
"policy_assignments_tbl",
"policy_assignment",
"policy_assignments",
),
}
PolicyAssignmentManager.SetVirtualObject(PolicyAssignmentManager)
}
type SPolicyAssignment struct {
db.SDomainLevelResourceBase
SPolicyDefinitionResourceBase
}
// 策略分配列表
func (manager *SPolicyAssignmentManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.PolicyAssignmentListInput) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SDomainLevelResourceBaseManager.ListItemFilter(ctx, q, userCred, query.DomainLevelResourceListInput)
if err != nil {
return nil, err
}
q, err = manager.SPolicyDefinitionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.PolicyDefinitionResourceListInput)
if err != nil {
return nil, err
}
return q, nil
}
func (manager *SPolicyAssignmentManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []interface{}, fields stringutils2.SSortedStrings, isList bool) []api.PolicyAssignmentDetails {
rows := make([]api.PolicyAssignmentDetails, len(objs))
domainRows := manager.SDomainLevelResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
definitionRows := manager.SPolicyDefinitionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = api.PolicyAssignmentDetails{
DomainLevelResourceDetails: domainRows[i],
PolicyDefinitionResourceInfo: definitionRows[i],
}
}
return rows
}
func (manager *SPolicyAssignmentManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.PolicyAssignmentListInput) (*sqlchemy.SQuery, error) {
q, err := manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
func (manager *SPolicyAssignmentManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.PolicyAssignmentCreateInput) (api.PolicyAssignmentCreateInput, error) {
return input, httperrors.NewInputParameterError("not support create")
}
func (manager *SPolicyAssignmentManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SDomainLevelResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
return q, httperrors.ErrNotFound
}
func (manager *SPolicyAssignmentManager) checkAndSetAssignment(definition *SPolicyDefinition, domainId string) error {
q := manager.Query().Equals("policydefinition_id", definition.Id).Equals("domain_id", domainId)
count, err := q.CountWithError()
if err != nil {
return errors.Wrap(err, "CountWithError")
}
if count == 0 {
return manager.newAssignment(definition, domainId)
}
return nil
}
func (manager *SPolicyAssignmentManager) newAssignment(definition *SPolicyDefinition, domainId string) error {
assignment := SPolicyAssignment{}
assignment.SetModelManager(manager, &assignment)
assignment.Name = fmt.Sprintf("assignment for %s domain %s", definition.Name, domainId)
assignment.DomainId = domainId
assignment.PolicydefinitionId = definition.Id
return manager.TableSpec().Insert(&assignment)
}

View File

@@ -0,0 +1,294 @@
// 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"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/compare"
"yunion.io/x/pkg/utils"
"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/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SPolicyDefinitionManager struct {
db.SStatusStandaloneResourceBaseManager
db.SExternalizedResourceBaseManager
SManagedResourceBaseManager
}
var PolicyDefinitionManager *SPolicyDefinitionManager
func init() {
PolicyDefinitionManager = &SPolicyDefinitionManager{
SStatusStandaloneResourceBaseManager: db.NewStatusStandaloneResourceBaseManager(
SPolicyDefinition{},
"policy_definitions_tbl",
"policy_definition",
"policy_definitions",
),
}
PolicyDefinitionManager.SetVirtualObject(PolicyDefinitionManager)
}
type SPolicyDefinition struct {
db.SStatusStandaloneResourceBase
db.SExternalizedResourceBase
SManagedResourceBase
// 参数
Parameters *jsonutils.JSONDict `get:"domain" list:"domain" create:"admin_optional"`
// 条件
Condition string `width:"32" charset:"ascii" nullable:"false" get:"domain" list:"domain" create:"required"`
// 类别
Category string `width:"16" charset:"ascii" nullable:"false" get:"domain" list:"domain" create:"required"`
}
// 策略列表
func (manager *SPolicyDefinitionManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.PolicyDefinitionListInput) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput)
if err != nil {
return nil, err
}
q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput)
if err != nil {
return nil, err
}
return q, nil
}
func (manager *SPolicyDefinitionManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.PolicyDefinitionCreateInput) (api.PolicyDefinitionCreateInput, error) {
return input, httperrors.NewUnsupportOperationError("not support create definition")
}
func (manager *SPolicyDefinitionManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.PolicyDefinitionListInput) (*sqlchemy.SQuery, error) {
q, err := manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
func (manager *SPolicyDefinitionManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
return q, httperrors.ErrNotFound
}
func (self *SPolicyDefinition) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.PolicyDefinitionDetails, error) {
return api.PolicyDefinitionDetails{}, nil
}
func (manager *SPolicyDefinitionManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []interface{}, fields stringutils2.SSortedStrings, isList bool) []api.PolicyDefinitionDetails {
rows := make([]api.PolicyDefinitionDetails, len(objs))
statusRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = api.PolicyDefinitionDetails{
StatusStandaloneResourceDetails: statusRows[i],
}
}
return rows
}
func (manager *SPolicyDefinitionManager) getPolicyDefinitionsByManagerId(providerId string) ([]SPolicyDefinition, error) {
definitions := []SPolicyDefinition{}
err := fetchByManagerId(manager, providerId, &definitions)
if err != nil {
return nil, errors.Wrap(err, "fetchByManagerId")
}
return definitions, nil
}
func (manager *SPolicyDefinitionManager) GetAvailablePolicyDefinitions(ctx context.Context, userCred mcclient.TokenCredential) ([]SPolicyDefinition, error) {
q := manager.Query()
sq := PolicyAssignmentManager.Query().SubQuery()
q = q.Join(sq, sqlchemy.Equals(q.Field("id"), sq.Field("policydefinition_id"))).Filter(
sqlchemy.Equals(sq.Field("domain_id"), userCred.GetDomainId()),
).Equals("status", api.POLICY_DEFINITION_STATUS_READY)
definitions := []SPolicyDefinition{}
err := db.FetchModelObjects(manager, q, &definitions)
if err != nil {
return nil, errors.Wrap(err, "db.FetchModelObjects")
}
return definitions, nil
}
func (manager *SPolicyDefinitionManager) SyncPolicyDefinitions(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, provider *SCloudprovider, iDefinitions []cloudprovider.ICloudPolicyDefinition) compare.SyncResult {
lockman.LockClass(ctx, manager, db.GetLockClassKey(manager, userCred))
defer lockman.ReleaseClass(ctx, manager, db.GetLockClassKey(manager, userCred))
syncResult := compare.SyncResult{}
dbDefinitions, err := manager.getPolicyDefinitionsByManagerId(provider.Id)
if err != nil {
syncResult.Error(err)
return syncResult
}
removed := make([]SPolicyDefinition, 0)
commondb := make([]SPolicyDefinition, 0)
commonext := make([]cloudprovider.ICloudPolicyDefinition, 0)
added := make([]cloudprovider.ICloudPolicyDefinition, 0)
err = compare.CompareSets(dbDefinitions, iDefinitions, &removed, &commondb, &commonext, &added)
if err != nil {
syncResult.Error(err)
return syncResult
}
for i := 0; i < len(removed); i += 1 {
err = removed[i].purge(ctx, userCred)
if err != nil {
syncResult.DeleteError(err)
continue
}
syncResult.Delete()
}
for i := 0; i < len(commondb); i += 1 {
err = commondb[i].SyncWithCloudPolicyDefinition(ctx, userCred, provider, commonext[i])
if err != nil {
syncResult.UpdateError(err)
continue
}
syncResult.Update()
}
for i := 0; i < len(added); i += 1 {
err = manager.newFromCloudPolicyDefinition(ctx, userCred, added[i], provider)
if err != nil {
syncResult.AddError(err)
continue
}
syncResult.Add()
}
return syncResult
}
func (self *SPolicyDefinition) constructParameters(ctx context.Context, userCred mcclient.TokenCredential, extDefinition cloudprovider.ICloudPolicyDefinition) error {
self.Category = extDefinition.GetCategory()
self.Condition = extDefinition.GetCondition()
switch self.Category {
case api.POLICY_DEFINITION_CATEGORY_CLOUDREGION:
if !utils.IsInStringArray(self.Condition, []string{api.POLICY_DEFINITION_CONDITION_NOT_IN, api.POLICY_DEFINITION_CONDITION_IN}) {
return fmt.Errorf("not support category %s condition %s", self.Category, self.Condition)
}
parameters := extDefinition.GetParameters()
if parameters == nil {
return fmt.Errorf("invalid parameters")
}
cloudregions := []string{}
err := parameters.Unmarshal(&cloudregions, "cloudregions")
if err != nil {
return errors.Wrap(err, "parameters.Unmarshal")
}
regions := api.SCloudregionPolicyDefinitions{Cloudregions: []api.SCloudregionPolicyDefinition{}}
for _, cloudregion := range cloudregions {
region, err := db.FetchByExternalId(CloudregionManager, cloudregion)
if err != nil {
return errors.Wrapf(err, "db.FetchByExternalId(%s)", cloudregion)
}
regionPolicyDefinition := api.SCloudregionPolicyDefinition{
Id: region.GetId(),
Name: region.GetName(),
}
regions.Cloudregions = append(regions.Cloudregions, regionPolicyDefinition)
}
self.Parameters = jsonutils.Marshal(regions).(*jsonutils.JSONDict)
case api.POLICY_DEFINITION_CATEGORY_TAG:
self.Parameters = extDefinition.GetParameters()
default:
return fmt.Errorf("not support category %s", self.Category)
}
self.Status = api.POLICY_DEFINITION_STATUS_READY
return nil
}
func (manager *SPolicyDefinitionManager) newFromCloudPolicyDefinition(ctx context.Context, userCred mcclient.TokenCredential, extDefinition cloudprovider.ICloudPolicyDefinition, provider *SCloudprovider) error {
definition := SPolicyDefinition{}
definition.SetModelManager(manager, &definition)
newName, err := db.GenerateName(manager, userCred, extDefinition.GetName())
if err != nil {
return errors.Wrap(err, "db.GenerateName")
}
definition.Name = newName
definition.ManagerId = provider.Id
definition.Status = api.POLICY_DEFINITION_STATUS_READY
definition.ExternalId = extDefinition.GetGlobalId()
definition.constructParameters(ctx, userCred, extDefinition)
err = manager.TableSpec().Insert(&definition)
if err != nil {
return errors.Wrap(err, "Insert")
}
return PolicyAssignmentManager.newAssignment(&definition, provider.DomainId)
}
func (self *SPolicyDefinition) GetPolicyAssignments() ([]SPolicyAssignment, error) {
assignments := []SPolicyAssignment{}
q := PolicyAssignmentManager.Query().Equals("policydefinition_id", self.Id)
err := db.FetchModelObjects(PolicyAssignmentManager, q, &assignments)
if err != nil {
return nil, errors.Wrap(err, "db.FetchModelObjects")
}
return assignments, nil
}
func (self *SPolicyDefinition) SyncWithCloudPolicyDefinition(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, extDefinition cloudprovider.ICloudPolicyDefinition) error {
_, err := db.UpdateWithLock(ctx, self, func() error {
return self.constructParameters(ctx, userCred, extDefinition)
})
if err != nil {
return errors.Wrap(err, "db.UpdateWithLock")
}
return PolicyAssignmentManager.checkAndSetAssignment(self, provider.DomainId)
}
func (self *SPolicyDefinition) AllowPerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return userCred.HasSystemAdminPrivilege()
}
// 同步策略状态
func (self *SPolicyDefinition) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.PolicyDefinitionSyncstatusInput) (jsonutils.JSONObject, error) {
if len(self.ManagerId) == 0 {
return nil, nil
}
return nil, StartResourceSyncStatusTask(ctx, userCred, self, "PolicyDefinitionSyncstatusTask", "")
}

View File

@@ -0,0 +1,70 @@
// 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"
"database/sql"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SPolicyDefinitionResourceBase struct {
// 策略Id
PolicydefinitionId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"`
}
type SPolicyDefinitionResourceBaseManager struct {
}
func (manager *SPolicyDefinitionResourceBaseManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.PolicyDefinitionResourceListInput) (*sqlchemy.SQuery, error) {
if len(query.Policydefinition) > 0 {
definition, err := PolicyDefinitionManager.FetchByIdOrName(userCred, query.Policydefinition)
if err != nil {
if errors.Cause(err) != sql.ErrNoRows {
return nil, httperrors.NewGeneralError(err)
}
return nil, httperrors.NewResourceNotFoundError2("policy_definition", query.Policydefinition)
}
q = q.Equals("policydefinition_id", definition.GetId())
}
return q, nil
}
func (manager *SPolicyDefinitionResourceBaseManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []interface{}, fields stringutils2.SSortedStrings, isList bool,
) []api.PolicyDefinitionResourceInfo {
rows := make([]api.PolicyDefinitionResourceInfo, len(objs))
definitionIds := make([]string, len(objs))
for i := range objs {
definitionIds[i] = objs[i].(*SPolicyAssignment).PolicydefinitionId
}
idMaps, err := db.FetchIdNameMap2(PolicyDefinitionManager, definitionIds)
if err != nil {
return rows
}
for i := range objs {
rows[i].Policydefinition, _ = idMaps[definitionIds[i]]
}
return rows
}

View File

@@ -1657,3 +1657,54 @@ func (manager *SCloudproviderQuotaManager) purgeAll(ctx context.Context, userCre
}
return nil
}
func (assignment *SPolicyAssignment) purge(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockObject(ctx, assignment)
defer lockman.ReleaseObject(ctx, assignment)
err := assignment.ValidateDeleteCondition(ctx)
if err != nil {
return errors.Wrapf(err, "assignment.ValidateDeleteCondition(%s(%s))", assignment.Name, assignment.Id)
}
return assignment.Delete(ctx, userCred)
}
func (definition *SPolicyDefinition) purge(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockObject(ctx, definition)
defer lockman.ReleaseObject(ctx, definition)
assignments, err := definition.GetPolicyAssignments()
if err != nil {
return errors.Wrap(err, "definition.GetPolicyAssignments")
}
for i := range assignments {
err = assignments[i].purge(ctx, userCred)
if err != nil {
return err
}
}
err = definition.ValidateDeleteCondition(ctx)
if err != nil {
return err
}
return definition.Delete(ctx, userCred)
}
func (manager *SPolicyDefinitionManager) purgeAll(ctx context.Context, userCred mcclient.TokenCredential, providerId string) error {
definitions := []SPolicyDefinition{}
err := fetchByManagerId(manager, providerId, &definitions)
if err != nil {
return err
}
for i := range definitions {
err := definitions[i].purge(ctx, userCred)
if err != nil {
return err
}
}
return nil
}

View File

@@ -34,6 +34,7 @@ var (
"loadbalanceragents",
"isolated-devices",
"reservedips",
"policy_definitions",
}
computeDomainResources = []string{
"cloudaccounts",
@@ -50,6 +51,7 @@ var (
"natgateways",
"natsentries",
"natdentries",
"policy_assignments",
}
computeUserResources = []string{
"keypairs",

View File

@@ -179,6 +179,8 @@ func InitHandlers(app *appsrv.Application) {
models.ScalingGroupManager,
models.ScalingPolicyManager,
models.ScalingActivityManager,
models.PolicyDefinitionManager,
models.PolicyAssignmentManager,
} {
db.RegisterModelManager(manager)
handler := db.NewModelHandler(manager)

View File

@@ -26,7 +26,6 @@ import (
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"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/logclient"
)
@@ -77,7 +76,7 @@ func (self *CloudProviderSyncInfoTask) GetSyncRange() models.SSyncRange {
func (self *CloudProviderSyncInfoTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
provider := obj.(*models.SCloudprovider)
self.SetStage("OnSyncCloudProviderQuotaInfoComplete", nil)
self.SetStage("OnSyncCloudProviderPreInfoComplete", nil)
taskman.LocalTaskRun(self, func() (jsonutils.JSONObject, error) {
p, err := provider.GetProvider()
@@ -85,22 +84,25 @@ func (self *CloudProviderSyncInfoTask) OnInit(ctx context.Context, obj db.IStand
return nil, errors.Wrap(err, "GetProvider")
}
quotas, err := p.GetICloudQuotas()
if err != nil {
if errors.Cause(err) != cloudprovider.ErrNotImplemented {
return nil, errors.Wrap(err, "GetICloudQuotas")
}
return nil, nil
if err == nil {
result := models.CloudproviderQuotaManager.SyncQuotas(ctx, self.GetUserCred(), provider.GetOwnerId(), provider, nil, api.CLOUD_PROVIDER_QUOTA_RANGE_CLOUDPROVIDER, quotas)
msg := result.Result()
notes := fmt.Sprintf("SyncQuotas for provider %s result: %s", provider.Name, msg)
log.Infof(notes)
}
policyDefinitions, err := p.GetICloudPolicyDefinitions()
if err == nil {
result := models.PolicyDefinitionManager.SyncPolicyDefinitions(ctx, self.GetUserCred(), provider.GetOwnerId(), provider, policyDefinitions)
msg := result.Result()
notes := fmt.Sprintf("SyncPolicyDefinitions for provider %s result: %s", provider.Name, msg)
log.Infof(notes)
}
result := models.CloudproviderQuotaManager.SyncQuotas(ctx, self.GetUserCred(), provider.GetOwnerId(), provider, nil, api.CLOUD_PROVIDER_QUOTA_RANGE_CLOUDPROVIDER, quotas)
msg := result.Result()
notes := fmt.Sprintf("SyncQuotas for provider %s result: %s", provider.Name, msg)
log.Infof(notes)
return nil, nil
})
}
func (self *CloudProviderSyncInfoTask) OnSyncCloudProviderQuotaInfoComplete(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
func (self *CloudProviderSyncInfoTask) OnSyncCloudProviderPreInfoComplete(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
provider := obj.(*models.SCloudprovider)
syncRange := self.GetSyncRange()
@@ -113,9 +115,9 @@ func (self *CloudProviderSyncInfoTask) OnSyncCloudProviderQuotaInfoComplete(ctx
})
}
func (self *CloudProviderSyncInfoTask) OnSyncCloudProviderQuotaInfoCompleteFailed(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
func (self *CloudProviderSyncInfoTask) OnSyncCloudProviderPreInfoCompleteFailed(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
log.Errorf("faild to sync provider quotas %s", body.String())
self.OnSyncCloudProviderQuotaInfoComplete(ctx, obj, body)
self.OnSyncCloudProviderPreInfoComplete(ctx, obj, body)
}
func (self *CloudProviderSyncInfoTask) OnSyncCloudProviderInfoComplete(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {

View File

@@ -0,0 +1,75 @@
// 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"
"fmt"
"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 PolicyDefinitionSyncstatusTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(PolicyDefinitionSyncstatusTask{})
}
func (self *PolicyDefinitionSyncstatusTask) taskFailed(ctx context.Context, definition *models.SPolicyDefinition, err error) {
definition.SetStatus(self.UserCred, api.POLICY_DEFINITION_STATUS_UNKNOWN, err.Error())
db.OpsLog.LogEvent(definition, db.ACT_SYNC_STATUS, err.Error(), self.GetUserCred())
logclient.AddActionLogWithStartable(self, definition, logclient.ACT_SYNC_STATUS, err.Error(), self.UserCred, false)
self.SetStageFailed(ctx, err.Error())
}
func (self *PolicyDefinitionSyncstatusTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
definition := obj.(*models.SPolicyDefinition)
cloudprovider := definition.GetCloudprovider()
if cloudprovider == nil {
self.taskFailed(ctx, definition, fmt.Errorf("failed to get cloudprovider for policy definition %s", definition.Name))
return
}
provider, err := cloudprovider.GetProvider()
if err != nil {
self.taskFailed(ctx, definition, errors.Wrap(err, "GetProvider"))
return
}
policyDefinitions, err := provider.GetICloudPolicyDefinitions()
if err != nil {
self.taskFailed(ctx, definition, errors.Wrap(err, "GetICloudPolicyDefinitions"))
return
}
for i := range policyDefinitions {
if policyDefinitions[i].GetGlobalId() == definition.ExternalId {
err = definition.SyncWithCloudPolicyDefinition(ctx, self.GetUserCred(), cloudprovider, policyDefinitions[i])
if err != nil {
self.taskFailed(ctx, definition, errors.Wrap(err, "SyncWithCloudPolicyDefinition"))
return
}
self.SetStageComplete(ctx, nil)
return
}
}
self.taskFailed(ctx, definition, fmt.Errorf("failed to found policy definition %s from cloud", definition.Name))
}

View File

@@ -83,6 +83,8 @@ const (
ErrTooManyAttempts = errors.Error("TooManyFailedAttempts")
ErrTooManyRequests = errors.Error("TooManyRequests")
ErrPolicyDefinition = errors.Error("PolicyDefinitionError")
)
var (
@@ -155,6 +157,8 @@ var (
ErrTooManyAttempts: 429,
ErrTooManyRequests: 429,
ErrPolicyDefinition: 409,
}
)

View File

@@ -94,6 +94,10 @@ func NewMissingParameterError(paramName string) *httputils.JSONClientError {
return httputils.NewJsonClientError(httpErrorCode[ErrMissingParameter], string(ErrMissingParameter), msg, paramName)
}
func NewPolicyDefinitionError(msg string, params ...interface{}) *httputils.JSONClientError {
return httputils.NewJsonClientError(httpErrorCode[ErrPolicyDefinition], string(ErrPolicyDefinition), msg, params...)
}
func NewInsufficientResourceError(msg string, params ...interface{}) *httputils.JSONClientError {
return httputils.NewJsonClientError(httpErrorCode[ErrInsufficientResource], string(ErrInsufficientResource), msg, params...)
}

View File

@@ -0,0 +1,33 @@
// 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 PolicyAssignmentManager struct {
modulebase.ResourceManager
}
var (
PolicyAssignment PolicyAssignmentManager
)
func init() {
PolicyAssignment = PolicyAssignmentManager{NewComputeManager("policy_assignment", "policy_assignments",
[]string{},
[]string{})}
registerCompute(&PolicyAssignment)
}

View File

@@ -0,0 +1,33 @@
// 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 PolicyDefinitionManager struct {
modulebase.ResourceManager
}
var (
PolicyDefinition PolicyDefinitionManager
)
func init() {
PolicyDefinition = PolicyDefinitionManager{NewComputeManager("policy_definition", "policy_definitions",
[]string{},
[]string{})}
registerCompute(&PolicyDefinition)
}

View File

@@ -85,6 +85,8 @@ var DEFAULT_API_VERSION = map[string]string{
"Microsoft.ClassicCompute/domainNames": "2015-12-01", //2014-01-01, 2014-06-01, 2015-06-01, 2015-10-01, 2015-12-01, 2016-04-01, 2016-11-01, 2017-11-01, 2017-11-15
"Microsoft.Compute/locations": "2018-06-01",
"microsoft.insights/eventtypes/management/values": "2017-03-01-preview",
"Microsoft.Authorization/policyDefinitions": "2019-09-01",
"Microsoft.Authorization/policyAssignments": "2019-09-01",
}
type AzureClientConfig struct {
@@ -128,6 +130,7 @@ func (cfg *AzureClientConfig) Debug(debug bool) *AzureClientConfig {
func NewAzureClient(cfg *AzureClientConfig) (*SAzureClient, error) {
client := SAzureClient{
AzureClientConfig: cfg,
debug: cfg.debug,
}
err := client.fetchRegions()
if err != nil {

View File

@@ -0,0 +1,250 @@
// 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"
"regexp"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SPolicyDefinitonPropertieParameterMetadata struct {
DisplayName string
Description string
StrongType string
AssignPermissions bool
}
type SPolicyDefinitonPropertieParameter struct {
Type string
Metadata SPolicyDefinitonPropertieParameterMetadata
AllowedValues []string
DefaultValue []string
}
type SPolicyDefinitonProperties struct {
DisplayName string
PolicyType string
Mode string
Description string
Metadata SPolicyDefinitonPropertieMetadata
Parameters map[string]SPolicyDefinitonPropertieParameter
PolicyRule SPolicyDefinitonPropertieRule
}
type SPolicyDefinitonPropertieRuleThen struct {
Effect string
}
type SPolicyDefinitonPropertieRuleInfo jsonutils.JSONDict
type SPolicyDefinitonPropertieRule struct {
If jsonutils.JSONObject
Then SPolicyDefinitonPropertieRuleThen
}
type SPolicyDefinitonPropertieMetadata struct {
Version string
Category string
}
type SPolicyDefinition struct {
Properties SPolicyDefinitonProperties
Id string
Name string
Type string
}
func (client *SAzureClient) GetPolicyDefinitions() ([]SPolicyDefinition, error) {
definitions := []SPolicyDefinition{}
err := client.ListAll("Microsoft.Authorization/policyDefinitions", &definitions)
if err != nil {
return nil, errors.Wrap(err, "Microsoft.Authorization/policyDefinitions.List")
}
return definitions, nil
}
func (client *SAzureClient) GetPolicyDefinition(id string) (*SPolicyDefinition, error) {
definition := &SPolicyDefinition{}
err := client.Get(id, []string{}, definition)
if err != nil {
return nil, errors.Wrapf(err, "get %s", id)
}
return definition, nil
}
type PolicyAssignmentPropertiesParameter struct {
Value []string
}
type PolicyAssignmentProperties struct {
DisplayName string
Parameters map[string]PolicyAssignmentPropertiesParameter
}
type SPolicyAssignment struct {
Id string
Properties PolicyAssignmentProperties
values []string
category string
condition string
parameters *jsonutils.JSONDict
}
func (assignment *SPolicyAssignment) GetName() string {
return assignment.Properties.DisplayName
}
func (assignment *SPolicyAssignment) GetGlobalId() string {
return strings.ToLower(assignment.Id)
}
func (assignment *SPolicyAssignment) GetCategory() string {
return assignment.category
}
func (assignment *SPolicyAssignment) GetCondition() string {
return assignment.condition
}
func (assignment *SPolicyAssignment) GetParameters() *jsonutils.JSONDict {
return assignment.parameters
}
func (client *SAzureClient) GetPolicyAssignments(defineId string) ([]SPolicyAssignment, error) {
assignments := []SPolicyAssignment{}
resource := "Microsoft.Authorization/policyAssignments"
if len(defineId) > 0 {
resource += ("?$filter=" + url.PathEscape("policyDefinitionId eq ") + fmt.Sprintf("'%s'", defineId))
}
err := client.ListAll(resource, &assignments)
if err != nil {
return nil, errors.Wrap(err, "Microsoft.Authorization/policyAssignments.List")
}
return assignments, nil
}
func (client *SAzureClient) GetICloudDefinitions() ([]cloudprovider.ICloudPolicyDefinition, error) {
ret := []cloudprovider.ICloudPolicyDefinition{}
definitions, err := client.GetPolicyDefinitions()
if err != nil {
return nil, errors.Wrap(err, "GetPolicyDefinitions")
}
for i := range definitions {
if definitions[i].Properties.PolicyRule.Then.Effect != "deny" {
continue
}
rule := definitions[i].Properties.PolicyRule.If
if rule.Contains("field") {
field, _ := rule.GetString("field")
if field == "location" {
defaultValue := []string{}
locationParameter := ""
for k, v := range definitions[i].Properties.Parameters {
if v.Metadata.StrongType == "location" {
defaultValue = v.DefaultValue
locationParameter = k
break
}
}
assignments, err := client.GetPolicyAssignments(definitions[i].Id)
if err != nil {
return nil, errors.Wrapf(err, "GetPolicyAssignments(%s)", definitions[i].Id)
}
for i := range assignments {
location, ok := assignments[i].Properties.Parameters[locationParameter]
if ok {
if len(location.Value) > 0 {
assignments[i].values = location.Value
} else {
assignments[i].values = defaultValue
}
}
regionIds := jsonutils.NewArray()
assignments[i].parameters = jsonutils.NewDict()
for _, value := range assignments[i].values {
region := client.GetRegion(value)
if region != nil {
regionIds.Add(jsonutils.NewString(region.GetGlobalId()))
} else {
log.Errorf("failed to found region %s", value)
}
}
assignments[i].category = api.POLICY_DEFINITION_CATEGORY_CLOUDREGION
if rule.Contains("in") {
assignments[i].condition = api.POLICY_DEFINITION_CONDITION_NOT_IN
} else if rule.Contains("notIn") {
assignments[i].condition = api.POLICY_DEFINITION_CONDITION_IN
}
assignments[i].parameters.Add(regionIds, "cloudregions")
ret = append(ret, &assignments[i])
}
} else if strings.Contains(field, "tags") {
reg := regexp.MustCompile(`^\[concat\('tags\[', parameters\('\w+'\), '\]'\)\]$`)
if !reg.MatchString(field) {
continue
}
if rule.Contains("exists") {
exists, _ := rule.Bool("exists")
defaultValue := []string{}
tagParameter := ""
for k, v := range definitions[i].Properties.Parameters {
tagParameter = k
defaultValue = v.DefaultValue
}
assignments, err := client.GetPolicyAssignments(definitions[i].Id)
if err != nil {
return nil, errors.Wrapf(err, "GetPolicyAssignments(%s)", definitions[i].Id)
}
for i := range assignments {
tag, ok := assignments[i].Properties.Parameters[tagParameter]
if ok {
if len(tag.Value) > 0 {
assignments[i].values = tag.Value
} else {
assignments[i].values = defaultValue
}
}
if len(assignments[i].values) == 0 {
continue
}
tags := jsonutils.NewArray()
for _, _tag := range assignments[i].values {
tags.Add(jsonutils.NewString(_tag))
}
assignments[i].parameters = jsonutils.NewDict()
assignments[i].category = api.POLICY_DEFINITION_CATEGORY_TAG
if exists {
assignments[i].condition = api.POLICY_DEFINITION_CONDITION_EXCEPT
} else {
assignments[i].condition = api.POLICY_DEFINITION_CONDITION_CONTAINS
}
assignments[i].parameters.Add(tags, "tags")
ret = append(ret, &assignments[i])
}
}
}
}
}
return ret, nil
}

View File

@@ -173,6 +173,10 @@ func (self *SAzureProvider) GetIRegions() []cloudprovider.ICloudRegion {
return self.client.GetIRegions()
}
func (self *SAzureProvider) GetICloudPolicyDefinitions() ([]cloudprovider.ICloudPolicyDefinition, error) {
return self.client.GetICloudDefinitions()
}
func (self *SAzureProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) {
return self.client.GetIRegionById(id)
}

View File

@@ -0,0 +1,73 @@
// 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/onecloud/pkg/multicloud/azure"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type PolicyListOptions struct {
}
shellutils.R(&PolicyListOptions{}, "policy-definition-list", "List policy definitions", func(cli *azure.SRegion, args *PolicyListOptions) error {
definitions, err := cli.GetClient().GetPolicyDefinitions()
if err != nil {
return err
}
printList(definitions, len(definitions), 0, 0, []string{})
return nil
})
type PolicyAssignmentListOptions struct {
DefinitionId string
}
shellutils.R(&PolicyAssignmentListOptions{}, "policy-assignment-list", "List policy assignment", func(cli *azure.SRegion, args *PolicyAssignmentListOptions) error {
assignments, err := cli.GetClient().GetPolicyAssignments(args.DefinitionId)
if err != nil {
return err
}
printList(assignments, len(assignments), 0, 0, []string{})
return nil
})
type PolicyIdOptions struct {
ID string
}
shellutils.R(&PolicyIdOptions{}, "policy-definition-show", "Show policy definition", func(cli *azure.SRegion, args *PolicyIdOptions) error {
definition, err := cli.GetClient().GetPolicyDefinition(args.ID)
if err != nil {
return err
}
printObject(definition)
return nil
})
shellutils.R(&PolicyListOptions{}, "policy-definition-list-onecloud", "List convert policy assignment", func(cli *azure.SRegion, args *PolicyListOptions) error {
definitions, err := cli.GetClient().GetICloudDefinitions()
if err != nil {
return err
}
for _, definition := range definitions {
fmt.Printf("definition %s category %s condition %s paramters: %s\n", definition.GetName(), definition.GetCategory(), definition.GetCondition(), definition.GetParameters())
}
return nil
})
}