Merge pull request #10677 from ioito/automated-cherry-pick-of-#10666-upstream-release-3.7

Automated cherry pick of #10666: feat: add nas sync
This commit is contained in:
Zexi Li
2021-04-09 11:19:38 +08:00
committed by GitHub
76 changed files with 6351 additions and 12 deletions
@@ -0,0 +1,26 @@
// 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/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options/compute"
)
func init() {
cmd := shell.NewResourceCmd(&modules.AccessGroupCaches).WithKeyword("access-group-cache")
cmd.List(&compute.AccessGroupCacheListOptions{})
}
@@ -0,0 +1,29 @@
// 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/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/compute"
)
func init() {
cmd := shell.NewResourceCmd(&modules.AccessGroupRules).WithKeyword("access-group-rule")
cmd.List(&compute.AccessGroupRuleListOptions{})
cmd.Delete(&options.BaseIdOptions{})
cmd.Create(&compute.AccessRuleCreateOptions{})
}
+30
View File
@@ -0,0 +1,30 @@
// 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/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/compute"
)
func init() {
cmd := shell.NewResourceCmd(&modules.AccessGroups).WithKeyword("access-group")
cmd.List(&compute.AccessGroupListOptions{})
cmd.Delete(&options.BaseIdOptions{})
cmd.Create(&options.BaseCreateOptions{})
cmd.Perform("syncstatus", &options.BaseIdOptions{})
}
+31
View File
@@ -0,0 +1,31 @@
// 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/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/compute"
)
func init() {
cmd := shell.NewResourceCmd(&modules.FileSystems).WithKeyword("file-system")
cmd.List(&compute.FileSystemListOptions{})
cmd.Show(&options.BaseIdOptions{})
cmd.Delete(&options.BaseIdOptions{})
cmd.Create(&compute.FileSystemCreateOptions{})
cmd.Perform("syncstatus", &compute.FileSystemIdOption{})
}
+31
View File
@@ -0,0 +1,31 @@
// 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/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/compute"
)
func init() {
cmd := shell.NewResourceCmd(&modules.MountTargets).WithKeyword("mount-target")
cmd.Show(&options.BaseIdOptions{})
cmd.Delete(&options.BaseIdOptions{})
cmd.List(&compute.MountTargetListOptions{})
cmd.Create(&compute.MountTargetCreateOptions{})
cmd.Perform("syncstatus", &options.BaseIdOptions{})
}
+29
View File
@@ -0,0 +1,29 @@
// 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/cmd/climc/shell"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
"yunion.io/x/onecloud/pkg/mcclient/options/compute"
)
func init() {
cmd := shell.NewResourceCmd(&modules.NasSkus).WithKeyword("nas-sku")
cmd.List(&compute.NasSkuListOption{})
cmd.Show(&compute.NasSkuIdOption{})
cmd.PerformClass("sync-skus", &options.SkuSyncOptions{})
}
+35
View File
@@ -0,0 +1,35 @@
// 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 AccessGroupCacheListInput struct {
apis.StatusStandaloneResourceListInput
apis.ExternalizedResourceBaseListInput
ManagedResourceListInput
RegionalFilterListInput
AccessGroupFilterListInput
}
type AccessGroupCacheDetails struct {
apis.StatusStandaloneResourceDetails
apis.DomainizedResourceInfo
ManagedResourceInfo
CloudregionResourceInfo
AccessGroupResourceInfo
}
+48
View File
@@ -0,0 +1,48 @@
// 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 AccessGroupRuleListInput struct {
apis.ResourceBaseListInput
AccessGroupFilterListInput
}
type AccessGroupRuleDetails struct {
apis.ResourceBaseDetails
AccessGroupResourceInfo
}
type AccessGroupRuleCreateInput struct {
apis.ResourceBaseCreateInput
Priority int
Source string
RWAccessType string
UserAccessType string
Description string
AccessGroupId string
}
type AccessGroupRuleUpdateInput struct {
Priority *int
Source string
RWAccessType string
UserAccessType string
Description string
}
+54
View File
@@ -0,0 +1,54 @@
// 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 (
DEFAULT_ACCESS_GROUP = "default"
ACCESS_GROUP_STATUS_AVAILABLE = "available"
ACCESS_GROUP_STATUS_DELETING = "deleting"
ACCESS_GROUP_STATUS_DELETE_FAILED = "delete_failed"
ACCESS_GROUP_STATUS_CREATING = "creating"
ACCESS_GROUP_STATUS_SYNC_RULES = "sync_rules"
ACCESS_GROUP_STATUS_SYNC_RULES_FAILED = "sync_rules_failed"
ACCESS_GROUP_STATUS_UNKNOWN = "unknown"
)
type AccessGroupListInput struct {
apis.StatusInfrasResourceBaseListInput
}
type AccessGroupDetails struct {
apis.StatusInfrasResourceBaseDetails
}
type AccessGroupResourceInfo struct {
// 权限组名称
AccessGroup string `json:"access_group"`
}
type AccessGroupFilterListInput struct {
// 权限组Id
AccessGroupId string `json:"access_group_id"`
// 以权限组排序
OrderByAccessGroup string `json:"order_by_access_group"`
}
type AccessGroupCreateInput struct {
apis.StatusInfrasResourceBaseCreateInput
}
+86
View File
@@ -0,0 +1,86 @@
// 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 (
// 可用
NAS_STATUS_AVAILABLE = "available"
// 不可用
NAS_STATUS_UNAVAILABLE = "unavailable"
// 扩容中
NAS_STATUS_EXTENDING = "extending"
// 创建中
NAS_STATUS_CREATING = "creating"
// 创建失败
NAS_STATUS_CREATE_FAILED = "create_failed"
// 未知
NAS_STATUS_UNKNOWN = "unknown"
// 删除中
NAS_STATUS_DELETING = "deleting"
NAS_STATUS_DELETE_FAILED = "delete_failed"
)
type FileSystemListInput struct {
apis.StatusInfrasResourceBaseListInput
apis.ExternalizedResourceBaseListInput
ManagedResourceListInput
RegionalFilterListInput
}
type FileSystemCreateInput struct {
apis.StatusInfrasResourceBaseCreateInput
// 协议类型
// enum: NFS, SMB, CPFS
Protocol string `json:"protocol"`
// 文件系统类型
// enmu: extreme, standard, cpfs
FileSystemType string `json:"file_system_type"`
// 容量大小
Capacity int64 `json:"capacity"`
// IP子网Id
NetworkId string `json:"network_id"`
// 存储类型
// enmu: performance, capacity, standard, advance, advance_100, advance_200
StorageType string `json:"storage_type"`
// 可用区Id, 若不指定IP子网,此参数必填
ZoneId string `json:"zone_id"`
//swagger:ignore
CloudregionId string `json:"cloudregion_id"`
// 订阅Id, 若传入network_id此参数可忽略
ManagerId string `json:"manager_id"`
}
type FileSystemSyncstatusInput struct {
}
type FileSystemDetails struct {
apis.StatusInfrasResourceBaseDetails
ManagedResourceInfo
CloudregionResourceInfo
Vpc string
Network string
Zone string
}
+76
View File
@@ -0,0 +1,76 @@
// 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 (
MOUNT_TARGET_STATUS_AVAILABLE = "available"
MOUNT_TARGET_STATUS_UNAVAILABLE = "unavailable"
MOUNT_TARGET_STATUS_CREATING = "creating"
MOUNT_TARGET_STATUS_CREATE_FAILED = "create_failed"
MOUNT_TARGET_STATUS_DELETING = "deleting"
MOUNT_TARGET_STATUS_DELETE_FAILED = "delete_failed"
MOUNT_TARGET_STATUS_UNKNOWN = "unknown"
)
type MountTargetListInput struct {
apis.StatusStandaloneResourceListInput
apis.ExternalizedResourceBaseListInput
AccessGroupFilterListInput
VpcFilterListInput
NetworkFilterListInput
// 文件系统Id
FileSystemId string `json:"file_system_id"`
}
type MountTargetDetails struct {
apis.StatusStandaloneResourceDetails
AccessGroupResourceInfo
VpcResourceInfo
NetworkResourceInfo
FileSystem string
}
type MountTargetCreateInput struct {
apis.StatusStandaloneResourceCreateInput
// 网络类型
// enmu: vpc, classic
// default: vpc
NetworkType string `json:"network_type"`
// 文件系统Id
// required: true
FileSystemId string `json:"file_system_id"`
// Ip子网名称或Id, network_type == vpc时有效
// required: true
NetworkId string `json:"network_id"`
// swagger:ignore
Network string `json:"network" yunion-deprecated-by:"network_id"`
// swagger:ignore
VpcId string `json:"vpc_id"`
// 权限组Id
AccessGroupId string `json:"access_group_id"`
}
type MountTargetSyncstatusInput struct {
}
+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 compute
import "yunion.io/x/onecloud/pkg/apis"
const (
NAS_SKU_AVAILABLE = "available"
NAS_SKU_SOLDOUT = "soldout"
)
type NasSkuListInput struct {
apis.EnabledStatusStandaloneResourceListInput
apis.ExternalizedResourceBaseListInput
RegionalFilterListInput
PostpaidStatus string `json:"postpaid_stauts"`
PrepaidStatus string `json:"prepaid_status"`
Providers []string `json:"providers"`
// swagger:ignore
// Deprecated
Provider []string `json:"provider" yunion-deprecated-by:"providers"`
}
type NasSkuDetails struct {
apis.EnabledStatusStandaloneResourceDetails
CloudregionResourceInfo
}
+5
View File
@@ -18,6 +18,11 @@ import (
"yunion.io/x/onecloud/pkg/apis"
)
const (
NETWORK_TYPE_VPC = "vpc"
NETWORK_TYPE_CLASSIC = "classic"
)
type WireResourceInput struct {
// 二层网络(ID或Name)的资源
WireId string `json:"wire_id"`
+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 cloudprovider
import (
"fmt"
"sort"
"strings"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
)
type SAccessGroup struct {
Name string
NetworkType string
FileSystemType string
Desc string
}
type TRWAccessType string
type TUserAccessType string
const (
RWAccessTypeRW = TRWAccessType("RW")
RWAccessTypeR = TRWAccessType("R")
UserAccessTypeNoRootSquash = TUserAccessType("no_root_squash")
UserAccessTypeRootSquash = TUserAccessType("root_squash")
UserAccessTypeAllSquash = TUserAccessType("all_squash")
)
func GetAccessGroupRuleInfo(group ICloudAccessGroup) (AccessGroupRuleInfo, error) {
ret := AccessGroupRuleInfo{
MinPriority: group.GetMinPriority(),
MaxPriority: group.GetMaxPriority(),
SupportedUserAccessType: group.GetSupporedUserAccessTypes(),
}
var err error
ret.Rules, err = group.GetRules()
if err != nil {
return ret, errors.Wrapf(err, "GetRules")
}
return ret, nil
}
type AccessGroupRule struct {
Id string
ExternalId string
Priority int
RWAccessType TRWAccessType
UserAccessType TUserAccessType
Source string
}
func (self AccessGroupRule) String() string {
return fmt.Sprintf("%s-%s-%s", self.RWAccessType, self.UserAccessType, self.Source)
}
type AccessGroupRuleSet []AccessGroupRule
func (srs AccessGroupRuleSet) Len() int {
return len(srs)
}
func (srs AccessGroupRuleSet) Swap(i, j int) {
srs[i], srs[j] = srs[j], srs[i]
}
func (srs AccessGroupRuleSet) Less(i, j int) bool {
return srs[i].Priority < srs[j].Priority || (srs[i].Priority == srs[j].Priority && srs[i].String() < srs[j].String())
}
type AccessGroupRuleInfo struct {
MaxPriority int
MinPriority int
SupportedUserAccessType []TUserAccessType
Rules AccessGroupRuleSet
}
func (self *AccessGroupRuleInfo) Sort() {
if self.MinPriority < self.MaxPriority {
sort.Sort(self.Rules)
return
}
sort.Sort(sort.Reverse(self.Rules))
}
func CompareAccessGroupRules(src, dest AccessGroupRuleInfo, debug bool) (common, added, removed AccessGroupRuleSet) {
src.Sort()
dest.Sort()
var addPriority = func(init int, min, max int) int {
inc := 1
if max < min {
max, min, inc = min, max, -1
}
if init >= max || init <= min {
return init
}
return init + inc
}
i, j, priority := 0, 0, (dest.MinPriority-1+dest.MaxPriority)/2
for i < len(src.Rules) || j < len(dest.Rules) {
if i < len(src.Rules) && j < len(dest.Rules) {
destRuleStr := dest.Rules[j].String()
srcRuleStr := src.Rules[i].String()
if debug {
log.Debugf("compare src %s priority(%d) %s -> dest %s priority(%d) %s\n",
src.Rules[i].ExternalId, src.Rules[i].Priority, src.Rules[i].String(),
dest.Rules[j].ExternalId, dest.Rules[j].Priority, dest.Rules[j].String())
}
cmp := strings.Compare(destRuleStr, srcRuleStr)
if cmp == 0 {
dest.Rules[j].Id = src.Rules[i].Id
common = append(common, dest.Rules[j])
priority = dest.Rules[j].Priority
i++
j++
} else if cmp < 0 {
removed = append(removed, dest.Rules[j])
j++
} else {
if isIn, _ := utils.InArray(src.Rules[i].UserAccessType, dest.SupportedUserAccessType); isIn {
priority = addPriority(priority, dest.MinPriority, dest.MaxPriority)
src.Rules[i].Priority = priority
added = append(added, src.Rules[i])
}
i++
}
} else if i >= len(src.Rules) {
removed = append(removed, dest.Rules[j])
j++
} else if j >= len(dest.Rules) {
if isIn, _ := utils.InArray(src.Rules[i].UserAccessType, dest.SupportedUserAccessType); isIn {
priority = addPriority(priority, dest.MinPriority, dest.MaxPriority)
src.Rules[i].Priority = priority
added = append(added, src.Rules[i])
}
i++
}
}
return common, added, removed
}
+1
View File
@@ -55,6 +55,7 @@ const (
CLOUD_CAPABILITY_INTERVPCNETWORK = "intervpcnetwork"
CLOUD_CAPABILITY_SAML_AUTH = "saml_auth" // 是否支持SAML 2.0
CLOUD_CAPABILITY_NAT = "nat" // NAT网关
CLOUD_CAPABILITY_NAS = "nas" // NAS
)
const (
+23
View File
@@ -0,0 +1,23 @@
// 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 cloudprovider
type SMountTargetCreateOptions struct {
AccessGroupId string
NetworkType string
VpcId string
NetworkId string
FileSystemId string
}
+31
View File
@@ -0,0 +1,31 @@
// 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 cloudprovider
import "yunion.io/x/onecloud/pkg/util/billing"
type FileSystemCraeteOptions struct {
Name string
Desc string
VpcId string
NetworkId string
Capacity int64
StorageType string
Protocol string
FileSystemType string
ZoneId string
BillingCycle *billing.SBillingCycle
}
+59
View File
@@ -153,6 +153,15 @@ type ICloudRegion interface {
GetCapabilities() []string
GetICloudQuotas() ([]ICloudQuota, error)
GetICloudFileSystems() ([]ICloudFileSystem, error)
GetICloudFileSystemById(id string) (ICloudFileSystem, error)
CreateICloudFileSystem(opts *FileSystemCraeteOptions) (ICloudFileSystem, error)
GetICloudAccessGroups() ([]ICloudAccessGroup, error)
CreateICloudAccessGroup(opts *SAccessGroup) (ICloudAccessGroup, error)
GetICloudAccessGroupById(id string) (ICloudAccessGroup, error)
}
type ICloudZone interface {
@@ -1217,3 +1226,53 @@ type ICloudInterVpcNetworkRoute interface {
GetEnabled() bool
GetCidr() string
}
type ICloudFileSystem interface {
ICloudResource
IBillingResource
GetFileSystemType() string
GetStorageType() string
GetProtocol() string
GetCapacityGb() int64
GetUsedCapacityGb() int64
GetMountTargetCountLimit() int
GetZoneId() string
GetMountTargets() ([]ICloudMountTarget, error)
CreateMountTarget(opts *SMountTargetCreateOptions) (ICloudMountTarget, error)
Delete() error
}
type ICloudMountTarget interface {
GetGlobalId() string
GetName() string
GetAccessGroupId() string
GetDomainName() string
GetNetworkType() string
GetVpcId() string
GetNetworkId() string
GetStatus() string
Delete() error
}
type ICloudAccessGroup interface {
GetGlobalId() string
GetName() string
GetDesc() string
IsDefault() bool
GetMaxPriority() int
GetMinPriority() int
GetSupporedUserAccessTypes() []TUserAccessType
GetNetworkType() string
GetFileSystemType() string
GetMountTargetCount() int
GetRules() ([]AccessGroupRule, error)
SyncRules(common, added, removed AccessGroupRuleSet) error
Delete() error
}
+628
View File
@@ -0,0 +1,628 @@
// 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/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/rbacutils"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SAccessGroupCacheManager struct {
db.SStatusStandaloneResourceBaseManager
db.SExternalizedResourceBaseManager
SManagedResourceBaseManager
SCloudregionResourceBaseManager
SAccessGroupResourceBaseManager
}
var AccessGroupCacheManager *SAccessGroupCacheManager
func init() {
AccessGroupCacheManager = &SAccessGroupCacheManager{
SStatusStandaloneResourceBaseManager: db.NewStatusStandaloneResourceBaseManager(
SAccessGroupCache{},
"access_group_caches_tbl",
"access_group_cache",
"access_group_caches",
),
}
AccessGroupCacheManager.SetVirtualObject(AccessGroupCacheManager)
}
type SAccessGroupCache struct {
db.SStatusStandaloneResourceBase
db.SExternalizedResourceBase
SCloudregionResourceBase
SManagedResourceBase
SAccessGroupResourceBase
// 已关联的挂载点数量
MountTargetCount int `nullable:"false" list:"user" json:"mount_target_count"`
FileSystemType string `width:"16" charset:"ascii" nullable:"false" index:"true" list:"user"`
NetworkType string `width:"8" charset:"ascii" nullable:"false" index:"true" list:"user" default:"vpc"`
}
func (manager *SAccessGroupCacheManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return false
}
func (manager *SAccessGroupCacheManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return db.IsDomainAllowList(userCred, manager)
}
func (self *SAccessGroupCache) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool {
group, err := self.GetAccessGroup()
if err != nil {
return false
}
return group.AllowUpdateItem(ctx, userCred)
}
func (manager *SAccessGroupCacheManager) ListItemFilter(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.AccessGroupCacheListInput,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput)
if err != nil {
return nil, errors.Wrapf(err, "SStatusStandaloneResourceBaseManager.ListItemFilter")
}
q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
if err != nil {
return nil, errors.Wrapf(err, "SExternalizedResourceBaseManager.ListItemFilter")
}
q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput)
if err != nil {
return nil, errors.Wrapf(err, "SManagedResourceBaseManager.ListItemFilter")
}
q, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput)
if err != nil {
return nil, errors.Wrapf(err, "SCloudregionResourceBaseManager.ListItemFilter")
}
q, err = manager.SAccessGroupResourceBaseManager.ListItemFilter(ctx, q, userCred, query.AccessGroupFilterListInput)
if err != nil {
return nil, errors.Wrapf(err, "SAccessGroupResourceBaseManager.ListItemFilter")
}
return q, nil
}
func (manager *SAccessGroupCacheManager) OrderByExtraFields(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.AccessGroupCacheListInput,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.OrderByExtraFields")
}
q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields")
}
q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput)
if err != nil {
return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields")
}
q, err = manager.SAccessGroupResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.AccessGroupFilterListInput)
if err != nil {
return nil, errors.Wrap(err, "SAccessGroupResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
func (manager *SAccessGroupCacheManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SAccessGroupResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
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
}
q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
return q, httperrors.ErrNotFound
}
func (manager *SAccessGroupCacheManager) FilterByOwner(q *sqlchemy.SQuery, userCred mcclient.IIdentityProvider, scope rbacutils.TRbacScope) *sqlchemy.SQuery {
if userCred != nil {
sq := AccessGroupManager.Query("id")
if len(userCred.GetProjectDomainId()) > 0 {
sq = sq.Equals("domain_id", userCred.GetProjectDomainId())
return q.In("access_group_id", sq)
}
}
return q
}
func (manager *SAccessGroupCacheManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []api.AccessGroupCacheDetails {
rows := make([]api.AccessGroupCacheDetails, len(objs))
stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
manRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
regRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
groupRows := manager.SAccessGroupResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = api.AccessGroupCacheDetails{
StatusStandaloneResourceDetails: stdRows[i],
ManagedResourceInfo: manRows[i],
CloudregionResourceInfo: regRows[i],
AccessGroupResourceInfo: groupRows[i],
}
}
return rows
}
func (manager *SAccessGroupCacheManager) ListItemExportKeys(ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
keys stringutils2.SSortedStrings,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusStandaloneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemExportKeys")
}
if keys.ContainsAny(manager.SManagedResourceBaseManager.GetExportKeys()...) {
q, err = manager.SManagedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemExportKeys")
}
}
if keys.ContainsAny(manager.SCloudregionResourceBaseManager.GetExportKeys()...) {
q, err = manager.SCloudregionResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemExportKeys")
}
}
if keys.ContainsAny(manager.SAccessGroupResourceBaseManager.GetExportKeys()...) {
q, err = manager.SAccessGroupResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SAccessGroupResourceBaseManager.ListItemExportKey")
}
}
return q, nil
}
func (self *SCloudregion) GetAccessGroupCaches() ([]SAccessGroupCache, error) {
caches := []SAccessGroupCache{}
q := AccessGroupCacheManager.Query().Equals("cloudregion_id", self.Id)
err := db.FetchModelObjects(AccessGroupCacheManager, q, &caches)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return caches, nil
}
func (self *SAccessGroupCache) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
return nil
}
func (self *SAccessGroupCache) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
return self.SStatusStandaloneResourceBase.Delete(ctx, userCred)
}
func (self *SCloudregion) SyncAccessGroups(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, iAccessGroups []cloudprovider.ICloudAccessGroup) compare.SyncResult {
lockman.LockRawObject(ctx, self.Id, "access_groups")
defer lockman.ReleaseRawObject(ctx, self.Id, "access_groups")
result := compare.SyncResult{}
dbCaches, err := self.GetAccessGroupCaches()
if err != nil {
result.Error(errors.Wrapf(err, "self.GetAccessGroupCaches"))
return result
}
removed := make([]SAccessGroupCache, 0)
commondb := make([]SAccessGroupCache, 0)
commonext := make([]cloudprovider.ICloudAccessGroup, 0)
added := make([]cloudprovider.ICloudAccessGroup, 0)
err = compare.CompareSets(dbCaches, iAccessGroups, &removed, &commondb, &commonext, &added)
if err != nil {
result.Error(errors.Wrapf(err, "compare.CompareSets"))
return result
}
for i := 0; i < len(removed); i += 1 {
err = removed[i].RealDelete(ctx, userCred)
if err != nil {
result.DeleteError(err)
continue
}
result.Delete()
}
for i := 0; i < len(commondb); i += 1 {
err = commondb[i].syncWithAccessGroup(ctx, userCred, commonext[i])
if err != nil {
result.UpdateError(err)
continue
}
result.Update()
}
for i := 0; i < len(added); i += 1 {
err := provider.newFromCloudAccessGroup(ctx, userCred, self, added[i])
if err != nil {
result.AddError(err)
continue
}
result.Add()
}
return result
}
func (self *SCloudprovider) GetDomainAccessGroups() ([]SAccessGroup, error) {
groups := []SAccessGroup{}
q := AccessGroupManager.Query().Equals("domain_id", self.DomainId).NotEquals("id", api.DEFAULT_ACCESS_GROUP)
err := db.FetchModelObjects(AccessGroupManager, q, &groups)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return groups, nil
}
func (self *SAccessGroupCache) init(iAccessGroup cloudprovider.ICloudAccessGroup) {
self.Name = iAccessGroup.GetName()
self.NetworkType = iAccessGroup.GetNetworkType()
self.FileSystemType = iAccessGroup.GetFileSystemType()
self.MountTargetCount = iAccessGroup.GetMountTargetCount()
self.ExternalId = iAccessGroup.GetGlobalId()
self.Description = iAccessGroup.GetDesc()
self.Status = api.ACCESS_GROUP_STATUS_AVAILABLE
}
func (self *SCloudprovider) newFromCloudAccessGroup(ctx context.Context, userCred mcclient.TokenCredential, region *SCloudregion, iAccessGroup cloudprovider.ICloudAccessGroup) error {
if iAccessGroup.IsDefault() {
cache := &SAccessGroupCache{}
cache.SetModelManager(AccessGroupCacheManager, cache)
cache.CloudregionId = region.Id
cache.ManagerId = self.Id
cache.AccessGroupId = api.DEFAULT_ACCESS_GROUP
cache.init(iAccessGroup)
return AccessGroupCacheManager.TableSpec().Insert(ctx, cache)
}
groups, err := self.GetDomainAccessGroups()
if err != nil {
return errors.Wrapf(err, "GetDomainAccessGroups")
}
src, err := cloudprovider.GetAccessGroupRuleInfo(iAccessGroup)
if err != nil {
return errors.Wrapf(err, "GetAccessGroupRuleInfo")
}
for i := range groups {
dest, err := groups[i].GetAccessGroupRuleInfo()
if err != nil {
continue
}
_, added, removed := cloudprovider.CompareAccessGroupRules(src, dest, false)
if len(added)+len(removed) == 0 {
cache := &SAccessGroupCache{}
cache.SetModelManager(AccessGroupCacheManager, cache)
cache.Name = iAccessGroup.GetName()
cache.AccessGroupId = groups[i].Id
cache.ManagerId = self.Id
cache.CloudregionId = region.Id
cache.init(iAccessGroup)
return AccessGroupCacheManager.TableSpec().Insert(ctx, cache)
}
}
group := &SAccessGroup{}
group.SetModelManager(AccessGroupManager, group)
group.Name, _ = db.GenerateName(AccessGroupManager, self.GetOwnerId(), iAccessGroup.GetName())
group.Status = api.ACCESS_GROUP_STATUS_AVAILABLE
group.DomainId = self.DomainId
err = AccessGroupManager.TableSpec().Insert(ctx, group)
if err != nil {
return errors.Wrapf(err, "AccessGroupManager.Insert")
}
err = group.SyncRules(ctx, userCred, src)
return nil
}
func (self *SAccessGroup) GetAccessGroupCaches() ([]SAccessGroupCache, error) {
q := AccessGroupCacheManager.Query().Equals("access_group_id", self.Id)
caches := []SAccessGroupCache{}
err := db.FetchModelObjects(AccessGroupCacheManager, q, &caches)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return caches, nil
}
func (self *SAccessGroup) removeRules(ctx context.Context, ruleIds []string) error {
rules := []SAccessGroupRule{}
q := AccessGroupRuleManager.Query().Equals("access_group_id", self.Id).In("id", ruleIds)
err := db.FetchModelObjects(AccessGroupRuleManager, q, &rules)
if err != nil {
return errors.Wrapf(err, "db.FetchModelObjects")
}
for i := range rules {
rules[i].Delete(ctx, nil)
}
return nil
}
func (self *SAccessGroup) newAccessGroupRule(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.AccessGroupRule) error {
rule := &SAccessGroupRule{}
rule.SetModelManager(AccessGroupRuleManager, rule)
rule.AccessGroupId = self.Id
rule.Source = ext.Source
rule.RWAccessType = string(ext.RWAccessType)
rule.UserAccessType = string(ext.UserAccessType)
rule.Priority = ext.Priority
return AccessGroupRuleManager.TableSpec().Insert(ctx, rule)
}
func (self *SAccessGroup) SyncRules(ctx context.Context, userCred mcclient.TokenCredential, src cloudprovider.AccessGroupRuleInfo) error {
dest, err := self.GetAccessGroupRuleInfo()
if err != nil {
return errors.Wrapf(err, "GetAccessGroupRuleInfo")
}
_, added, removed := cloudprovider.CompareAccessGroupRules(src, dest, false)
removeIds := []string{}
for i := range removed {
if len(removed[i].ExternalId) > 0 {
removeIds = append(removeIds, removed[i].ExternalId)
}
}
self.removeRules(ctx, removeIds)
for i := range added {
self.newAccessGroupRule(ctx, userCred, added[i])
}
return nil
}
func (self *SAccessGroupCache) syncAccessGroupBaseInfo(ctx context.Context, userCred mcclient.TokenCredential, iAccessGroup cloudprovider.ICloudAccessGroup) error {
_, err := db.Update(self, func() error {
self.init(iAccessGroup)
return nil
})
return errors.Wrapf(err, "db.Update")
}
func (self *SAccessGroupCache) syncWithAccessGroup(ctx context.Context, userCred mcclient.TokenCredential, iAccessGroup cloudprovider.ICloudAccessGroup) error {
err := self.syncAccessGroupBaseInfo(ctx, userCred, iAccessGroup)
if err != nil {
return errors.Wrapf(err, "syncAccessGroupBaseInfo")
}
if self.AccessGroupId == api.DEFAULT_ACCESS_GROUP {
return nil
}
group, err := self.GetAccessGroup()
if err != nil {
return errors.Wrapf(err, "GetAccessGroup")
}
caches, err := group.GetAccessGroupCaches()
if err != nil {
return errors.Wrapf(err, "GetAccessGroupCaches")
}
if len(caches) > 1 {
return nil
}
src, err := cloudprovider.GetAccessGroupRuleInfo(iAccessGroup)
if err != nil {
return errors.Wrapf(err, "cloudprovider.GetAccessGroupRuleInfo")
}
return group.SyncRules(ctx, userCred, src)
}
func (self *SAccessGroupCache) GetRegion() (*SCloudregion, error) {
region, err := CloudregionManager.FetchById(self.CloudregionId)
if err != nil {
return nil, errors.Wrapf(err, "CloudregionManager.FetchById(%s)", self.CloudregionId)
}
return region.(*SCloudregion), nil
}
func (self *SAccessGroupCache) GetIRegion() (cloudprovider.ICloudRegion, error) {
provider, err := self.GetDriver()
if err != nil {
return nil, errors.Wrapf(err, "self.GetDriver")
}
region, err := self.GetRegion()
if err != nil {
return nil, errors.Wrapf(err, "self.GetRegion")
}
return provider.GetIRegionById(region.ExternalId)
}
func (self *SAccessGroupCache) GetICloudAccessGroup() (cloudprovider.ICloudAccessGroup, error) {
if len(self.ExternalId) == 0 {
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty external id")
}
iRegion, err := self.GetIRegion()
if err != nil {
return nil, errors.Wrapf(err, "self.GetIRegion")
}
iAccessGroup, err := iRegion.GetICloudAccessGroupById(self.ExternalId)
if err != nil {
return nil, errors.Wrapf(err, "iRegion.GetICloudAccessGroupById(%s)", self.ExternalId)
}
return iAccessGroup, nil
}
func (self *SAccessGroupCache) SyncRules() error {
group, err := self.GetAccessGroup()
if err != nil {
return errors.Wrapf(err, "GetAccessGroup")
}
src, err := group.GetAccessGroupRuleInfo()
if err != nil {
return errors.Wrapf(err, "GetAccessGroupRuleInfo")
}
iAccessGroup, err := self.GetICloudAccessGroup()
if err != nil {
return errors.Wrapf(err, "GetICloudAccessGroup")
}
dest, err := cloudprovider.GetAccessGroupRuleInfo(iAccessGroup)
if err != nil {
return errors.Wrapf(err, "GetAccessGroupRuleInfo")
}
common, added, removed := cloudprovider.CompareAccessGroupRules(src, dest, false)
return iAccessGroup.SyncRules(common, added, removed)
}
func (self *SAccessGroupCache) CreateIAccessGroup() error {
iRegion, err := self.GetIRegion()
if err != nil {
return errors.Wrapf(err, "self.GetIRegion")
}
opts := &cloudprovider.SAccessGroup{
Name: self.Name,
NetworkType: self.NetworkType,
FileSystemType: self.FileSystemType,
Desc: self.Description,
}
iAccessGroup, err := iRegion.CreateICloudAccessGroup(opts)
if err != nil {
return errors.Wrapf(err, "iRegion.CreateIAccessGroup")
}
_, err = db.Update(self, func() error {
self.ExternalId = iAccessGroup.GetGlobalId()
self.Status = api.ACCESS_GROUP_STATUS_AVAILABLE
return nil
})
if err != nil {
return errors.Wrapf(err, "db.Update")
}
return self.SyncRules()
}
type SAccessGroupCacheRegisterInput struct {
Name string
Desc string
ManagerId string
CloudregionId string
FileSystemType string
NetworkType string
AccessGroupId string
}
func (manager *SAccessGroupCacheManager) Register(ctx context.Context, opts *SAccessGroupCacheRegisterInput) (*SAccessGroupCache, error) {
lockman.LockClass(ctx, manager, "")
defer lockman.ReleaseClass(ctx, manager, "")
cache := &SAccessGroupCache{}
cache.SetModelManager(manager, cache)
cache.Name = opts.Name
cache.Description = opts.Desc
cache.Status = api.ACCESS_GROUP_STATUS_CREATING
cache.ManagerId = opts.ManagerId
cache.CloudregionId = opts.CloudregionId
cache.FileSystemType = opts.FileSystemType
cache.NetworkType = opts.NetworkType
cache.AccessGroupId = opts.AccessGroupId
err := manager.TableSpec().Insert(ctx, cache)
if err != nil {
return nil, errors.Wrapf(err, "Insert")
}
return cache, cache.CreateIAccessGroup()
}
func (self *SAccessGroupCache) ValidateDeleteCondition(ctx context.Context) error {
if self.AccessGroupId == api.DEFAULT_ACCESS_GROUP {
return httperrors.NewProtectedResourceError("not allow to delete default access group")
}
if self.MountTargetCount > 0 && self.Status != api.ACCESS_GROUP_STATUS_UNKNOWN {
return httperrors.NewNotEmptyError("access group not empty, please delete mount target first")
}
return self.SStatusStandaloneResourceBase.ValidateDeleteCondition(ctx)
}
func (self *SAccessGroupCache) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
return self.StartDeleteTask(ctx, userCred, "")
}
func (self *SAccessGroupCache) StartDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
var err = func() error {
task, err := taskman.TaskManager.NewTask(ctx, "AccessGroupCacheDeleteTask", self, userCred, nil, parentTaskId, "", nil)
if err != nil {
return errors.Wrapf(err, "NewTask")
}
return task.ScheduleRun(nil)
}()
if err != nil {
self.SetStatus(userCred, api.ACCESS_GROUP_STATUS_DELETE_FAILED, err.Error())
return nil
}
self.SetStatus(userCred, api.ACCESS_GROUP_STATUS_DELETING, "")
return nil
}
func (self *SAccessGroupCache) SyncStatus(ctx context.Context, userCred mcclient.TokenCredential) error {
iAccessGroup, err := self.GetICloudAccessGroup()
if err != nil {
self.SetStatus(userCred, api.ACCESS_GROUP_STATUS_CREATING, err.Error())
return err
}
return self.syncAccessGroupBaseInfo(ctx, userCred, iAccessGroup)
}
func (self *SAccessGroupCache) AllowPerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return db.IsDomainAllowPerform(userCred, self, "syncstatus")
}
// 同步权限组缓存状态
func (self *SAccessGroupCache) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.MountTargetSyncstatusInput) (jsonutils.JSONObject, error) {
return nil, self.SyncStatus(ctx, userCred)
}
+161
View File
@@ -0,0 +1,161 @@
// 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/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/reflectutils"
"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/validators"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SAccessGroupResourceBase struct {
// 权限组Id
AccessGroupId string `width:"36" charset:"ascii" nullable:"false" create:"required" index:"true" list:"user"`
}
type SAccessGroupResourceBaseManager struct{}
func (self *SAccessGroupResourceBase) GetAccessGroup() (*SAccessGroup, error) {
group, err := AccessGroupManager.FetchById(self.AccessGroupId)
if err != nil {
return nil, errors.Wrapf(err, "AccessGroupManager.FetchById(%s)", self.AccessGroupId)
}
return group.(*SAccessGroup), nil
}
func (manager *SAccessGroupResourceBaseManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []api.AccessGroupResourceInfo {
rows := make([]api.AccessGroupResourceInfo, len(objs))
groupIds := make([]string, len(objs))
for i := range objs {
var base *SAccessGroupResourceBase
err := reflectutils.FindAnonymouStructPointer(objs[i], &base)
if err != nil {
log.Errorf("Cannot find SAccessGroupResourceBase in object %s", objs[i])
continue
}
groupIds[i] = base.AccessGroupId
}
groupNames, err := db.FetchIdNameMap2(AccessGroupManager, groupIds)
if err != nil {
return rows
}
for i := range rows {
rows[i].AccessGroup, _ = groupNames[groupIds[i]]
}
return rows
}
func (manager *SAccessGroupResourceBaseManager) ListItemFilter(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.AccessGroupFilterListInput,
) (*sqlchemy.SQuery, error) {
if len(query.AccessGroupId) > 0 {
_, err := validators.ValidateModel(userCred, AccessGroupManager, &query.AccessGroupId)
if err != nil {
return nil, err
}
q = q.Equals("access_group_id", query.AccessGroupId)
}
return q, nil
}
func (manager *SAccessGroupResourceBaseManager) OrderByExtraFields(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.AccessGroupFilterListInput,
) (*sqlchemy.SQuery, error) {
if !db.NeedOrderQuery(manager.GetOrderByFields(query)) {
return q, nil
}
orderQ := AccessGroupManager.Query("id")
orderSubQ := orderQ.SubQuery()
orderQ, orders, fields := manager.GetOrderBySubQuery(orderQ, orderSubQ, orderQ.Field("id"), userCred, query, nil, nil)
q = q.LeftJoin(orderSubQ, sqlchemy.Equals(q.Field("access_group_id"), orderSubQ.Field("id")))
q = db.OrderByFields(q, orders, fields)
return q, nil
}
func (manager *SAccessGroupResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
if field == "access_group" {
groupQuery := AccessGroupManager.Query("name", "id").Distinct().SubQuery()
q.AppendField(groupQuery.Field("name", field))
q = q.Join(groupQuery, sqlchemy.Equals(q.Field("access_group_id"), groupQuery.Field("id")))
q.GroupBy(groupQuery.Field("name"))
return q, nil
}
return q, httperrors.ErrNotFound
}
func (manager *SAccessGroupResourceBaseManager) GetOrderBySubQuery(
q *sqlchemy.SQuery,
subq *sqlchemy.SSubQuery,
joinField sqlchemy.IQueryField,
userCred mcclient.TokenCredential,
query api.AccessGroupFilterListInput,
orders []string,
fields []sqlchemy.IQueryField,
) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) {
if !db.NeedOrderQuery(manager.GetOrderByFields(query)) {
return q, orders, fields
}
groupQ := AccessGroupManager.Query().SubQuery()
q = q.LeftJoin(groupQ, sqlchemy.Equals(joinField, groupQ.Field("id")))
q = q.AppendField(groupQ.Field("name").Label("access_group"))
orders = append(orders, query.OrderByAccessGroup)
fields = append(fields, subq.Field("access_group"))
return q, orders, fields
}
func (manager *SAccessGroupResourceBaseManager) GetOrderByFields(query api.AccessGroupFilterListInput) []string {
return []string{query.OrderByAccessGroup}
}
func (manager *SAccessGroupResourceBaseManager) ListItemExportKeys(ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
keys stringutils2.SSortedStrings,
) (*sqlchemy.SQuery, error) {
if keys.ContainsAny(manager.GetExportKeys()...) {
subq := AccessGroupManager.Query("id", "name").SubQuery()
q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("access_group_id"), subq.Field("id")))
q = q.AppendField(subq.Field("name", "access_group"))
}
return q, nil
}
func (manager *SAccessGroupResourceBaseManager) GetExportKeys() []string {
return []string{"access_group"}
}
+375
View File
@@ -0,0 +1,375 @@
// 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/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/regutils"
"yunion.io/x/pkg/util/stringutils"
"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/validators"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/logclient"
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SAccessGroupRuleManager struct {
db.SResourceBaseManager
SAccessGroupResourceBaseManager
}
var AccessGroupRuleManager *SAccessGroupRuleManager
func init() {
AccessGroupRuleManager = &SAccessGroupRuleManager{
SResourceBaseManager: db.NewResourceBaseManager(
SAccessGroupRule{},
"access_group_rules_tbl",
"access_group_rule",
"access_group_rules",
),
}
AccessGroupRuleManager.SetVirtualObject(AccessGroupRuleManager)
}
type SAccessGroupRule struct {
db.SResourceBase
SAccessGroupResourceBase
Id string `width:"128" charset:"ascii" primary:"true" list:"user"`
Priority int `default:"1" list:"user" update:"user" list:"user"`
Source string `width:"16" charset:"ascii" list:"user" update:"user" create:"required"`
RWAccessType string `width:"16" charset:"ascii" list:"user" update:"user" create:"required"`
UserAccessType string `width:"16" charset:"ascii" list:"user" update:"user" create:"required"`
Description string `width:"256" charset:"utf8" list:"user" update:"user" create:"optional"`
}
func (self *SAccessGroupRule) BeforeInsert() {
if len(self.Id) == 0 {
self.Id = stringutils.UUID4()
}
}
func (self *SAccessGroupRule) GetId() string {
return self.Id
}
func (manager *SAccessGroupRuleManager) FetchUniqValues(ctx context.Context, data jsonutils.JSONObject) jsonutils.JSONObject {
groupId, _ := data.GetString("access_group_id")
return jsonutils.Marshal(map[string]string{"access_group_id": groupId})
}
func (manager *SAccessGroupRuleManager) FilterByUniqValues(q *sqlchemy.SQuery, values jsonutils.JSONObject) *sqlchemy.SQuery {
groupId, _ := values.GetString("access_group_id")
if len(groupId) > 0 {
q = q.Equals("access_group_id", groupId)
}
return q
}
func (manager *SAccessGroupRuleManager) FetchOwnerId(ctx context.Context, data jsonutils.JSONObject) (mcclient.IIdentityProvider, error) {
groupId, _ := data.GetString("access_group_id")
if len(groupId) > 0 {
accessGroup, err := db.FetchById(AccessGroupManager, groupId)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchById(%s)", groupId)
}
return accessGroup.(*SAccessGroup).GetOwnerId(), nil
}
return db.FetchDomainInfo(ctx, data)
}
func (manager *SAccessGroupRuleManager) FilterByOwner(q *sqlchemy.SQuery, userCred mcclient.IIdentityProvider, scope rbacutils.TRbacScope) *sqlchemy.SQuery {
sq := AccessGroupManager.Query("id")
sq = db.SharableManagerFilterByOwner(AccessGroupManager, sq, userCred, scope)
return q.In("access_group_id", sq.SubQuery())
}
func (manager *SAccessGroupRuleManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return db.IsDomainAllowCreate(userCred, manager)
}
func (manager *SAccessGroupRuleManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return db.IsDomainAllowList(userCred, manager)
}
func (self *SAccessGroupRule) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool {
if self.AccessGroupId == api.DEFAULT_ACCESS_GROUP {
return false
}
group, err := self.GetAccessGroup()
if err != nil {
return false
}
return group.AllowUpdateItem(ctx, userCred)
}
func (self *SAccessGroupRule) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
group, err := self.GetAccessGroup()
if err != nil {
return false
}
return group.AllowDeleteItem(ctx, userCred, query, data)
}
func (manager *SAccessGroupRuleManager) FilterById(q *sqlchemy.SQuery, idStr string) *sqlchemy.SQuery {
return q.Equals("id", idStr)
}
// 权限组规则列表
func (manager *SAccessGroupRuleManager) ListItemFilter(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.AccessGroupRuleListInput,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SResourceBaseManager.ListItemFilter")
}
q, err = manager.SAccessGroupResourceBaseManager.ListItemFilter(ctx, q, userCred, query.AccessGroupFilterListInput)
if err != nil {
return nil, errors.Wrapf(err, "SAccessGroupResourceBaseManager.ListItemFilter")
}
return q, nil
}
func (manager *SAccessGroupRuleManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []api.AccessGroupRuleDetails {
rows := make([]api.AccessGroupRuleDetails, len(objs))
bRows := manager.SResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
gRows := manager.SAccessGroupResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = api.AccessGroupRuleDetails{
ResourceBaseDetails: bRows[i],
AccessGroupResourceInfo: gRows[i],
}
}
return rows
}
func (manager *SAccessGroupRuleManager) OrderByExtraFields(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.AccessGroupRuleListInput,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SResourceBaseManager.OrderByExtraFields")
}
q, err = manager.SAccessGroupResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.AccessGroupFilterListInput)
if err != nil {
return nil, errors.Wrapf(err, "SAccessGroupResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
func (manager *SAccessGroupRuleManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
q, err = manager.SAccessGroupResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
return q, httperrors.ErrNotFound
}
func (self *SAccessGroupRule) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
return db.DeleteModel(ctx, userCred, self)
}
// 创建权限组规则
func (manager *SAccessGroupRuleManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.AccessGroupRuleCreateInput) (api.AccessGroupRuleCreateInput, error) {
if len(input.AccessGroupId) == 0 {
return input, httperrors.NewMissingParameterError("access_group_id")
}
if input.AccessGroupId == api.DEFAULT_ACCESS_GROUP {
return input, httperrors.NewNotSupportedError("can not add rule for default access group")
}
_ag, err := validators.ValidateModel(userCred, AccessGroupManager, &input.AccessGroupId)
if err != nil {
return input, err
}
ag := _ag.(*SAccessGroup)
if !ag.IsOwner(userCred) && !userCred.HasSystemAdminPrivilege() {
return input, httperrors.NewForbiddenError("not enough privilege")
}
if ag.Status != api.ACCESS_GROUP_STATUS_AVAILABLE {
return input, httperrors.NewInvalidStatusError("access group %s status is not available", ag.Name)
}
if len(input.Source) == 0 {
return input, httperrors.NewMissingParameterError("source")
}
if !regutils.MatchCIDR(input.Source) && !regutils.MatchIP4Addr(input.Source) {
return input, httperrors.NewInputParameterError("invalid source %s", input.Source)
}
if input.Priority < 1 || input.Priority > 100 {
return input, httperrors.NewOutOfRangeError("Invalid priority %d, must be in range or 1 ~ 100", input.Priority)
}
if len(input.RWAccessType) == 0 {
return input, httperrors.NewMissingParameterError("rw_access_type")
}
if isIn, _ := utils.InArray(cloudprovider.TRWAccessType(input.RWAccessType), []cloudprovider.TRWAccessType{
cloudprovider.RWAccessTypeR,
cloudprovider.RWAccessTypeRW,
}); !isIn {
return input, httperrors.NewInputParameterError("invalid rw_access_type %s", input.RWAccessType)
}
if len(input.UserAccessType) == 0 {
return input, httperrors.NewMissingParameterError("user_access_type")
}
if isIn, _ := utils.InArray(cloudprovider.TUserAccessType(input.UserAccessType), []cloudprovider.TUserAccessType{
cloudprovider.UserAccessTypeAllSquash,
cloudprovider.UserAccessTypeRootSquash,
cloudprovider.UserAccessTypeNoRootSquash,
}); !isIn {
return input, httperrors.NewInputParameterError("invalid user_access_type %s", input.UserAccessType)
}
input.ResourceBaseCreateInput, err = manager.SResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.ResourceBaseCreateInput)
if err != nil {
return input, err
}
return input, nil
}
func (self *SAccessGroupRule) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
self.SResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
log.Debugf("POST Create %s", data)
group, err := self.GetAccessGroup()
if err == nil {
logclient.AddSimpleActionLog(group, logclient.ACT_ALLOCATE, data, userCred, true)
group.DoSync(ctx, userCred)
}
}
func (self *SAccessGroupRule) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.AccessGroupRuleUpdateInput) (api.AccessGroupRuleUpdateInput, error) {
if input.Priority != nil && *input.Priority < 1 || *input.Priority > 100 {
return input, httperrors.NewOutOfRangeError("Invalid priority %d, must be in range or 1 ~ 100", input.Priority)
}
if len(input.Source) > 0 && !regutils.MatchCIDR(input.Source) {
return input, httperrors.NewInputParameterError("invalid source %s", input.Source)
}
if isIn, _ := utils.InArray(cloudprovider.TRWAccessType(input.RWAccessType), []cloudprovider.TRWAccessType{
cloudprovider.RWAccessTypeR,
cloudprovider.RWAccessTypeRW,
}); !isIn && len(input.RWAccessType) > 0 {
return input, httperrors.NewInputParameterError("invalid rw_access_type %s", input.RWAccessType)
}
if isIn, _ := utils.InArray(cloudprovider.TUserAccessType(input.UserAccessType), []cloudprovider.TUserAccessType{
cloudprovider.UserAccessTypeAllSquash,
cloudprovider.UserAccessTypeRootSquash,
cloudprovider.UserAccessTypeNoRootSquash,
}); !isIn && len(input.UserAccessType) > 0 {
return input, httperrors.NewInputParameterError("invalid user_access_type %s", input.UserAccessType)
}
return input, nil
}
func (self *SAccessGroupRule) GetOwnerId() mcclient.IIdentityProvider {
group, err := self.GetAccessGroup()
if err != nil {
return nil
}
return group.GetOwnerId()
}
func (manager *SAccessGroupRuleManager) ListItemExportKeys(ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
keys stringutils2.SSortedStrings,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SResourceBaseManager.ListItemExportKeys")
}
q, err = manager.SAccessGroupResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrapf(err, "SAccessGroupResourceBaseManager.ListItemExportKeys")
}
return q, nil
}
func (self *SAccessGroupRule) PreDelete(ctx context.Context, userCred mcclient.TokenCredential) {
self.SResourceBase.PreDelete(ctx, userCred)
group, err := self.GetAccessGroup()
if err == nil {
logclient.AddSimpleActionLog(group, logclient.ACT_DELETE, jsonutils.Marshal(self), userCred, true)
group.DoSync(ctx, userCred)
}
}
func (self *SAccessGroupRule) ValidateDeleteCondition(ctx context.Context) error {
if self.AccessGroupId == api.DEFAULT_ACCESS_GROUP {
return httperrors.NewProtectedResourceError("not allow to delete default access group rule")
}
return self.SResourceBase.ValidateDeleteCondition(ctx)
}
func (manager *SAccessGroupRuleManager) InitializeData() error {
q := manager.Query().Equals("access_group_id", api.DEFAULT_ACCESS_GROUP)
rules := []SAccessGroupRule{}
err := db.FetchModelObjects(manager, q, &rules)
if err != nil {
return errors.Wrapf(err, "db.FetchModelObjects")
}
if len(rules) == 0 {
rule := &SAccessGroupRule{}
rule.SetModelManager(manager, rule)
rule.AccessGroupId = api.DEFAULT_ACCESS_GROUP
rule.Source = "0.0.0.0/0"
rule.RWAccessType = string(cloudprovider.RWAccessTypeRW)
rule.UserAccessType = string(cloudprovider.UserAccessTypeNoRootSquash)
err = manager.TableSpec().Insert(context.TODO(), rule)
return errors.Wrapf(err, "Insert")
}
return nil
}
+335
View File
@@ -0,0 +1,335 @@
// 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"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"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/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/mcclient/auth"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SAccessGroupManager struct {
db.SStatusInfrasResourceBaseManager
}
var AccessGroupManager *SAccessGroupManager
func init() {
AccessGroupManager = &SAccessGroupManager{
SStatusInfrasResourceBaseManager: db.NewStatusInfrasResourceBaseManager(
SAccessGroup{},
"access_groups_tbl",
"access_group",
"access_groups",
),
}
AccessGroupManager.SetVirtualObject(AccessGroupManager)
}
type SAccessGroup struct {
db.SStatusInfrasResourceBase
IsDirty bool `nullable:"false" default:"false"`
}
func (manager *SAccessGroupManager) ListItemFilter(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.AccessGroupListInput,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusInfrasResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusInfrasResourceBaseListInput)
if err != nil {
return nil, errors.Wrapf(err, "SStatusInfrasResourceBaseManager.ListItemFilter")
}
return q, nil
}
func (manager SAccessGroupManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []api.AccessGroupDetails {
rows := make([]api.AccessGroupDetails, len(objs))
stdRows := manager.SStatusInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = api.AccessGroupDetails{
StatusInfrasResourceBaseDetails: stdRows[i],
}
}
return rows
}
func (manager *SAccessGroupManager) ListItemExportKeys(ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
keys stringutils2.SSortedStrings,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusInfrasResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SStatusInfrasResourceBaseManager.ListItemExportKeys")
}
return q, nil
}
func (manager *SAccessGroupManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusInfrasResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
return q, nil
}
func (manager *SAccessGroupManager) OrderByExtraFields(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.AccessGroupListInput,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusInfrasResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusInfrasResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SStatusInfrasResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
func (self *SAccessGroup) GetChangeOwnerCandidateDomainIds() []string {
return []string{}
}
func (self *SAccessGroup) GetEmptyAccessGroupRuleInfo() cloudprovider.AccessGroupRuleInfo {
return cloudprovider.AccessGroupRuleInfo{
MinPriority: 1,
MaxPriority: 100,
Rules: cloudprovider.AccessGroupRuleSet{},
SupportedUserAccessType: []cloudprovider.TUserAccessType{
cloudprovider.UserAccessTypeRootSquash,
cloudprovider.UserAccessTypeNoRootSquash,
cloudprovider.UserAccessTypeAllSquash,
},
}
}
func (self *SAccessGroup) GetAccessGroupRuleInfo() (cloudprovider.AccessGroupRuleInfo, error) {
ret := self.GetEmptyAccessGroupRuleInfo()
rules, err := self.GetAccessGroupRules()
if err != nil {
return ret, errors.Wrapf(err, "GetAccessGroupRules")
}
for _, rule := range rules {
userType := cloudprovider.TUserAccessType(rule.UserAccessType)
if isIn, _ := utils.InArray(userType, ret.SupportedUserAccessType); !isIn {
ret.SupportedUserAccessType = append(ret.SupportedUserAccessType, userType)
}
ret.Rules = append(ret.Rules, cloudprovider.AccessGroupRule{
ExternalId: rule.Id,
Source: rule.Source,
RWAccessType: cloudprovider.TRWAccessType(rule.RWAccessType),
UserAccessType: userType,
Priority: rule.Priority,
})
}
return ret, nil
}
func (self *SAccessGroup) GetAccessGroupRules() ([]SAccessGroupRule, error) {
rules := []SAccessGroupRule{}
q := AccessGroupRuleManager.Query().Equals("access_group_id", self.Id)
err := db.FetchModelObjects(AccessGroupRuleManager, q, &rules)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return rules, nil
}
func (manager *SAccessGroupManager) InitializeData() error {
_, err := manager.FetchById(api.DEFAULT_ACCESS_GROUP)
if err != nil {
if errors.Cause(err) != sql.ErrNoRows {
return errors.Wrapf(err, "manager.FetchById(%s)", api.DEFAULT_ACCESS_GROUP)
}
log.Infof("Init default access group")
accessGroup := &SAccessGroup{}
accessGroup.SetModelManager(manager, accessGroup)
accessGroup.Id = api.DEFAULT_ACCESS_GROUP
accessGroup.Name = "Default"
accessGroup.Status = api.ACCESS_GROUP_STATUS_AVAILABLE
accessGroup.DomainId = auth.AdminCredential().GetProjectDomainId()
accessGroup.IsPublic = true
accessGroup.Deleted = false
err = manager.TableSpec().InsertOrUpdate(context.TODO(), accessGroup)
if err != nil {
return errors.Wrapf(err, "InsertOrUpdate default access group")
}
}
return nil
}
func (manager *SAccessGroupManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.AccessGroupCreateInput) (api.AccessGroupCreateInput, error) {
var err error
input.StatusInfrasResourceBaseCreateInput, err = manager.SStatusInfrasResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StatusInfrasResourceBaseCreateInput)
if err != nil {
return input, err
}
input.Status = api.ACCESS_GROUP_STATUS_AVAILABLE
return input, nil
}
func (self *SAccessGroup) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
return self.StartDeleteTask(ctx, userCred, "")
}
func (self *SAccessGroup) StartDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
var err = func() error {
task, err := taskman.TaskManager.NewTask(ctx, "AccessGroupDeleteTask", self, userCred, nil, parentTaskId, "", nil)
if err != nil {
return errors.Wrapf(err, "NewTask")
}
return task.ScheduleRun(nil)
}()
if err != nil {
self.SetStatus(userCred, api.ACCESS_GROUP_STATUS_DELETE_FAILED, err.Error())
return nil
}
self.SetStatus(userCred, api.ACCESS_GROUP_STATUS_DELETING, "")
return nil
}
func (self *SAccessGroup) GetMountTargets() ([]SMountTarget, error) {
mts := []SMountTarget{}
q := MountTargetManager.Query().Equals("access_group_id", self.Id)
err := db.FetchModelObjects(MountTargetManager, q, &mts)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return mts, nil
}
func (self *SAccessGroup) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
return nil
}
func (self *SAccessGroup) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
return self.SStatusInfrasResourceBase.Delete(ctx, userCred)
}
func (self *SAccessGroup) ValidateDeleteCondition(ctx context.Context) error {
if self.Id == api.DEFAULT_ACCESS_GROUP {
return httperrors.NewProtectedResourceError("not allow to delete default access group")
}
mts, err := self.GetMountTargets()
if err != nil {
return errors.Wrapf(err, "GetMountTargets")
}
if len(mts) > 0 {
return httperrors.NewNotEmptyError("access group not empty, please delete mount target first")
}
return self.SStatusInfrasResourceBase.ValidateDeleteCondition(ctx)
}
func (self *SAccessGroup) DoSync(ctx context.Context, userCred mcclient.TokenCredential) {
if _, err := db.Update(self, func() error {
self.IsDirty = true
return nil
}); err != nil {
log.Errorf("Update Security Group error: %s", err.Error())
}
time.AfterFunc(10*time.Second, func() {
AccessGroupManager.DelaySync(context.Background(), userCred, self.Id)
})
}
func (manager *SAccessGroupManager) DelaySync(ctx context.Context, userCred mcclient.TokenCredential, idStr string) error {
_group, err := manager.FetchById(idStr)
if err != nil {
return errors.Wrapf(err, "FetchById(%s)", idStr)
}
group := _group.(*SAccessGroup)
needSync := false
func() {
lockman.LockObject(ctx, group)
defer lockman.ReleaseObject(ctx, group)
if group.IsDirty {
if _, err := db.Update(group, func() error {
group.IsDirty = false
return nil
}); err != nil {
log.Errorf("Update Access Group error: %s", err.Error())
}
needSync = true
}
}()
if needSync {
return group.StartSyncRulesTask(ctx, userCred, "")
}
return nil
}
func (self *SAccessGroup) StartSyncRulesTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
var err = func() error {
task, err := taskman.TaskManager.NewTask(ctx, "AccessGroupSyncRulesTask", self, userCred, nil, parentTaskId, "", nil)
if err != nil {
return errors.Wrapf(err, "NewTask")
}
return task.ScheduleRun(nil)
}()
if err != nil {
self.SetStatus(userCred, api.ACCESS_GROUP_STATUS_SYNC_RULES_FAILED, err.Error())
return err
}
self.SetStatus(userCred, api.ACCESS_GROUP_STATUS_SYNC_RULES, "")
return nil
}
func (self *SAccessGroup) AllowPerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return db.IsDomainAllowPerform(userCred, self, "syncstatus")
}
// 同步权限组状态
func (self *SAccessGroup) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.MountTargetSyncstatusInput) (jsonutils.JSONObject, error) {
return nil, self.StartSyncstatus(ctx, userCred, "")
}
func (self *SAccessGroup) StartSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
return StartResourceSyncStatusTask(ctx, userCred, self, "AccessGroupSyncstatusTask", parentTaskId)
}
+4
View File
@@ -53,6 +53,8 @@ type SCapabilities struct {
DisabledSamlAuthBrands []string `json:",allowempty"`
NatBrands []string `json:",allowempty"`
DisabledNatBrands []string `json:",allowempty"`
NasBrands []string `json:",allowempty"`
DisabledNasBrands []string `json:",allowempty"`
PublicIpBrands []string `json:",allowempty"`
NetworkManageBrands []string `json:",allowempty"`
DisabledNetworkManageBrands []string `json:",allowempty"`
@@ -289,6 +291,7 @@ func getBrands(region *SCloudregion, zone *SZone, domainId string, capa *SCapabi
capa.LoadbalancerEngineBrands, _ = CloudaccountManager.getBrandsOfCapability(region, zone, domainId, tristate.True, cloudprovider.CLOUD_CAPABILITY_LOADBALANCER)
capa.SamlAuthBrands, _ = CloudaccountManager.getBrandsOfCapability(region, zone, domainId, tristate.True, cloudprovider.CLOUD_CAPABILITY_SAML_AUTH)
capa.NatBrands, _ = CloudaccountManager.getBrandsOfCapability(region, zone, domainId, tristate.True, cloudprovider.CLOUD_CAPABILITY_NAT)
capa.NasBrands, _ = CloudaccountManager.getBrandsOfCapability(region, zone, domainId, tristate.True, cloudprovider.CLOUD_CAPABILITY_NAS)
if utils.IsInStringArray(api.HYPERVISOR_KVM, capa.Hypervisors) || utils.IsInStringArray(api.HYPERVISOR_BAREMETAL, capa.Hypervisors) {
capa.Brands = append(capa.Brands, api.ONECLOUD_BRAND_ONECLOUD)
@@ -309,6 +312,7 @@ func getBrands(region *SCloudregion, zone *SZone, domainId string, capa *SCapabi
capa.DisabledCloudIdBrands, _ = CloudaccountManager.getBrandsOfCapability(region, zone, domainId, tristate.False, cloudprovider.CLOUD_CAPABILITY_CLOUDID)
capa.DisabledSamlAuthBrands, _ = CloudaccountManager.getBrandsOfCapability(region, zone, domainId, tristate.False, cloudprovider.CLOUD_CAPABILITY_SAML_AUTH)
capa.DisabledNatBrands, _ = CloudaccountManager.getBrandsOfCapability(region, zone, domainId, tristate.False, cloudprovider.CLOUD_CAPABILITY_NAT)
capa.DisabledNasBrands, _ = CloudaccountManager.getBrandsOfCapability(region, zone, domainId, tristate.False, cloudprovider.CLOUD_CAPABILITY_NAS)
return
}
+1
View File
@@ -2400,6 +2400,7 @@ func (account *SCloudaccount) PerformSyncSkus(ctx context.Context, userCred mccl
ElasticcacheSkuManager.Keyword(),
DBInstanceSkuManager.Keyword(),
NatSkuManager.Keyword(),
NasSkuManager.Keyword(),
}) {
return nil, httperrors.NewInputParameterError("invalid resource %s", input.Resource)
}
+2
View File
@@ -1397,6 +1397,8 @@ func (self *SCloudprovider) RealDelete(ctx context.Context, userCred mcclient.To
DBInstanceManager,
DBInstanceBackupManager,
ElasticcacheManager,
AccessGroupCacheManager,
FileSystemManager,
VpcManager,
ElasticipManager,
NetworkInterfaceManager,
+60
View File
@@ -256,6 +256,63 @@ func syncRegionVPCs(ctx context.Context, userCred mcclient.TokenCredential, sync
}
}
func syncRegionAccessGroups(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, provider *SCloudprovider, localRegion *SCloudregion, remoteRegion cloudprovider.ICloudRegion, syncRange *SSyncRange) {
accessGroups, err := remoteRegion.GetICloudAccessGroups()
if err != nil {
if errors.Cause(err) == cloudprovider.ErrNotImplemented || errors.Cause(err) == cloudprovider.ErrNotSupported {
return
}
log.Errorf("GetICloudFileSystems for region %s error: %v", localRegion.Name, err)
return
}
result := localRegion.SyncAccessGroups(ctx, userCred, provider, accessGroups)
syncResults.Add(AccessGroupCacheManager, result)
log.Infof("Sync Access Group Caches for region %s result: %s", localRegion.Name, result.Result())
}
func syncRegionFileSystems(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, provider *SCloudprovider, localRegion *SCloudregion, remoteRegion cloudprovider.ICloudRegion, syncRange *SSyncRange) {
filesystems, err := remoteRegion.GetICloudFileSystems()
if err != nil {
if errors.Cause(err) == cloudprovider.ErrNotImplemented || errors.Cause(err) == cloudprovider.ErrNotSupported {
return
}
log.Errorf("GetICloudFileSystems for region %s error: %v", localRegion.Name, err)
return
}
localFSs, removeFSs, result := localRegion.SyncFileSystems(ctx, userCred, provider, filesystems)
syncResults.Add(FileSystemManager, result)
log.Infof("Sync FileSystem for region %s result: %s", localRegion.Name, result.Result())
for j := 0; j < len(localFSs); j += 1 {
func() {
// lock file system
lockman.LockObject(ctx, &localFSs[j])
defer lockman.ReleaseObject(ctx, &localFSs[j])
if localFSs[j].Deleted {
return
}
syncFileSystemMountTargets(ctx, userCred, &localFSs[j], removeFSs[j])
}()
}
}
func syncFileSystemMountTargets(ctx context.Context, userCred mcclient.TokenCredential, localFs *SFileSystem, remoteFs cloudprovider.ICloudFileSystem) {
mountTargets, err := remoteFs.GetMountTargets()
if err != nil {
if errors.Cause(err) == cloudprovider.ErrNotImplemented || errors.Cause(err) == cloudprovider.ErrNotSupported {
return
}
log.Errorf("GetMountTargets for %s error: %v", localFs.Name, err)
return
}
result := localFs.SyncMountTargets(ctx, userCred, mountTargets)
log.Infof("SyncMountTargets for FileSystem %s result: %s", localFs.Name, result.Result())
}
func syncVpcPeerConnections(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, provider *SCloudprovider, localVpc *SVpc, remoteVpc cloudprovider.ICloudVpc, syncRange *SSyncRange) {
peerConnections, err := remoteVpc.GetICloudVpcPeeringConnections()
if err != nil {
@@ -1182,6 +1239,9 @@ func syncPublicCloudProviderInfo(
syncRegionSnapshots(ctx, userCred, syncResults, provider, localRegion, remoteRegion, syncRange)
}
syncRegionAccessGroups(ctx, userCred, syncResults, provider, localRegion, remoteRegion, syncRange)
syncRegionFileSystems(ctx, userCred, syncResults, provider, localRegion, remoteRegion, syncRange)
if cloudprovider.IsSupportLoadbalancer(driver) {
syncRegionLoadbalancerAcls(ctx, userCred, syncResults, provider, localRegion, remoteRegion, syncRange)
syncRegionLoadbalancerCertificates(ctx, userCred, syncResults, provider, localRegion, remoteRegion, syncRange)
+523
View File
@@ -0,0 +1,523 @@
// 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"
"strings"
"time"
"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/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"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 SFileSystemManager struct {
db.SStatusInfrasResourceBaseManager
db.SExternalizedResourceBaseManager
SManagedResourceBaseManager
SCloudregionResourceBaseManager
SZoneResourceBaseManager
SDeletePreventableResourceBaseManager
}
var FileSystemManager *SFileSystemManager
func init() {
FileSystemManager = &SFileSystemManager{
SStatusInfrasResourceBaseManager: db.NewStatusInfrasResourceBaseManager(
SFileSystem{},
"file_systems_tbl",
"file_system",
"file_systems",
),
}
FileSystemManager.SetVirtualObject(FileSystemManager)
}
type SFileSystem struct {
db.SStatusInfrasResourceBase
db.SExternalizedResourceBase
SManagedResourceBase
SBillingResourceBase
SCloudregionResourceBase
SZoneResourceBase
SDeletePreventableResourceBase
// 文件系统类型
// enmu: extreme, standard, cpfs
FileSystemType string `width:"32" charset:"ascii" nullable:"false" list:"user" create:"required"`
// 存储类型
// enmu: performance, capacity, standard, advance, advance_100, advance_200
StorageType string `width:"32" charset:"ascii" nullable:"false" list:"user" create:"required"`
// 协议类型
// enum: NFS, SMB, cpfs
Protocol string `width:"32" charset:"ascii" nullable:"false" list:"user" create:"required"`
// 容量, 单位Gb
Capacity int64 `nullable:"false" list:"user" create:"optional"`
// 已使用容量, 单位Gb
UsedCapacity int64 `nullable:"false" list:"user"`
// 最多支持挂载点数量, -1代表无限制
MountTargetCountLimit int `nullable:"false" list:"user" default:"-1"`
}
func (manager *SFileSystemManager) GetContextManagers() [][]db.IModelManager {
return [][]db.IModelManager{
{CloudregionManager},
}
}
func (self *SFileSystem) GetCloudproviderId() string {
return self.ManagerId
}
func (manager *SFileSystemManager) ListItemFilter(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.FileSystemListInput,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusInfrasResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusInfrasResourceBaseListInput)
if err != nil {
return nil, errors.Wrapf(err, "SStatusInfrasResourceBaseManager.ListItemFilter")
}
q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
if err != nil {
return nil, errors.Wrapf(err, "SExternalizedResourceBaseManager.ListItemFilter")
}
q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput)
if err != nil {
return nil, errors.Wrapf(err, "SManagedResourceBaseManager.ListItemFilter")
}
q, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput)
if err != nil {
return nil, errors.Wrapf(err, "SCloudregionResourceBaseManager.ListItemFilter")
}
return q, nil
}
func (man *SFileSystemManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.FileSystemCreateInput) (api.FileSystemCreateInput, error) {
var err error
if len(input.NetworkId) > 0 {
net, err := validators.ValidateModel(userCred, NetworkManager, &input.NetworkId)
if err != nil {
return input, err
}
network := net.(*SNetwork)
zone := network.GetZone()
input.ManagerId = network.GetVpc().ManagerId
input.ZoneId = zone.Id
input.CloudregionId = zone.CloudregionId
} else if len(input.ZoneId) > 0 {
_zone, err := validators.ValidateModel(userCred, ZoneManager, &input.ZoneId)
if err != nil {
return input, err
}
zone := _zone.(*SZone)
input.CloudregionId = zone.CloudregionId
} else {
return input, httperrors.NewMissingParameterError("zone_id")
}
if len(input.ManagerId) == 0 {
return input, httperrors.NewMissingParameterError("manager_id")
}
input.StatusInfrasResourceBaseCreateInput, err = man.SStatusInfrasResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StatusInfrasResourceBaseCreateInput)
if err != nil {
return input, err
}
return input, nil
}
func (self *SFileSystem) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
self.SStatusInfrasResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
self.StartCreateTask(ctx, userCred, jsonutils.GetAnyString(data, []string{"network_id"}), "")
}
func (self *SFileSystem) StartCreateTask(ctx context.Context, userCred mcclient.TokenCredential, networkId string, parentTaskId string) error {
var err = func() error {
params := jsonutils.NewDict()
params.Add(jsonutils.NewString(networkId), "network_id")
task, err := taskman.TaskManager.NewTask(ctx, "FileSystemCreateTask", self, userCred, params, parentTaskId, "", nil)
if err != nil {
return errors.Wrapf(err, "NewTask")
}
return task.ScheduleRun(nil)
}()
if err != nil {
self.SetStatus(userCred, api.NAS_STATUS_CREATE_FAILED, err.Error())
return err
}
self.SetStatus(userCred, api.NAS_STATUS_CREATING, "")
return nil
}
func (manager SFileSystemManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []api.FileSystemDetails {
rows := make([]api.FileSystemDetails, len(objs))
stdRows := manager.SStatusInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
regionRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
mRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
zoneIds := make([]string, len(objs))
for i := range rows {
rows[i] = api.FileSystemDetails{
StatusInfrasResourceBaseDetails: stdRows[i],
CloudregionResourceInfo: regionRows[i],
ManagedResourceInfo: mRows[i],
}
nas := objs[i].(*SFileSystem)
zoneIds[i] = nas.ZoneId
}
zoneMaps, err := db.FetchIdNameMap2(ZoneManager, zoneIds)
if err != nil {
return rows
}
for i := range rows {
rows[i].Zone, _ = zoneMaps[zoneIds[i]]
}
return rows
}
func (manager *SFileSystemManager) ListItemExportKeys(ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
keys stringutils2.SSortedStrings,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusInfrasResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SStatusInfrasResourceBaseManager.ListItemExportKeys")
}
q, err = manager.SCloudregionResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemExportKeys")
}
return q, nil
}
func (manager *SFileSystemManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusInfrasResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
return q, httperrors.ErrNotFound
}
func (manager *SFileSystemManager) OrderByExtraFields(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.FileSystemListInput,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusInfrasResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusInfrasResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SStatusInfrasResourceBaseManager.OrderByExtraFields")
}
q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput)
if err != nil {
return nil, errors.Wrapf(err, "SManagedResourceBaseManager.OrderByExtraFields")
}
q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput)
if err != nil {
return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
func (self *SCloudregion) GetFileSystems() ([]SFileSystem, error) {
ret := []SFileSystem{}
q := FileSystemManager.Query().Equals("cloudregion_id", self.Id)
err := db.FetchModelObjects(FileSystemManager, q, &ret)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return ret, nil
}
func (self *SCloudregion) SyncFileSystems(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, filesystems []cloudprovider.ICloudFileSystem) ([]SFileSystem, []cloudprovider.ICloudFileSystem, compare.SyncResult) {
lockman.LockRawObject(ctx, self.Id, "filesystems")
defer lockman.ReleaseRawObject(ctx, self.Id, "filesystems")
result := compare.SyncResult{}
localFSs := []SFileSystem{}
remoteFSs := []cloudprovider.ICloudFileSystem{}
dbFSs, err := self.GetFileSystems()
if err != nil {
result.Error(errors.Wrapf(err, "self.GetFileSystems"))
return localFSs, remoteFSs, result
}
removed := make([]SFileSystem, 0)
commondb := make([]SFileSystem, 0)
commonext := make([]cloudprovider.ICloudFileSystem, 0)
added := make([]cloudprovider.ICloudFileSystem, 0)
err = compare.CompareSets(dbFSs, filesystems, &removed, &commondb, &commonext, &added)
if err != nil {
result.Error(errors.Wrapf(err, "compare.CompareSets"))
return localFSs, remoteFSs, result
}
for i := 0; i < len(removed); i += 1 {
err = removed[i].syncRemove(ctx, userCred)
if err != nil {
result.DeleteError(err)
continue
}
result.Delete()
}
for i := 0; i < len(commondb); i += 1 {
err = commondb[i].SyncWithCloudFileSystem(ctx, userCred, commonext[i])
if err != nil {
result.UpdateError(err)
continue
}
syncMetadata(ctx, userCred, &commondb[i], commonext[i])
localFSs = append(localFSs, commondb[i])
remoteFSs = append(remoteFSs, commonext[i])
result.Update()
}
for i := 0; i < len(added); i += 1 {
newFs, err := self.newFromCloudFileSystem(ctx, userCred, provider, added[i])
if err != nil {
result.AddError(err)
continue
}
syncMetadata(ctx, userCred, newFs, added[i])
localFSs = append(localFSs, *newFs)
remoteFSs = append(remoteFSs, added[i])
result.Add()
}
return localFSs, remoteFSs, result
}
func (self *SFileSystem) syncRemove(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockObject(ctx, self)
defer lockman.ReleaseObject(ctx, self)
self.DeletePreventionOff(self, userCred)
err := self.ValidateDeleteCondition(ctx)
if err != nil { // cannot delete
return self.SetStatus(userCred, api.NAS_STATUS_UNKNOWN, "sync to delete")
}
return self.RealDelete(ctx, userCred)
}
func (self *SFileSystem) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
return self.StartDeleteTask(ctx, userCred, "")
}
func (self *SFileSystem) StartDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
var err = func() error {
task, err := taskman.TaskManager.NewTask(ctx, "FileSystemDeleteTask", self, userCred, nil, parentTaskId, "", nil)
if err != nil {
return errors.Wrapf(err, "NewTask")
}
return task.ScheduleRun(nil)
}()
if err != nil {
self.SetStatus(userCred, api.NAS_STATUS_DELETE_FAILED, err.Error())
return nil
}
self.SetStatus(userCred, api.NAS_STATUS_DELETING, "")
return nil
}
func (self *SFileSystem) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
return nil
}
func (self *SFileSystem) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
mts, err := self.GetMountTargets()
if err != nil {
return errors.Wrapf(err, "GetMountTargets")
}
for i := range mts {
err = mts[i].RealDelete(ctx, userCred)
if err != nil {
return errors.Wrapf(err, "mount target %s real delete", mts[i].DomainName)
}
}
return self.SInfrasResourceBase.Delete(ctx, userCred)
}
func (self *SFileSystem) ValidateDeleteCondition(ctx context.Context) error {
if self.DisableDelete.IsTrue() {
return httperrors.NewInvalidStatusError("FileSystem is locked, cannot delete")
}
return self.SStatusInfrasResourceBase.ValidateDeleteCondition(ctx)
}
func (self *SFileSystem) SyncAllWithCloudFileSystem(ctx context.Context, userCred mcclient.TokenCredential, fs cloudprovider.ICloudFileSystem) error {
syncFileSystemMountTargets(ctx, userCred, self, fs)
return self.SyncWithCloudFileSystem(ctx, userCred, fs)
}
func (self *SFileSystem) SyncWithCloudFileSystem(ctx context.Context, userCred mcclient.TokenCredential, fs cloudprovider.ICloudFileSystem) error {
_, err := db.Update(self, func() error {
self.Status = fs.GetStatus()
self.StorageType = fs.GetStorageType()
self.Protocol = fs.GetProtocol()
self.Capacity = fs.GetCapacityGb()
self.UsedCapacity = fs.GetUsedCapacityGb()
self.FileSystemType = fs.GetFileSystemType()
self.MountTargetCountLimit = fs.GetMountTargetCountLimit()
if zoneId := fs.GetZoneId(); len(zoneId) > 0 {
region, err := self.GetRegion()
if err != nil {
return errors.Wrapf(err, "self.GetRegion")
}
self.ZoneId, _ = region.getZoneIdBySuffix(zoneId)
}
return nil
})
return errors.Wrapf(err, "db.Update")
}
func (self *SCloudregion) getZoneIdBySuffix(zoneId string) (string, error) {
zones, err := self.GetZones()
if err != nil {
return "", errors.Wrapf(err, "region.GetZones")
}
for _, zone := range zones {
if strings.HasSuffix(zone.ExternalId, zoneId) {
return zone.Id, nil
}
}
return "", errors.Wrapf(cloudprovider.ErrNotFound, zoneId)
}
func (self *SCloudregion) newFromCloudFileSystem(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, fs cloudprovider.ICloudFileSystem) (*SFileSystem, error) {
nas := SFileSystem{}
nas.SetModelManager(FileSystemManager, &nas)
var err error
nas.Name, err = db.GenerateName(FileSystemManager, userCred, fs.GetName())
if err != nil {
return nil, errors.Wrapf(err, "db.GenerateName")
}
nas.ExternalId = fs.GetGlobalId()
nas.CloudregionId = self.Id
nas.ManagerId = provider.Id
nas.Status = fs.GetStatus()
nas.CreatedAt = fs.GetCreatedAt()
nas.StorageType = fs.GetStorageType()
nas.Protocol = fs.GetProtocol()
nas.Capacity = fs.GetCapacityGb()
nas.UsedCapacity = fs.GetCapacityGb()
nas.FileSystemType = fs.GetFileSystemType()
nas.MountTargetCountLimit = fs.GetMountTargetCountLimit()
if zoneId := fs.GetZoneId(); len(zoneId) > 0 {
nas.ZoneId, _ = self.getZoneIdBySuffix(zoneId)
}
return &nas, FileSystemManager.TableSpec().Insert(ctx, &nas)
}
func (self *SFileSystem) AllowPerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return db.IsAdminAllowPerform(userCred, self, "syncstatus")
}
// 同步NAS状态
func (self *SFileSystem) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.FileSystemSyncstatusInput) (jsonutils.JSONObject, error) {
var openTask = true
count, err := taskman.TaskManager.QueryTasksOfObject(self, time.Now().Add(-3*time.Minute), &openTask).CountWithError()
if err != nil {
return nil, err
}
if count > 0 {
return nil, httperrors.NewBadRequestError("Nas has %d task active, can't sync status", count)
}
return nil, self.StartSyncstatus(ctx, userCred, "")
}
func (self *SFileSystem) StartSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
return StartResourceSyncStatusTask(ctx, userCred, self, "FileSystemSyncstatusTask", parentTaskId)
}
func (self *SFileSystem) GetRegion() (*SCloudregion, error) {
region, err := CloudregionManager.FetchById(self.CloudregionId)
if err != nil {
return nil, errors.Wrap(err, "CloudregionManager.FetchById")
}
return region.(*SCloudregion), nil
}
func (self *SFileSystem) GetIRegion() (cloudprovider.ICloudRegion, error) {
provider, err := self.GetDriver()
if err != nil {
return nil, errors.Wrapf(err, "self.GetDriver")
}
region, err := self.GetRegion()
if err != nil {
return nil, errors.Wrapf(err, "self.GetRegion")
}
iRegion, err := provider.GetIRegionById(region.ExternalId)
if err != nil {
return nil, errors.Wrapf(err, "provider.GetIRegionById")
}
return iRegion, nil
}
func (self *SFileSystem) GetICloudFileSystem() (cloudprovider.ICloudFileSystem, error) {
if len(self.ExternalId) == 0 {
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty externalId")
}
iRegion, err := self.GetIRegion()
if err != nil {
return nil, errors.Wrap(err, "self.GetIRegion")
}
return iRegion.GetICloudFileSystemById(self.ExternalId)
}
+2
View File
@@ -69,6 +69,8 @@ func InitDB() error {
DBInstanceDatabaseManager,
SnapshotPolicyDiskManager,
AccessGroupManager,
AccessGroupRuleManager,
} {
err := manager.InitializeData()
if err != nil {
+518
View File
@@ -0,0 +1,518 @@
// 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/log"
"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/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SMountTargetManager struct {
db.SStatusStandaloneResourceBaseManager
db.SExternalizedResourceBaseManager
SVpcResourceBaseManager
SNetworkResourceBaseManager
SAccessGroupResourceBaseManager
}
var MountTargetManager *SMountTargetManager
func init() {
MountTargetManager = &SMountTargetManager{
SStatusStandaloneResourceBaseManager: db.NewStatusStandaloneResourceBaseManager(
SMountTarget{},
"mount_targets_tbl",
"mount_target",
"mount_targets",
),
}
MountTargetManager.SetVirtualObject(MountTargetManager)
}
type SMountTarget struct {
db.SStatusStandaloneResourceBase
db.SExternalizedResourceBase
SVpcResourceBase
SNetworkResourceBase
SAccessGroupResourceBase
NetworkType string `width:"8" charset:"ascii" nullable:"false" create:"required" index:"true" list:"user" default:"vpc"`
DomainName string `charset:"utf8" nullable:"true" create:"optional" list:"user"`
FileSystemId string `width:"36" charset:"ascii" nullable:"false" create:"required" index:"true" list:"user"`
}
func (manager *SMountTargetManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return db.IsDomainAllowCreate(userCred, manager)
}
func (manager *SMountTargetManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return db.IsDomainAllowList(userCred, manager)
}
func (self *SMountTarget) GetFileSystem() (*SFileSystem, error) {
fs, err := FileSystemManager.FetchById(self.FileSystemId)
if err != nil {
return nil, errors.Wrapf(err, "FileSystemManager.FetchById(%s)", self.FileSystemId)
}
return fs.(*SFileSystem), nil
}
func (self *SMountTarget) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool {
fs, err := self.GetFileSystem()
if err != nil {
return false
}
return fs.AllowUpdateItem(ctx, userCred)
}
func (manager *SMountTargetManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.MountTargetCreateInput) (api.MountTargetCreateInput, error) {
if len(input.FileSystemId) == 0 {
return input, httperrors.NewMissingParameterError("file_system_id")
}
_fs, err := validators.ValidateModel(userCred, FileSystemManager, &input.FileSystemId)
if err != nil {
return input, err
}
fs := _fs.(*SFileSystem)
if fs.MountTargetCountLimit > -1 {
mts, err := fs.GetMountTargets()
if err != nil {
return input, httperrors.NewGeneralError(errors.Wrapf(err, "fs.GetMountTargets"))
}
if len(mts) > fs.MountTargetCountLimit {
return input, httperrors.NewOutOfLimitError("Mount target reached the upper limit")
}
}
if len(input.NetworkType) == 0 {
input.NetworkType = api.NETWORK_TYPE_VPC
}
if !utils.IsInStringArray(input.NetworkType, []string{api.NETWORK_TYPE_VPC, api.NETWORK_TYPE_CLASSIC}) {
return input, httperrors.NewInputParameterError("invalid network type %s", input.NetworkType)
}
if input.NetworkType == api.NETWORK_TYPE_VPC {
if len(input.NetworkId) == 0 {
return input, httperrors.NewMissingParameterError("network_id")
}
_network, err := validators.ValidateModel(userCred, NetworkManager, &input.NetworkId)
if err != nil {
return input, err
}
network := _network.(*SNetwork)
vpc := network.GetVpc()
if vpc == nil {
return input, httperrors.NewGeneralError(fmt.Errorf("failed to found vpc for network %s", input.NetworkId))
}
if vpc.ManagerId != fs.ManagerId {
return input, httperrors.NewConflictError("network and filesystem do not belong to the same account")
}
if vpc.CloudregionId != fs.CloudregionId {
return input, httperrors.NewConflictError("network and filesystem are not in the same region")
}
input.VpcId = vpc.Id
}
if len(input.AccessGroupId) == 0 {
return input, httperrors.NewMissingParameterError("access_group_id")
}
_, err = validators.ValidateModel(userCred, AccessGroupManager, &input.AccessGroupId)
if err != nil {
return input, err
}
input.StatusStandaloneResourceCreateInput, err = manager.SStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StatusStandaloneResourceCreateInput)
if err != nil {
return input, err
}
return input, nil
}
func (self *SMountTarget) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
self.SStatusStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
if self.NetworkType == api.NETWORK_TYPE_CLASSIC {
db.Update(self, func() error {
self.VpcId = ""
self.NetworkId = ""
return nil
})
}
self.StartCreateTask(ctx, userCred, "")
}
func (self *SMountTarget) StartCreateTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
var err = func() error {
task, err := taskman.TaskManager.NewTask(ctx, "MountTargetCreateTask", self, userCred, nil, parentTaskId, "", nil)
if err != nil {
return errors.Wrapf(err, "NewTask")
}
return task.ScheduleRun(nil)
}()
if err != nil {
self.SetStatus(userCred, api.MOUNT_TARGET_STATUS_CREATE_FAILED, err.Error())
return nil
}
self.SetStatus(userCred, api.MOUNT_TARGET_STATUS_CREATING, "")
return nil
}
func (manager *SMountTargetManager) ListItemFilter(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.MountTargetListInput,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput)
if err != nil {
return nil, errors.Wrapf(err, "SStatusStandaloneResourceBaseManager.ListItemFilter")
}
q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
if err != nil {
return nil, errors.Wrapf(err, "SExternalizedResourceBaseManager.ListItemFilter")
}
q, err = manager.SAccessGroupResourceBaseManager.ListItemFilter(ctx, q, userCred, query.AccessGroupFilterListInput)
if err != nil {
return nil, errors.Wrapf(err, "SAccessGroupResourceBaseManager.ListItemFilter")
}
q, err = manager.SVpcResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VpcFilterListInput)
if err != nil {
return nil, errors.Wrapf(err, "SVpcResourceBaseManager.ListItemFilter")
}
q, err = manager.SNetworkResourceBaseManager.ListItemFilter(ctx, q, userCred, query.NetworkFilterListInput)
if err != nil {
return nil, errors.Wrapf(err, "SNetworkResourceBaseManager.ListItemFilter")
}
if len(query.FileSystemId) > 0 {
_, err := validators.ValidateModel(userCred, FileSystemManager, &query.FileSystemId)
if err != nil {
return nil, err
}
q = q.Equals("file_system_id", query.FileSystemId)
}
return q, nil
}
func (manager *SMountTargetManager) OrderByExtraFields(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.MountTargetListInput,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.OrderByExtraFields")
}
q, err = manager.SAccessGroupResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.AccessGroupFilterListInput)
if err != nil {
return nil, errors.Wrapf(err, "SAccessGroupResourceBaseManager.OrderByExtraFields")
}
q, err = manager.SVpcResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VpcFilterListInput)
if err != nil {
return nil, errors.Wrapf(err, "SVpcResourceBaseManager.OrderByExtraFields")
}
q, err = manager.SNetworkResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.NetworkFilterListInput)
if err != nil {
return nil, errors.Wrapf(err, "SNetworkResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
func (manager *SMountTargetManager) 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.SAccessGroupResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
q, err = manager.SVpcResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
q, err = manager.SNetworkResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
return q, httperrors.ErrNotFound
}
func (manager *SMountTargetManager) FilterByOwner(q *sqlchemy.SQuery, userCred mcclient.IIdentityProvider, scope rbacutils.TRbacScope) *sqlchemy.SQuery {
if userCred != nil {
sq := FileSystemManager.Query("id")
if len(userCred.GetProjectDomainId()) > 0 {
sq = sq.Equals("domain_id", userCred.GetProjectDomainId())
return q.In("file_system_id", sq)
}
}
return q
}
func (manager *SMountTargetManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []api.MountTargetDetails {
rows := make([]api.MountTargetDetails, len(objs))
stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
netRows := manager.SNetworkResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
acRows := manager.SAccessGroupResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
fsIds := make([]string, len(objs))
for i := range rows {
rows[i] = api.MountTargetDetails{
StatusStandaloneResourceDetails: stdRows[i],
VpcResourceInfo: vpcRows[i],
NetworkResourceInfo: netRows[i],
AccessGroupResourceInfo: acRows[i],
}
mount := objs[i].(*SMountTarget)
fsIds[i] = mount.FileSystemId
}
fsMaps, err := db.FetchIdNameMap2(FileSystemManager, fsIds)
if err != nil {
return rows
}
for i := range rows {
rows[i].FileSystem, _ = fsMaps[fsIds[i]]
}
return rows
}
func (manager *SMountTargetManager) ListItemExportKeys(ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
keys stringutils2.SSortedStrings,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStatusStandaloneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemExportKeys")
}
q, err = manager.SVpcResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrapf(err, "SVpcResourceBaseManager.ListItemExportKeys")
}
q, err = manager.SNetworkResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrapf(err, "SNetworkResourceBaseManager.ListItemExportKeys")
}
q, err = manager.SAccessGroupResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrapf(err, "SAccessGroupResourceBaseManager.ListItemExportKeys")
}
return q, nil
}
func (self *SMountTarget) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
return nil
}
func (self *SMountTarget) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
return self.SStatusStandaloneResourceBase.Delete(ctx, userCred)
}
// 删除挂载点
func (self *SMountTarget) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query api.ServerDeleteInput, input api.NatgatewayDeleteInput) error {
return self.StartDeleteTask(ctx, userCred, "")
}
func (self *SMountTarget) StartDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
var err = func() error {
task, err := taskman.TaskManager.NewTask(ctx, "MountTargetDeleteTask", self, userCred, nil, parentTaskId, "", nil)
if err != nil {
return errors.Wrapf(err, "NewTask")
}
return task.ScheduleRun(nil)
}()
if err != nil {
self.SetStatus(userCred, api.MOUNT_TARGET_STATUS_DELETE_FAILED, err.Error())
return err
}
return self.SetStatus(userCred, api.MOUNT_TARGET_STATUS_DELETING, "")
}
func (self *SFileSystem) GetMountTargets() ([]SMountTarget, error) {
mounts := []SMountTarget{}
q := MountTargetManager.Query().Equals("file_system_id", self.Id)
err := db.FetchModelObjects(MountTargetManager, q, &mounts)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return mounts, nil
}
func (self *SFileSystem) SyncMountTargets(ctx context.Context, userCred mcclient.TokenCredential, extMounts []cloudprovider.ICloudMountTarget) compare.SyncResult {
lockman.LockRawObject(ctx, self.Id, MountTargetManager.KeywordPlural())
lockman.ReleaseRawObject(ctx, self.Id, MountTargetManager.KeywordPlural())
result := compare.SyncResult{}
dbMounts, err := self.GetMountTargets()
if err != nil {
result.Error(errors.Wrapf(err, "self.GetMountTargets"))
return result
}
removed := make([]SMountTarget, 0)
commondb := make([]SMountTarget, 0)
commonext := make([]cloudprovider.ICloudMountTarget, 0)
added := make([]cloudprovider.ICloudMountTarget, 0)
err = compare.CompareSets(dbMounts, extMounts, &removed, &commondb, &commonext, &added)
if err != nil {
result.Error(errors.Wrapf(err, "compare.CompareSets"))
return result
}
for i := 0; i < len(removed); i += 1 {
err = removed[i].RealDelete(ctx, userCred)
if err != nil {
result.DeleteError(err)
continue
}
result.Delete()
}
for i := 0; i < len(commondb); i += 1 {
err = commondb[i].SyncWithMountTarget(ctx, userCred, self.ManagerId, commonext[i])
if err != nil {
result.UpdateError(err)
continue
}
result.Update()
}
for i := 0; i < len(added); i += 1 {
err := self.newFromCloudMountTarget(ctx, userCred, added[i])
if err != nil {
result.AddError(err)
continue
}
result.Add()
}
return result
}
func (self *SMountTarget) SyncWithMountTarget(ctx context.Context, userCred mcclient.TokenCredential, managerId string, m cloudprovider.ICloudMountTarget) error {
_, err := db.Update(self, func() error {
self.Status = m.GetStatus()
self.Name = m.GetName()
self.DomainName = m.GetDomainName()
self.ExternalId = m.GetGlobalId()
if groupId := m.GetAccessGroupId(); len(groupId) > 0 {
_cache, _ := db.FetchByExternalIdAndManagerId(AccessGroupCacheManager, groupId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
return q.Equals("manager_id", managerId)
})
if _cache != nil {
cache := _cache.(*SAccessGroupCache)
self.AccessGroupId = cache.AccessGroupId
}
}
return nil
})
return errors.Wrapf(err, "db.Update")
}
func (self *SFileSystem) newFromCloudMountTarget(ctx context.Context, userCred mcclient.TokenCredential, m cloudprovider.ICloudMountTarget) error {
mount := &SMountTarget{}
mount.SetModelManager(MountTargetManager, mount)
mount.FileSystemId = self.Id
mount.Name = m.GetName()
mount.Status = m.GetStatus()
mount.ExternalId = m.GetGlobalId()
mount.DomainName = m.GetDomainName()
mount.NetworkType = m.GetNetworkType()
if mount.NetworkType == api.NETWORK_TYPE_VPC {
if vpcId := m.GetVpcId(); len(vpcId) > 0 {
vpc, err := db.FetchByExternalIdAndManagerId(VpcManager, vpcId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
return q.Equals("manager_id", self.ManagerId)
})
if err != nil {
log.Errorf("failed to found vpc for mount point %s by externalId: %s", mount.Name, vpcId)
} else {
mount.VpcId = vpc.GetId()
}
}
if networkId := m.GetNetworkId(); len(networkId) > 0 {
network, err := db.FetchByExternalIdAndManagerId(NetworkManager, networkId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
wire := WireManager.Query().SubQuery()
vpc := VpcManager.Query().SubQuery()
return q.Join(wire, sqlchemy.Equals(wire.Field("id"), q.Field("wire_id"))).
Join(vpc, sqlchemy.Equals(vpc.Field("id"), wire.Field("vpc_id"))).
Filter(sqlchemy.Equals(vpc.Field("manager_id"), self.ManagerId))
})
if err != nil {
log.Errorf("failed to found network for mount point %s by externalId: %s", mount.Name, networkId)
} else {
mount.NetworkId = network.GetId()
}
}
}
return MountTargetManager.TableSpec().Insert(ctx, mount)
}
func (self *SMountTarget) GetNetwork() (*SNetwork, error) {
network, err := NetworkManager.FetchById(self.NetworkId)
if err != nil {
return nil, errors.Wrapf(err, "NetworkManager.FetchById(%s)", self.NetworkId)
}
return network.(*SNetwork), nil
}
func (self *SMountTarget) GetVpc() (*SVpc, error) {
vpc, err := VpcManager.FetchById(self.VpcId)
if err != nil {
return nil, errors.Wrapf(err, "VpcManager.FetchById(%s)", self.VpcId)
}
return vpc.(*SVpc), nil
}
func (self *SMountTarget) AllowPerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return db.IsDomainAllowPerform(userCred, self, "syncstatus")
}
// 同步挂载点状态
func (self *SMountTarget) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.MountTargetSyncstatusInput) (jsonutils.JSONObject, error) {
return nil, self.StartSyncstatus(ctx, userCred, "")
}
func (self *SMountTarget) StartSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
return StartResourceSyncStatusTask(ctx, userCred, self, "MountTargetSyncstatusTask", parentTaskId)
}
+339
View File
@@ -0,0 +1,339 @@
// 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"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"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/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SNasSkuManager struct {
db.SEnabledStatusStandaloneResourceBaseManager
db.SExternalizedResourceBaseManager
SCloudregionResourceBaseManager
}
var NasSkuManager *SNasSkuManager
func init() {
NasSkuManager = &SNasSkuManager{
SEnabledStatusStandaloneResourceBaseManager: db.NewEnabledStatusStandaloneResourceBaseManager(
SNasSku{},
"nas_skus_tbl",
"nas_sku",
"nas_skus",
),
}
NasSkuManager.NameRequireAscii = false
NasSkuManager.SetVirtualObject(NasSkuManager)
}
type SNasSku struct {
db.SEnabledStatusStandaloneResourceBase
db.SExternalizedResourceBase
SCloudregionResourceBase
PrepaidStatus string `width:"32" charset:"utf8" nullable:"false" list:"user" create:"admin_optional" update:"admin" default:"available"` // 预付费资源状态 available|soldout
PostpaidStatus string `width:"32" charset:"utf8" nullable:"false" list:"user" create:"admin_optional" update:"admin" default:"available"` // 按需付费资源状态 available|soldout
StorageType string `width:"32" index:"true" list:"user" create:"optional"`
DiskSizeStep int `list:"user" default:"-1" create:"optional"` //步长
MaxDiskSizeGb int `list:"user" create:"optional"`
MinDiskSizeGb int `list:"user" create:"optional"`
NetworkTypes string `list:"user" create:"optional"`
FileSystemType string `list:"user" create:"optional"`
Protocol string `list:"user" create:"optional"`
Provider string `width:"32" charset:"ascii" nullable:"false" list:"user" create:"admin_required" update:"admin"`
ZoneIds string `charset:"utf8" nullable:"true" list:"user" update:"admin" create:"admin_optional" json:"zone_ids"`
}
func (manager *SNasSkuManager) ListItemFilter(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.NasSkuListInput,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
if err != nil {
return nil, errors.Wrapf(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemFilter")
}
q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
if err != nil {
return nil, errors.Wrapf(err, "SExternalizedResourceBaseManager.ListItemFilter")
}
q, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput)
if err != nil {
return nil, errors.Wrapf(err, "SCloudregionResourceBaseManager.ListItemFilter")
}
if len(query.PostpaidStatus) > 0 {
q = q.Equals("postpaid_status", query.PostpaidStatus)
}
if len(query.PrepaidStatus) > 0 {
q = q.Equals("prepaid_status", query.PrepaidStatus)
}
if len(query.Providers) > 0 {
q = q.In("provider", query.Providers)
}
return q, nil
}
func (manager *SNasSkuManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []api.NasSkuDetails {
rows := make([]api.NasSkuDetails, len(objs))
stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
regRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = api.NasSkuDetails{
EnabledStatusStandaloneResourceDetails: stdRows[i],
CloudregionResourceInfo: regRows[i],
}
}
return rows
}
func (manager *SNasSkuManager) ListItemExportKeys(ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
keys stringutils2.SSortedStrings,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SEnabledStatusStandaloneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemExportKeys")
}
q, err = manager.SCloudregionResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemExportKeys")
}
return q, nil
}
func (manager *SNasSkuManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
return q, httperrors.ErrNotFound
}
func (manager *SNasSkuManager) OrderByExtraFields(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.NasSkuListInput,
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields")
}
q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput)
if err != nil {
return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
func (self *SCloudregion) GetNasSkus() ([]SNasSku, error) {
skus := []SNasSku{}
q := NasSkuManager.Query().Equals("cloudregion_id", self.Id)
err := db.FetchModelObjects(NasSkuManager, q, &skus)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return skus, nil
}
func (self SNasSku) GetGlobalId() string {
return self.ExternalId
}
func (self *SCloudregion) SyncNasSkus(ctx context.Context, userCred mcclient.TokenCredential, meta *SSkuResourcesMeta) compare.SyncResult {
lockman.LockRawObject(ctx, self.Id, "nas-sku")
defer lockman.ReleaseRawObject(ctx, self.Id, "nas-sku")
syncResult := compare.SyncResult{}
iskus, err := meta.GetNasSkusByRegionExternalId(self.ExternalId)
if err != nil {
syncResult.Error(err)
return syncResult
}
dbSkus, err := self.GetNasSkus()
if err != nil {
syncResult.Error(err)
return syncResult
}
removed := make([]SNasSku, 0)
commondb := make([]SNasSku, 0)
commonext := make([]SNasSku, 0)
added := make([]SNasSku, 0)
err = compare.CompareSets(dbSkus, iskus, &removed, &commondb, &commonext, &added)
if err != nil {
syncResult.Error(err)
return syncResult
}
for i := 0; i < len(removed); i += 1 {
err = removed[i].Delete(ctx, userCred)
if err != nil {
syncResult.DeleteError(err)
continue
}
syncResult.Delete()
}
for i := 0; i < len(commondb); i += 1 {
err = commondb[i].syncWithCloudSku(ctx, userCred, commonext[i])
if err != nil {
syncResult.UpdateError(err)
continue
}
syncResult.Update()
}
for i := 0; i < len(added); i += 1 {
err = self.newFromCloudNasSku(ctx, userCred, added[i])
if err != nil {
syncResult.AddError(err)
} else {
syncResult.Add()
}
}
return syncResult
}
func (self *SNasSku) syncWithCloudSku(ctx context.Context, userCred mcclient.TokenCredential, sku SNasSku) error {
_, err := db.Update(self, func() error {
jsonutils.Update(self, sku)
self.Status = api.NAS_SKU_AVAILABLE
return nil
})
return err
}
func (self *SCloudregion) newFromCloudNasSku(ctx context.Context, userCred mcclient.TokenCredential, isku SNasSku) error {
sku := &isku
sku.SetModelManager(NasSkuManager, sku)
sku.Id = "" //避免使用yunion meta的id,导致出现duplicate entry问题
sku.Status = api.NAS_SKU_AVAILABLE
sku.SetEnabled(true)
sku.CloudregionId = self.Id
return NasSkuManager.TableSpec().Insert(ctx, sku)
}
func SyncNasSkus(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
err := SyncRegionNasSkus(ctx, userCred, "", isStart)
if err != nil {
log.Errorf("SyncRegionNasSkus error: %v", err)
}
}
func SyncRegionNasSkus(ctx context.Context, userCred mcclient.TokenCredential, regionId string, isStart bool) error {
if isStart {
q := NasSkuManager.Query()
if len(regionId) > 0 {
q = q.Equals("cloudregion_id", regionId)
}
cnt, err := q.Limit(1).CountWithError()
if err != nil && err != sql.ErrNoRows {
return errors.Wrapf(err, "SyncRegionNasSkus.QueryNasSku")
}
if cnt > 0 {
log.Debugf("SyncRegionNasSkus synced skus, skip...")
return nil
}
}
q := CloudregionManager.Query()
q = q.In("provider", CloudproviderManager.GetPublicProviderProvidersQuery())
if len(regionId) > 0 {
q = q.Equals("id", regionId)
}
regions := []SCloudregion{}
err := db.FetchModelObjects(CloudregionManager, q, &regions)
if err != nil {
return errors.Wrapf(err, "db.FetchModelObjects")
}
meta, err := FetchSkuResourcesMeta()
if err != nil {
return errors.Wrapf(err, "FetchSkuResourcesMeta")
}
for i := range regions {
if !regions[i].GetDriver().IsSupportedNas() {
log.Infof("region %s(%s) not support nas, skip sync", regions[i].Name, regions[i].Id)
continue
}
result := regions[i].SyncNasSkus(ctx, userCred, meta)
msg := result.Result()
notes := fmt.Sprintf("SyncNasSkus for region %s result: %s", regions[i].Name, msg)
log.Infof(notes)
}
return nil
}
func (manager *SNasSkuManager) AllowSyncSkus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return db.IsAdminAllowPerform(userCred, manager, "sync-skus")
}
func (manager *SNasSkuManager) PerformSyncSkus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.SkuSyncInput) (jsonutils.JSONObject, error) {
return PerformActionSyncSkus(ctx, userCred, manager.Keyword(), input)
}
func (manager *SNasSkuManager) AllowGetPropertySyncTasks(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return db.IsAdminAllowGetSpec(userCred, manager, "sync-tasks")
}
func (manager *SNasSkuManager) GetPropertySyncTasks(ctx context.Context, userCred mcclient.TokenCredential, query api.SkuTaskQueryInput) (jsonutils.JSONObject, error) {
return GetPropertySkusSyncTasks(ctx, userCred, query)
}
-5
View File
@@ -63,11 +63,6 @@ type SNatSku struct {
PrepaidStatus string `width:"32" charset:"utf8" nullable:"false" list:"user" create:"admin_optional" update:"admin" default:"available"` // 预付费资源状态 available|soldout
PostpaidStatus string `width:"32" charset:"utf8" nullable:"false" list:"user" create:"admin_optional" update:"admin" default:"available"` // 按需付费资源状态 available|soldout
Cps int `nullable:"false" list:"user" create:"optional" update:"admin"`
Conns int `nullable:"false" list:"user" create:"optional" update:"admin"`
Pps int `nullable:"false" list:"user" create:"optional" update:"admin"`
Throughput int `nullable:"false" list:"user" create:"optional" update:"admin"`
Provider string `width:"32" charset:"ascii" nullable:"false" list:"user" create:"admin_required" update:"admin"`
ZoneIds string `charset:"utf8" nullable:"true" list:"user" update:"admin" create:"admin_optional" json:"zone_ids"`
}
+48
View File
@@ -1789,6 +1789,54 @@ func (manager *SPolicyDefinitionManager) purgeAll(ctx context.Context, userCred
return nil
}
func (self *SAccessGroupCache) purge(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockObject(ctx, self)
defer lockman.ReleaseObject(ctx, self)
return self.RealDelete(ctx, userCred)
}
func (manager *SAccessGroupCacheManager) purgeAll(ctx context.Context, userCred mcclient.TokenCredential, providerId string) error {
caches := []SAccessGroupCache{}
err := fetchByManagerId(manager, providerId, &caches)
if err != nil {
return errors.Wrapf(err, "fetchByManagerId")
}
for i := range caches {
err := caches[i].purge(ctx, userCred)
if err != nil {
return errors.Wrapf(err, "cache purge")
}
}
return nil
}
func (self *SFileSystem) purge(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockObject(ctx, self)
defer lockman.ReleaseObject(ctx, self)
return self.RealDelete(ctx, userCred)
}
func (manager *SFileSystemManager) purgeAll(ctx context.Context, userCred mcclient.TokenCredential, providerId string) error {
files := []SFileSystem{}
err := fetchByManagerId(manager, providerId, &files)
if err != nil {
return errors.Wrapf(err, "fetchByManagerId")
}
for i := range files {
err := files[i].purge(ctx, userCred)
if err != nil {
return errors.Wrapf(err, "cache purge")
}
}
return nil
}
func (vpcPC *SVpcPeeringConnection) purge(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockObject(ctx, vpcPC)
defer lockman.ReleaseObject(ctx, vpcPC)
+6
View File
@@ -177,6 +177,12 @@ type IDBInstanceDriver interface {
INatGatewayDriver
IElasticIpDriver
INasDriver
}
type INasDriver interface {
RequestSyncAccessGroup(ctx context.Context, userCred mcclient.TokenCredential, fs *SFileSystem, mt *SMountTarget, ag *SAccessGroup, task taskman.ITask) error
IsSupportedNas() bool
}
// NAT
+21 -1
View File
@@ -1,3 +1,17 @@
// 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 (
@@ -19,7 +33,13 @@ import (
)
func PerformActionSyncSkus(ctx context.Context, userCred mcclient.TokenCredential, resourceKey string, input apis.SkuSyncInput) (jsonutils.JSONObject, error) {
if !utils.IsInStringArray(resourceKey, []string{ServerSkuManager.Keyword(), ElasticcacheSkuManager.Keyword(), DBInstanceSkuManager.Keyword(), NatSkuManager.Keyword()}) {
if !utils.IsInStringArray(resourceKey, []string{
ServerSkuManager.Keyword(),
ElasticcacheSkuManager.Keyword(),
DBInstanceSkuManager.Keyword(),
NatSkuManager.Keyword(),
NasSkuManager.Keyword(),
}) {
return nil, httperrors.NewUnsupportOperationError("resource %s is not support sync skus", resourceKey)
}
+38
View File
@@ -48,6 +48,7 @@ type SSkuResourcesMeta struct {
ElasticCacheBase string `json:"elastic_cache_base"`
ImageBase string `json:"image_base"`
NatBase string `json:"nat_base"`
NasBase string `json:"nas_base"`
}
func (self *SSkuResourcesMeta) getZoneIdBySuffix(zoneMaps map[string]string, suffix string) string {
@@ -161,6 +162,43 @@ func (self *SSkuResourcesMeta) GetNatSkusByRegionExternalId(regionExternalId str
return result, nil
}
func (self *SSkuResourcesMeta) GetNasSkusByRegionExternalId(regionExternalId string) ([]SNasSku, error) {
regionId, zoneMaps, err := self.GetRegionIdAndZoneMaps(regionExternalId)
if err != nil {
return nil, errors.Wrap(err, "GetRegionIdAndZoneMaps")
}
result := []SNasSku{}
objs, err := self.getObjsByRegion(self.NasBase, regionExternalId)
if err != nil {
return nil, errors.Wrapf(err, "getSkusByRegion")
}
for _, obj := range objs {
sku := SNasSku{}
sku.SetModelManager(NasSkuManager, &sku)
err = obj.Unmarshal(&sku)
if err != nil {
return nil, errors.Wrapf(err, "obj.Unmarshal")
}
if len(sku.ZoneIds) > 0 {
zoneIds := []string{}
for _, zoneExtId := range strings.Split(sku.ZoneIds, ",") {
zoneId := self.getZoneIdBySuffix(zoneMaps, zoneExtId) // Huawei rds sku zone1 maybe is cn-north-4f
if len(zoneId) == 0 {
log.Warningf("invalid nat sku %s(%s) %s zone: %s", sku.Name, sku.Id, sku.CloudregionId, zoneExtId)
continue
}
zoneIds = append(zoneIds, zoneId)
}
sku.ZoneIds = strings.Join(zoneIds, ",")
}
sku.Id = ""
sku.CloudregionId = regionId
result = append(result, sku)
}
return result, nil
}
func (self *SSkuResourcesMeta) getCloudregion(regionExternalId string) (*SCloudregion, error) {
region, err := db.FetchByExternalId(CloudregionManager, regionExternalId)
if err != nil {
+12
View File
@@ -300,6 +300,18 @@ var (
Action: PolicyActionGet,
Result: rbacutils.Allow,
},
{
Service: api.SERVICE_TYPE,
Resource: "nas_skus",
Action: PolicyActionList,
Result: rbacutils.Allow,
},
{
Service: api.SERVICE_TYPE,
Resource: "nas_skus",
Action: PolicyActionGet,
Result: rbacutils.Allow,
},
},
},
{
+53
View File
@@ -1474,3 +1474,56 @@ func (self *SAliyunRegionDriver) ValidateCreateNatGateway(ctx context.Context, u
func (self *SAliyunRegionDriver) IsSupportedNatGateway() bool {
return true
}
func (self *SAliyunRegionDriver) IsSupportedNas() bool {
return true
}
func (self *SAliyunRegionDriver) RequestSyncAccessGroup(ctx context.Context, userCred mcclient.TokenCredential, fs *models.SFileSystem, mt *models.SMountTarget, ag *models.SAccessGroup, task taskman.ITask) error {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
if mt.AccessGroupId == api.DEFAULT_ACCESS_GROUP {
return jsonutils.Marshal(
map[string]string{
"access_group_id": fmt.Sprintf("DEFAULT_%s_GROUP_NAME", strings.ToUpper(mt.NetworkType)),
}), nil
}
caches, err := ag.GetAccessGroupCaches()
if err != nil {
return nil, errors.Wrapf(err, "ag.GetAccessGroupCaches")
}
for i := range caches {
if caches[i].CloudregionId == fs.CloudregionId &&
caches[i].ManagerId == fs.ManagerId &&
caches[i].FileSystemType == fs.FileSystemType &&
caches[i].NetworkType == mt.NetworkType {
if len(caches[i].ExternalId) > 0 {
err := caches[i].SyncRules()
if err != nil {
return nil, errors.Wrapf(err, "cache.SyncRules")
}
return jsonutils.Marshal(map[string]string{"access_group_id": caches[i].ExternalId}), nil
}
err := caches[i].CreateIAccessGroup()
if err != nil {
return nil, errors.Wrapf(err, "CreateIAccessGroup")
}
return jsonutils.Marshal(map[string]string{"access_group_id": caches[i].ExternalId}), nil
}
}
opts := models.SAccessGroupCacheRegisterInput{
Name: ag.Name,
Desc: ag.Description,
ManagerId: fs.ManagerId,
CloudregionId: fs.CloudregionId,
NetworkType: mt.NetworkType,
FileSystemType: fs.FileSystemType,
AccessGroupId: ag.Id,
}
cache, err := models.AccessGroupCacheManager.Register(ctx, &opts)
if err != nil {
return nil, errors.Wrapf(err, "Register")
}
return jsonutils.Marshal(map[string]string{"access_group_id": cache.ExternalId}), nil
})
return nil
}
+8
View File
@@ -428,6 +428,10 @@ func (self *SBaseRegionDriver) IsSupportedNatGateway() bool {
return false
}
func (self *SBaseRegionDriver) IsSupportedNas() bool {
return false
}
func (self *SBaseRegionDriver) OnNatEntryDeleteComplete(ctx context.Context, userCred mcclient.TokenCredential, eip *models.SElasticip) error {
return nil
}
@@ -443,3 +447,7 @@ func (self *SBaseRegionDriver) IsSupportedNatAutoRenew() bool {
func (self *SBaseRegionDriver) RequestAssociatEip(ctx context.Context, userCred mcclient.TokenCredential, eip *models.SElasticip, input api.ElasticipAssociateInput, obj db.IStatusStandaloneModel, task taskman.ITask) error {
return httperrors.NewNotImplementedError("RequestAssociatEip")
}
func (self *SBaseRegionDriver) RequestSyncAccessGroup(ctx context.Context, userCred mcclient.TokenCredential, fs *models.SFileSystem, mt *models.SMountTarget, ag *models.SAccessGroup, task taskman.ITask) error {
return errors.Wrapf(cloudprovider.ErrNotImplemented, "RequestSyncAccessGroup")
}
+7
View File
@@ -205,6 +205,13 @@ func InitHandlers(app *appsrv.Application) {
models.InterVpcNetworkManager,
models.NatSkuManager,
models.NasSkuManager,
models.FileSystemManager,
models.AccessGroupManager,
models.AccessGroupRuleManager,
models.AccessGroupCacheManager,
models.MountTargetManager,
} {
db.RegisterModelManager(manager)
handler := db.NewModelHandler(manager)
+1
View File
@@ -153,6 +153,7 @@ func StartService() {
cron.AddJobEveryFewDays("SyncSkus", opts.SyncSkusDay, opts.SyncSkusHour, 0, 0, models.SyncServerSkus, true)
cron.AddJobEveryFewDays("SyncDBInstanceSkus", opts.SyncSkusDay, opts.SyncSkusHour, 0, 0, models.SyncDBInstanceSkus, true)
cron.AddJobEveryFewDays("SyncNatSkus", opts.SyncSkusDay, opts.SyncSkusHour, 0, 0, models.SyncNatSkus, false)
cron.AddJobEveryFewDays("SyncNasSkus", opts.SyncSkusDay, opts.SyncSkusHour, 0, 0, models.SyncNasSkus, false)
cron.AddJobEveryFewDays("SyncElasticCacheSkus", opts.SyncSkusDay, opts.SyncSkusHour, 0, 0, models.SyncElasticCacheSkus, true)
cron.AddJobEveryFewDays("StorageSnapshotsRecycle", 1, 2, 0, 0, models.StorageManager.StorageSnapshotsRecycle, false)
@@ -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 cachereed 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 langucachee 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/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/logclient"
)
type AccessGroupCacheDeleteTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(AccessGroupCacheDeleteTask{})
}
func (self *AccessGroupCacheDeleteTask) taskFailed(ctx context.Context, cache *models.SAccessGroupCache, err error) {
cache.SetStatus(self.UserCred, api.ACCESS_GROUP_STATUS_DELETE_FAILED, err.Error())
logclient.AddActionLogWithStartable(self, cache, logclient.ACT_DELOCATE, err, self.UserCred, false)
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *AccessGroupCacheDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
cache := obj.(*models.SAccessGroupCache)
iAccessGroup, err := cache.GetICloudAccessGroup()
if err != nil {
if errors.Cause(err) == cloudprovider.ErrNotFound {
self.taskComplete(ctx, cache)
return
}
self.taskFailed(ctx, cache, errors.Wrapf(err, "GetICloudAccessGroup"))
return
}
err = iAccessGroup.Delete()
if err != nil {
self.taskFailed(ctx, cache, errors.Wrapf(err, "iAccessGroup.Delete"))
return
}
self.taskComplete(ctx, cache)
}
func (self *AccessGroupCacheDeleteTask) taskComplete(ctx context.Context, cache *models.SAccessGroupCache) {
cache.RealDelete(ctx, self.GetUserCred())
self.SetStageComplete(ctx, nil)
}
@@ -0,0 +1,80 @@
// 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/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/logclient"
)
type AccessGroupDeleteTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(AccessGroupDeleteTask{})
}
func (self *AccessGroupDeleteTask) taskFailed(ctx context.Context, ag *models.SAccessGroup, cache *models.SAccessGroupCache, err error) {
ag.SetStatus(self.UserCred, api.ACCESS_GROUP_STATUS_DELETE_FAILED, err.Error())
if cache != nil {
cache.SetStatus(self.UserCred, api.ACCESS_GROUP_STATUS_DELETE_FAILED, err.Error())
}
logclient.AddActionLogWithStartable(self, ag, logclient.ACT_DELOCATE, err, self.UserCred, false)
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *AccessGroupDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
ag := obj.(*models.SAccessGroup)
caches, err := ag.GetAccessGroupCaches()
if err != nil {
self.taskFailed(ctx, ag, nil, errors.Wrapf(err, "GetAccessGroupCaches"))
return
}
for i := range caches {
caches[i].SetStatus(self.GetUserCred(), api.ACCESS_GROUP_STATUS_DELETING, "")
iAccessGroup, err := caches[i].GetICloudAccessGroup()
if err != nil {
if errors.Cause(err) == cloudprovider.ErrNotFound {
caches[i].RealDelete(ctx, self.GetUserCred())
continue
}
self.taskFailed(ctx, ag, &caches[i], errors.Wrapf(err, "cache.GetICloudAccessGroup"))
return
}
err = iAccessGroup.Delete()
if err != nil {
self.taskFailed(ctx, ag, &caches[i], errors.Wrapf(err, "iAccessGroup.Delete"))
return
}
caches[i].RealDelete(ctx, self.GetUserCred())
}
self.taskComplete(ctx, ag)
}
func (self *AccessGroupDeleteTask) taskComplete(ctx context.Context, ag *models.SAccessGroup) {
ag.RealDelete(ctx, self.GetUserCred())
self.SetStageComplete(ctx, nil)
}
@@ -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 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 AccessGroupSyncRulesTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(AccessGroupSyncRulesTask{})
}
func (self *AccessGroupSyncRulesTask) taskFail(ctx context.Context, ag *models.SAccessGroup, err error) {
ag.SetStatus(self.GetUserCred(), api.ACCESS_GROUP_STATUS_AVAILABLE, err.Error())
logclient.AddActionLogWithStartable(self, ag, logclient.ACT_SYNC_CONF, err, self.UserCred, false)
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *AccessGroupSyncRulesTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
ag := obj.(*models.SAccessGroup)
caches, err := ag.GetAccessGroupCaches()
if err != nil {
self.taskFail(ctx, ag, errors.Wrapf(err, "ag.GetAccessGroupCaches"))
return
}
for i := range caches {
err := caches[i].SyncRules()
if err != nil {
caches[i].SetStatus(self.GetUserCred(), api.ACCESS_GROUP_STATUS_SYNC_RULES_FAILED, err.Error())
}
}
ag.SetStatus(self.GetUserCred(), api.ACCESS_GROUP_STATUS_AVAILABLE, "")
self.SetStageComplete(ctx, nil)
}
@@ -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 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 AccessGroupSyncstatusTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(AccessGroupSyncstatusTask{})
}
func (self *AccessGroupSyncstatusTask) taskFail(ctx context.Context, ag *models.SAccessGroup, err error) {
ag.SetStatus(self.GetUserCred(), api.ACCESS_GROUP_STATUS_AVAILABLE, err.Error())
logclient.AddActionLogWithStartable(self, ag, logclient.ACT_SYNC_STATUS, err, self.UserCred, false)
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *AccessGroupSyncstatusTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
ag := obj.(*models.SAccessGroup)
caches, err := ag.GetAccessGroupCaches()
if err != nil {
self.taskFail(ctx, ag, errors.Wrapf(err, "ag.GetAccessGroupCaches"))
return
}
for i := range caches {
caches[i].SyncStatus(ctx, self.GetUserCred())
}
ag.SetStatus(self.GetUserCred(), api.ACCESS_GROUP_STATUS_AVAILABLE, "")
self.SetStageComplete(ctx, nil)
}
@@ -105,6 +105,9 @@ func (self *CloudAccountSyncSkusTask) OnInit(ctx context.Context, obj db.IStanda
case models.NatSkuManager.Keyword():
result := region.SyncNatSkus(ctx, self.GetUserCred(), meta)
log.Infof("Sync %s %s skus for region %s result: %s", region.Provider, res, region.Name, result.Result())
case models.NasSkuManager.Keyword():
result := region.SyncNasSkus(ctx, self.GetUserCred(), meta)
log.Infof("Sync %s %s skus for region %s result: %s", region.Provider, res, region.Name, result.Result())
}
if syncFunc != nil {
+100
View File
@@ -0,0 +1,100 @@
// 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 fsreed 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 langufse governing permissions and
// limitations under the License.
package tasks
import (
"context"
"strings"
"time"
"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/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"
)
type FileSystemCreateTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(FileSystemCreateTask{})
}
func (self *FileSystemCreateTask) taskFailed(ctx context.Context, fs *models.SFileSystem, err error) {
fs.SetStatus(self.UserCred, api.NAS_STATUS_CREATE_FAILED, err.Error())
logclient.AddActionLogWithStartable(self, fs, logclient.ACT_ALLOCATE, err, self.UserCred, false)
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *FileSystemCreateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
fs := obj.(*models.SFileSystem)
iRegion, err := fs.GetIRegion()
if err != nil {
self.taskFailed(ctx, fs, errors.Wrapf(err, "fs.GetIRegion"))
return
}
opts := &cloudprovider.FileSystemCraeteOptions{
Name: fs.Name,
Desc: fs.Description,
Capacity: fs.Capacity,
StorageType: fs.StorageType,
Protocol: fs.Protocol,
FileSystemType: fs.FileSystemType,
ZoneId: strings.TrimPrefix(fs.GetZone().ExternalId, iRegion.GetGlobalId()+"/"),
}
netId := jsonutils.GetAnyString(self.GetParams(), []string{"network_id"})
if len(netId) > 0 {
net, err := models.NetworkManager.FetchById(netId)
if err != nil {
self.taskFailed(ctx, fs, errors.Wrapf(err, "NetworkManager.FetchById(%s)", netId))
return
}
network := net.(*models.SNetwork)
opts.NetworkId = network.ExternalId
opts.VpcId = network.GetVpc().ExternalId
}
log.Infof("nas create params: %v", opts)
iFs, err := iRegion.CreateICloudFileSystem(opts)
if err != nil {
self.taskFailed(ctx, fs, errors.Wrapf(err, "iRegion.CreaetICloudFileSystem"))
return
}
db.SetExternalId(fs, self.GetUserCred(), iFs.GetGlobalId())
cloudprovider.WaitStatus(iFs, api.NAS_STATUS_AVAILABLE, time.Second*5, time.Minute*3)
self.SetStage("OnSyncstatusComplete", nil)
fs.StartSyncstatus(ctx, self.GetUserCred(), self.GetTaskId())
}
func (self *FileSystemCreateTask) OnSyncstatusComplete(ctx context.Context, fs *models.SFileSystem, data jsonutils.JSONObject) {
self.SetStageComplete(ctx, nil)
}
func (self *FileSystemCreateTask) OnSyncstatusCompleteFailed(ctx context.Context, fs *models.SFileSystem, data jsonutils.JSONObject) {
self.SetStageFailed(ctx, data)
}
@@ -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 fsreed 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 langufse governing permissions and
// limitations under the License.
package tasks
import (
"context"
"time"
"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/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/logclient"
)
type FileSystemDeleteTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(FileSystemDeleteTask{})
}
func (self *FileSystemDeleteTask) taskFailed(ctx context.Context, fs *models.SFileSystem, err error) {
fs.SetStatus(self.UserCred, api.NAS_STATUS_DELETE_FAILED, err.Error())
logclient.AddActionLogWithStartable(self, fs, logclient.ACT_DELOCATE, err, self.UserCred, false)
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *FileSystemDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
fs := obj.(*models.SFileSystem)
if len(fs.ExternalId) == 0 {
self.taskComplete(ctx, fs)
return
}
iFs, err := fs.GetICloudFileSystem()
if err != nil {
if errors.Cause(err) == cloudprovider.ErrNotFound {
self.taskComplete(ctx, fs)
return
}
self.taskFailed(ctx, fs, errors.Wrapf(err, "fs.GetICloudFileSystem"))
return
}
err = iFs.Delete()
if err != nil {
self.taskFailed(ctx, fs, errors.Wrapf(err, "iFs.Delete"))
return
}
cloudprovider.WaitDeleted(iFs, time.Second*10, time.Minute*5)
self.taskComplete(ctx, fs)
}
func (self *FileSystemDeleteTask) taskComplete(ctx context.Context, fs *models.SFileSystem) {
fs.RealDelete(ctx, self.GetUserCred())
self.SetStageComplete(ctx, nil)
}
@@ -0,0 +1,61 @@
// 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 FileSystemSyncstatusTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(FileSystemSyncstatusTask{})
}
func (self *FileSystemSyncstatusTask) taskFail(ctx context.Context, nas *models.SFileSystem, err error) {
nas.SetStatus(self.GetUserCred(), api.NAS_STATUS_UNKNOWN, err.Error())
db.OpsLog.LogEvent(nas, db.ACT_SYNC_STATUS, err, self.UserCred)
logclient.AddActionLogWithStartable(self, nas, logclient.ACT_SYNC_STATUS, err, self.UserCred, false)
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *FileSystemSyncstatusTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
nas := obj.(*models.SFileSystem)
iNas, err := nas.GetICloudFileSystem()
if err != nil {
self.taskFail(ctx, nas, errors.Wrapf(err, "nas.GetICloudFileSystem"))
return
}
err = nas.SyncAllWithCloudFileSystem(ctx, self.GetUserCred(), iNas)
if err != nil {
self.taskFail(ctx, nas, errors.Wrapf(err, "nas.SyncAllWithCloudFileSystem"))
return
}
self.SetStageComplete(ctx, nil)
}
@@ -0,0 +1,142 @@
// 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"
"time"
"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/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"
)
type MountTargetCreateTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(MountTargetCreateTask{})
}
func (self *MountTargetCreateTask) taskFailed(ctx context.Context, mt *models.SMountTarget, err error) {
mt.SetStatus(self.UserCred, api.MOUNT_TARGET_STATUS_CREATE_FAILED, err.Error())
logclient.AddActionLogWithStartable(self, mt, logclient.ACT_ALLOCATE, err, self.UserCred, false)
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *MountTargetCreateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
mt := obj.(*models.SMountTarget)
fs, err := mt.GetFileSystem()
if err != nil {
self.taskFailed(ctx, mt, errors.Wrapf(err, "GetFileSystem"))
return
}
region, err := fs.GetRegion()
if err != nil {
self.taskFailed(ctx, mt, errors.Wrapf(err, "fs.GetRegion"))
return
}
ag, err := mt.GetAccessGroup()
if err != nil {
self.taskFailed(ctx, mt, errors.Wrapf(err, "mt.GetAccessGroup"))
return
}
self.SetStage("OnSyncAccessGroupComplete", nil)
err = region.GetDriver().RequestSyncAccessGroup(ctx, self.GetUserCred(), fs, mt, ag, self)
if err != nil {
self.taskFailed(ctx, mt, errors.Wrapf(err, "RequestSyncAccessGroup"))
return
}
}
func (self *MountTargetCreateTask) OnSyncAccessGroupCompleteFailed(ctx context.Context, mt *models.SMountTarget, data jsonutils.JSONObject) {
self.taskFailed(ctx, mt, errors.Error(data.String()))
}
func (self *MountTargetCreateTask) OnSyncAccessGroupComplete(ctx context.Context, mt *models.SMountTarget, data jsonutils.JSONObject) {
opts := cloudprovider.SMountTargetCreateOptions{NetworkType: mt.NetworkType}
data.Unmarshal(&opts)
if len(opts.AccessGroupId) == 0 {
self.taskFailed(ctx, mt, errors.Error("empty access_group_id after sync"))
return
}
fs, err := mt.GetFileSystem()
if err != nil {
self.taskFailed(ctx, mt, errors.Wrapf(err, "GetFileSystem"))
return
}
iFs, err := fs.GetICloudFileSystem()
if err != nil {
self.taskFailed(ctx, mt, errors.Wrapf(err, "fs.GetICloudFileSystem"))
return
}
if opts.NetworkType == api.NETWORK_TYPE_VPC {
network, err := mt.GetNetwork()
if err != nil {
self.taskFailed(ctx, mt, errors.Wrapf(err, "mt.GetNetwork"))
return
}
opts.NetworkId = network.ExternalId
vpc, err := mt.GetVpc()
if err != nil {
self.taskFailed(ctx, mt, errors.Wrapf(err, "mt.GetVpc"))
return
}
opts.VpcId = vpc.ExternalId
}
opts.FileSystemId = fs.ExternalId
iMt, err := iFs.CreateMountTarget(&opts)
if err != nil {
self.taskFailed(ctx, mt, errors.Wrapf(err, "iFs.CreateMountTarget"))
return
}
cloudprovider.Wait(time.Second*10, time.Minute*3, func() (bool, error) {
mts, err := iFs.GetMountTargets()
if err != nil {
return false, errors.Wrapf(err, "iFs.GetMountTargets")
}
for i := range mts {
if mts[i].GetGlobalId() == iMt.GetGlobalId() {
status := mts[i].GetStatus()
log.Infof("expect mount point status %s current is %s", api.MOUNT_TARGET_STATUS_AVAILABLE, status)
if status == api.MOUNT_TARGET_STATUS_AVAILABLE {
iMt = mts[i]
return true, nil
}
}
}
return false, nil
})
mt.SyncWithMountTarget(ctx, self.GetUserCred(), fs.ManagerId, iMt)
self.SetStageComplete(ctx, nil)
}
@@ -0,0 +1,88 @@
// 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 MountTargetDeleteTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(MountTargetDeleteTask{})
}
func (self *MountTargetDeleteTask) taskFailed(ctx context.Context, mt *models.SMountTarget, err error) {
mt.SetStatus(self.UserCred, api.MOUNT_TARGET_STATUS_DELETE_FAILED, err.Error())
logclient.AddActionLogWithStartable(self, mt, logclient.ACT_DELOCATE, err, self.UserCred, false)
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *MountTargetDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
mt := obj.(*models.SMountTarget)
if len(mt.ExternalId) == 0 {
self.taskComplete(ctx, nil, mt)
return
}
fs, err := mt.GetFileSystem()
if err != nil {
self.taskFailed(ctx, mt, errors.Wrapf(err, "GetFileSystem"))
return
}
iFileSystem, err := fs.GetICloudFileSystem()
if err != nil {
self.taskFailed(ctx, mt, errors.Wrapf(err, "GetICloudFileSystem"))
return
}
iMountTargets, err := iFileSystem.GetMountTargets()
if err != nil {
self.taskFailed(ctx, mt, errors.Wrapf(err, "GetMountTargets"))
return
}
for i := range iMountTargets {
if iMountTargets[i].GetGlobalId() == mt.ExternalId {
err = iMountTargets[i].Delete()
if err != nil {
self.taskFailed(ctx, mt, errors.Wrapf(err, "iMountTarget.Delete"))
return
}
self.taskComplete(ctx, fs, mt)
return
}
}
self.taskComplete(ctx, fs, mt)
}
func (self *MountTargetDeleteTask) taskComplete(ctx context.Context, fs *models.SFileSystem, mt *models.SMountTarget) {
if fs != nil {
logclient.AddActionLogWithStartable(self, fs, logclient.ACT_DELOCATE, mt, self.UserCred, true)
}
mt.RealDelete(ctx, self.GetUserCred())
self.SetStageComplete(ctx, nil)
}
@@ -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 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/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/logclient"
)
type MountTargetSyncstatusTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(MountTargetSyncstatusTask{})
}
func (self *MountTargetSyncstatusTask) taskFail(ctx context.Context, mt *models.SMountTarget, err error) {
mt.SetStatus(self.GetUserCred(), api.MOUNT_TARGET_STATUS_UNKNOWN, err.Error())
db.OpsLog.LogEvent(mt, db.ACT_SYNC_STATUS, err, self.UserCred)
logclient.AddActionLogWithStartable(self, mt, logclient.ACT_SYNC_STATUS, err, self.UserCred, false)
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
func (self *MountTargetSyncstatusTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
mt := obj.(*models.SMountTarget)
fs, err := mt.GetFileSystem()
if err != nil {
self.taskFail(ctx, mt, errors.Wrapf(err, "GetFileSystem"))
return
}
iFs, err := fs.GetICloudFileSystem()
if err != nil {
self.taskFail(ctx, mt, errors.Wrapf(err, "fs.GetICloudFileSystem"))
return
}
mts, err := iFs.GetMountTargets()
if err != nil {
self.taskFail(ctx, mt, errors.Wrapf(err, "iFs.GetMountTargets"))
return
}
for i := range mts {
if mts[i].GetGlobalId() == mt.ExternalId {
mt.SyncWithMountTarget(ctx, self.GetUserCred(), fs.ManagerId, mts[i])
self.SetStageComplete(ctx, nil)
return
}
}
self.taskFail(ctx, mt, errors.Wrapf(cloudprovider.ErrNotFound, mt.ExternalId))
}
@@ -0,0 +1,35 @@
// 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 AccessGroupCacheManager struct {
modulebase.ResourceManager
}
var (
AccessGroupCaches AccessGroupCacheManager
)
func init() {
AccessGroupCaches = AccessGroupCacheManager{NewComputeManager("access_group_cache", "access_group_caches",
[]string{},
[]string{})}
registerCompute(&AccessGroupCaches)
}
@@ -0,0 +1,35 @@
// 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 AccessGroupRuleManager struct {
modulebase.ResourceManager
}
var (
AccessGroupRules AccessGroupRuleManager
)
func init() {
AccessGroupRules = AccessGroupRuleManager{NewComputeManager("access_group_rule", "access_group_rules",
[]string{},
[]string{})}
registerCompute(&AccessGroupRules)
}
+35
View File
@@ -0,0 +1,35 @@
// 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 AccessGroupManager struct {
modulebase.ResourceManager
}
var (
AccessGroups AccessGroupManager
)
func init() {
AccessGroups = AccessGroupManager{NewComputeManager("access_group", "access_groups",
[]string{},
[]string{})}
registerCompute(&AccessGroups)
}
+35
View File
@@ -0,0 +1,35 @@
// 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 FileSystemManager struct {
modulebase.ResourceManager
}
var (
FileSystems FileSystemManager
)
func init() {
FileSystems = FileSystemManager{NewComputeManager("file_system", "file_systems",
[]string{},
[]string{})}
registerCompute(&FileSystems)
}
+35
View File
@@ -0,0 +1,35 @@
// 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 MountTargetManager struct {
modulebase.ResourceManager
}
var (
MountTargets MountTargetManager
)
func init() {
MountTargets = MountTargetManager{NewComputeManager("mount_target", "mount_targets",
[]string{},
[]string{})}
registerCompute(&MountTargets)
}
+33
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 NasSkusManager struct {
modulebase.ResourceManager
}
var (
NasSkus NasSkusManager
)
func init() {
NasSkus = NasSkusManager{NewComputeManager("nas_sku", "nas_skus",
[]string{},
[]string{})}
registerCompute(&NasSkus)
}
+4
View File
@@ -375,6 +375,10 @@ type BaseCreateOptions struct {
Desc string `metavar:"<DESCRIPTION>" help:"Description" json:"description"`
}
func (opts *BaseCreateOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(opts), nil
}
type EnabledStatusCreateOptions struct {
BaseCreateOptions
Status string
+1 -1
View File
@@ -840,7 +840,7 @@ func (opts *CloudaccountShareModeOptions) Params() (jsonutils.JSONObject, error)
type CloudaccountSyncSkusOptions struct {
SCloudAccountIdOptions
RESOURCE string `help:"Resource of skus" choices:"serversku|elasticcachesku|dbinstance_sku|nat_sku"`
RESOURCE string `help:"Resource of skus" choices:"serversku|elasticcachesku|dbinstance_sku|nat_sku|nas_sku"`
Force bool `help:"Force sync no matter what"`
Cloudprovider string `help:"provider to sync"`
Region string `help:"region to sync"`
@@ -0,0 +1,41 @@
// 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 AccessGroupCacheListOptions struct {
options.BaseListOptions
}
func (opts *AccessGroupCacheListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
type AccessGroupCacheIdOption struct {
ID string `help:"Access group cache Id"`
}
func (opts *AccessGroupCacheIdOption) GetId() string {
return opts.ID
}
func (opts *AccessGroupCacheIdOption) Params() (jsonutils.JSONObject, error) {
return nil, nil
}
@@ -0,0 +1,54 @@
// 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 AccessGroupRuleListOptions struct {
options.BaseListOptions
}
func (opts *AccessGroupRuleListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
type AccessGroupRuleIdOption struct {
ID string `help:"Access group rule Id"`
}
func (opts *AccessGroupRuleIdOption) GetId() string {
return opts.ID
}
func (opts *AccessGroupRuleIdOption) Params() (jsonutils.JSONObject, error) {
return nil, nil
}
type AccessRuleCreateOptions struct {
Priority int
Source string
RWAccessType string `choices:"rw|r"`
UserAccessType string `choices:""`
Description string
AccessGroupId string
}
func (opts *AccessRuleCreateOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(opts), nil
}
@@ -0,0 +1,41 @@
// 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 AccessGroupListOptions struct {
options.BaseListOptions
}
func (opts *AccessGroupListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
type AccessGroupIdOption struct {
ID string `help:"Access group Id"`
}
func (opts *AccessGroupIdOption) GetId() string {
return opts.ID
}
func (opts *AccessGroupIdOption) Params() (jsonutils.JSONObject, error) {
return nil, nil
}
@@ -0,0 +1,56 @@
// 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 FileSystemListOptions struct {
options.BaseListOptions
}
func (opts *FileSystemListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
type FileSystemIdOption struct {
ID string `help:"File system Id"`
}
func (opts *FileSystemIdOption) GetId() string {
return opts.ID
}
func (opts *FileSystemIdOption) Params() (jsonutils.JSONObject, error) {
return nil, nil
}
type FileSystemCreateOptions struct {
NAME string
Protocol string `choices:"NFS|SMB|CPFS"`
FileSystemType string
Capacity int64 `json:"capacity"`
NetworkId string `json:"network_id"`
StorageType string `json:"storage_type"`
ZoneId string `json:"zone_id"`
ManagerId string `json:"manager_id"`
}
func (opts *FileSystemCreateOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(opts), nil
}
@@ -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/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type MountTargetListOptions struct {
options.BaseListOptions
}
func (opts *MountTargetListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
type MountTargetIdOption struct {
ID string `help:"Mount Target Id"`
}
func (opts *MountTargetIdOption) GetId() string {
return opts.ID
}
func (opts *MountTargetIdOption) Params() (jsonutils.JSONObject, error) {
return nil, nil
}
type MountTargetCreateOptions struct {
NAME string
NetworkType string `choices:"vpc|classic"`
FileSystemId string `json:"file_system_id"`
NetworkId string `json:"network_id"`
AccessGroupId string `json:"access_group_id"`
}
func (opts *MountTargetCreateOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(opts), nil
}
+41
View File
@@ -0,0 +1,41 @@
// 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 NasSkuListOption struct {
options.BaseListOptions
}
func (opts *NasSkuListOption) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(opts)
}
type NasSkuIdOption struct {
ID string `help:"Nas Id or name"`
}
func (opts *NasSkuIdOption) Params() (jsonutils.JSONObject, error) {
return nil, nil
}
func (opts *NasSkuIdOption) GetId() string {
return opts.ID
}
+324
View File
@@ -0,0 +1,324 @@
// 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 aliyun
import (
"fmt"
"strings"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SAccessGroup struct {
region *SRegion
RuleCount int
AccessGroupType string
Description string
AccessGroupName string
MountTargetCount int
FileSystemType string
}
func (self *SAccessGroup) GetName() string {
return self.AccessGroupName
}
func (self *SAccessGroup) GetGlobalId() string {
return fmt.Sprintf("%s/%s", self.GetFileSystemType(), self.AccessGroupName)
}
func (self *SAccessGroup) GetFileSystemType() string {
return self.FileSystemType
}
func (self *SAccessGroup) IsDefault() bool {
return self.AccessGroupName == "DEFAULT_CLASSIC_GROUP_NAME" || self.AccessGroupName == "DEFAULT_VPC_GROUP_NAME"
}
func (self *SAccessGroup) GetDesc() string {
return self.Description
}
func (self *SAccessGroup) GetMountTargetCount() int {
return self.MountTargetCount
}
func (self *SAccessGroup) GetNetworkType() string {
return strings.ToLower(self.AccessGroupType)
}
func (self *SAccessGroup) GetMaxPriority() int {
return 1
}
func (self *SAccessGroup) GetMinPriority() int {
return 100
}
func (self *SAccessGroup) Delete() error {
return self.region.DeleteAccessGroup(self.FileSystemType, self.AccessGroupName)
}
func (self *SAccessGroup) GetSupporedUserAccessTypes() []cloudprovider.TUserAccessType {
return []cloudprovider.TUserAccessType{
cloudprovider.UserAccessTypeAllSquash,
cloudprovider.UserAccessTypeRootSquash,
cloudprovider.UserAccessTypeNoRootSquash,
}
}
func (self *SAccessGroup) GetRules() ([]cloudprovider.AccessGroupRule, error) {
rules := []SAccessGroupRule{}
num := 1
for {
part, total, err := self.region.GetAccessGroupRules(self.AccessGroupName, 50, num)
if err != nil {
return nil, errors.Wrapf(err, "GetAccessGroupRules")
}
rules = append(rules, part...)
if len(rules) >= total {
break
}
}
ret := []cloudprovider.AccessGroupRule{}
for i := range rules {
rule := cloudprovider.AccessGroupRule{
ExternalId: rules[i].AccessRuleId,
Priority: rules[i].Priority,
Source: rules[i].SourceCidrIp,
}
switch rules[i].RWAccess {
case "RDWR":
rule.RWAccessType = cloudprovider.RWAccessTypeRW
case "RDONLY":
rule.RWAccessType = cloudprovider.RWAccessTypeR
}
switch rules[i].UserAccess {
case "no_squash":
rule.UserAccessType = cloudprovider.UserAccessTypeNoRootSquash
case "root_squash":
rule.UserAccessType = cloudprovider.UserAccessTypeRootSquash
case "all_squash":
rule.UserAccessType = cloudprovider.UserAccessTypeAllSquash
}
ret = append(ret, rule)
}
return ret, nil
}
func (self *SRegion) getAccessGroups(fsType string, pageSize, pageNum int) ([]SAccessGroup, int, error) {
if pageSize < 1 || pageSize > 100 {
pageSize = 50
}
if pageNum < 1 {
pageNum = 1
}
params := map[string]string{
"RegionId": self.RegionId,
"PageSize": fmt.Sprintf("%d", pageSize),
"PageNumber": fmt.Sprintf("%d", pageNum),
"FileSystemType": fsType,
}
resp, err := self.nasRequest("DescribeAccessGroups", params)
if err != nil {
return nil, 0, errors.Wrapf(err, "DescribeAccessGroups")
}
ret := struct {
TotalCount int
AccessGroups struct {
AccessGroup []SAccessGroup
}
}{}
err = resp.Unmarshal(&ret)
if err != nil {
return nil, 0, errors.Wrapf(err, "resp.Unmarshal")
}
return ret.AccessGroups.AccessGroup, ret.TotalCount, nil
}
type SAccessGroupRule struct {
RWAccess string
UserAccess string
Priority int
SourceCidrIp string
AccessRuleId string
}
func (self *SRegion) GetAccessGroupRules(groupName string, pageSize, pageNum int) ([]SAccessGroupRule, int, error) {
if pageSize < 1 || pageSize > 100 {
pageSize = 50
}
if pageNum < 1 {
pageNum = 1
}
params := map[string]string{
"RegionId": self.RegionId,
"AccessGroupName": groupName,
"PageSize": fmt.Sprintf("%d", pageSize),
"PageNumber": fmt.Sprintf("%d", pageNum),
}
resp, err := self.nasRequest("DescribeAccessRules", params)
if err != nil {
return nil, 0, errors.Wrapf(err, "DescribeAccessRules")
}
ret := struct {
TotalCount int
AccessRules struct {
AccessRule []SAccessGroupRule
}
}{}
err = resp.Unmarshal(&ret)
if err != nil {
return nil, 0, errors.Wrapf(err, "resp.Unmarshal")
}
return ret.AccessRules.AccessRule, ret.TotalCount, nil
}
func (self *SRegion) GetAccessGroups(fsType string) ([]SAccessGroup, error) {
accessGroups := []SAccessGroup{}
num := 1
for {
part, total, err := self.getAccessGroups(fsType, 50, num)
if err != nil {
return nil, errors.Wrapf(err, "GetAccessGroups")
}
for i := range part {
part[i].FileSystemType = fsType
accessGroups = append(accessGroups, part[i])
}
if len(accessGroups) >= total {
break
}
}
return accessGroups, nil
}
func (self *SRegion) GetICloudAccessGroups() ([]cloudprovider.ICloudAccessGroup, error) {
standardAccessGroups, err := self.GetAccessGroups("standard")
if err != nil {
return nil, errors.Wrapf(err, "GetAccessGroups")
}
extremeAccessGroups, err := self.GetAccessGroups("extreme")
if err != nil {
return nil, errors.Wrapf(err, "GetAccessGroups")
}
ret := []cloudprovider.ICloudAccessGroup{}
for _, accessGroups := range [][]SAccessGroup{standardAccessGroups, extremeAccessGroups} {
for i := range accessGroups {
accessGroups[i].region = self
ret = append(ret, &accessGroups[i])
}
}
return ret, nil
}
func (self *SRegion) GetICloudAccessGroupById(id string) (cloudprovider.ICloudAccessGroup, error) {
groups, err := self.GetICloudAccessGroups()
if err != nil {
return nil, errors.Wrapf(err, "self.GetICloudAccessGroups")
}
for i := range groups {
if groups[i].GetGlobalId() == id {
return groups[i], nil
}
}
return nil, errors.Wrapf(err, "GetICloudAccessGroupById(%s)", id)
}
func (self *SRegion) CreateICloudAccessGroup(opts *cloudprovider.SAccessGroup) (cloudprovider.ICloudAccessGroup, error) {
err := self.CreateAccessGroup(opts)
if err != nil {
return nil, errors.Wrapf(err, "CreateAccessGroup")
}
return self.GetICloudAccessGroupById(fmt.Sprintf("%s/%s", opts.FileSystemType, opts.Name))
}
func (self *SRegion) CreateAccessGroup(opts *cloudprovider.SAccessGroup) error {
params := map[string]string{
"RegionId": self.RegionId,
"AccessGroupName": opts.Name,
"AccessGroupType": opts.NetworkType,
"FileSystemType": opts.FileSystemType,
}
_, err := self.nasRequest("CreateAccessGroup", params)
return errors.Wrapf(err, "CreateAccessGroup")
}
func (self *SRegion) DeleteAccessGroup(fsType, name string) error {
params := map[string]string{
"RegionId": self.RegionId,
"AccessGroupName": name,
"FileSystemType": fsType,
}
_, err := self.nasRequest("DeleteAccessGroup", params)
return errors.Wrapf(err, "DeleteAccessGroup")
}
func (self *SRegion) DeleteAccessGroupRule(fsType, groupName, ruleId string) error {
params := map[string]string{
"RegionId": self.RegionId,
"AccessRuleId": ruleId,
"AccessGroupName": groupName,
"FileSystemType": fsType,
}
_, err := self.nasRequest("DeleteAccessRule", params)
return errors.Wrapf(err, "DeleteAccessRule")
}
func (self *SRegion) CreateAccessGroupRule(source, fsType, groupName string, rwType cloudprovider.TRWAccessType, userType cloudprovider.TUserAccessType, priority int) error {
params := map[string]string{
"RegionId": self.RegionId,
"SourceCidrIp": source,
"AccessGroupName": groupName,
"Priority": fmt.Sprintf("%d", priority),
"FileSystemType": fsType,
}
switch rwType {
case cloudprovider.RWAccessTypeR:
params["RWAccessType"] = "RDONLY"
case cloudprovider.RWAccessTypeRW:
params["RWAccessType"] = "RDWR"
}
switch userType {
case cloudprovider.UserAccessTypeAllSquash:
params["UserAccessType"] = "all_squash"
case cloudprovider.UserAccessTypeRootSquash:
params["UserAccessType"] = "root_squash"
case cloudprovider.UserAccessTypeNoRootSquash:
params["UserAccessType"] = "no_squash"
}
_, err := self.nasRequest("CreateAccessRule", params)
return errors.Wrapf(err, "CreateAccessRule")
}
func (self *SAccessGroup) SyncRules(common, added, removed cloudprovider.AccessGroupRuleSet) error {
for _, rule := range removed {
err := self.region.DeleteAccessGroupRule(self.FileSystemType, self.AccessGroupName, rule.ExternalId)
if err != nil {
return errors.Wrapf(err, "DeleteAccessGroupRule")
}
}
for _, rule := range added {
err := self.region.CreateAccessGroupRule(rule.Source, self.FileSystemType, self.AccessGroupName, rule.RWAccessType, rule.UserAccessType, rule.Priority)
if err != nil {
return errors.Wrapf(err, "CreateAccessGroupRule")
}
}
return nil
}
+15 -5
View File
@@ -64,6 +64,7 @@ const (
ALIYUN_CBN_API_VERSION = "2017-09-12"
ALIYUN_CDN_API_VERSION = "2018-05-10"
ALIYUN_IMS_API_VERSION = "2019-08-15"
ALIYUN_NAS_API_VERSION = "2017-06-26"
ALIYUN_SERVICE_ECS = "ecs"
ALIYUN_SERVICE_VPC = "vpc"
@@ -159,13 +160,21 @@ func jsonRequest(client *sdk.Client, domain, apiVersion, apiName string, params
switch code {
case "InvalidAccessKeyId.NotFound":
return nil, err
case "SignatureNonceUsed",
"InvalidInstance.NotSupported",
"BackendServer.configuring",
"OperationUnsupported.EipNatBWPCheck":
case "404 Not Found":
return nil, errors.Wrap(cloudprovider.ErrNotFound, err.Error())
case "InvalidInstance.NotSupported",
"SignatureNonceUsed", // SignatureNonce 重复。每次请求的 SignatureNonce 在 15 分钟内不能重复。
"BackendServer.configuring", // 负载均衡的前一个配置项正在配置中,请稍后再试。
"Operation.Conflict", // 您当前的操作可能与其他人的操作产生了冲突,请稍后重试。
"OperationDenied.ResourceControl", // 指定的区域处于资源控制中,请稍后再试。
"ServiceIsStopping", // 监听正在停止,请稍后重试。
"ProcessingSameRequest", // 正在处理相同的请求。请稍后再试。
"ResourceInOperating", // 当前资源正在操作中,请求稍后重试。
"InvalidFileSystemStatus.Ordering", // Message: The filesystem is ordering now, please check it later.
"OperationUnsupported.EipNatBWPCheck": // create nat snat
retry = true
default:
if strings.HasPrefix(code, "EntityNotExist") || strings.HasSuffix(code, "NotFound") {
if strings.HasPrefix(code, "EntityNotExist.") || strings.HasSuffix(code, ".NotFound") {
return nil, errors.Wrap(cloudprovider.ErrNotFound, err.Error())
}
return nil, err
@@ -554,6 +563,7 @@ func (region *SAliyunClient) GetCapabilities() []string {
cloudprovider.CLOUD_CAPABILITY_INTERVPCNETWORK,
cloudprovider.CLOUD_CAPABILITY_SAML_AUTH,
cloudprovider.CLOUD_CAPABILITY_NAT,
cloudprovider.CLOUD_CAPABILITY_NAS,
}
return caps
}
+350
View File
@@ -0,0 +1,350 @@
// 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 aliyun
import (
"fmt"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
billing_api "yunion.io/x/onecloud/pkg/apis/billing"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
type SupportedFeatures struct {
SupportedFeature []string
}
type MountTargets struct {
MountTarget []SMountTarget
}
type Package struct {
}
type Packages struct {
Package []Package
}
type SFileSystem struct {
multicloud.SNasBase
region *SRegion
Status string
Description string
StorageType string
MountTargetCountLimit int
Ldap string
ZoneId string
// 2021-03-22T10:08:15CST
CreateTime string
MeteredIASize int
SupportedFeatures SupportedFeatures
MountTargets MountTargets
AutoSnapshotPolicyId string
MeteredSize int64
EncryptType int
Capacity int64
ProtocolType string
ChargeType string
Packages Packages
ExpiredTime string
FileSystemType string
FileSystemId string
RegionId string
Tags Tags
}
func (self *SFileSystem) GetId() string {
return self.FileSystemId
}
func (self *SFileSystem) GetGlobalId() string {
return self.FileSystemId
}
func (self *SFileSystem) GetName() string {
if len(self.Description) > 0 {
return self.Description
}
return self.FileSystemId
}
func (self *SFileSystem) GetFileSystemType() string {
return self.FileSystemType
}
func (self *SFileSystem) GetMountTargetCountLimit() int {
return self.MountTargetCountLimit
}
func (self *SFileSystem) GetStatus() string {
switch self.Status {
case "", "Running":
return api.NAS_STATUS_AVAILABLE
case "Extending":
return api.NAS_STATUS_EXTENDING
case "Stopping", "Stopped":
return api.NAS_STATUS_UNAVAILABLE
case "Pending":
return api.NAS_STATUS_CREATING
default:
return api.NAS_STATUS_UNKNOWN
}
}
func (self *SFileSystem) GetBillintType() string {
if self.ChargeType == "PayAsYouGo" {
return billing_api.BILLING_TYPE_POSTPAID
}
return billing_api.BILLING_TYPE_PREPAID
}
func (self *SFileSystem) GetStorageType() string {
return strings.ToLower(self.StorageType)
}
func (self *SFileSystem) GetProtocol() string {
return self.ProtocolType
}
func (self *SFileSystem) GetCapacityGb() int64 {
return self.Capacity
}
func (self *SFileSystem) GetUsedCapacityGb() int64 {
return self.MeteredSize
}
func (self *SFileSystem) GetZoneId() string {
return self.ZoneId
}
func (self *SFileSystem) Delete() error {
return self.region.DeleteFileSystem(self.FileSystemId)
}
func (self *SFileSystem) GetCreatedAt() time.Time {
ret, _ := time.Parse("2006-01-02T15:04:05CST", self.CreateTime)
if !ret.IsZero() {
ret = ret.Add(time.Hour * 8)
}
return ret
}
func (self *SFileSystem) GetExpiredAt() time.Time {
ret, _ := time.Parse("2006-01-02T15:04:05CST", self.ExpiredTime)
if !ret.IsZero() {
ret = ret.Add(time.Hour * 8)
}
return ret
}
func (self *SFileSystem) Refresh() error {
fs, err := self.region.GetFileSystem(self.FileSystemId)
if err != nil {
return errors.Wrapf(err, "GetFileSystem(%s)", self.FileSystemId)
}
return jsonutils.Update(self, fs)
}
func (self *SFileSystem) GetTags() (map[string]string, error) {
return self.Tags.GetTags()
}
func (self *SRegion) GetFileSystems(id string, pageSize, pageNum int) ([]SFileSystem, int, error) {
if pageSize < 1 || pageSize > 100 {
pageSize = 50
}
if pageNum < 1 {
pageNum = 1
}
params := map[string]string{
"RegionId": self.RegionId,
"PageSize": fmt.Sprintf("%d", pageSize),
"PageNumber": fmt.Sprintf("%d", pageNum),
}
if len(id) > 0 {
params["FileSystemId"] = id
}
resp, err := self.nasRequest("DescribeFileSystems", params)
if err != nil {
return nil, 0, errors.Wrapf(err, "DescribeFileSystems")
}
ret := struct {
TotalCount int
FileSystems struct {
FileSystem []SFileSystem
}
}{}
err = resp.Unmarshal(&ret)
if err != nil {
return nil, 0, errors.Wrapf(err, "resp.Unmarshal")
}
return ret.FileSystems.FileSystem, ret.TotalCount, nil
}
func (self *SRegion) GetICloudFileSystems() ([]cloudprovider.ICloudFileSystem, error) {
nas := []SFileSystem{}
num := 1
for {
part, total, err := self.GetFileSystems("", 100, num)
if err != nil {
return nil, errors.Wrapf(err, "GetFileSystems")
}
nas = append(nas, part...)
if total <= len(nas) {
break
}
num++
}
ret := []cloudprovider.ICloudFileSystem{}
for i := range nas {
nas[i].region = self
ret = append(ret, &nas[i])
}
return ret, nil
}
func (self *SRegion) GetFileSystem(id string) (*SFileSystem, error) {
if len(id) == 0 {
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty id")
}
nas, total, err := self.GetFileSystems(id, 1, 1)
if err != nil {
return nil, errors.Wrapf(err, "GetFileSystems")
}
if total == 1 {
nas[0].region = self
return &nas[0], nil
}
if total == 0 {
return nil, errors.Wrapf(cloudprovider.ErrNotFound, id)
}
return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, id)
}
func (self *SRegion) GetICloudFileSystemById(id string) (cloudprovider.ICloudFileSystem, error) {
fs, err := self.GetFileSystem(id)
if err != nil {
return nil, errors.Wrapf(err, "self.GetFileSystem")
}
return fs, nil
}
func (self *SRegion) CreateMountTarget(opts *cloudprovider.SMountTargetCreateOptions) (*SMountTarget, error) {
params := map[string]string{
"RegionId": self.RegionId,
"FileSystemId": opts.FileSystemId,
"AccessGroupName": strings.TrimPrefix(strings.TrimPrefix(opts.AccessGroupId, "extreme/"), "standard/"),
"NetworkType": opts.NetworkType,
"VpcId": opts.VpcId,
"VSwitchId": opts.NetworkId,
}
resp, err := self.nasRequest("CreateMountTarget", params)
if err != nil {
return nil, errors.Wrapf(err, "CreateMountTarget")
}
ret := struct {
MountTargetDomain string
}{}
err = resp.Unmarshal(&ret)
if err != nil {
return nil, errors.Wrapf(err, "resp.Unmarshal")
}
mts, _, err := self.GetMountTargets(opts.FileSystemId, ret.MountTargetDomain, 10, 1)
if err != nil {
return nil, errors.Wrapf(err, "self.GetMountTargets")
}
for i := range mts {
if mts[i].MountTargetDomain == ret.MountTargetDomain {
return &mts[i], nil
}
}
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "afeter create with mount domain %s", ret.MountTargetDomain)
}
func (self *SFileSystem) CreateMountTarget(opts *cloudprovider.SMountTargetCreateOptions) (cloudprovider.ICloudMountTarget, error) {
mt, err := self.region.CreateMountTarget(opts)
if err != nil {
return nil, errors.Wrapf(err, "CreateMountTarget")
}
mt.fs = self
return mt, nil
}
func (self *SRegion) DeleteFileSystem(id string) error {
params := map[string]string{
"RegionId": self.RegionId,
"FileSystemId": id,
}
_, err := self.nasRequest("DeleteFileSystem", params)
return errors.Wrapf(err, "DeleteFileSystem")
}
func (self *SRegion) CreateICloudFileSystem(opts *cloudprovider.FileSystemCraeteOptions) (cloudprovider.ICloudFileSystem, error) {
fs, err := self.CreateFileSystem(opts)
if err != nil {
return nil, errors.Wrapf(err, "self.CreateFileSystem")
}
return fs, nil
}
func (self *SRegion) CreateFileSystem(opts *cloudprovider.FileSystemCraeteOptions) (*SFileSystem, error) {
params := map[string]string{
"RegionId": self.RegionId,
"ProtocolType": opts.Protocol,
"ZoneId": opts.ZoneId,
"EncryptType": "0",
"FileSystemType": opts.FileSystemType,
"StorageType": opts.StorageType,
"ClientToken": utils.GenRequestId(20),
"Description": opts.Name,
}
switch opts.FileSystemType {
case "standard":
params["StorageType"] = utils.Capitalize(opts.StorageType)
case "cpfs":
params["ProtocolType"] = "cpfs"
switch opts.StorageType {
case "advance_100":
params["Bandwidth"] = "100"
case "advance_200":
params["Bandwidth"] = "200"
}
case "extreme":
params["Capacity"] = fmt.Sprintf("%d", opts.Capacity)
}
if len(opts.VpcId) > 0 {
params["VpcId"] = opts.VpcId
}
if len(opts.NetworkId) > 0 {
params["VSwitchId"] = opts.NetworkId
}
resp, err := self.nasRequest("CreateFileSystem", params)
if err != nil {
return nil, errors.Wrapf(err, "CreateFileSystem")
}
fsId, _ := resp.GetString("FileSystemId")
return self.GetFileSystem(fsId)
}
+159
View File
@@ -0,0 +1,159 @@
// 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 aliyun
import (
"fmt"
"strings"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type ClientMasterNode struct {
EcsIp string
EcsId string
DefaultPasswd string
}
type ClientMasterNodes struct {
ClientMasterNode []ClientMasterNode
}
type SMountTarget struct {
fs *SFileSystem
Status string
NetworkType string
VswId string
VpcId string
MountTargetDomain string
AccessGroup string
ClientMasterNodes ClientMasterNodes
Tags Tags
}
func (self *SMountTarget) GetGlobalId() string {
return self.MountTargetDomain
}
func (self *SMountTarget) GetName() string {
return self.MountTargetDomain
}
func (self *SMountTarget) GetNetworkType() string {
return strings.ToLower(self.NetworkType)
}
func (self *SMountTarget) GetStatus() string {
switch self.Status {
case "Active":
return api.MOUNT_TARGET_STATUS_AVAILABLE
case "Inactive":
return api.MOUNT_TARGET_STATUS_UNAVAILABLE
case "Pending":
return api.MOUNT_TARGET_STATUS_CREATING
case "Deleting":
return api.MOUNT_TARGET_STATUS_DELETING
default:
return strings.ToLower(self.Status)
}
}
func (self *SMountTarget) GetVpcId() string {
return self.VpcId
}
func (self *SMountTarget) GetNetworkId() string {
return self.VswId
}
func (self *SMountTarget) GetDomainName() string {
return self.MountTargetDomain
}
func (self *SMountTarget) GetAccessGroupId() string {
return fmt.Sprintf("%s/%s", self.fs.FileSystemType, self.AccessGroup)
}
func (self *SMountTarget) Delete() error {
return self.fs.region.DeleteMountTarget(self.fs.FileSystemId, self.MountTargetDomain)
}
func (self *SRegion) GetMountTargets(fsId, domainName string, pageSize, pageNum int) ([]SMountTarget, int, error) {
if pageSize < 1 || pageSize > 100 {
pageSize = 50
}
if pageNum < 1 {
pageNum = 1
}
params := map[string]string{
"RegionId": self.RegionId,
"FileSystemId": fsId,
"PageSize": fmt.Sprintf("%d", pageSize),
"PageNumber": fmt.Sprintf("%d", pageNum),
}
if len(domainName) > 0 {
params["MountTargetDomain"] = domainName
}
resp, err := self.nasRequest("DescribeMountTargets", params)
if err != nil {
return nil, 0, errors.Wrapf(err, "DescribeMountTargets")
}
ret := struct {
TotalCount int
MountTargets struct {
MountTarget []SMountTarget
}
}{}
err = resp.Unmarshal(&ret)
if err != nil {
return nil, 0, errors.Wrapf(err, "resp.Unmarshal")
}
return ret.MountTargets.MountTarget, ret.TotalCount, nil
}
func (self *SFileSystem) GetMountTargets() ([]cloudprovider.ICloudMountTarget, error) {
targets := []SMountTarget{}
num := 1
for {
part, total, err := self.region.GetMountTargets(self.FileSystemId, "", 50, num)
if err != nil {
return nil, errors.Wrapf(err, "GetMountTargets")
}
targets = append(targets, part...)
if len(part) >= total {
break
}
}
ret := []cloudprovider.ICloudMountTarget{}
for i := range targets {
targets[i].fs = self
ret = append(ret, &targets[i])
}
return ret, nil
}
func (self *SRegion) DeleteMountTarget(fsId, id string) error {
params := map[string]string{
"RegionId": self.RegionId,
"FileSystemId": fsId,
"MountTargetDomain": id,
}
_, err := self.nasRequest("DeleteMountTarget", params)
return errors.Wrapf(err, "DeleteMountTarget")
}
+9
View File
@@ -153,6 +153,15 @@ func (self *SRegion) vpcRequest(action string, params map[string]string) (jsonut
return jsonRequest(client, "vpc.aliyuncs.com", ALIYUN_API_VERSION_VPC, action, params, self.client.debug)
}
func (self *SRegion) nasRequest(action string, params map[string]string) (jsonutils.JSONObject, error) {
client, err := self.getSdkClient()
if err != nil {
return nil, err
}
return jsonRequest(client, "nas.aliyuncs.com", ALIYUN_NAS_API_VERSION, action, params, self.client.debug)
}
func (self *SRegion) kvsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) {
client, err := self.getSdkClient()
if err != nil {
+8
View File
@@ -66,6 +66,14 @@ type Tags struct {
Tag []Tag
}
func (t Tags) GetTags() (map[string]string, error) {
ret := map[string]string{}
for _, tag := range t.Tag {
ret[tag.TagKey] = tag.TagValue
}
return ret, nil
}
type Tag struct {
TagKey string
TagValue string
@@ -0,0 +1,87 @@
// 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/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud/aliyun"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type NasAccessGroupListOptions struct {
FileSystemType string `choices:"standard|extreme" default:"standard"`
}
shellutils.R(&NasAccessGroupListOptions{}, "access-group-list", "List Nas AccessGroups", func(cli *aliyun.SRegion, args *NasAccessGroupListOptions) error {
ags, err := cli.GetAccessGroups(args.FileSystemType)
if err != nil {
return err
}
printList(ags, 0, 0, 0, []string{})
return nil
})
shellutils.R(&cloudprovider.SAccessGroup{}, "access-group-create", "Create Nas AccessGroup", func(cli *aliyun.SRegion, args *cloudprovider.SAccessGroup) error {
return cli.CreateAccessGroup(args)
})
type AccessGroupDeleteOptions struct {
FileSystemType string
NAME string
}
shellutils.R(&AccessGroupDeleteOptions{}, "access-group-delete", "Delete AccessGroup", func(cli *aliyun.SRegion, args *AccessGroupDeleteOptions) error {
return cli.DeleteAccessGroup(args.FileSystemType, args.NAME)
})
type NasAccessGroupRuleListOptions struct {
GROUP string
PageSize int `help:"page size"`
PageNum int `help:"page num"`
}
shellutils.R(&NasAccessGroupRuleListOptions{}, "access-group-rule-list", "List Nas AccessGroup Rules", func(cli *aliyun.SRegion, args *NasAccessGroupRuleListOptions) error {
rules, _, err := cli.GetAccessGroupRules(args.GROUP, args.PageSize, args.PageNum)
if err != nil {
return err
}
printList(rules, 0, 0, 0, []string{})
return nil
})
type AccessRuleDeleteOptions struct {
FileSystemType string
GROUP string
RULE_ID string
}
shellutils.R(&AccessRuleDeleteOptions{}, "access-group-rule-delete", "Delete AccessGroup Rule", func(cli *aliyun.SRegion, args *AccessRuleDeleteOptions) error {
return cli.DeleteAccessGroupRule(args.FileSystemType, args.GROUP, args.RULE_ID)
})
type AccessRuleCreateOptions struct {
SOURCE string
FileSystemType string
GroupName string
RwType cloudprovider.TRWAccessType
UserType cloudprovider.TUserAccessType
Priority int
}
shellutils.R(&AccessRuleCreateOptions{}, "access-group-rule-create", "Delete AccessGroup Rule", func(cli *aliyun.SRegion, args *AccessRuleCreateOptions) error {
return cli.CreateAccessGroupRule(args.SOURCE, args.FileSystemType, args.GroupName, args.RwType, args.UserType, args.Priority)
})
}
+54
View File
@@ -0,0 +1,54 @@
// 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/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud/aliyun"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type FileSystemListOptions struct {
Id string `help:"FileSystem Id"`
PageSize int `help:"page size"`
PageNum int `help:"page num"`
}
shellutils.R(&FileSystemListOptions{}, "file-system-list", "List FileSystem", func(cli *aliyun.SRegion, args *FileSystemListOptions) error {
nas, _, err := cli.GetFileSystems(args.Id, args.PageSize, args.PageNum)
if err != nil {
return err
}
printList(nas, 0, 0, 0, []string{})
return nil
})
type FileSystemDeleteOptions struct {
ID string `help:"File System ID"`
}
shellutils.R(&FileSystemDeleteOptions{}, "file-system-delete", "Delete filesystem", func(cli *aliyun.SRegion, args *FileSystemDeleteOptions) error {
return cli.DeleteFileSystem(args.ID)
})
shellutils.R(&cloudprovider.FileSystemCraeteOptions{}, "file-system-create", "Create filesystem", func(cli *aliyun.SRegion, args *cloudprovider.FileSystemCraeteOptions) error {
fs, err := cli.CreateFileSystem(args)
if err != nil {
return err
}
printObject(fs)
return nil
})
}
@@ -0,0 +1,56 @@
// 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/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud/aliyun"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type MountTargetListOptions struct {
ID string `help:"Id"`
DomainName string
PageSize int `help:"page size"`
PageNum int `help:"page num"`
}
shellutils.R(&MountTargetListOptions{}, "mount-target-list", "List MountTargets", func(cli *aliyun.SRegion, args *MountTargetListOptions) error {
mounts, _, err := cli.GetMountTargets(args.ID, args.DomainName, args.PageSize, args.PageNum)
if err != nil {
return err
}
printList(mounts, 0, 0, 0, []string{})
return nil
})
shellutils.R(&cloudprovider.SMountTargetCreateOptions{}, "mount-target-create", "Create Nas MountTarget", func(cli *aliyun.SRegion, args *cloudprovider.SMountTargetCreateOptions) error {
mt, err := cli.CreateMountTarget(args)
if err != nil {
return err
}
printObject(mt)
return nil
})
type MountTargetDeleteOptions struct {
FILE_SYSTEM_ID string
MOUT_POINT_ID string
}
shellutils.R(&MountTargetDeleteOptions{}, "mount-target-delete", "Delete Nas MountTarget", func(cli *aliyun.SRegion, args *MountTargetDeleteOptions) error {
return cli.DeleteMountTarget(args.FILE_SYSTEM_ID, args.MOUT_POINT_ID)
})
}
+20
View File
@@ -0,0 +1,20 @@
// 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 multicloud
type SNasBase struct {
SResourceBase
SBillingBase
}
+24
View File
@@ -149,3 +149,27 @@ func (self *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) {
func (self *SRegion) CreateInternetGateway() (cloudprovider.ICloudInternetGateway, error) {
return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "CreateInternetGateway")
}
func (self *SRegion) GetICloudFileSystems() ([]cloudprovider.ICloudFileSystem, error) {
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetICloudFileSystems")
}
func (self *SRegion) GetICloudFileSystemById(id string) (cloudprovider.ICloudFileSystem, error) {
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetICloudFileSystemById")
}
func (self *SRegion) GetICloudAccessGroups() ([]cloudprovider.ICloudAccessGroup, error) {
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetICloudAccessGroups")
}
func (self *SRegion) GetICloudAccessGroupById(id string) (cloudprovider.ICloudAccessGroup, error) {
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetICloudAccessGroupById")
}
func (self *SRegion) CreateICloudAccessGroup(opts *cloudprovider.SAccessGroup) (cloudprovider.ICloudAccessGroup, error) {
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "CreateICloudAccessGroup")
}
func (self *SRegion) CreateICloudFileSystem(opts *cloudprovider.FileSystemCraeteOptions) (cloudprovider.ICloudFileSystem, error) {
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "CreateICloudFileSystem")
}