mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-21 06:09:39 +08:00
Merge pull request #7318 from ioito/hotfix/qx-fix-openstack-project
fix: openstack多项目问题
This commit is contained in:
@@ -180,7 +180,7 @@ type CloudaccountCreateInput struct {
|
||||
// 自动同步间隔时间
|
||||
SyncIntervalSeconds int `json:"sync_interval_seconds"`
|
||||
|
||||
// 自动根据云上项目或订阅创建本地项目
|
||||
// 自动根据云上项目或订阅创建本地项目, OpenStack此参数为true
|
||||
// default: false
|
||||
AutoCreateProject *bool `json:"auto_create_project"`
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ var (
|
||||
STORAGE_ZSTACK_LOCAL_STORAGE, STORAGE_ZSTACK_CEPH, STORAGE_GPFS,
|
||||
}
|
||||
|
||||
HOST_STORAGE_LOCAL_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_ZSTACK_LOCAL_STORAGE}
|
||||
HOST_STORAGE_LOCAL_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_ZSTACK_LOCAL_STORAGE, STORAGE_OPENSTACK_NOVA}
|
||||
|
||||
STORAGE_LIMITED_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_NAS, STORAGE_RBD, STORAGE_NFS, STORAGE_GPFS}
|
||||
|
||||
|
||||
@@ -190,6 +190,8 @@ type ICloudProviderFactory interface {
|
||||
GetMaxCloudEventSyncDays() int
|
||||
GetMaxCloudEventKeepDays() int
|
||||
|
||||
IsNeedForceAutoCreateProject() bool
|
||||
|
||||
IsSupportClouduser() bool
|
||||
IsSupportClouduserPolicy() bool
|
||||
IsSupportResetClouduserPassword() bool
|
||||
@@ -483,6 +485,10 @@ func (factory *baseProviderFactory) GetMaxCloudEventKeepDays() int {
|
||||
return 7
|
||||
}
|
||||
|
||||
func (factory *baseProviderFactory) IsNeedForceAutoCreateProject() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (factory *baseProviderFactory) IsSupportClouduser() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ func (region *SFakeOnPremiseRegion) GetISecurityGroupById(id string) (ICloudSecu
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (region *SFakeOnPremiseRegion) GetISecurityGroupByName(vpcId string, name string) (ICloudSecurityGroup, error) {
|
||||
func (region *SFakeOnPremiseRegion) GetISecurityGroupByName(opts *SecurityGroupFilterOptions) (ICloudSecurityGroup, error) {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// 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 SNetworkCreateOptions struct {
|
||||
Name string
|
||||
Desc string
|
||||
ProjectId string
|
||||
Cidr string
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/billing"
|
||||
"yunion.io/x/onecloud/pkg/util/rbacutils"
|
||||
)
|
||||
|
||||
type ICloudResource interface {
|
||||
@@ -70,7 +71,7 @@ type ICloudRegion interface {
|
||||
GetIDiskById(id string) (ICloudDisk, error)
|
||||
|
||||
GetISecurityGroupById(secgroupId string) (ICloudSecurityGroup, error)
|
||||
GetISecurityGroupByName(vpcId string, name string) (ICloudSecurityGroup, error)
|
||||
GetISecurityGroupByName(opts *SecurityGroupFilterOptions) (ICloudSecurityGroup, error)
|
||||
CreateISecurityGroup(conf *SecurityGroupCreateInput) (ICloudSecurityGroup, error)
|
||||
|
||||
CreateIVpc(name string, desc string, cidr string) (ICloudVpc, error)
|
||||
@@ -345,7 +346,7 @@ type ICloudEIP interface {
|
||||
}
|
||||
|
||||
type ICloudSecurityGroup interface {
|
||||
ICloudResource
|
||||
IVirtualResource
|
||||
|
||||
GetDescription() string
|
||||
GetRules() ([]SecurityRule, error)
|
||||
@@ -453,7 +454,7 @@ type ICloudWire interface {
|
||||
|
||||
GetINetworkById(netid string) (ICloudNetwork, error)
|
||||
|
||||
CreateINetwork(name string, cidr string, desc string) (ICloudNetwork, error)
|
||||
CreateINetwork(opts *SNetworkCreateOptions) (ICloudNetwork, error)
|
||||
}
|
||||
|
||||
type ICloudNetwork interface {
|
||||
@@ -466,8 +467,11 @@ type ICloudNetwork interface {
|
||||
GetIpMask() int8
|
||||
GetGateway() string
|
||||
GetServerType() string
|
||||
// GetIsPublic() bool
|
||||
// GetPublicScope() rbacutils.TRbacScope
|
||||
//GetIsPublic() bool
|
||||
// 仅私有云有用,公有云无效
|
||||
// 1. scope = none 非共享, network仅会属于一个项目,并且私有
|
||||
// 2. scope = system 系统共享 云账号共享会跟随云账号共享,云账号非共享,会共享到network所在域
|
||||
GetPublicScope() rbacutils.TRbacScope
|
||||
|
||||
Delete() error
|
||||
|
||||
|
||||
@@ -24,11 +24,18 @@ import (
|
||||
|
||||
const DEFAULT_CLOUD_RULE_ID = "default_cloud_rule_id"
|
||||
|
||||
type SecurityGroupFilterOptions struct {
|
||||
VpcId string
|
||||
Name string
|
||||
ProjectId string
|
||||
}
|
||||
|
||||
type SecurityGroupCreateInput struct {
|
||||
Name string
|
||||
Desc string
|
||||
VpcId string
|
||||
Rules []secrules.SecurityRule
|
||||
Name string
|
||||
Desc string
|
||||
VpcId string
|
||||
ProjectId string
|
||||
Rules []secrules.SecurityRule
|
||||
}
|
||||
|
||||
type SecurityRule struct {
|
||||
|
||||
@@ -321,7 +321,7 @@ func (self *SManagedVirtualizedGuestDriver) RequestDeployGuestOnHost(ctx context
|
||||
|
||||
secgroups := guest.GetSecgroups()
|
||||
for i, secgroup := range secgroups {
|
||||
externalId, err := region.GetDriver().RequestSyncSecurityGroup(ctx, task.GetUserCred(), vpcId, vpc, &secgroup)
|
||||
externalId, err := region.GetDriver().RequestSyncSecurityGroup(ctx, task.GetUserCred(), vpcId, vpc, &secgroup, desc.ProjectId)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "RequestSyncSecurityGroup")
|
||||
}
|
||||
@@ -976,10 +976,19 @@ func (self *SManagedVirtualizedGuestDriver) RequestSyncSecgroupsOnHost(ctx conte
|
||||
return errors.Wrap(err, "GetSecurityGroupVpcId")
|
||||
}
|
||||
|
||||
remoteProjectId := ""
|
||||
provider := host.GetCloudprovider()
|
||||
if provider != nil {
|
||||
remoteProjectId, err = provider.SyncProject(ctx, task.GetUserCred(), guest.ProjectId)
|
||||
if err != nil {
|
||||
log.Errorf("failed to sync project %s for guest %s error: %v", guest.ProjectId, guest.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
secgroups := guest.GetSecgroups()
|
||||
externalIds := []string{}
|
||||
for _, secgroup := range secgroups {
|
||||
externalId, err := region.GetDriver().RequestSyncSecurityGroup(ctx, task.GetUserCred(), vpcId, vpc, &secgroup)
|
||||
externalId, err := region.GetDriver().RequestSyncSecurityGroup(ctx, task.GetUserCred(), vpcId, vpc, &secgroup, remoteProjectId)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "RequestSyncSecurityGroup")
|
||||
}
|
||||
|
||||
@@ -809,6 +809,16 @@ func (manager *SCloudaccountManager) ValidateCreateData(
|
||||
return input, err
|
||||
}
|
||||
|
||||
if !cloudprovider.IsSupported(input.Provider) {
|
||||
return input, httperrors.NewInputParameterError("Unsupported provider %s", input.Provider)
|
||||
}
|
||||
providerDriver, _ := cloudprovider.GetProviderFactory(input.Provider)
|
||||
|
||||
forceAutoCreateProject := providerDriver.IsNeedForceAutoCreateProject()
|
||||
if forceAutoCreateProject {
|
||||
input.AutoCreateProject = &forceAutoCreateProject
|
||||
}
|
||||
|
||||
if len(input.ProjectId) > 0 {
|
||||
var proj *db.STenant
|
||||
proj, input.ProjectizedResourceInput, err = db.ValidateProjectizedResourceInput(ctx, input.ProjectizedResourceInput)
|
||||
@@ -821,17 +831,15 @@ func (manager *SCloudaccountManager) ValidateCreateData(
|
||||
if input.AutoCreateProject != nil && *input.AutoCreateProject {
|
||||
log.Warningf("project_id and auto_create_project should not be turned on at the same time")
|
||||
}
|
||||
input.AutoCreateProject = nil
|
||||
if !forceAutoCreateProject {
|
||||
input.AutoCreateProject = nil
|
||||
}
|
||||
} else if input.AutoCreateProject == nil || !*input.AutoCreateProject {
|
||||
log.Warningf("auto_create_project is off while no project_id specified")
|
||||
createProject := true
|
||||
input.AutoCreateProject = &createProject
|
||||
}
|
||||
|
||||
if !cloudprovider.IsSupported(input.Provider) {
|
||||
return input, httperrors.NewInputParameterError("Unsupported provider %s", input.Provider)
|
||||
}
|
||||
providerDriver, _ := cloudprovider.GetProviderFactory(input.Provider)
|
||||
input.SCloudaccount, err = providerDriver.ValidateCreateCloudaccountData(ctx, userCred, input.SCloudaccountCredential)
|
||||
if err != nil {
|
||||
return input, err
|
||||
|
||||
@@ -921,7 +921,7 @@ func (self *SElasticcache) GetCreateHuaweiElasticcacheParams(data *jsonutils.JSO
|
||||
|
||||
// fill security group here
|
||||
if len(self.SecurityGroupId) > 0 {
|
||||
sgCache, err := SecurityGroupCacheManager.GetSecgroupCache(context.Background(), nil, self.SecurityGroupId, self.VpcId, self.GetRegion().Id, self.GetCloudprovider().Id)
|
||||
sgCache, err := SecurityGroupCacheManager.GetSecgroupCache(context.Background(), nil, self.SecurityGroupId, self.VpcId, self.GetRegion().Id, self.GetCloudprovider().Id, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "elasticcache.GetCreateHuaweiElasticcacheParams.SecurityGroup")
|
||||
}
|
||||
|
||||
@@ -711,7 +711,14 @@ func (self *SNetwork) SyncWithCloudNetwork(ctx context.Context, userCred mcclien
|
||||
SyncCloudProject(userCred, self, syncOwnerId, extNet, vpc.ManagerId)
|
||||
|
||||
if provider != nil {
|
||||
self.SyncShareState(ctx, userCred, provider.getAccountShareInfo())
|
||||
shareInfo := provider.getAccountShareInfo()
|
||||
if utils.IsInStringArray(provider.Provider, api.PRIVATE_CLOUD_PROVIDERS) && extNet.GetPublicScope() == rbacutils.ScopeNone {
|
||||
shareInfo = apis.SAccountShareInfo{
|
||||
IsPublic: false,
|
||||
PublicScope: rbacutils.ScopeNone,
|
||||
}
|
||||
}
|
||||
self.SyncShareState(ctx, userCred, shareInfo)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -753,7 +760,14 @@ func (manager *SNetworkManager) newFromCloudNetwork(ctx context.Context, userCre
|
||||
SyncCloudProject(userCred, &net, syncOwnerId, extNet, vpc.ManagerId)
|
||||
|
||||
if provider != nil {
|
||||
net.SyncShareState(ctx, userCred, provider.getAccountShareInfo())
|
||||
shareInfo := provider.getAccountShareInfo()
|
||||
if utils.IsInStringArray(provider.Provider, api.PRIVATE_CLOUD_PROVIDERS) && extNet.GetPublicScope() == rbacutils.ScopeNone {
|
||||
shareInfo = apis.SAccountShareInfo{
|
||||
IsPublic: false,
|
||||
PublicScope: rbacutils.ScopeNone,
|
||||
}
|
||||
}
|
||||
net.SyncShareState(ctx, userCred, shareInfo)
|
||||
}
|
||||
|
||||
db.OpsLog.LogEvent(&net, db.ACT_CREATE, net.GetShortDesc(ctx), userCred)
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/billing"
|
||||
"yunion.io/x/onecloud/pkg/util/rbacutils"
|
||||
)
|
||||
|
||||
type IRegionDriver interface {
|
||||
@@ -117,8 +118,8 @@ type IRegionDriver interface {
|
||||
RequestUnBindIPFromNatgateway(ctx context.Context, task taskman.ITask, nat INatHelper, natgateway *SNatGateway) error
|
||||
BindIPToNatgatewayRollback(ctx context.Context, eipId string) error
|
||||
|
||||
RequestCacheSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, region *SCloudregion, vpc *SVpc, secgroup *SSecurityGroup, classic bool, task taskman.ITask) error
|
||||
RequestSyncSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, vpcId string, vpc *SVpc, secgroup *SSecurityGroup) (string, error)
|
||||
RequestCacheSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, region *SCloudregion, vpc *SVpc, secgroup *SSecurityGroup, classic bool, removeProjectId string, task taskman.ITask) error
|
||||
RequestSyncSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, vpcId string, vpc *SVpc, secgroup *SSecurityGroup, removeProjectId string) (string, error)
|
||||
GetSecurityGroupRuleOrder() cloudprovider.TPriorityOrder // Desc(priority值越大,优先级越高) Asc(priority值越小,优先级越高)
|
||||
GetDefaultSecurityGroupInRule() cloudprovider.SecurityRule
|
||||
GetDefaultSecurityGroupOutRule() cloudprovider.SecurityRule
|
||||
@@ -131,6 +132,7 @@ type IRegionDriver interface {
|
||||
IsSecurityGroupBelongGlobalVpc() bool //安全组子账号范围内可用
|
||||
GetDefaultSecurityGroupVpcId() string
|
||||
GetSecurityGroupVpcId(ctx context.Context, userCred mcclient.TokenCredential, region *SCloudregion, host *SHost, vpc *SVpc, classic bool) (string, error)
|
||||
GetSecurityGroupPublicScope() rbacutils.TRbacScope
|
||||
|
||||
IsSupportedBillingCycle(bc billing.SBillingCycle, resource string) bool
|
||||
GetSecgroupVpcid(vpcId string) string
|
||||
|
||||
@@ -57,7 +57,8 @@ type SSecurityGroupCache struct {
|
||||
// SecgroupId string `width:"128" charset:"ascii" list:"user" create:"required"`
|
||||
|
||||
// 虚拟私有网络外部Id
|
||||
VpcId string `width:"128" charset:"ascii" list:"user" create:"required"`
|
||||
VpcId string `width:"128" charset:"ascii" list:"user" create:"required"`
|
||||
ExternalProjectId string `width:"128" charset:"ascii" list:"user" create:"optional"`
|
||||
}
|
||||
|
||||
var SecurityGroupCacheManager *SSecurityGroupCacheManager
|
||||
@@ -260,7 +261,7 @@ func (manager *SSecurityGroupCacheManager) FetchCustomizeColumns(
|
||||
return rows
|
||||
}
|
||||
|
||||
func (manager *SSecurityGroupCacheManager) GetSecgroupCache(ctx context.Context, userCred mcclient.TokenCredential, secgroupId, vpcId string, regionId string, providerId string) (*SSecurityGroupCache, error) {
|
||||
func (manager *SSecurityGroupCacheManager) GetSecgroupCache(ctx context.Context, userCred mcclient.TokenCredential, secgroupId, vpcId string, regionId string, providerId string, projectId string) (*SSecurityGroupCache, error) {
|
||||
secgroupCache := SSecurityGroupCache{}
|
||||
query := manager.Query()
|
||||
conds := []sqlchemy.ICondition{
|
||||
@@ -268,6 +269,9 @@ func (manager *SSecurityGroupCacheManager) GetSecgroupCache(ctx context.Context,
|
||||
sqlchemy.Equals(query.Field("vpc_id"), vpcId),
|
||||
sqlchemy.Equals(query.Field("manager_id"), providerId),
|
||||
}
|
||||
if len(projectId) > 0 {
|
||||
conds = append(conds, sqlchemy.Equals(query.Field("external_project_id"), projectId))
|
||||
}
|
||||
_region, err := CloudregionManager.FetchById(regionId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "CloudregionManager.FetchById(%s)", regionId)
|
||||
@@ -290,7 +294,7 @@ func (manager *SSecurityGroupCacheManager) GetSecgroupCache(ctx context.Context,
|
||||
return &secgroupCache, nil
|
||||
}
|
||||
|
||||
func (manager *SSecurityGroupCacheManager) NewCache(ctx context.Context, userCred mcclient.TokenCredential, secgroupId, vpcId, regionId string, providerId string) (*SSecurityGroupCache, error) {
|
||||
func (manager *SSecurityGroupCacheManager) NewCache(ctx context.Context, userCred mcclient.TokenCredential, secgroupId, vpcId, regionId string, providerId string, projectId string) (*SSecurityGroupCache, error) {
|
||||
lockman.LockClass(ctx, manager, userCred.GetProjectId())
|
||||
defer lockman.ReleaseClass(ctx, manager, userCred.GetProjectId())
|
||||
|
||||
@@ -306,6 +310,7 @@ func (manager *SSecurityGroupCacheManager) NewCache(ctx context.Context, userCre
|
||||
secgroupCache.Status = api.SECGROUP_CACHE_STATUS_CACHING
|
||||
secgroupCache.CloudregionId = regionId
|
||||
secgroupCache.Name = secgroup.GetName()
|
||||
secgroupCache.ExternalProjectId = projectId
|
||||
secgroupCache.SetModelManager(manager, secgroupCache)
|
||||
if err := manager.TableSpec().Insert(ctx, secgroupCache); err != nil {
|
||||
log.Errorf("insert secgroupcache error: %v", err)
|
||||
@@ -314,8 +319,8 @@ func (manager *SSecurityGroupCacheManager) NewCache(ctx context.Context, userCre
|
||||
return secgroupCache, nil
|
||||
}
|
||||
|
||||
func (manager *SSecurityGroupCacheManager) Register(ctx context.Context, userCred mcclient.TokenCredential, secgroupId, vpcId, regionId string, providerId string) (*SSecurityGroupCache, error) {
|
||||
secgroupCache, err := manager.GetSecgroupCache(ctx, userCred, secgroupId, vpcId, regionId, providerId)
|
||||
func (manager *SSecurityGroupCacheManager) Register(ctx context.Context, userCred mcclient.TokenCredential, secgroupId, vpcId, regionId string, providerId string, projectId string) (*SSecurityGroupCache, error) {
|
||||
secgroupCache, err := manager.GetSecgroupCache(ctx, userCred, secgroupId, vpcId, regionId, providerId, projectId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -324,7 +329,7 @@ func (manager *SSecurityGroupCacheManager) Register(ctx context.Context, userCre
|
||||
return secgroupCache, nil
|
||||
}
|
||||
|
||||
return manager.NewCache(ctx, userCred, secgroupId, vpcId, regionId, providerId)
|
||||
return manager.NewCache(ctx, userCred, secgroupId, vpcId, regionId, providerId, projectId)
|
||||
}
|
||||
|
||||
func (manager *SSecurityGroupCacheManager) getSecgroupcachesByProvider(provider *SCloudprovider, region *SCloudregion, vpcId string) ([]SSecurityGroupCache, error) {
|
||||
@@ -414,6 +419,7 @@ func (manager *SSecurityGroupCacheManager) SyncSecurityGroupCaches(ctx context.C
|
||||
commondb[i].Status = api.SECGROUP_CACHE_STATUS_READY
|
||||
commondb[i].Name = commonext[i].GetName()
|
||||
commondb[i].Description = commonext[i].GetDescription()
|
||||
commondb[i].ExternalProjectId = commonext[i].GetProjectId()
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
@@ -442,7 +448,7 @@ func (manager *SSecurityGroupCacheManager) SyncSecurityGroupCaches(ctx context.C
|
||||
log.Warningf("failed to set secgroup %s(%s) project sharable", secgroup.Name, secgroup.Id)
|
||||
}
|
||||
}
|
||||
cache, err := manager.NewCache(ctx, userCred, secgroup.Id, vpcId, vpc.CloudregionId, provider.Id)
|
||||
cache, err := manager.NewCache(ctx, userCred, secgroup.Id, vpcId, vpc.CloudregionId, provider.Id, added[i].GetProjectId())
|
||||
if err != nil {
|
||||
syncResult.AddError(fmt.Errorf("failed to create secgroup cache for secgroup %s(%s) provider: %s: %s", secgroup.Name, secgroup.Name, provider.Name, err))
|
||||
continue
|
||||
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/billing"
|
||||
"yunion.io/x/onecloud/pkg/util/rbacutils"
|
||||
)
|
||||
|
||||
type SBaseRegionDriver struct {
|
||||
@@ -217,7 +218,7 @@ func (self *SBaseRegionDriver) RequestDeleteVpc(ctx context.Context, userCred mc
|
||||
return fmt.Errorf("Not implement RequestDeleteVpc")
|
||||
}
|
||||
|
||||
func (self *SBaseRegionDriver) RequestCacheSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, region *models.SCloudregion, vpc *models.SVpc, secgroup *models.SSecurityGroup, classic bool, task taskman.ITask) error {
|
||||
func (self *SBaseRegionDriver) RequestCacheSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, region *models.SCloudregion, vpc *models.SVpc, secgroup *models.SSecurityGroup, classic bool, remoteProjectId string, task taskman.ITask) error {
|
||||
return fmt.Errorf("Not Implemented RequestCacheSecurityGroup")
|
||||
}
|
||||
|
||||
@@ -241,11 +242,15 @@ func (self *SBaseRegionDriver) GetDefaultSecurityGroupVpcId() string {
|
||||
return api.NORMAL_VPC_ID
|
||||
}
|
||||
|
||||
func (self *SBaseRegionDriver) GetSecurityGroupPublicScope() rbacutils.TRbacScope {
|
||||
return rbacutils.ScopeSystem
|
||||
}
|
||||
|
||||
func (self *SBaseRegionDriver) GetSecurityGroupVpcId(ctx context.Context, userCred mcclient.TokenCredential, region *models.SCloudregion, host *models.SHost, vpc *models.SVpc, classic bool) (string, error) {
|
||||
return "", cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SBaseRegionDriver) RequestSyncSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, vpcId string, vpc *models.SVpc, secgroup *models.SSecurityGroup) (string, error) {
|
||||
func (self *SBaseRegionDriver) RequestSyncSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, vpcId string, vpc *models.SVpc, secgroup *models.SSecurityGroup, removeProjectId string) (string, error) {
|
||||
return "", fmt.Errorf("Not Implemented RequestSyncSecurityGroup")
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/billing"
|
||||
"yunion.io/x/onecloud/pkg/util/rand"
|
||||
"yunion.io/x/onecloud/pkg/util/rbacutils"
|
||||
)
|
||||
|
||||
type SManagedVirtualizationRegionDriver struct {
|
||||
@@ -1457,7 +1458,7 @@ func (self *SManagedVirtualizationRegionDriver) GetSecurityGroupVpcId(ctx contex
|
||||
return region.GetDriver().GetDefaultSecurityGroupVpcId(), nil
|
||||
}
|
||||
|
||||
func (self *SManagedVirtualizationRegionDriver) RequestSyncSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, vpcId string, vpc *models.SVpc, secgroup *models.SSecurityGroup) (string, error) {
|
||||
func (self *SManagedVirtualizationRegionDriver) RequestSyncSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, vpcId string, vpc *models.SVpc, secgroup *models.SSecurityGroup, remoteProjectId string) (string, error) {
|
||||
lockman.LockRawObject(ctx, "secgroupcache", fmt.Sprintf("%s-%s-%s", secgroup.Id, vpcId, vpc.ManagerId))
|
||||
defer lockman.ReleaseRawObject(ctx, "secgroupcache", fmt.Sprintf("%s-%s-%s", secgroup.Id, vpcId, vpc.ManagerId))
|
||||
|
||||
@@ -1466,7 +1467,11 @@ func (self *SManagedVirtualizationRegionDriver) RequestSyncSecurityGroup(ctx con
|
||||
return "", errors.Wrap(err, "vpc.GetRegon")
|
||||
}
|
||||
|
||||
cache, err := models.SecurityGroupCacheManager.Register(ctx, userCred, secgroup.Id, vpcId, region.Id, vpc.ManagerId)
|
||||
if region.GetDriver().GetSecurityGroupPublicScope() == rbacutils.ScopeSystem {
|
||||
remoteProjectId = ""
|
||||
}
|
||||
|
||||
cache, err := models.SecurityGroupCacheManager.Register(ctx, userCred, secgroup.Id, vpcId, region.Id, vpc.ManagerId, remoteProjectId)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "SSecurityGroupCache.Register")
|
||||
}
|
||||
@@ -1495,9 +1500,13 @@ func (self *SManagedVirtualizationRegionDriver) RequestSyncSecurityGroup(ctx con
|
||||
randomString := func(prefix string, length int) string {
|
||||
return fmt.Sprintf("%s-%s", prefix, rand.String(length))
|
||||
}
|
||||
groupName := randomString(secgroup.Name, 1)
|
||||
opts := &cloudprovider.SecurityGroupFilterOptions{
|
||||
Name: randomString(secgroup.Name, 1),
|
||||
VpcId: vpcId,
|
||||
ProjectId: remoteProjectId,
|
||||
}
|
||||
for i := 2; i < 30; i++ {
|
||||
_, err := iRegion.GetISecurityGroupByName(vpc.ExternalId, groupName)
|
||||
_, err := iRegion.GetISecurityGroupByName(opts)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == cloudprovider.ErrNotFound {
|
||||
break
|
||||
@@ -1506,13 +1515,14 @@ func (self *SManagedVirtualizationRegionDriver) RequestSyncSecurityGroup(ctx con
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
groupName = randomString(secgroup.Name, i)
|
||||
opts.Name = randomString(secgroup.Name, i)
|
||||
}
|
||||
conf := &cloudprovider.SecurityGroupCreateInput{
|
||||
Name: groupName,
|
||||
Desc: secgroup.Description,
|
||||
VpcId: vpcId,
|
||||
Rules: secgroup.GetSecRules(""),
|
||||
Name: opts.Name,
|
||||
Desc: secgroup.Description,
|
||||
VpcId: vpcId,
|
||||
ProjectId: remoteProjectId,
|
||||
Rules: secgroup.GetSecRules(""),
|
||||
}
|
||||
iSecgroup, err = iRegion.CreateISecurityGroup(conf)
|
||||
if err != nil {
|
||||
@@ -1560,14 +1570,13 @@ func (self *SManagedVirtualizationRegionDriver) RequestSyncSecurityGroup(ctx con
|
||||
return cache.ExternalId, nil
|
||||
}
|
||||
|
||||
func (self *SManagedVirtualizationRegionDriver) RequestCacheSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, region *models.SCloudregion, vpc *models.SVpc, secgroup *models.SSecurityGroup, classic bool, task taskman.ITask) error {
|
||||
|
||||
func (self *SManagedVirtualizationRegionDriver) RequestCacheSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, region *models.SCloudregion, vpc *models.SVpc, secgroup *models.SSecurityGroup, classic bool, removeProjectId string, task taskman.ITask) error {
|
||||
vpcId, err := region.GetDriver().GetSecurityGroupVpcId(ctx, userCred, region, nil, vpc, classic)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetSecurityGroupVpcId")
|
||||
}
|
||||
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
|
||||
_, err := self.RequestSyncSecurityGroup(ctx, userCred, vpcId, vpc, secgroup)
|
||||
_, err := self.RequestSyncSecurityGroup(ctx, userCred, vpcId, vpc, secgroup, removeProjectId)
|
||||
return nil, err
|
||||
})
|
||||
return nil
|
||||
@@ -1636,7 +1645,7 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateDBInstance(ctx cont
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetSecurityGroupVpcId")
|
||||
}
|
||||
desc.SecgroupId, err = region.GetDriver().RequestSyncSecurityGroup(ctx, userCred, vpcId, vpc, secgroup)
|
||||
desc.SecgroupId, err = region.GetDriver().RequestSyncSecurityGroup(ctx, userCred, vpcId, vpc, secgroup, desc.ProjectId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SyncSecurityGroup")
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/rbacutils"
|
||||
)
|
||||
|
||||
type SOpenStackRegionDriver struct {
|
||||
@@ -61,6 +62,10 @@ func (self *SOpenStackRegionDriver) IsOnlySupportAllowRules() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SOpenStackRegionDriver) GetSecurityGroupPublicScope() rbacutils.TRbacScope {
|
||||
return rbacutils.ScopeProject
|
||||
}
|
||||
|
||||
func (self *SOpenStackRegionDriver) GetProvider() string {
|
||||
return api.CLOUD_PROVIDER_OPENSTACK
|
||||
}
|
||||
|
||||
@@ -72,7 +72,19 @@ func (self *NetworkCreateTask) OnInit(ctx context.Context, obj db.IStandaloneMod
|
||||
return
|
||||
}
|
||||
|
||||
inet, err := iwire.CreateINetwork(network.Name, prefix.String(), network.Description)
|
||||
opts := cloudprovider.SNetworkCreateOptions{
|
||||
Name: network.Name,
|
||||
Cidr: prefix.String(),
|
||||
Desc: network.Description,
|
||||
}
|
||||
|
||||
provider := wire.GetCloudprovider()
|
||||
opts.ProjectId, err = provider.SyncProject(ctx, self.GetUserCred(), network.ProjectId)
|
||||
if err != nil {
|
||||
log.Errorf("failed to sync project %s for create %s network %s error: %v", network.ProjectId, provider.Provider, network.Name, err)
|
||||
}
|
||||
|
||||
inet, err := iwire.CreateINetwork(&opts)
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, network, "createinetwork", err)
|
||||
return
|
||||
|
||||
@@ -69,7 +69,7 @@ func (self *SecurityGroupCacheTask) OnInit(ctx context.Context, obj db.IStandalo
|
||||
|
||||
self.SetStage("OnCacheSecurityGroupComplete", nil)
|
||||
|
||||
err = region.GetDriver().RequestCacheSecurityGroup(ctx, self.UserCred, region, vpc, secgroup, classic, self)
|
||||
err = region.GetDriver().RequestCacheSecurityGroup(ctx, self.UserCred, region, vpc, secgroup, classic, "", self)
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, secgroup, jsonutils.Marshal(err))
|
||||
return
|
||||
|
||||
@@ -769,8 +769,8 @@ func (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.I
|
||||
return secgroup, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
secgroups, total, err := region.GetSecurityGroups(vpcId, name, []string{}, 0, 0)
|
||||
func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
secgroups, total, err := region.GetSecurityGroups(opts.VpcId, opts.Name, []string{}, 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -112,8 +112,8 @@ func (self *SWire) GetBandwidth() int {
|
||||
return 10000
|
||||
}
|
||||
|
||||
func (self *SWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) {
|
||||
vswitchId, err := self.zone.region.createVSwitch(self.zone.ZoneId, self.vpc.VpcId, name, cidr, desc)
|
||||
func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) {
|
||||
vswitchId, err := self.zone.region.createVSwitch(self.zone.ZoneId, self.vpc.VpcId, opts.Name, opts.Cidr, opts.Desc)
|
||||
if err != nil {
|
||||
log.Errorf("createVSwitch error %s", err)
|
||||
return nil, err
|
||||
|
||||
@@ -1027,8 +1027,8 @@ func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICl
|
||||
return &secgroups[0], nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
secgroups, total, err := self.GetSecurityGroups(vpcId, name, "", 0, 1)
|
||||
func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
secgroups, total, err := self.GetSecurityGroups(opts.VpcId, opts.Name, "", 0, 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -93,8 +93,8 @@ func (self *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, e
|
||||
return nil, ErrorNotFound()
|
||||
}
|
||||
|
||||
func (self *SWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) {
|
||||
networkId, err := self.zone.region.createNetwork(self.zone.ZoneId, self.vpc.VpcId, name, cidr, desc)
|
||||
func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) {
|
||||
networkId, err := self.zone.region.createNetwork(self.zone.ZoneId, self.vpc.VpcId, opts.Name, opts.Cidr, opts.Desc)
|
||||
if err != nil {
|
||||
log.Errorf("createNetwork error %s", err)
|
||||
return nil, err
|
||||
|
||||
@@ -74,7 +74,7 @@ func (self *SClassicWire) addNetwork(network *SClassicNetwork) {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SClassicWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) {
|
||||
func (self *SClassicWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
// if network, err := self.zone.region.createNetwork(self.vpc, name, cidr, desc); err != nil {
|
||||
// return nil, err
|
||||
|
||||
@@ -540,9 +540,9 @@ func (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.I
|
||||
return region.GetSecurityGroupDetails(secgroupId)
|
||||
}
|
||||
|
||||
func (region *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
if strings.Contains(strings.ToLower(vpcId), "microsoft.classicnetwork") {
|
||||
secgroups, err := region.GetClassicSecurityGroups(name)
|
||||
func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
if strings.Contains(strings.ToLower(opts.VpcId), "microsoft.classicnetwork") {
|
||||
secgroups, err := region.GetClassicSecurityGroups(opts.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -554,7 +554,7 @@ func (region *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloud
|
||||
}
|
||||
return &secgroups[0], nil
|
||||
}
|
||||
secgroups, err := region.GetSecurityGroups(name)
|
||||
secgroups, err := region.GetSecurityGroups(opts.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -100,8 +100,8 @@ func (self *SRegion) createNetwork(vpc *SVpc, subnetName string, cidr string, de
|
||||
return &subnet, nil
|
||||
}
|
||||
|
||||
func (self *SWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) {
|
||||
network, err := self.zone.region.createNetwork(self.vpc, name, cidr, desc)
|
||||
func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) {
|
||||
network, err := self.zone.region.createNetwork(self.vpc, opts.Name, opts.Cidr, opts.Desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -131,14 +131,14 @@ func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICl
|
||||
return self.GetSecurityGroupDetails(secgroupId)
|
||||
}
|
||||
|
||||
func (self *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
segroups, err := self.GetSecurityGroups(vpcId)
|
||||
func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
segroups, err := self.GetSecurityGroups(opts.VpcId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SRegion.GetISecurityGroupByName.GetSecurityGroups")
|
||||
}
|
||||
|
||||
for i := range segroups {
|
||||
if segroups[i].Name == name {
|
||||
if segroups[i].Name == opts.Name {
|
||||
return &segroups[i], nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ func getDefaultGateWay(cidr string) (string, error) {
|
||||
return startIp.String(), nil
|
||||
}
|
||||
|
||||
func (self *SWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) {
|
||||
func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) {
|
||||
var ZoneId string
|
||||
if len(self.inetworks) > 0 {
|
||||
ZoneId = self.inetworks[0].(*SNetwork).ZoneID
|
||||
@@ -117,7 +117,7 @@ func (self *SWire) CreateINetwork(name string, cidr string, desc string) (cloudp
|
||||
return nil, fmt.Errorf("SWire.CreateINetwork region %s zone is empty", self.region.GetName())
|
||||
}
|
||||
}
|
||||
network, err := self.region.CreateNetwork(self.vpc.GetId(), ZoneId, name, cidr, "true")
|
||||
network, err := self.region.CreateNetwork(self.vpc.GetId(), ZoneId, opts.Name, opts.Cidr, "true")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SWire.CreateINetwork.CreateNetwork")
|
||||
}
|
||||
|
||||
@@ -329,8 +329,8 @@ func (region *SRegion) GetISecurityGroupById(id string) (cloudprovider.ICloudSec
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (region *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
ivpc, err := region.GetIVpcById(vpcId)
|
||||
func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
ivpc, err := region.GetIVpcById(opts.VpcId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -339,7 +339,7 @@ func (region *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloud
|
||||
return nil, errors.Wrap(err, "ivpc.GetISecurityGroups")
|
||||
}
|
||||
for _, secgroup := range secgroups {
|
||||
if strings.ToLower(secgroup.GetName()) == strings.ToLower(name) {
|
||||
if strings.ToLower(secgroup.GetName()) == strings.ToLower(opts.Name) {
|
||||
return secgroup, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,8 +38,8 @@ func (wire *SWire) GetName() string {
|
||||
return wire.vpc.GetName()
|
||||
}
|
||||
|
||||
func (wire *SWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) {
|
||||
network, err := wire.vpc.region.CreateNetwork(name, wire.vpc.globalnetwork.SelfLink, cidr, desc)
|
||||
func (wire *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) {
|
||||
network, err := wire.vpc.region.CreateNetwork(opts.Name, wire.vpc.globalnetwork.SelfLink, opts.Cidr, opts.Desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package multicloud
|
||||
|
||||
type SHostBase struct {
|
||||
SResourceBase
|
||||
}
|
||||
|
||||
func (self *SHostBase) GetCpuCmtbound() float32 {
|
||||
|
||||
@@ -516,8 +516,8 @@ func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICl
|
||||
return self.GetSecurityGroupDetails(secgroupId)
|
||||
}
|
||||
|
||||
func (self *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
secgroups, err := self.GetSecurityGroups(vpcId, name)
|
||||
func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
secgroups, err := self.GetSecurityGroups(opts.VpcId, opts.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -101,8 +101,8 @@ func (self *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, e
|
||||
华为云子网可用区,类似一个zone标签。即使指定了zone子网在整个region依然是可用。
|
||||
通过华为web控制台创建子网需要指定可用区。这里是不指定的。
|
||||
*/
|
||||
func (self *SWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) {
|
||||
networkId, err := self.region.createNetwork(self.vpc.GetId(), name, cidr, desc)
|
||||
func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) {
|
||||
networkId, err := self.region.createNetwork(self.vpc.GetId(), opts.Name, opts.Cidr, opts.Desc)
|
||||
if err != nil {
|
||||
log.Errorf("createNetwork error %s", err)
|
||||
return nil, err
|
||||
|
||||
@@ -17,6 +17,7 @@ package openstack
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -28,6 +29,7 @@ import (
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud"
|
||||
"yunion.io/x/onecloud/pkg/util/version"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -58,12 +60,12 @@ const (
|
||||
)
|
||||
|
||||
type Attachment struct {
|
||||
ServerID string
|
||||
AttachmentID string
|
||||
ServerId string
|
||||
AttachmentId string
|
||||
HostName string
|
||||
VolumeID string
|
||||
VolumeId string
|
||||
Device string
|
||||
ID string
|
||||
Id string
|
||||
}
|
||||
|
||||
type Link struct {
|
||||
@@ -78,18 +80,17 @@ type VolumeImageMetadata struct {
|
||||
MinRAM int
|
||||
DiskFormat string
|
||||
ImageName string
|
||||
ImageID string
|
||||
ImageId string
|
||||
ContainerFormat string
|
||||
MinDisk int
|
||||
Size int
|
||||
}
|
||||
|
||||
type SDisk struct {
|
||||
nova *SNovaStorage
|
||||
storage *SStorage
|
||||
multicloud.SDisk
|
||||
|
||||
ID string
|
||||
Id string
|
||||
Name string
|
||||
|
||||
MigrationStatus string
|
||||
@@ -100,10 +101,10 @@ type SDisk struct {
|
||||
Host string `json:"os-vol-host-attr:host"`
|
||||
Encrypted bool
|
||||
ReplicationStatus string
|
||||
SnapshotID string
|
||||
SnapshotId string
|
||||
Size int
|
||||
UserID string
|
||||
TenantID string `json:"os-vol-tenant-attr:tenant_id"`
|
||||
UserId string
|
||||
TenantId string `json:"os-vol-tenant-attr:tenant_id"`
|
||||
Migstat string `json:"os-vol-mig-status-attr:migstat"`
|
||||
Metadata Metadata
|
||||
|
||||
@@ -111,9 +112,9 @@ type SDisk struct {
|
||||
Description string
|
||||
Multiattach string
|
||||
SourceVolid string
|
||||
ConsistencygroupID string
|
||||
ConsistencygroupId string
|
||||
VolumeImageMetadata VolumeImageMetadata
|
||||
NameID string `json:"os-vol-mig-status-attr:name_id"`
|
||||
NameId string `json:"os-vol-mig-status-attr:name_id"`
|
||||
Bootable bool
|
||||
CreatedAt time.Time
|
||||
VolumeType string
|
||||
@@ -126,61 +127,40 @@ func (disk *SDisk) GetMetadata() *jsonutils.JSONDict {
|
||||
return data
|
||||
}
|
||||
|
||||
func (region *SRegion) GetDisks(category, volumeBackendName string) ([]SDisk, error) {
|
||||
url := "/volumes/detail"
|
||||
func (region *SRegion) GetDisks() ([]SDisk, error) {
|
||||
disks := []SDisk{}
|
||||
for len(url) > 0 {
|
||||
_, resp, err := region.CinderList(url, "", nil)
|
||||
resource := "/volumes/detail"
|
||||
query := url.Values{}
|
||||
query.Set("all_tenants", "true")
|
||||
for {
|
||||
resp, err := region.bsList(resource, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "bsList")
|
||||
}
|
||||
_disks := []SDisk{}
|
||||
err = resp.Unmarshal(&_disks, "volumes")
|
||||
part := struct {
|
||||
Volumes []SDisk
|
||||
VolumesLinks SNextLinks
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, `resp.Unmarshal(&_disks, "volumes")`)
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
disks = append(disks, _disks...)
|
||||
url = ""
|
||||
if resp.Contains("volumes_links") {
|
||||
nextLink := []SNextLink{}
|
||||
err = resp.Unmarshal(&nextLink, "volumes_links")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, `resp.Unmarshal(&nextLink, "volumes_links")`)
|
||||
}
|
||||
for _, next := range nextLink {
|
||||
if next.Rel == "next" {
|
||||
url = next.Href
|
||||
break
|
||||
}
|
||||
}
|
||||
disks = append(disks, part.Volumes...)
|
||||
marker := part.VolumesLinks.GetNextMark()
|
||||
if len(marker) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", marker)
|
||||
}
|
||||
result := []SDisk{}
|
||||
for _, disk := range disks {
|
||||
if len(category) > 0 {
|
||||
if disk.VolumeType == category {
|
||||
result = append(result, disk)
|
||||
}
|
||||
} else if len(volumeBackendName) > 0 {
|
||||
if strings.HasSuffix(disk.Host, "#"+volumeBackendName) {
|
||||
result = append(result, disk)
|
||||
}
|
||||
} else {
|
||||
result = append(result, disk)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
return disks, nil
|
||||
}
|
||||
|
||||
func (disk *SDisk) GetId() string {
|
||||
return disk.ID
|
||||
return disk.Id
|
||||
}
|
||||
|
||||
func (disk *SDisk) Delete(ctx context.Context) error {
|
||||
if disk.nova != nil {
|
||||
return nil
|
||||
}
|
||||
err := disk.storage.zone.region.DeleteDisk(disk.ID)
|
||||
err := disk.storage.zone.region.DeleteDisk(disk.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -191,12 +171,12 @@ func (disk *SDisk) attachInstances(attachments []Attachment) error {
|
||||
for _, attachment := range attachments {
|
||||
startTime := time.Now()
|
||||
for time.Now().Sub(startTime) < 5*time.Minute {
|
||||
if err := disk.storage.zone.region.AttachDisk(attachment.ServerID, disk.ID); err != nil {
|
||||
if err := disk.storage.zone.region.AttachDisk(attachment.ServerId, disk.Id); err != nil {
|
||||
if strings.Contains(err.Error(), "status must be available or downloading") {
|
||||
time.Sleep(time.Second * 10)
|
||||
continue
|
||||
}
|
||||
log.Errorf("recover attach disk %s => instance %s error: %v", disk.ID, attachment.ServerID, err)
|
||||
log.Errorf("recover attach disk %s => instance %s error: %v", disk.Id, attachment.ServerId, err)
|
||||
return err
|
||||
} else {
|
||||
return nil
|
||||
@@ -207,18 +187,24 @@ func (disk *SDisk) attachInstances(attachments []Attachment) error {
|
||||
}
|
||||
|
||||
func (disk *SDisk) Resize(ctx context.Context, sizeMb int64) error {
|
||||
if disk.nova != nil {
|
||||
return cloudprovider.ErrNotSupported
|
||||
maxVersion := ""
|
||||
for _, service := range []string{OPENSTACK_SERVICE_VOLUMEV3, OPENSTACK_SERVICE_VOLUMEV2, OPENSTACK_SERVICE_VOLUME} {
|
||||
maxVersion, _ = disk.storage.zone.region.GetMaxVersion(service)
|
||||
if len(maxVersion) > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if version.GE(maxVersion, "3.42") {
|
||||
return disk.storage.zone.region.ResizeDisk(disk.Id, sizeMb)
|
||||
}
|
||||
instanceIds := []string{}
|
||||
|
||||
for _, attachement := range disk.Attachments {
|
||||
if err := disk.storage.zone.region.DetachDisk(attachement.ServerID, disk.ID); err != nil {
|
||||
if err := disk.storage.zone.region.DetachDisk(attachement.ServerId, disk.Id); err != nil {
|
||||
return err
|
||||
}
|
||||
instanceIds = append(instanceIds, attachement.ServerID)
|
||||
instanceIds = append(instanceIds, attachement.ServerId)
|
||||
}
|
||||
err := disk.storage.zone.region.ResizeDisk(disk.ID, sizeMb)
|
||||
err := disk.storage.zone.region.ResizeDisk(disk.Id, sizeMb)
|
||||
if err != nil {
|
||||
disk.attachInstances(disk.Attachments)
|
||||
return err
|
||||
@@ -230,11 +216,11 @@ func (disk *SDisk) GetName() string {
|
||||
if len(disk.Name) > 0 {
|
||||
return disk.Name
|
||||
}
|
||||
return disk.ID
|
||||
return disk.Id
|
||||
}
|
||||
|
||||
func (disk *SDisk) GetGlobalId() string {
|
||||
return disk.ID
|
||||
return disk.Id
|
||||
}
|
||||
|
||||
func (disk *SDisk) IsEmulated() bool {
|
||||
@@ -242,9 +228,6 @@ func (disk *SDisk) IsEmulated() bool {
|
||||
}
|
||||
|
||||
func (disk *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) {
|
||||
if disk.nova != nil {
|
||||
return disk.nova, nil
|
||||
}
|
||||
return disk.storage, nil
|
||||
}
|
||||
|
||||
@@ -270,10 +253,7 @@ func (disk *SDisk) GetStatus() string {
|
||||
}
|
||||
|
||||
func (disk *SDisk) Refresh() error {
|
||||
if disk.nova != nil {
|
||||
return nil
|
||||
}
|
||||
_disk, err := disk.storage.zone.region.GetDisk(disk.ID)
|
||||
_disk, err := disk.storage.zone.region.GetDisk(disk.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -281,10 +261,7 @@ func (disk *SDisk) Refresh() error {
|
||||
}
|
||||
|
||||
func (disk *SDisk) ResizeDisk(sizeMb int64) error {
|
||||
if disk.nova != nil {
|
||||
return cloudprovider.ErrNotSupported
|
||||
}
|
||||
return disk.storage.zone.region.ResizeDisk(disk.ID, sizeMb)
|
||||
return disk.storage.zone.region.ResizeDisk(disk.Id, sizeMb)
|
||||
}
|
||||
|
||||
func (disk *SDisk) GetDiskFormat() string {
|
||||
@@ -300,7 +277,7 @@ func (disk *SDisk) GetIsAutoDelete() bool {
|
||||
}
|
||||
|
||||
func (disk *SDisk) GetTemplateId() string {
|
||||
return disk.VolumeImageMetadata.ImageID
|
||||
return disk.VolumeImageMetadata.ImageId
|
||||
}
|
||||
|
||||
func (disk *SDisk) GetDiskType() string {
|
||||
@@ -330,11 +307,11 @@ func (disk *SDisk) GetMountpoint() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateDisk(imageRef string, category string, name string, sizeGb int, desc string, projectId string) (*SDisk, error) {
|
||||
func (region *SRegion) CreateDisk(imageRef string, volumeType string, name string, sizeGb int, desc string, projectId string) (*SDisk, error) {
|
||||
params := map[string]map[string]interface{}{
|
||||
"volume": {
|
||||
"size": sizeGb,
|
||||
"volume_type": category,
|
||||
"volume_type": volumeType,
|
||||
"name": name,
|
||||
"description": desc,
|
||||
},
|
||||
@@ -342,14 +319,15 @@ func (region *SRegion) CreateDisk(imageRef string, category string, name string,
|
||||
if len(imageRef) > 0 {
|
||||
params["volume"]["imageRef"] = imageRef
|
||||
}
|
||||
_, resp, err := region.CinderCreate(projectId, "/volumes", "", jsonutils.Marshal(params))
|
||||
resp, err := region.bsCreate(projectId, "/volumes", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "bsCreate")
|
||||
}
|
||||
|
||||
disk := &SDisk{}
|
||||
if err := resp.Unmarshal(disk, "volume"); err != nil {
|
||||
return nil, err
|
||||
err = resp.Unmarshal(disk, "volume")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
//这里由于不好初始化disk的storage就手动循环了,如果是通过镜像创建,有个下载过程,比较慢,等待时间较长
|
||||
startTime := time.Now()
|
||||
@@ -361,7 +339,7 @@ func (region *SRegion) CreateDisk(imageRef string, category string, name string,
|
||||
for time.Now().Sub(startTime) < timeout {
|
||||
disk, err = region.GetDisk(disk.GetGlobalId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "GetDisk(%s)", disk.GetGlobalId())
|
||||
}
|
||||
log.Debugf("disk status %s expect %s", disk.GetStatus(), api.DISK_READY)
|
||||
status := disk.GetStatus()
|
||||
@@ -369,29 +347,37 @@ func (region *SRegion) CreateDisk(imageRef string, category string, name string,
|
||||
break
|
||||
}
|
||||
if status == api.DISK_ALLOC_FAILED {
|
||||
region.DeleteDisk(disk.GetGlobalId())
|
||||
return nil, fmt.Errorf("allocate disk failed, status is error")
|
||||
messages, _ := region.GetMessages(disk.Id)
|
||||
if len(messages) > 0 {
|
||||
return nil, fmt.Errorf("allocate disk %s failed, status is %s message: %s", disk.Name, disk.Status, messages[0].UserMessage)
|
||||
}
|
||||
return nil, fmt.Errorf("allocate disk %s failed, status is %s", disk.Name, disk.Status)
|
||||
}
|
||||
time.Sleep(time.Second * 10)
|
||||
}
|
||||
if disk.GetStatus() != api.DISK_READY {
|
||||
region.DeleteDisk(disk.GetGlobalId())
|
||||
return nil, fmt.Errorf("timeout for waitting disk ready, current status: %s", disk.Status)
|
||||
}
|
||||
return disk, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetDisk(diskId string) (*SDisk, error) {
|
||||
_, resp, err := region.CinderGet("/volumes/"+diskId, "", nil)
|
||||
resource := fmt.Sprintf("/volumes/%s", diskId)
|
||||
resp, err := region.bsGet(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "bsGet")
|
||||
}
|
||||
disk := &SDisk{}
|
||||
return disk, resp.Unmarshal(disk, "volume")
|
||||
err = resp.Unmarshal(disk, "volume")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return disk, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) DeleteDisk(diskId string) error {
|
||||
_, err := region.CinderDelete("/volumes/"+diskId, "")
|
||||
resource := fmt.Sprintf("/volumes/%s", diskId)
|
||||
_, err := region.bsDelete(resource)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -401,27 +387,24 @@ func (region *SRegion) ResizeDisk(diskId string, sizeMb int64) error {
|
||||
"new_size": sizeMb / 1024,
|
||||
},
|
||||
}
|
||||
_, _, err := region.CinderAction(fmt.Sprintf("/volumes/%s/action", diskId), "", jsonutils.Marshal(params))
|
||||
resource := fmt.Sprintf("/volumes/%s/action", diskId)
|
||||
_, err := region.bsPost(resource, params)
|
||||
return err
|
||||
}
|
||||
|
||||
func (region *SRegion) ResetDisk(diskId, snapshotId string) error {
|
||||
//目前测试接口不能使用
|
||||
return cloudprovider.ErrNotSupported
|
||||
// params := map[string]map[string]interface{}{
|
||||
// "revert": {
|
||||
// "snapshot_id": snapshotId,
|
||||
// },
|
||||
// }
|
||||
// _, _, err := region.CinderAction(fmt.Sprintf("/volumes/%s/action", diskId), "3.40", jsonutils.Marshal(params))
|
||||
// return err
|
||||
params := map[string]map[string]interface{}{
|
||||
"revert": {
|
||||
"snapshot_id": snapshotId,
|
||||
},
|
||||
}
|
||||
resource := fmt.Sprintf("/volumes/%s/action", diskId)
|
||||
_, err := region.bsPost(resource, params)
|
||||
return err
|
||||
}
|
||||
|
||||
func (disk *SDisk) CreateISnapshot(ctx context.Context, name, desc string) (cloudprovider.ICloudSnapshot, error) {
|
||||
if disk.nova != nil {
|
||||
return nil, cloudprovider.ErrNotSupported
|
||||
}
|
||||
snapshot, err := disk.storage.zone.region.CreateSnapshot(disk.ID, name, desc)
|
||||
snapshot, err := disk.storage.zone.region.CreateSnapshot(disk.Id, name, desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -429,24 +412,24 @@ func (disk *SDisk) CreateISnapshot(ctx context.Context, name, desc string) (clou
|
||||
}
|
||||
|
||||
func (disk *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) {
|
||||
if disk.nova != nil {
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
return disk.storage.zone.region.GetISnapshotById(snapshotId)
|
||||
}
|
||||
|
||||
func (disk *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
|
||||
if disk.nova != nil {
|
||||
return []cloudprovider.ICloudSnapshot{}, nil
|
||||
snapshots, err := disk.storage.zone.region.GetSnapshots(disk.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetSnapshots(%s)", disk.Id)
|
||||
}
|
||||
return disk.storage.zone.region.GetSnapshots(disk.ID)
|
||||
isnapshots := []cloudprovider.ICloudSnapshot{}
|
||||
for i := range snapshots {
|
||||
snapshots[i].region = disk.storage.zone.region
|
||||
isnapshots = append(isnapshots, &snapshots[i])
|
||||
}
|
||||
return isnapshots, nil
|
||||
}
|
||||
|
||||
func (disk *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) {
|
||||
if disk.nova != nil {
|
||||
return "", cloudprovider.ErrNotSupported
|
||||
}
|
||||
return disk.ID, disk.storage.zone.region.ResetDisk(disk.ID, snapshotId)
|
||||
return disk.Id, disk.storage.zone.region.ResetDisk(disk.Id, snapshotId)
|
||||
}
|
||||
|
||||
func (disk *SDisk) GetBillingType() string {
|
||||
@@ -470,5 +453,5 @@ func (disk *SDisk) Rebuild(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (disk *SDisk) GetProjectId() string {
|
||||
return disk.TenantID
|
||||
return disk.TenantId
|
||||
}
|
||||
|
||||
@@ -56,33 +56,28 @@ type SEipAddress struct {
|
||||
RevisionNumber int `json:"revision_number"`
|
||||
ProjectId string `json:"project_id"`
|
||||
PortId string `json:"port_id"`
|
||||
ID string `json:"id"`
|
||||
Id string `json:"id"`
|
||||
QosPolicyId string `json:"qos_policy_id"`
|
||||
}
|
||||
|
||||
func (region *SRegion) GetEip(eipId string) (*SEipAddress, error) {
|
||||
_, resp, err := region.Get("network", "/v2.0/floatingips/"+eipId, "", nil)
|
||||
resource := fmt.Sprintf("/v2.0/floatingips/%s", eipId)
|
||||
resp, err := region.vpcGet(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
eip := &SEipAddress{region: region}
|
||||
return eip, resp.Unmarshal(eip, "floatingip")
|
||||
err = resp.Unmarshal(eip, "floatingip")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return eip, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetEipByIp(ip string) (*SEipAddress, error) {
|
||||
params := url.Values{}
|
||||
if len(ip) == 0 {
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
params.Add("floating_ip_address", ip)
|
||||
_, resp, err := region.List("network", "/v2.0/floatingips?"+params.Encode(), "", nil)
|
||||
eips, err := region.GetEips(ip)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
eips := []SEipAddress{}
|
||||
err = resp.Unmarshal(&eips, "floatingips")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "GetEips")
|
||||
}
|
||||
if len(eips) == 1 {
|
||||
eips[0].region = region
|
||||
@@ -94,40 +89,38 @@ func (region *SRegion) GetEipByIp(ip string) (*SEipAddress, error) {
|
||||
return nil, cloudprovider.ErrDuplicateId
|
||||
}
|
||||
|
||||
func (region *SRegion) GetEips() ([]SEipAddress, error) {
|
||||
url := "/v2.0/floatingips"
|
||||
func (region *SRegion) GetEips(ip string) ([]SEipAddress, error) {
|
||||
resource := "/v2.0/floatingips"
|
||||
eips := []SEipAddress{}
|
||||
for len(url) > 0 {
|
||||
_, resp, err := region.List("network", url, "", nil)
|
||||
query := url.Values{}
|
||||
if len(ip) > 0 {
|
||||
query.Set("floating_ip_address", ip)
|
||||
}
|
||||
for {
|
||||
part := struct {
|
||||
Floatingips []SEipAddress
|
||||
FloatingipsLinks SNextLinks
|
||||
}{}
|
||||
resp, err := region.vpcList(resource, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "vpcList")
|
||||
}
|
||||
_eips := []SEipAddress{}
|
||||
err = resp.Unmarshal(&_eips, "floatingips")
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, `resp.Unmarshal(&_eips, "floatingips")`)
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
eips = append(eips, _eips...)
|
||||
url = ""
|
||||
if resp.Contains("floatingips_links") {
|
||||
nextLink := []SNextLink{}
|
||||
err = resp.Unmarshal(&nextLink, "floatingips_links")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, `resp.Unmarshal(&nextLink, "floatingips_links")`)
|
||||
}
|
||||
for _, next := range nextLink {
|
||||
if next.Rel == "next" {
|
||||
url = next.Href
|
||||
break
|
||||
}
|
||||
}
|
||||
eips = append(eips, part.Floatingips...)
|
||||
marker := part.FloatingipsLinks.GetNextMark()
|
||||
if len(marker) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", marker)
|
||||
}
|
||||
return eips, nil
|
||||
}
|
||||
|
||||
func (eip *SEipAddress) GetId() string {
|
||||
return eip.ID
|
||||
return eip.Id
|
||||
}
|
||||
|
||||
func (eip *SEipAddress) GetName() string {
|
||||
@@ -135,7 +128,7 @@ func (eip *SEipAddress) GetName() string {
|
||||
}
|
||||
|
||||
func (eip *SEipAddress) GetGlobalId() string {
|
||||
return eip.ID
|
||||
return eip.Id
|
||||
}
|
||||
|
||||
func (eip *SEipAddress) GetStatus() string {
|
||||
@@ -147,17 +140,17 @@ func (eip *SEipAddress) GetStatus() string {
|
||||
case "ERROR":
|
||||
return api.EIP_STATUS_UNKNOWN
|
||||
default:
|
||||
log.Errorf("Unknown eip %s status %s", eip.ID, eip.Status)
|
||||
log.Errorf("Unknown eip %s status %s", eip.Id, eip.Status)
|
||||
return api.EIP_STATUS_UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
func (eip *SEipAddress) Refresh() error {
|
||||
new, err := eip.region.GetEip(eip.ID)
|
||||
_eip, err := eip.region.GetEip(eip.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return jsonutils.Update(eip, new)
|
||||
return jsonutils.Update(eip, _eip)
|
||||
}
|
||||
|
||||
func (eip *SEipAddress) IsEmulated() bool {
|
||||
@@ -208,7 +201,7 @@ func (eip *SEipAddress) GetExpiredAt() time.Time {
|
||||
}
|
||||
|
||||
func (eip *SEipAddress) Delete() error {
|
||||
return eip.region.DeleteEip(eip.ID)
|
||||
return eip.region.DeleteEip(eip.Id)
|
||||
}
|
||||
|
||||
func (eip *SEipAddress) GetBandwidth() int {
|
||||
@@ -223,7 +216,7 @@ func (eip *SEipAddress) GetINetworkId() string {
|
||||
}
|
||||
for _, network := range networks {
|
||||
if network.Contains(eip.FloatingIPAddress) {
|
||||
return network.ID
|
||||
return network.Id
|
||||
}
|
||||
}
|
||||
log.Errorf("failed to find eip %s(%s) networkId", eip.FloatingIPAddress, eip.FloatingNetworkId)
|
||||
@@ -235,11 +228,11 @@ func (eip *SEipAddress) GetInternetChargeType() string {
|
||||
}
|
||||
|
||||
func (eip *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error {
|
||||
return eip.region.AssociateEip(conf.InstanceId, eip.ID)
|
||||
return eip.region.AssociateEip(conf.InstanceId, eip.Id)
|
||||
}
|
||||
|
||||
func (eip *SEipAddress) Dissociate() error {
|
||||
return eip.region.DisassociateEip(eip.ID)
|
||||
return eip.region.DisassociateEip(eip.Id)
|
||||
}
|
||||
|
||||
func (eip *SEipAddress) ChangeBandwidth(bw int) error {
|
||||
@@ -250,27 +243,30 @@ func (eip *SEipAddress) GetProjectId() string {
|
||||
return eip.ProjectId
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateEip(eip *cloudprovider.SEip) (*SEipAddress, error) {
|
||||
network, err := region.GetNetwork(eip.NetworkExternalId)
|
||||
if err != nil {
|
||||
log.Errorf("failed to get subnet %s", eip.NetworkExternalId)
|
||||
return nil, err
|
||||
}
|
||||
parmas := map[string]map[string]string{
|
||||
"floatingip": {
|
||||
"floating_network_id": network.NetworkID,
|
||||
"subnet_id": network.ID,
|
||||
func (region *SRegion) CreateEip(vpcId, networkId, ip string, projectId string) (*SEipAddress, error) {
|
||||
params := map[string]map[string]string{
|
||||
"floatingip": map[string]string{
|
||||
"floating_network_id": vpcId,
|
||||
"subnet_id": networkId,
|
||||
},
|
||||
}
|
||||
if len(eip.IP) > 0 {
|
||||
parmas["floatingip"]["floating_ip_address"] = eip.IP
|
||||
if len(projectId) > 0 {
|
||||
params["floatingip"]["tenant_id"] = projectId
|
||||
}
|
||||
_, resp, err := region.PostWithProject(eip.ProjectId, "network", "/v2.0/floatingips", "", jsonutils.Marshal(parmas))
|
||||
if len(ip) > 0 {
|
||||
params["floatingip"]["floating_ip_address"] = ip
|
||||
}
|
||||
resource := "/v2.0/floatingips"
|
||||
resp, err := region.vpcPost(resource, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "vpcPost")
|
||||
}
|
||||
ieip := &SEipAddress{region: region}
|
||||
return ieip, resp.Unmarshal(ieip, "floatingip")
|
||||
eip := &SEipAddress{region: region}
|
||||
err = resp.Unmarshal(eip, "floatingip")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return eip, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) AssociateEip(instanceId, eipId string) error {
|
||||
@@ -281,7 +277,7 @@ func (region *SRegion) AssociateEip(instanceId, eipId string) error {
|
||||
for networkName, address := range instance.Addresses {
|
||||
for i := 0; i < len(address); i++ {
|
||||
if instance.Addresses[networkName][i].Type == "fixed" {
|
||||
ports, err := region.GetPorts(instance.Addresses[networkName][i].MacAddr)
|
||||
ports, err := region.GetPorts(instance.Addresses[networkName][i].MacAddr, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -292,7 +288,8 @@ func (region *SRegion) AssociateEip(instanceId, eipId string) error {
|
||||
"port_id": ports[0].ID,
|
||||
},
|
||||
}
|
||||
_, _, err = region.Update("network", "/v2.0/floatingips/"+eipId, "", jsonutils.Marshal(params))
|
||||
resource := "/v2.0/floatingips/" + eipId
|
||||
_, err = region.vpcUpdate(resource, params)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -313,11 +310,12 @@ func (region *SRegion) DisassociateEip(eipId string) error {
|
||||
"port_id": null,
|
||||
},
|
||||
}`))
|
||||
_, _, err := region.Update("network", "/v2.0/floatingips/"+eipId, "", params)
|
||||
_, err := region.vpcUpdate("/v2.0/floatingips/"+eipId, params)
|
||||
return err
|
||||
}
|
||||
|
||||
func (region *SRegion) DeleteEip(eipId string) error {
|
||||
_, err := region.Delete("network", "/v2.0/floatingips/"+eipId, "")
|
||||
resource := "/v2.0/floatingips/" + eipId
|
||||
_, err := region.vpcDelete(resource)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package openstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
@@ -29,7 +30,7 @@ type SFlavor struct {
|
||||
multicloud.SServerSku
|
||||
region *SRegion
|
||||
|
||||
ID string
|
||||
Id string
|
||||
Disk int
|
||||
Ephemeral int
|
||||
ExtraSpecs ExtraSpecs
|
||||
@@ -41,44 +42,45 @@ type SFlavor struct {
|
||||
}
|
||||
|
||||
func (region *SRegion) GetFlavors() ([]SFlavor, error) {
|
||||
url := "/flavors/detail"
|
||||
resource := "/flavors/detail"
|
||||
flavors := []SFlavor{}
|
||||
for len(url) > 0 {
|
||||
_, resp, err := region.List("compute", url, "", nil)
|
||||
query := url.Values{}
|
||||
for {
|
||||
resp, err := region.ecsList(resource, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "ecsList")
|
||||
}
|
||||
_flavors := []SFlavor{}
|
||||
err = resp.Unmarshal(&_flavors, "flavors")
|
||||
part := struct {
|
||||
Flavors []SFlavor
|
||||
FlavorsLinks SNextLinks
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, `resp.Unmarshal(&_flavors, "flavors")`)
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
flavors = append(flavors, _flavors...)
|
||||
url = ""
|
||||
if resp.Contains("flavors_links") {
|
||||
nextLink := []SNextLink{}
|
||||
err = resp.Unmarshal(&nextLink, "flavors_links")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, `resp.Unmarshal(&nextLink, "flavors_links")`)
|
||||
}
|
||||
for _, next := range nextLink {
|
||||
if next.Rel == "next" {
|
||||
url = next.Href
|
||||
break
|
||||
}
|
||||
}
|
||||
flavors = append(flavors, part.Flavors...)
|
||||
|
||||
marker := part.FlavorsLinks.GetNextMark()
|
||||
if len(marker) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", marker)
|
||||
}
|
||||
return flavors, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetFlavor(flavorId string) (*SFlavor, error) {
|
||||
_, resp, err := region.Get("compute", "/flavors/"+flavorId, "", nil)
|
||||
resource := fmt.Sprintf("/flavors/%s", flavorId)
|
||||
resp, err := region.ecsGet(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "ecsGet")
|
||||
}
|
||||
flavor := &SFlavor{region: region}
|
||||
return flavor, resp.Unmarshal(flavor, "flavor")
|
||||
err = resp.Unmarshal(flavor, "flavor")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return flavor, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) SyncFlavor(name string, cpu, memoryMb, diskGB int) (string, error) {
|
||||
@@ -100,7 +102,7 @@ func (region *SRegion) syncFlavor(name string, cpu, memoryMb, diskGB int) (strin
|
||||
flavorName := flavor.GetName()
|
||||
if (len(name) == 0 || flavorName == name || flavorName == fmt.Sprintf("%s-%d", name, diskGB)) && flavor.GetCpuCoreCount() == cpu && flavor.GetMemorySizeMB() == memoryMb {
|
||||
if diskGB <= flavor.GetSysDiskMaxSizeGB() {
|
||||
return flavor.ID, nil
|
||||
return flavor.Id, nil
|
||||
}
|
||||
match = true
|
||||
}
|
||||
@@ -115,7 +117,7 @@ func (region *SRegion) syncFlavor(name string, cpu, memoryMb, diskGB int) (strin
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "CreateFlavor")
|
||||
}
|
||||
return flavor.ID, nil
|
||||
return flavor.Id, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateISku(name string, vCpu int, memoryMb int) error {
|
||||
@@ -135,21 +137,25 @@ func (region *SRegion) CreateFlavor(name string, cpu int, memoryMb int, diskGB i
|
||||
"disk": diskGB,
|
||||
},
|
||||
}
|
||||
_, resp, err := region.Post("compute", "/flavors", "", jsonutils.Marshal(params))
|
||||
resp, err := region.ecsPost("/flavors", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "ecsPost")
|
||||
}
|
||||
flavor := &SFlavor{region: region}
|
||||
return flavor, resp.Unmarshal(flavor, "flavor")
|
||||
err = resp.Unmarshal(flavor, "flavor")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return flavor, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) DeleteFlavor(flavorId string) error {
|
||||
_, err := region.Delete("compute", "/flavors/"+flavorId, "")
|
||||
_, err := region.ecsDelete("/flavors/" + flavorId)
|
||||
return err
|
||||
}
|
||||
|
||||
func (flavor *SFlavor) Delete() error {
|
||||
return flavor.region.DeleteFlavor(flavor.ID)
|
||||
return flavor.region.DeleteFlavor(flavor.Id)
|
||||
}
|
||||
|
||||
func (flavor *SFlavor) GetMetadata() *jsonutils.JSONDict {
|
||||
@@ -161,11 +167,11 @@ func (flavor *SFlavor) IsEmulated() bool {
|
||||
}
|
||||
|
||||
func (flavor *SFlavor) Refresh() error {
|
||||
new, err := flavor.region.GetFlavor(flavor.ID)
|
||||
_flavor, err := flavor.region.GetFlavor(flavor.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return jsonutils.Update(flavor, new)
|
||||
return jsonutils.Update(flavor, _flavor)
|
||||
}
|
||||
|
||||
func (flavor *SFlavor) GetName() string {
|
||||
@@ -176,11 +182,11 @@ func (flavor *SFlavor) GetName() string {
|
||||
}
|
||||
|
||||
func (flavor *SFlavor) GetId() string {
|
||||
return flavor.ID
|
||||
return flavor.Id
|
||||
}
|
||||
|
||||
func (flavor *SFlavor) GetGlobalId() string {
|
||||
return flavor.ID
|
||||
return flavor.Id
|
||||
}
|
||||
|
||||
func (flavor *SFlavor) GetInstanceTypeFamily() string {
|
||||
|
||||
@@ -15,486 +15,15 @@
|
||||
package openstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud"
|
||||
)
|
||||
|
||||
const (
|
||||
VOLUME_TYPES_API_VERSION = "2.67"
|
||||
)
|
||||
|
||||
type CpuInfo struct {
|
||||
Arch string
|
||||
Model string
|
||||
Vendor string
|
||||
Feature []string
|
||||
Topology map[string]int
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
Host string
|
||||
ID string
|
||||
DisabledReason string
|
||||
}
|
||||
|
||||
type SResource struct {
|
||||
CPU int
|
||||
DiskGB int
|
||||
Host string
|
||||
MemoryMb int
|
||||
Project string
|
||||
}
|
||||
|
||||
type SHost struct {
|
||||
multicloud.SHostBase
|
||||
zone *SZone
|
||||
|
||||
CpuInfo string
|
||||
|
||||
Aggregates []string
|
||||
CurrentWorkload int
|
||||
Status string
|
||||
State string
|
||||
DiskAvailableLeast int
|
||||
HostIP string
|
||||
FreeDiskGB int
|
||||
FreeRamMB int
|
||||
HypervisorHostname string
|
||||
HypervisorType string
|
||||
HypervisorVersion string
|
||||
ID string
|
||||
LocalGB int
|
||||
LocalGbUsed int
|
||||
MemoryMB int
|
||||
MemoryMbUsed int
|
||||
RunningVms int
|
||||
Service Service
|
||||
Vcpus int
|
||||
VcpusUsed int8
|
||||
|
||||
// less then version 2.28
|
||||
HostName string
|
||||
Zone string
|
||||
Resource []map[string]SResource
|
||||
}
|
||||
|
||||
func (host *SHost) GetId() string {
|
||||
if len(host.ID) > 0 {
|
||||
return host.ID
|
||||
}
|
||||
return host.HostName
|
||||
}
|
||||
|
||||
func (host *SHost) GetName() string {
|
||||
if len(host.Service.Host) > 0 {
|
||||
return host.Service.Host
|
||||
}
|
||||
return host.HostName
|
||||
}
|
||||
|
||||
func (host *SHost) GetGlobalId() string {
|
||||
return host.GetId()
|
||||
}
|
||||
|
||||
func (host *SHost) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (host *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) {
|
||||
return host.zone.GetIWires()
|
||||
}
|
||||
|
||||
func (host *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
|
||||
istorages, err := host.zone.GetIStorages()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
storageTypes := host.zone.getAvailableStorages()
|
||||
storageTypes = append(storageTypes, host.zone.getUnavailableStorage()...)
|
||||
result := []cloudprovider.ICloudStorage{}
|
||||
|
||||
for _, istorage := range istorages {
|
||||
if utils.IsInStringArray(istorage.GetStorageType(), storageTypes) {
|
||||
result = append(result, istorage)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (host *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
|
||||
return host.zone.GetIStorageById(id)
|
||||
}
|
||||
|
||||
func (host *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
instances, err := host.zone.region.GetInstances(host.GetName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iVMs := []cloudprovider.ICloudVM{}
|
||||
for i := 0; i < len(instances); i++ {
|
||||
instances[i].host = host
|
||||
iVMs = append(iVMs, &instances[i])
|
||||
}
|
||||
return iVMs, nil
|
||||
}
|
||||
|
||||
func (host *SHost) GetIVMById(gid string) (cloudprovider.ICloudVM, error) {
|
||||
instance, err := host.zone.region.GetInstance(gid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instance.host = host
|
||||
return instance, nil
|
||||
}
|
||||
|
||||
func (host *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
|
||||
network, err := host.zone.region.GetNetwork(desc.ExternalNetworkId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
zoneName := ""
|
||||
for zone, hosts := range host.zone.cachedHosts {
|
||||
if utils.IsInStringArray(host.GetName(), hosts) {
|
||||
zoneName = zone
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(zoneName) == 0 {
|
||||
return nil, fmt.Errorf("failed to find zone info for host %s", host.GetName())
|
||||
}
|
||||
|
||||
secgroups := []map[string]string{}
|
||||
|
||||
for _, secgroupId := range desc.ExternalSecgroupIds {
|
||||
if secgroupId != SECGROUP_NOT_SUPPORT {
|
||||
secgroups = append(secgroups, map[string]string{"name": secgroupId})
|
||||
}
|
||||
}
|
||||
|
||||
image, err := host.zone.region.GetImage(desc.ExternalImageId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sysDiskSizeGB := image.Size / 1024 / 1024 / 1024
|
||||
if desc.SysDisk.SizeGB < sysDiskSizeGB {
|
||||
desc.SysDisk.SizeGB = sysDiskSizeGB
|
||||
}
|
||||
|
||||
if desc.SysDisk.SizeGB < image.GetMinOsDiskSizeGb() {
|
||||
desc.SysDisk.SizeGB = image.GetMinOsDiskSizeGb()
|
||||
}
|
||||
|
||||
BlockDeviceMappingV2 := []map[string]interface{}{}
|
||||
|
||||
diskIds := []string{}
|
||||
|
||||
defer func() {
|
||||
for _, diskId := range diskIds {
|
||||
err = host.zone.region.DeleteDisk(diskId)
|
||||
if err != nil {
|
||||
log.Errorf("clean disk %s error: %v", diskId, err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if desc.SysDisk.StorageType != api.STORAGE_OPENSTACK_NOVA { //新建volume
|
||||
istorage, err := host.zone.GetIStorageById(desc.SysDisk.StorageExternalId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetIStorageById(%s)", desc.SysDisk.StorageExternalId)
|
||||
}
|
||||
|
||||
_sysDisk, err := host.zone.region.CreateDisk(desc.ExternalImageId, istorage.GetName(), "", desc.SysDisk.SizeGB, desc.SysDisk.Name, desc.ProjectId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "CreateDisk %s", desc.SysDisk.Name)
|
||||
}
|
||||
|
||||
diskIds = append(diskIds, _sysDisk.GetGlobalId())
|
||||
|
||||
BlockDeviceMappingV2 = append(BlockDeviceMappingV2, map[string]interface{}{
|
||||
"boot_index": 0,
|
||||
"uuid": _sysDisk.GetGlobalId(),
|
||||
"source_type": "volume",
|
||||
"destination_type": "volume",
|
||||
"delete_on_termination": true,
|
||||
})
|
||||
} else {
|
||||
BlockDeviceMappingV2 = append(BlockDeviceMappingV2, map[string]interface{}{
|
||||
"boot_index": 0,
|
||||
"uuid": image.ID,
|
||||
"source_type": "image",
|
||||
"destination_type": "local",
|
||||
"delete_on_termination": true,
|
||||
})
|
||||
}
|
||||
|
||||
var _disk *SDisk
|
||||
for index, disk := range desc.DataDisks {
|
||||
istorage, err := host.zone.GetIStorageById(disk.StorageExternalId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetIStorageById(%s)", disk.StorageExternalId)
|
||||
}
|
||||
_disk, err = host.zone.region.CreateDisk("", istorage.GetName(), "", disk.SizeGB, disk.Name, desc.ProjectId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "CreateDisk %s", disk.Name)
|
||||
}
|
||||
diskIds = append(diskIds, _disk.ID)
|
||||
|
||||
mapping := map[string]interface{}{
|
||||
"source_type": "volume",
|
||||
"destination_type": "volume",
|
||||
"delete_on_termination": true,
|
||||
"boot_index": index + 1,
|
||||
"uuid": _disk.ID,
|
||||
}
|
||||
|
||||
BlockDeviceMappingV2 = append(BlockDeviceMappingV2, mapping)
|
||||
}
|
||||
|
||||
params := map[string]map[string]interface{}{
|
||||
"server": {
|
||||
"name": desc.Name,
|
||||
"adminPass": desc.Password,
|
||||
//"description": desc.Description,
|
||||
"accessIPv4": desc.IpAddr,
|
||||
"availability_zone": fmt.Sprintf("%s:%s", zoneName, host.GetName()),
|
||||
"networks": []map[string]string{
|
||||
{
|
||||
"uuid": network.NetworkID,
|
||||
"fixed_ip": desc.IpAddr,
|
||||
},
|
||||
},
|
||||
"security_groups": secgroups,
|
||||
"user_data": desc.UserData,
|
||||
"imageRef": desc.ExternalImageId,
|
||||
"block_device_mapping_v2": BlockDeviceMappingV2,
|
||||
},
|
||||
}
|
||||
|
||||
flavorId, err := host.zone.region.syncFlavor(desc.InstanceType, desc.Cpu, desc.MemoryMB, desc.SysDisk.SizeGB)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
params["server"]["flavorRef"] = flavorId
|
||||
|
||||
if len(desc.PublicKey) > 0 {
|
||||
keypairName, err := host.zone.region.syncKeypair(desc.Name, desc.PublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
params["server"]["key_name"] = keypairName
|
||||
}
|
||||
|
||||
_, resp, err := host.zone.region.PostWithProject(desc.ProjectId, "compute", "/servers", "", jsonutils.Marshal(params))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
diskIds = []string{}
|
||||
serverId, err := resp.GetString("server", "id")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instance, err := host.zone.region.GetInstance(serverId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instance.host = host
|
||||
return instance, nil
|
||||
}
|
||||
|
||||
func (host *SHost) GetEnabled() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (host *SHost) GetAccessIp() string {
|
||||
return host.HostIP
|
||||
}
|
||||
|
||||
func (host *SHost) GetAccessMac() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (host *SHost) GetSysInfo() jsonutils.JSONObject {
|
||||
info := jsonutils.NewDict()
|
||||
info.Add(jsonutils.NewString(CLOUD_PROVIDER_OPENSTACK), "manufacture")
|
||||
return info
|
||||
}
|
||||
|
||||
func (host *SHost) GetSN() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (host *SHost) GetCpuCmtbound() float32 {
|
||||
aggregates, err := host.zone.region.GetAggregates()
|
||||
if err != nil || len(aggregates) == 0 {
|
||||
return 16.0
|
||||
}
|
||||
CpuCmtbound := 1000000.0
|
||||
for _, aggregate := range aggregates {
|
||||
if utils.IsInStringArray(host.GetName(), aggregate.Hosts) {
|
||||
if _cmtbound, ok := aggregate.Metadata["cpu_allocation_ratio"]; ok {
|
||||
cmtbound, err := strconv.ParseFloat(_cmtbound, 32)
|
||||
if err == nil && CpuCmtbound > cmtbound {
|
||||
CpuCmtbound = cmtbound
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if CpuCmtbound >= 1000000.0 {
|
||||
return 16.0
|
||||
}
|
||||
return float32(CpuCmtbound)
|
||||
}
|
||||
|
||||
func (host *SHost) GetMemCmtbound() float32 {
|
||||
aggregates, err := host.zone.region.GetAggregates()
|
||||
if err != nil || len(aggregates) == 0 {
|
||||
return 1.5
|
||||
}
|
||||
MemCmtbound := 1000000.0
|
||||
for _, aggregate := range aggregates {
|
||||
if utils.IsInStringArray(host.GetName(), aggregate.Hosts) {
|
||||
if _cmtbound, ok := aggregate.Metadata["ram_allocation_ratio"]; ok {
|
||||
cmtbound, err := strconv.ParseFloat(_cmtbound, 32)
|
||||
if err == nil && MemCmtbound > cmtbound {
|
||||
MemCmtbound = cmtbound
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if MemCmtbound >= 1000000.0 {
|
||||
return 1.5
|
||||
}
|
||||
return float32(MemCmtbound)
|
||||
}
|
||||
|
||||
func (host *SHost) GetCpuCount() int {
|
||||
if host.Vcpus > 0 {
|
||||
return host.Vcpus
|
||||
}
|
||||
host.Refresh()
|
||||
return host.Vcpus
|
||||
}
|
||||
|
||||
func (host *SHost) GetNodeCount() int8 {
|
||||
if len(host.CpuInfo) > 0 {
|
||||
info, err := jsonutils.Parse([]byte(host.CpuInfo))
|
||||
if err == nil {
|
||||
cpuInfo := &CpuInfo{}
|
||||
err = info.Unmarshal(cpuInfo)
|
||||
if err == nil {
|
||||
if cell, ok := cpuInfo.Topology["cells"]; ok {
|
||||
return int8(cell)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return int8(host.GetCpuCount())
|
||||
}
|
||||
|
||||
func (host *SHost) GetCpuDesc() string {
|
||||
return host.CpuInfo
|
||||
}
|
||||
|
||||
func (host *SHost) GetCpuMhz() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (host *SHost) GetMemSizeMB() int {
|
||||
if host.MemoryMB > 0 {
|
||||
return host.MemoryMB
|
||||
}
|
||||
host.Refresh()
|
||||
return host.MemoryMB
|
||||
}
|
||||
|
||||
func (host *SHost) GetStorageSizeMB() int {
|
||||
if host.LocalGB > 0 {
|
||||
return host.LocalGB * 1024
|
||||
}
|
||||
host.Refresh()
|
||||
return host.LocalGB * 1024
|
||||
}
|
||||
|
||||
func (host *SHost) GetStorageType() string {
|
||||
return api.DISK_TYPE_HYBRID
|
||||
}
|
||||
|
||||
func (host *SHost) GetHostType() string {
|
||||
return api.HOST_TYPE_OPENSTACK
|
||||
}
|
||||
|
||||
func (host *SHost) GetHostStatus() string {
|
||||
if host.Status == "disabled" {
|
||||
return api.HOST_OFFLINE
|
||||
}
|
||||
switch host.State {
|
||||
case "up", "":
|
||||
return api.HOST_ONLINE
|
||||
default:
|
||||
return api.HOST_OFFLINE
|
||||
}
|
||||
}
|
||||
|
||||
func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) {
|
||||
return nil, cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
func (host *SHost) GetIsMaintenance() bool {
|
||||
switch host.Status {
|
||||
case "enabled", "":
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func (host *SHost) GetVersion() string {
|
||||
_, version, _ := host.zone.region.GetVersion("compute")
|
||||
return version
|
||||
}
|
||||
|
||||
func (host *SHost) GetStatus() string {
|
||||
return api.HOST_STATUS_RUNNING
|
||||
}
|
||||
|
||||
func (host *SHost) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (host *SHost) Refresh() error {
|
||||
new, err := host.zone.region.GetIHostById(host.GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := jsonutils.Update(host, new); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(host.Resource) > 0 {
|
||||
for _, resouce := range host.Resource {
|
||||
for _, info := range resouce {
|
||||
if info.Project == "(total)" {
|
||||
host.LocalGB = info.DiskGB
|
||||
host.Vcpus = info.CPU
|
||||
host.MemoryMB = info.MemoryMb
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
Service string
|
||||
}
|
||||
|
||||
type SAggregate struct {
|
||||
@@ -509,9 +38,9 @@ type SAggregate struct {
|
||||
}
|
||||
|
||||
func (region *SRegion) GetAggregates() ([]SAggregate, error) {
|
||||
_, resp, err := region.List("compute", "/os-aggregates", "", nil)
|
||||
resp, err := region.ecsList("/os-aggregates", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "ecsList")
|
||||
}
|
||||
aggregates := []SAggregate{}
|
||||
err = resp.Unmarshal(&aggregates, "aggregates")
|
||||
@@ -520,3 +49,16 @@ func (region *SRegion) GetAggregates() ([]SAggregate, error) {
|
||||
}
|
||||
return aggregates, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetHosts() ([]SHost, error) {
|
||||
hosts := []SHost{}
|
||||
resp, err := region.ecsList("/os-hosts", nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ecsList(os-hosts)")
|
||||
}
|
||||
err = resp.Unmarshal(&hosts, "hosts")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return hosts, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,351 @@
|
||||
// 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 openstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud"
|
||||
)
|
||||
|
||||
type CpuInfo struct {
|
||||
Arch string
|
||||
Model string
|
||||
Vendor string
|
||||
Feature []string
|
||||
Topology map[string]int
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
Host string
|
||||
ID string
|
||||
DisabledReason string
|
||||
}
|
||||
|
||||
type SResource struct {
|
||||
CPU int
|
||||
DiskGB int
|
||||
Host string
|
||||
MemoryMb int
|
||||
Project string
|
||||
}
|
||||
|
||||
type SHypervisor struct {
|
||||
multicloud.SHostBase
|
||||
zone *SZone
|
||||
|
||||
CpuInfo string
|
||||
|
||||
Aggregates []string
|
||||
CurrentWorkload int
|
||||
Status string
|
||||
State string
|
||||
DiskAvailableLeast int
|
||||
HostIP string
|
||||
FreeDiskGB int
|
||||
FreeRamMB int
|
||||
HypervisorHostname string
|
||||
HypervisorType string
|
||||
HypervisorVersion string
|
||||
Id string
|
||||
LocalGB int
|
||||
LocalGbUsed int
|
||||
MemoryMB int
|
||||
MemoryMbUsed int
|
||||
RunningVms int
|
||||
Service Service
|
||||
Vcpus int
|
||||
VcpusUsed int8
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetId() string {
|
||||
return host.Id
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetName() string {
|
||||
if len(host.HypervisorHostname) > 0 {
|
||||
return host.HypervisorHostname
|
||||
}
|
||||
return host.Service.Host
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetGlobalId() string {
|
||||
return host.GetId()
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetIWires() ([]cloudprovider.ICloudWire, error) {
|
||||
return host.zone.GetIWires()
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
|
||||
istorages := []cloudprovider.ICloudStorage{}
|
||||
storages, err := host.zone.region.GetStorageTypes()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetStorageTypes")
|
||||
}
|
||||
for i := range storages {
|
||||
storages[i].zone = host.zone
|
||||
istorages = append(istorages, &storages[i])
|
||||
}
|
||||
nova := &SNovaStorage{host: host, zone: host.zone}
|
||||
istorages = append(istorages, nova)
|
||||
return istorages, nil
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
|
||||
return host.zone.GetIStorageById(id)
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetIVMs() ([]cloudprovider.ICloudVM, error) {
|
||||
instances, err := host.zone.region.GetInstances(host.HypervisorHostname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iVMs := []cloudprovider.ICloudVM{}
|
||||
for i := 0; i < len(instances); i++ {
|
||||
instances[i].host = host
|
||||
iVMs = append(iVMs, &instances[i])
|
||||
}
|
||||
return iVMs, nil
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetIVMById(gid string) (cloudprovider.ICloudVM, error) {
|
||||
instance, err := host.zone.region.GetInstance(gid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instance.host = host
|
||||
return instance, nil
|
||||
}
|
||||
|
||||
func (host *SHypervisor) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
|
||||
instance, err := host.zone.CreateVM(host.Service.Host, desc)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "CreateVM")
|
||||
}
|
||||
instance.host = host
|
||||
return instance, nil
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetEnabled() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetAccessIp() string {
|
||||
return host.HostIP
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetAccessMac() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetSysInfo() jsonutils.JSONObject {
|
||||
info := jsonutils.NewDict()
|
||||
info.Add(jsonutils.NewString(CLOUD_PROVIDER_OPENSTACK), "manufacture")
|
||||
return info
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetSN() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetCpuCmtbound() float32 {
|
||||
aggregates, err := host.zone.region.GetAggregates()
|
||||
if err != nil || len(aggregates) == 0 {
|
||||
return 16.0
|
||||
}
|
||||
CpuCmtbound := 1000000.0
|
||||
for _, aggregate := range aggregates {
|
||||
if utils.IsInStringArray(host.GetName(), aggregate.Hosts) {
|
||||
if _cmtbound, ok := aggregate.Metadata["cpu_allocation_ratio"]; ok {
|
||||
cmtbound, err := strconv.ParseFloat(_cmtbound, 32)
|
||||
if err == nil && CpuCmtbound > cmtbound {
|
||||
CpuCmtbound = cmtbound
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if CpuCmtbound >= 1000000.0 {
|
||||
return 16.0
|
||||
}
|
||||
return float32(CpuCmtbound)
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetMemCmtbound() float32 {
|
||||
aggregates, err := host.zone.region.GetAggregates()
|
||||
if err != nil || len(aggregates) == 0 {
|
||||
return 1.5
|
||||
}
|
||||
MemCmtbound := 1000000.0
|
||||
for _, aggregate := range aggregates {
|
||||
if utils.IsInStringArray(host.GetName(), aggregate.Hosts) {
|
||||
if _cmtbound, ok := aggregate.Metadata["ram_allocation_ratio"]; ok {
|
||||
cmtbound, err := strconv.ParseFloat(_cmtbound, 32)
|
||||
if err == nil && MemCmtbound > cmtbound {
|
||||
MemCmtbound = cmtbound
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if MemCmtbound >= 1000000.0 {
|
||||
return 1.5
|
||||
}
|
||||
return float32(MemCmtbound)
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetCpuCount() int {
|
||||
if host.Vcpus > 0 {
|
||||
return host.Vcpus
|
||||
}
|
||||
host.Refresh()
|
||||
return host.Vcpus
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetNodeCount() int8 {
|
||||
if len(host.CpuInfo) > 0 {
|
||||
info, err := jsonutils.Parse([]byte(host.CpuInfo))
|
||||
if err == nil {
|
||||
cpuInfo := &CpuInfo{}
|
||||
err = info.Unmarshal(cpuInfo)
|
||||
if err == nil {
|
||||
if cell, ok := cpuInfo.Topology["cells"]; ok {
|
||||
return int8(cell)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return int8(host.GetCpuCount())
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetCpuDesc() string {
|
||||
return host.CpuInfo
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetCpuMhz() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetMemSizeMB() int {
|
||||
if host.MemoryMB > 0 {
|
||||
return host.MemoryMB
|
||||
}
|
||||
host.Refresh()
|
||||
return host.MemoryMB
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetStorageSizeMB() int {
|
||||
return host.LocalGB * 1024
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetStorageType() string {
|
||||
return api.DISK_TYPE_HYBRID
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetHostType() string {
|
||||
return api.HOST_TYPE_OPENSTACK
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetHostStatus() string {
|
||||
if host.Status == "disabled" {
|
||||
return api.HOST_OFFLINE
|
||||
}
|
||||
switch host.State {
|
||||
case "up", "":
|
||||
return api.HOST_ONLINE
|
||||
default:
|
||||
return api.HOST_OFFLINE
|
||||
}
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) {
|
||||
return nil, cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetIsMaintenance() bool {
|
||||
switch host.Status {
|
||||
case "enabled", "":
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetVersion() string {
|
||||
version, _ := host.zone.region.GetMaxVersion(OPENSTACK_SERVICE_COMPUTE)
|
||||
return version
|
||||
}
|
||||
|
||||
func (host *SHypervisor) GetStatus() string {
|
||||
return api.HOST_STATUS_RUNNING
|
||||
}
|
||||
|
||||
func (host *SHypervisor) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (host *SHypervisor) Refresh() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetHypervisors() ([]SHypervisor, error) {
|
||||
hypervisors := []SHypervisor{}
|
||||
resource := "/os-hypervisors/detail"
|
||||
query := url.Values{}
|
||||
for {
|
||||
resp, err := region.ecsList(resource, query)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ecsList")
|
||||
}
|
||||
|
||||
part := struct {
|
||||
Hypervisors []SHypervisor
|
||||
HypervisorsLinks SNextLinks
|
||||
}{}
|
||||
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
hypervisors = append(hypervisors, part.Hypervisors...)
|
||||
marker := part.HypervisorsLinks.GetNextMark()
|
||||
if len(marker) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", marker)
|
||||
}
|
||||
return hypervisors, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetHypervisor(id string) (*SHypervisor, error) {
|
||||
resource := fmt.Sprintf("/os-hypervisors/%s", id)
|
||||
resp, err := region.ecsGet(resource)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ecsGet")
|
||||
}
|
||||
hypervisor := &SHypervisor{}
|
||||
err = resp.Unmarshal(hypervisor, "hypervisor")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return hypervisor, nil
|
||||
}
|
||||
@@ -16,6 +16,8 @@ package openstack
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -24,7 +26,6 @@ import (
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/util/osprofile"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
@@ -58,7 +59,7 @@ type SImage struct {
|
||||
Self string
|
||||
MinDisk int
|
||||
Protected bool
|
||||
ID string
|
||||
Id string
|
||||
File string
|
||||
Checksum string
|
||||
OsHashAlgo string
|
||||
@@ -79,30 +80,36 @@ func (image *SImage) GetMinRamSizeMb() int {
|
||||
}
|
||||
|
||||
func (region *SRegion) GetImages(name string, status string, imageId string) ([]SImage, error) {
|
||||
params := url.Values{}
|
||||
if utils.IsInStringArray(status, []string{QUEUED, SAVING, ACTIVE, KILLED, DELETED, PENDING_DELETE, DEACTIVATED, UPLOADING, IMPORTING}) {
|
||||
params.Add("status", status)
|
||||
query := url.Values{}
|
||||
if len(status) > 0 {
|
||||
query.Set("status", status)
|
||||
}
|
||||
if len(name) > 0 {
|
||||
params.Add("name", name)
|
||||
query.Set("name", name)
|
||||
}
|
||||
if len(imageId) > 0 {
|
||||
params.Add("id", imageId)
|
||||
query.Set("id", imageId)
|
||||
}
|
||||
url := "/v2/images?" + params.Encode()
|
||||
images := []SImage{}
|
||||
for len(url) > 0 {
|
||||
_, resp, err := region.List("image", url, "", nil)
|
||||
resource := "/v2/images"
|
||||
for {
|
||||
resp, err := region.imageList(resource, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "imageList")
|
||||
}
|
||||
_images := []SImage{}
|
||||
err = resp.Unmarshal(&_images, "images")
|
||||
part := struct {
|
||||
Images []SImage
|
||||
Next string
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, `resp.Unmarshal(&_images, "images")`)
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
images = append(images, _images...)
|
||||
url, _ = resp.GetString("next")
|
||||
images = append(images, part.Images...)
|
||||
if len(part.Next) == 0 {
|
||||
break
|
||||
}
|
||||
resource = part.Next
|
||||
}
|
||||
return images, nil
|
||||
}
|
||||
@@ -112,7 +119,7 @@ func (image *SImage) GetMetadata() *jsonutils.JSONDict {
|
||||
}
|
||||
|
||||
func (image *SImage) GetId() string {
|
||||
return image.ID
|
||||
return image.Id
|
||||
}
|
||||
|
||||
func (image *SImage) GetName() string {
|
||||
@@ -124,11 +131,11 @@ func (image *SImage) IsEmulated() bool {
|
||||
}
|
||||
|
||||
func (image *SImage) GetGlobalId() string {
|
||||
return image.ID
|
||||
return image.Id
|
||||
}
|
||||
|
||||
func (image *SImage) Delete(ctx context.Context) error {
|
||||
return image.storageCache.region.DeleteImage(image.ID)
|
||||
return image.storageCache.region.DeleteImage(image.Id)
|
||||
}
|
||||
|
||||
func (image *SImage) GetStatus() string {
|
||||
@@ -160,11 +167,11 @@ func (image *SImage) GetImageStatus() string {
|
||||
}
|
||||
|
||||
func (image *SImage) Refresh() error {
|
||||
new, err := image.storageCache.region.GetImage(image.ID)
|
||||
_image, err := image.storageCache.region.GetImage(image.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "GetImage")
|
||||
}
|
||||
return jsonutils.Update(image, new)
|
||||
return jsonutils.Update(image, _image)
|
||||
}
|
||||
|
||||
func (image *SImage) GetImageType() string {
|
||||
@@ -243,7 +250,7 @@ func (image *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache {
|
||||
}
|
||||
|
||||
func (region *SRegion) DeleteImage(imageId string) error {
|
||||
_, err := region.Delete("image", "/v2/images/"+imageId, "")
|
||||
_, err := region.imageDelete("/v2/images/" + imageId)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -266,7 +273,7 @@ func (region *SRegion) GetImageByName(name string) (*SImage, error) {
|
||||
return &images[0], nil
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateImage(imageName string, osType string, osDist string, minDiskGb int, minRam int) (*SImage, error) {
|
||||
func (region *SRegion) CreateImage(imageName string, osType string, osDist string, minDiskGb int, minRam int, body io.Reader) (*SImage, error) {
|
||||
params := map[string]interface{}{
|
||||
"container_format": "bare",
|
||||
"disk_format": string(qemuimg.QCOW2),
|
||||
@@ -278,12 +285,21 @@ func (region *SRegion) CreateImage(imageName string, osType string, osDist strin
|
||||
"hw_qemu_guest_agent": "yes",
|
||||
}
|
||||
|
||||
_, resp, err := region.Post("image", "/v2/images", "", jsonutils.Marshal(params))
|
||||
resp, err := region.imagePost("/v2/images", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "imagePost")
|
||||
}
|
||||
image := &SImage{}
|
||||
return image, resp.Unmarshal(image)
|
||||
err = resp.Unmarshal(image)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
url := fmt.Sprintf("/v2/images/%s/file", image.Id)
|
||||
err = region.imageUpload(url, body)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "imageUpload")
|
||||
}
|
||||
return image, nil
|
||||
}
|
||||
|
||||
func (self *SImage) UEFI() bool {
|
||||
|
||||
@@ -20,10 +20,11 @@ import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"gopkg.in/fatih/set.v0"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"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"
|
||||
@@ -62,7 +63,7 @@ type SPrivate struct {
|
||||
}
|
||||
|
||||
type SecurityGroup struct {
|
||||
ID string
|
||||
Id string
|
||||
Name string
|
||||
Description string
|
||||
}
|
||||
@@ -73,17 +74,17 @@ type ExtraSpecs struct {
|
||||
}
|
||||
|
||||
type Resource struct {
|
||||
ID string
|
||||
Id string
|
||||
Links []Link
|
||||
}
|
||||
|
||||
type Image struct {
|
||||
ID string
|
||||
Id string
|
||||
Links []Link
|
||||
}
|
||||
|
||||
type VolumesAttached struct {
|
||||
ID string
|
||||
Id string
|
||||
DeleteOnTermination bool
|
||||
}
|
||||
|
||||
@@ -95,8 +96,7 @@ type SFault struct {
|
||||
|
||||
type SInstance struct {
|
||||
multicloud.SInstanceBase
|
||||
|
||||
host *SHost
|
||||
host *SHypervisor
|
||||
|
||||
DiskConfig string `json:"OS-DCF:diskConfig,omitempty"`
|
||||
AvailabilityZone string `json:"OS-EXT-AZ:availability_zone,omitempty"`
|
||||
@@ -104,10 +104,10 @@ type SInstance struct {
|
||||
Hostname string `json:"OS-EXT-SRV-ATTR:hostname,omitempty"`
|
||||
HypervisorHostname string `json:"OS-EXT-SRV-ATTR:hypervisor_hostname,omitempty"`
|
||||
InstanceName string `json:"OS-EXT-SRV-ATTR:instance_name,omitempty"`
|
||||
KernelID string `json:"OS-EXT-SRV-ATTR:kernel_id,omitempty"`
|
||||
KernelId string `json:"OS-EXT-SRV-ATTR:kernel_id,omitempty"`
|
||||
LaunchIndex int `json:"OS-EXT-SRV-ATTR:launch_index,omitempty"`
|
||||
RamdiskID string `json:"OS-EXT-SRV-ATTR:ramdisk_id,omitempty"`
|
||||
ReservationID string `json:"OS-EXT-SRV-ATTR:reservation_id,omitempty"`
|
||||
RamdiskId string `json:"OS-EXT-SRV-ATTR:ramdisk_id,omitempty"`
|
||||
ReservationId string `json:"OS-EXT-SRV-ATTR:reservation_id,omitempty"`
|
||||
RootDeviceName string `json:"OS-EXT-SRV-ATTR:root_device_name,omitempty"`
|
||||
UserData string `json:"OS-EXT-SRV-ATTR:user_data,omitempty"`
|
||||
PowerState int `json:"OS-EXT-STS:power_state,omitempty"`
|
||||
@@ -123,9 +123,9 @@ type SInstance struct {
|
||||
Created time.Time
|
||||
Description string
|
||||
Flavor SFlavor
|
||||
HostID string
|
||||
HostId string
|
||||
HostStatus string
|
||||
ID string
|
||||
Id string
|
||||
image Image //有可能是字符串
|
||||
KeyName string
|
||||
Links []Link
|
||||
@@ -137,101 +137,91 @@ type SInstance struct {
|
||||
SecurityGroups []SecurityGroup
|
||||
Status string
|
||||
Tags []string
|
||||
TenantID string
|
||||
TenantId string
|
||||
TrustedImageCertificates []string
|
||||
Updated time.Time
|
||||
UserID string
|
||||
UserId string
|
||||
Fault SFault
|
||||
}
|
||||
|
||||
func (region *SRegion) GetSecurityGroupsByInstance(instanceId string) ([]SecurityGroup, error) {
|
||||
_, resp, err := region.Get("compute", fmt.Sprintf("/servers/%s/os-security-groups", instanceId), "", nil)
|
||||
resource := fmt.Sprintf("/servers/%s/os-security-groups", instanceId)
|
||||
resp, err := region.ecsGet(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "ecsGet")
|
||||
}
|
||||
secgroups := []SecurityGroup{}
|
||||
return secgroups, resp.Unmarshal(&secgroups, "security_groups")
|
||||
err = resp.Unmarshal(&secgroups, "security_groups")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return secgroups, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetInstances(hostName string) ([]SInstance, error) {
|
||||
_, maxVersion, _ := region.GetVersion("compute")
|
||||
url := "/servers/detail?all_tenants=True"
|
||||
func (region *SRegion) GetInstances(host string) ([]SInstance, error) {
|
||||
instances := []SInstance{}
|
||||
for len(url) > 0 {
|
||||
_, resp, err := region.List("compute", url, maxVersion, nil)
|
||||
resource := "/servers/detail"
|
||||
query := url.Values{}
|
||||
query.Set("all_tenants", "True")
|
||||
for {
|
||||
resp, err := region.ecsList(resource, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "ecsList")
|
||||
}
|
||||
_instances := []SInstance{}
|
||||
err = resp.Unmarshal(&_instances, "servers")
|
||||
part := struct {
|
||||
Servers []SInstance
|
||||
ServersLinks SNextLinks
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, `resp.Unmarshal(&_instances, "servers")`)
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
instances = append(instances, _instances...)
|
||||
url = ""
|
||||
if resp.Contains("servers_links") {
|
||||
nextLink := []SNextLink{}
|
||||
err = resp.Unmarshal(&nextLink, "servers_links")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, `resp.Unmarshal(&nextLink, "servers")`)
|
||||
}
|
||||
for _, next := range nextLink {
|
||||
if next.Rel == "next" {
|
||||
url = next.Href
|
||||
break
|
||||
}
|
||||
for i := range part.Servers {
|
||||
if len(host) == 0 || part.Servers[i].Host == host || part.Servers[i].HypervisorHostname == host {
|
||||
instances = append(instances, part.Servers[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
result := []SInstance{}
|
||||
for i := 0; i < len(instances); i++ {
|
||||
if len(hostName) == 0 || hostName == instances[i].Host {
|
||||
result = append(result, instances[i])
|
||||
marker := part.ServersLinks.GetNextMark()
|
||||
if len(marker) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", marker)
|
||||
}
|
||||
return result, nil
|
||||
return instances, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetInstance(instanceId string) (*SInstance, error) {
|
||||
_, maxVersion, _ := region.GetVersion("compute")
|
||||
_, resp, err := region.Get("compute", "/servers/"+instanceId, maxVersion, nil)
|
||||
resource := "/servers/" + instanceId
|
||||
resp, err := region.ecsGet(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "ecsGet")
|
||||
}
|
||||
instance := &SInstance{}
|
||||
return instance, resp.Unmarshal(instance, "server")
|
||||
err = resp.Unmarshal(instance, "server")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarsha")
|
||||
}
|
||||
return instance, nil
|
||||
}
|
||||
|
||||
func (instance *SInstance) GetSecurityGroupIds() ([]string, error) {
|
||||
secgroupIds := []string{}
|
||||
secgroups, err := instance.host.zone.region.GetSecurityGroupsByInstance(instance.ID)
|
||||
secgroups, err := instance.host.zone.region.GetSecurityGroupsByInstance(instance.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, secgroup := range secgroups {
|
||||
secgroupIds = append(secgroupIds, secgroup.ID)
|
||||
secgroupIds = append(secgroupIds, secgroup.Id)
|
||||
}
|
||||
return secgroupIds, nil
|
||||
}
|
||||
|
||||
func (instance *SInstance) GetMetadata() *jsonutils.JSONDict {
|
||||
data := jsonutils.NewDict()
|
||||
|
||||
instance.fetchFlavor()
|
||||
|
||||
priceKey := fmt.Sprintf("%s::%s", instance.host.zone.ZoneName, instance.Flavor.OriginalName)
|
||||
data.Add(jsonutils.NewString(priceKey), "price_key")
|
||||
|
||||
data.Add(jsonutils.NewString(instance.host.zone.GetGlobalId()), "zone_ext_id")
|
||||
return data
|
||||
}
|
||||
|
||||
func (instance *SInstance) GetIHost() cloudprovider.ICloudHost {
|
||||
return instance.host
|
||||
}
|
||||
|
||||
func (instance *SInstance) GetId() string {
|
||||
return instance.ID
|
||||
return instance.Id
|
||||
}
|
||||
|
||||
func (instance *SInstance) GetName() string {
|
||||
@@ -239,7 +229,7 @@ func (instance *SInstance) GetName() string {
|
||||
}
|
||||
|
||||
func (instance *SInstance) GetGlobalId() string {
|
||||
return instance.ID
|
||||
return instance.Id
|
||||
}
|
||||
|
||||
func (instance *SInstance) IsEmulated() bool {
|
||||
@@ -247,8 +237,8 @@ func (instance *SInstance) IsEmulated() bool {
|
||||
}
|
||||
|
||||
func (instance *SInstance) fetchFlavor() error {
|
||||
if len(instance.Flavor.ID) > 0 && instance.Flavor.Vcpus == 0 {
|
||||
flavor, err := instance.host.zone.region.GetFlavor(instance.Flavor.ID)
|
||||
if len(instance.Flavor.Id) > 0 && instance.Flavor.Vcpus == 0 {
|
||||
flavor, err := instance.host.zone.region.GetFlavor(instance.Flavor.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -258,7 +248,10 @@ func (instance *SInstance) fetchFlavor() error {
|
||||
}
|
||||
|
||||
func (instance *SInstance) GetInstanceType() string {
|
||||
instance.fetchFlavor()
|
||||
err := instance.fetchFlavor()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return instance.Flavor.GetName()
|
||||
}
|
||||
|
||||
@@ -266,54 +259,60 @@ func (instance *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
|
||||
disks := []SDisk{}
|
||||
hasSysDisk := false
|
||||
for i := 0; i < len(instance.VolumesAttached); i++ {
|
||||
disk, err := instance.host.zone.region.GetDisk(instance.VolumesAttached[i].ID)
|
||||
disk, err := instance.host.zone.region.GetDisk(instance.VolumesAttached[i].Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "GetDisk(%s)", instance.VolumesAttached[i].Id)
|
||||
}
|
||||
disks = append(disks, *disk)
|
||||
if disk.Bootable {
|
||||
if disk.GetDiskType() == api.DISK_TYPE_SYS {
|
||||
hasSysDisk = true
|
||||
}
|
||||
}
|
||||
iDisks := []cloudprovider.ICloudDisk{}
|
||||
idisks := []cloudprovider.ICloudDisk{}
|
||||
for i := 0; i < len(disks); i++ {
|
||||
store, err := instance.host.zone.getStorageByCategory(disks[i].VolumeType)
|
||||
store, err := instance.host.zone.getStorageByCategory(disks[i].VolumeType, disks[i].Host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "getStorageByCategory(%s.%s)", disks[i].Id, disks[i].VolumeType)
|
||||
}
|
||||
disks[i].storage = store
|
||||
iDisks = append(iDisks, &disks[i])
|
||||
idisks = append(idisks, &disks[i])
|
||||
}
|
||||
|
||||
if !hasSysDisk {
|
||||
nova := SNovaStorage{zone: instance.host.zone}
|
||||
sysDisk, _ := nova.GetIDiskById(instance.ID)
|
||||
iDisks = append([]cloudprovider.ICloudDisk{sysDisk}, iDisks...)
|
||||
store := &SNovaStorage{zone: instance.host.zone, host: instance.host}
|
||||
disk := &SNovaDisk{storage: store, instanceId: instance.Id, region: instance.host.zone.region}
|
||||
idisks = append([]cloudprovider.ICloudDisk{disk}, idisks...)
|
||||
}
|
||||
|
||||
return iDisks, nil
|
||||
return idisks, nil
|
||||
}
|
||||
|
||||
func (instance *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) {
|
||||
nics := []cloudprovider.ICloudNic{}
|
||||
for networkName, address := range instance.Addresses {
|
||||
for i := 0; i < len(address); i++ {
|
||||
if instance.Addresses[networkName][i].Type == "fixed" {
|
||||
instance.Addresses[networkName][i].instance = instance
|
||||
nics = append(nics, &instance.Addresses[networkName][i])
|
||||
}
|
||||
}
|
||||
nics, err := instance.host.zone.region.GetInstancePorts(instance.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetInstancePorts")
|
||||
}
|
||||
return nics, nil
|
||||
inics := []cloudprovider.ICloudNic{}
|
||||
for i := range nics {
|
||||
nics[i].region = instance.host.zone.region
|
||||
inics = append(inics, &nics[i])
|
||||
}
|
||||
return inics, nil
|
||||
}
|
||||
|
||||
func (instance *SInstance) GetVcpuCount() int {
|
||||
instance.fetchFlavor()
|
||||
err := instance.fetchFlavor()
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return instance.Flavor.Vcpus
|
||||
}
|
||||
|
||||
func (instance *SInstance) GetVmemSizeMB() int {
|
||||
instance.fetchFlavor()
|
||||
err := instance.fetchFlavor()
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return instance.Flavor.RAM
|
||||
}
|
||||
|
||||
@@ -374,11 +373,11 @@ func (instance *SInstance) GetStatus() string {
|
||||
}
|
||||
|
||||
func (instance *SInstance) Refresh() error {
|
||||
new, err := instance.host.zone.region.GetInstance(instance.ID)
|
||||
_instance, err := instance.host.zone.region.GetInstance(instance.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return jsonutils.Update(instance, new)
|
||||
return jsonutils.Update(instance, _instance)
|
||||
}
|
||||
|
||||
func (instance *SInstance) UpdateVM(ctx context.Context, name string) error {
|
||||
@@ -388,7 +387,8 @@ func (instance *SInstance) UpdateVM(ctx context.Context, name string) error {
|
||||
"name": name,
|
||||
},
|
||||
}
|
||||
_, _, err := instance.host.zone.region.Update("compute", "/servers/"+instance.ID, "", jsonutils.Marshal(params))
|
||||
resource := "/servers/" + instance.Id
|
||||
_, err := instance.host.zone.region.ecsUpdate(resource, params)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -399,59 +399,61 @@ func (instance *SInstance) GetHypervisor() string {
|
||||
}
|
||||
|
||||
func (instance *SInstance) StartVM(ctx context.Context) error {
|
||||
if err := instance.host.zone.region.StartVM(instance.ID); err != nil {
|
||||
return err
|
||||
err := instance.host.zone.region.StartVM(instance.Id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "StartVM(%s)", instance.Id)
|
||||
}
|
||||
return cloudprovider.WaitStatus(instance, api.VM_RUNNING, 10*time.Second, 8*time.Minute)
|
||||
}
|
||||
|
||||
func (instance *SInstance) StopVM(ctx context.Context, isForce bool) error {
|
||||
if err := instance.host.zone.region.StopVM(instance.ID, isForce); err != nil {
|
||||
return err
|
||||
err := instance.host.zone.region.StopVM(instance.Id, isForce)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "StopVM(%s)", instance.Id)
|
||||
}
|
||||
return cloudprovider.WaitStatus(instance, api.VM_READY, 10*time.Second, 8*time.Minute)
|
||||
}
|
||||
|
||||
func (region *SRegion) GetInstanceVNCUrl(instanceId string) (string, error) {
|
||||
_, maxVersion, _ := region.GetVersion("compute")
|
||||
params := map[string]map[string]string{
|
||||
"remote_console": {
|
||||
"protocol": "vnc",
|
||||
"type": "novnc",
|
||||
},
|
||||
}
|
||||
_, resp, err := region.Post("compute", fmt.Sprintf("/servers/%s/remote-consoles", instanceId), maxVersion, jsonutils.Marshal(params))
|
||||
resource := fmt.Sprintf("/servers/%s/remote-consoles", instanceId)
|
||||
resp, err := region.ecsPost(resource, params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.Wrap(err, "ecsPost")
|
||||
}
|
||||
return resp.GetString("remote_console", "url")
|
||||
}
|
||||
|
||||
func (instance *SInstance) GetVNCInfo() (jsonutils.JSONObject, error) {
|
||||
url, err := instance.host.zone.region.GetInstanceVNCUrl(instance.ID)
|
||||
url, err := instance.host.zone.region.GetInstanceVNCUrl(instance.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "GetInstanceVNCUrl")
|
||||
}
|
||||
ret := jsonutils.NewDict()
|
||||
ret.Add(jsonutils.NewString(url), "url")
|
||||
ret.Add(jsonutils.NewString("openstack"), "protocol")
|
||||
ret.Add(jsonutils.NewString(instance.ID), "instance_id")
|
||||
ret.Add(jsonutils.NewString(instance.Id), "instance_id")
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (instance *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error {
|
||||
return instance.host.zone.region.DeployVM(instance.ID, name, password, publicKey, deleteKeypair, description)
|
||||
return instance.host.zone.region.DeployVM(instance.Id, name, password, publicKey, deleteKeypair, description)
|
||||
}
|
||||
|
||||
func (instance *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) {
|
||||
return instance.ID, instance.host.zone.region.ReplaceSystemDisk(instance.ID, desc.ImageId, desc.Password, desc.PublicKey, desc.SysSizeGB)
|
||||
return instance.Id, instance.host.zone.region.ReplaceSystemDisk(instance.Id, desc.ImageId, desc.Password, desc.PublicKey, desc.SysSizeGB)
|
||||
}
|
||||
|
||||
func (instance *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error {
|
||||
if (len(config.InstanceType) > 0 && instance.GetInstanceType() != config.InstanceType) || instance.GetVcpuCount() != config.Cpu || instance.GetVmemSizeMB() != config.MemoryMB {
|
||||
flavorId, err := instance.host.zone.region.syncFlavor(config.InstanceType, config.Cpu, config.MemoryMB, 40)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrapf(err, "syncFlavor(%s)", config.InstanceType)
|
||||
}
|
||||
return instance.host.zone.region.ChangeConfig(instance, flavorId)
|
||||
}
|
||||
@@ -464,35 +466,30 @@ func (region *SRegion) ChangeConfig(instance *SInstance, flavorId string) error
|
||||
"flavorRef": flavorId,
|
||||
},
|
||||
}
|
||||
_, maxVersion, _ := region.GetVersion("compute")
|
||||
_, _, err := region.Post("compute", fmt.Sprintf("/servers/%s/action", instance.ID), maxVersion, jsonutils.Marshal(params))
|
||||
resource := fmt.Sprintf("/servers/%s/action", instance.Id)
|
||||
_, err := region.ecsPost(resource, params)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "ecsPost")
|
||||
}
|
||||
if err := cloudprovider.WaitStatus(instance, api.VM_SYNC_CONFIG, time.Second*3, time.Minute*4); err != nil {
|
||||
return err
|
||||
err = cloudprovider.WaitStatus(instance, api.VM_SYNC_CONFIG, time.Second*3, time.Minute*4)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "WaitStatsAfterChangeConfig")
|
||||
}
|
||||
return region.instanceOperation(instance.ID, "confirmResize")
|
||||
return region.instanceOperation(instance.Id, "confirmResize")
|
||||
}
|
||||
|
||||
func (instance *SInstance) AttachDisk(ctx context.Context, diskId string) error {
|
||||
return instance.host.zone.region.AttachDisk(instance.ID, diskId)
|
||||
return instance.host.zone.region.AttachDisk(instance.Id, diskId)
|
||||
}
|
||||
|
||||
func (instance *SInstance) DetachDisk(ctx context.Context, diskId string) error {
|
||||
return instance.host.zone.region.DetachDisk(instance.ID, diskId)
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateInstance(name string, imageId string, instanceType string, securityGroupId string,
|
||||
zoneId string, desc string, passwd string, disks []SDisk, networkId string, ipAddr string,
|
||||
keypair string, userData string, bc *billing.SBillingCycle) (string, error) {
|
||||
return "", cloudprovider.ErrNotImplemented
|
||||
return instance.host.zone.region.DetachDisk(instance.Id, diskId)
|
||||
}
|
||||
|
||||
func (region *SRegion) instanceOperation(instanceId, operate string) error {
|
||||
params := jsonutils.Marshal(map[string]string{operate: ""})
|
||||
_, maxVersion, _ := region.GetVersion("compute")
|
||||
_, _, err := region.Post("compute", fmt.Sprintf("/servers/%s/action", instanceId), maxVersion, params)
|
||||
params := map[string]string{operate: ""}
|
||||
resource := fmt.Sprintf("/servers/%s/action", instanceId)
|
||||
_, err := region.ecsPost(resource, params)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -515,11 +512,10 @@ func (region *SRegion) StopVM(instanceId string, isForce bool) error {
|
||||
func (region *SRegion) DeleteVM(instanceId string) error {
|
||||
instance, err := region.GetInstance(instanceId)
|
||||
if err != nil {
|
||||
if err == cloudprovider.ErrNotFound {
|
||||
if errors.Cause(err) == cloudprovider.ErrNotFound {
|
||||
return nil
|
||||
}
|
||||
log.Errorf("failed to get instance %s %v", instanceId, err)
|
||||
return err
|
||||
return errors.Wrapf(err, "GetInstance(%s)", instanceId)
|
||||
}
|
||||
status := instance.GetStatus()
|
||||
log.Debugf("Instance status on delete is %s", status)
|
||||
@@ -536,15 +532,15 @@ func (region *SRegion) DeployVM(instanceId string, name string, password string,
|
||||
"adminPass": password,
|
||||
},
|
||||
}
|
||||
_, maxVersion, _ := region.GetVersion("compute")
|
||||
_, _, err := region.Post("compute", fmt.Sprintf("/servers/%s/action", instanceId), maxVersion, jsonutils.Marshal(params))
|
||||
resource := fmt.Sprintf("/servers/%s/action", instanceId)
|
||||
_, err := region.ecsPost(resource, params)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (instance *SInstance) DeleteVM(ctx context.Context) error {
|
||||
return instance.host.zone.region.DeleteVM(instance.ID)
|
||||
return instance.host.zone.region.DeleteVM(instance.Id)
|
||||
}
|
||||
|
||||
func (region *SRegion) ReplaceSystemDisk(instanceId string, imageId string, passwd string, publicKey string, sysDiskSizeGB int) error {
|
||||
@@ -565,31 +561,23 @@ func (region *SRegion) ReplaceSystemDisk(instanceId string, imageId string, pass
|
||||
if len(passwd) > 0 {
|
||||
params["rebuild"]["adminPass"] = passwd
|
||||
}
|
||||
|
||||
_, maxVersion, _ := region.GetVersion("compute")
|
||||
_, _, err := region.Post("compute", fmt.Sprintf("/servers/%s/action", instanceId), maxVersion, jsonutils.Marshal(params))
|
||||
resource := fmt.Sprintf("/servers/%s/action", instanceId)
|
||||
_, err := region.ecsPost(resource, params)
|
||||
return err
|
||||
}
|
||||
|
||||
func (region *SRegion) ChangeVMConfig(zoneId string, instanceId string, ncpu int, vmem int, disks []*SDisk) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (region *SRegion) ChangeVMConfig2(zoneId string, instanceId string, instanceType string, disks []*SDisk) error {
|
||||
return cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (region *SRegion) DetachDisk(instanceId string, diskId string) error {
|
||||
_, err := region.Delete("compute", fmt.Sprintf("/servers/%s/os-volume_attachments/%s", instanceId, diskId), "")
|
||||
resource := fmt.Sprintf("/servers/%s/os-volume_attachments/%s", instanceId, diskId)
|
||||
_, err := region.ecsDelete(resource)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "ecsDelete")
|
||||
}
|
||||
status := ""
|
||||
startTime := time.Now()
|
||||
for time.Now().Sub(startTime) < time.Minute*10 {
|
||||
disk, err := region.GetDisk(diskId)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrapf(err, "GetDisk(%s)", diskId)
|
||||
}
|
||||
status = disk.Status
|
||||
log.Debugf("status %s expect %s", status, DISK_STATUS_AVAILABLE)
|
||||
@@ -607,16 +595,17 @@ func (region *SRegion) AttachDisk(instanceId string, diskId string) error {
|
||||
"volumeId": diskId,
|
||||
},
|
||||
}
|
||||
_, _, err := region.Post("compute", fmt.Sprintf("/servers/%s/os-volume_attachments", instanceId), "", jsonutils.Marshal(params))
|
||||
resource := fmt.Sprintf("/servers/%s/os-volume_attachments", instanceId)
|
||||
_, err := region.ecsPost(resource, params)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "ecsPost")
|
||||
}
|
||||
status := ""
|
||||
startTime := time.Now()
|
||||
for time.Now().Sub(startTime) < time.Minute*10 {
|
||||
disk, err := region.GetDisk(diskId)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrapf(err, "GetDisk(%s)", diskId)
|
||||
}
|
||||
status = disk.Status
|
||||
log.Debugf("status %s expect %s", status, DISK_STATUS_IN_USE)
|
||||
@@ -636,8 +625,8 @@ func (region *SRegion) MigrateVM(instanceId string, hostName string) error {
|
||||
migrate.Add(jsonutils.NewString(hostName), "host")
|
||||
}
|
||||
params.Add(migrate, "migrate")
|
||||
_, maxVersion, _ := region.GetVersion("compute")
|
||||
_, _, err := region.Post("compute", fmt.Sprintf("/servers/%s/action", instanceId), maxVersion, jsonutils.Marshal(params))
|
||||
resource := fmt.Sprintf("/servers/%s/action", instanceId)
|
||||
_, err := region.ecsPost(resource, params)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "On Requst Migrate instance:%s", instanceId)
|
||||
}
|
||||
@@ -653,8 +642,8 @@ func (region *SRegion) LiveMigrateVM(instanceId string, hostName string) error {
|
||||
osMigrateLive.Add(jsonutils.NewString(hostName), "host")
|
||||
}
|
||||
params.Add(osMigrateLive, "os-migrateLive")
|
||||
_, maxVersion, _ := region.GetVersion("compute")
|
||||
_, _, err := region.Post("compute", fmt.Sprintf("/servers/%s/action", instanceId), maxVersion, params)
|
||||
resource := fmt.Sprintf("/servers/%s/action", instanceId)
|
||||
_, err := region.ecsPost(resource, params)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "On Requst LiveMigrate instance:%s", instanceId)
|
||||
}
|
||||
@@ -663,8 +652,8 @@ func (region *SRegion) LiveMigrateVM(instanceId string, hostName string) error {
|
||||
|
||||
//仅live-migration
|
||||
func (region *SRegion) ListServerMigration(instanceId string) error {
|
||||
_, maxVersion, _ := region.GetVersion("compute")
|
||||
_, _, err := region.Get("compute", fmt.Sprintf("/servers/%s/migrations", instanceId), maxVersion, nil)
|
||||
resource := fmt.Sprintf("/servers/%s/migrations", instanceId)
|
||||
_, err := region.ecsGet(resource)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "ListServerMigration")
|
||||
}
|
||||
@@ -673,8 +662,8 @@ func (region *SRegion) ListServerMigration(instanceId string) error {
|
||||
|
||||
//仅live-migration
|
||||
func (region *SRegion) DeleteMigration(instanceId string, migrationId string) error {
|
||||
_, maxVersion, _ := region.GetVersion("compute")
|
||||
_, err := region.Delete("compute", fmt.Sprintf("/servers/%s/migrations/%s", instanceId, migrationId), maxVersion)
|
||||
resource := fmt.Sprintf("/servers/%s/migrations/%s", instanceId, migrationId)
|
||||
_, err := region.ecsDelete(resource)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "On Requst delete LiveMigrate:%s", migrationId)
|
||||
}
|
||||
@@ -685,8 +674,8 @@ func (region *SRegion) DeleteMigration(instanceId string, migrationId string) er
|
||||
func (region *SRegion) ForceCompleteMigration(instanceId string, migrationId string) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.JSONNull, "force_complete")
|
||||
_, maxVersion, _ := region.GetVersion("compute")
|
||||
_, _, err := region.Post("compute", fmt.Sprintf("/servers/%s/migrations/%s/action", instanceId, migrationId), maxVersion, params)
|
||||
resource := fmt.Sprintf("/servers/%s/migrations/%s/action", instanceId, migrationId)
|
||||
_, err := region.ecsPost(resource, params)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "On Requst delete LiveMigrate:%s", migrationId)
|
||||
}
|
||||
@@ -694,14 +683,11 @@ func (region *SRegion) ForceCompleteMigration(instanceId string, migrationId str
|
||||
}
|
||||
|
||||
func (region *SRegion) GetMigrations(instanceId string, migrationType string) (jsonutils.JSONObject, error) {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(instanceId), "instance_uuid")
|
||||
params.Add(jsonutils.NewString(migrationType), "migration_type")
|
||||
query := url.Values{}
|
||||
query.Set("instance_uuid", instanceId)
|
||||
query.Set("migration_type", migrationType)
|
||||
_, maxVersion, _ := region.GetVersion("compute")
|
||||
_, migrations, err := region.Get("compute", "/os-migrations?"+query.Encode(), maxVersion, nil)
|
||||
resource := "/os-migrations"
|
||||
migrations, err := region.ecsList(resource, query)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "On Get instance :%s Migration,migration_type:%s", instanceId, migrationType)
|
||||
}
|
||||
@@ -714,14 +700,15 @@ func (instance *SInstance) AssignSecurityGroup(secgroupId string) error {
|
||||
}
|
||||
secgroup, err := instance.host.zone.region.GetSecurityGroup(secgroupId)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrapf(err, "GetSecurityGroup(%s)", secgroupId)
|
||||
}
|
||||
params := map[string]map[string]string{
|
||||
"addSecurityGroup": {
|
||||
"name": secgroup.Name,
|
||||
},
|
||||
}
|
||||
_, _, err = instance.host.zone.region.Post("compute", fmt.Sprintf("/servers/%s/action", instance.ID), "", jsonutils.Marshal(params))
|
||||
resource := fmt.Sprintf("/servers/%s/action", instance.Id)
|
||||
_, err = instance.host.zone.region.ecsDo(instance.GetProjectId(), resource, params)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -732,36 +719,43 @@ func (instance *SInstance) RevokeSecurityGroup(secgroupId string) error {
|
||||
}
|
||||
secgroup, err := instance.host.zone.region.GetSecurityGroup(secgroupId)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrapf(err, "GetSecurityGroup(%s)", secgroupId)
|
||||
}
|
||||
params := map[string]map[string]string{
|
||||
"removeSecurityGroup": {
|
||||
"name": secgroup.Name,
|
||||
},
|
||||
}
|
||||
_, _, err = instance.host.zone.region.Post("compute", fmt.Sprintf("/servers/%s/action", instance.ID), "", jsonutils.Marshal(params))
|
||||
resource := fmt.Sprintf("/servers/%s/action", instance.Id)
|
||||
_, err = instance.host.zone.region.ecsDo(instance.GetProjectId(), resource, params)
|
||||
return err
|
||||
}
|
||||
|
||||
func (instance *SInstance) SetSecurityGroups(secgroupIds []string) error {
|
||||
secgroups, err := instance.host.zone.region.GetSecurityGroupsByInstance(instance.ID)
|
||||
secgroups, err := instance.host.zone.region.GetSecurityGroupsByInstance(instance.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrapf(err, "GetSecurityGroupsByInstance(%s)", instance.Id)
|
||||
}
|
||||
originIds := []string{}
|
||||
local := set.New(set.ThreadSafe)
|
||||
for _, secgroup := range secgroups {
|
||||
if !utils.IsInStringArray(secgroup.ID, secgroupIds) {
|
||||
if err := instance.RevokeSecurityGroup(secgroup.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
originIds = append(originIds, secgroup.ID)
|
||||
local.Add(secgroup.Id)
|
||||
}
|
||||
newG := set.New(set.ThreadSafe)
|
||||
for _, secgroupId := range secgroupIds {
|
||||
if !utils.IsInStringArray(secgroupId, originIds) {
|
||||
if err := instance.AssignSecurityGroup(secgroupId); err != nil {
|
||||
return err
|
||||
}
|
||||
newG.Add(secgroupId)
|
||||
}
|
||||
for _, del := range set.Difference(local, newG).List() {
|
||||
secgroupId := del.(string)
|
||||
err := instance.RevokeSecurityGroup(secgroupId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "RevokeSecurityGroup(%s)", secgroupId)
|
||||
}
|
||||
}
|
||||
for _, add := range set.Difference(newG, local).List() {
|
||||
secgroupId := add.(string)
|
||||
err := instance.AssignSecurityGroup(secgroupId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "AssignSecurityGroup(%s)", secgroupId)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -807,12 +801,12 @@ func (region *SRegion) RenewInstances(instanceId []string, bc billing.SBillingCy
|
||||
}
|
||||
|
||||
func (instance *SInstance) GetProjectId() string {
|
||||
return instance.TenantID
|
||||
return instance.TenantId
|
||||
}
|
||||
|
||||
func (self *SInstance) GetError() error {
|
||||
if self.Status == INSTANCE_STATUS_ERROR && len(self.Fault.Message) > 0 {
|
||||
return fmt.Errorf(self.Fault.Message)
|
||||
return errors.Error(self.Fault.Message)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -828,10 +822,12 @@ func (instance *SInstance) MigrateVM(hostId string) error {
|
||||
}
|
||||
|
||||
previousHostName := instance.Host
|
||||
if err := instance.host.zone.region.MigrateVM(instance.ID, hostName); err != nil {
|
||||
err := instance.host.zone.region.MigrateVM(instance.Id, hostName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "MigrateVm")
|
||||
}
|
||||
if err := cloudprovider.WaitMultiStatus(instance, []string{api.VM_SYNC_CONFIG, api.VM_READY, api.VM_UNKNOWN}, time.Second*10, time.Hour*3); err != nil {
|
||||
err = cloudprovider.WaitMultiStatus(instance, []string{api.VM_SYNC_CONFIG, api.VM_READY, api.VM_UNKNOWN}, time.Second*10, time.Hour*3)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "WaitMultiStatus")
|
||||
}
|
||||
if instance.GetStatus() == api.VM_UNKNOWN {
|
||||
@@ -843,7 +839,7 @@ func (instance *SInstance) MigrateVM(hostId string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return instance.host.zone.region.instanceOperation(instance.ID, "confirmResize")
|
||||
return instance.host.zone.region.instanceOperation(instance.Id, "confirmResize")
|
||||
}
|
||||
|
||||
func (instance *SInstance) LiveMigrateVM(hostId string) error {
|
||||
@@ -856,10 +852,12 @@ func (instance *SInstance) LiveMigrateVM(hostId string) error {
|
||||
hostName = iHost.GetName()
|
||||
}
|
||||
previousHostName := instance.Host
|
||||
if err := instance.host.zone.region.LiveMigrateVM(instance.ID, hostName); err != nil {
|
||||
err := instance.host.zone.region.LiveMigrateVM(instance.Id, hostName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "LiveMIgrateVm")
|
||||
}
|
||||
if err := cloudprovider.WaitMultiStatus(instance, []string{api.VM_SYNC_CONFIG, api.VM_RUNNING, api.VM_UNKNOWN}, time.Second*10, time.Hour*3); err != nil {
|
||||
err = cloudprovider.WaitMultiStatus(instance, []string{api.VM_SYNC_CONFIG, api.VM_RUNNING, api.VM_UNKNOWN}, time.Second*10, time.Hour*3)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "WaitMultiStatus")
|
||||
}
|
||||
if instance.GetStatus() == api.VM_UNKNOWN {
|
||||
@@ -871,18 +869,178 @@ func (instance *SInstance) LiveMigrateVM(hostId string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return instance.host.zone.region.instanceOperation(instance.ID, "confirmResize")
|
||||
return instance.host.zone.region.instanceOperation(instance.Id, "confirmResize")
|
||||
}
|
||||
func (instance *SInstance) GetIHostId() string {
|
||||
iHosts, err := instance.host.zone.region.GetIHosts()
|
||||
err := instance.host.zone.fetchHosts()
|
||||
if err != nil {
|
||||
log.Errorf("instance.host.zone.region.GetIHosts error:%s", err)
|
||||
return ""
|
||||
}
|
||||
for _, iHost := range iHosts {
|
||||
if iHost.GetName() == instance.Host {
|
||||
return iHost.GetId()
|
||||
for _, host := range instance.host.zone.hosts {
|
||||
if instance.HypervisorHostname == host.HypervisorHostname {
|
||||
return host.GetGlobalId()
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (region *SRegion) GetInstanceMetadata(instanceId string) (map[string]string, error) {
|
||||
resource := fmt.Sprintf("/servers/%s/metadata", instanceId)
|
||||
resp, err := region.ecsList(resource, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ecsList")
|
||||
}
|
||||
result := struct {
|
||||
Metadata map[string]string
|
||||
}{}
|
||||
err = resp.Unmarshal(&result)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return result.Metadata, nil
|
||||
}
|
||||
|
||||
func (zone *SZone) CreateVM(hypervisor string, opts *cloudprovider.SManagedVMCreateConfig) (*SInstance, error) {
|
||||
region := zone.region
|
||||
network, err := region.GetNetwork(opts.ExternalNetworkId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
secgroups := []map[string]string{}
|
||||
for _, secgroupId := range opts.ExternalSecgroupIds {
|
||||
if secgroupId != SECGROUP_NOT_SUPPORT {
|
||||
secgroups = append(secgroups, map[string]string{"name": secgroupId})
|
||||
}
|
||||
}
|
||||
|
||||
image, err := region.GetImage(opts.ExternalImageId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetImage(%s)", opts.ExternalImageId)
|
||||
}
|
||||
|
||||
sysDiskSizeGB := image.Size / 1024 / 1024 / 1024
|
||||
if opts.SysDisk.SizeGB < sysDiskSizeGB {
|
||||
opts.SysDisk.SizeGB = sysDiskSizeGB
|
||||
}
|
||||
|
||||
if opts.SysDisk.SizeGB < image.GetMinOsDiskSizeGb() {
|
||||
opts.SysDisk.SizeGB = image.GetMinOsDiskSizeGb()
|
||||
}
|
||||
|
||||
BlockDeviceMappingV2 := []map[string]interface{}{}
|
||||
|
||||
diskIds := []string{}
|
||||
|
||||
defer func() {
|
||||
for _, diskId := range diskIds {
|
||||
err = region.DeleteDisk(diskId)
|
||||
if err != nil {
|
||||
log.Errorf("clean disk %s error: %v", diskId, err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if opts.SysDisk.StorageType != api.STORAGE_OPENSTACK_NOVA { //新建volume
|
||||
istorage, err := zone.GetIStorageById(opts.SysDisk.StorageExternalId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetIStorageById(%s)", opts.SysDisk.StorageExternalId)
|
||||
}
|
||||
|
||||
_sysDisk, err := region.CreateDisk(opts.ExternalImageId, istorage.GetName(), "", opts.SysDisk.SizeGB, opts.SysDisk.Name, opts.ProjectId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "CreateDisk %s", opts.SysDisk.Name)
|
||||
}
|
||||
|
||||
diskIds = append(diskIds, _sysDisk.GetGlobalId())
|
||||
|
||||
BlockDeviceMappingV2 = append(BlockDeviceMappingV2, map[string]interface{}{
|
||||
"boot_index": 0,
|
||||
"uuid": _sysDisk.GetGlobalId(),
|
||||
"source_type": "volume",
|
||||
"destination_type": "volume",
|
||||
"delete_on_termination": true,
|
||||
})
|
||||
} else {
|
||||
BlockDeviceMappingV2 = append(BlockDeviceMappingV2, map[string]interface{}{
|
||||
"boot_index": 0,
|
||||
"uuid": image.Id,
|
||||
"source_type": "image",
|
||||
"destination_type": "local",
|
||||
"delete_on_termination": true,
|
||||
})
|
||||
}
|
||||
|
||||
var _disk *SDisk
|
||||
for index, disk := range opts.DataDisks {
|
||||
istorage, err := zone.GetIStorageById(disk.StorageExternalId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetIStorageById(%s)", disk.StorageExternalId)
|
||||
}
|
||||
_disk, err = region.CreateDisk("", istorage.GetName(), "", disk.SizeGB, disk.Name, opts.ProjectId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "CreateDisk %s", disk.Name)
|
||||
}
|
||||
diskIds = append(diskIds, _disk.Id)
|
||||
|
||||
mapping := map[string]interface{}{
|
||||
"source_type": "volume",
|
||||
"destination_type": "volume",
|
||||
"delete_on_termination": true,
|
||||
"boot_index": index + 1,
|
||||
"uuid": _disk.Id,
|
||||
}
|
||||
|
||||
BlockDeviceMappingV2 = append(BlockDeviceMappingV2, mapping)
|
||||
}
|
||||
|
||||
az := zone.ZoneName
|
||||
if len(hypervisor) > 0 {
|
||||
az = fmt.Sprintf("%s:%s", zone.ZoneName, hypervisor)
|
||||
}
|
||||
|
||||
params := map[string]map[string]interface{}{
|
||||
"server": {
|
||||
"name": opts.Name,
|
||||
"adminPass": opts.Password,
|
||||
"accessIPv4": opts.IpAddr,
|
||||
"availability_zone": az,
|
||||
"networks": []map[string]string{
|
||||
{
|
||||
"uuid": network.NetworkId,
|
||||
"fixed_ip": opts.IpAddr,
|
||||
},
|
||||
},
|
||||
"security_groups": secgroups,
|
||||
"user_data": opts.UserData,
|
||||
"imageRef": opts.ExternalImageId,
|
||||
"block_device_mapping_v2": BlockDeviceMappingV2,
|
||||
},
|
||||
}
|
||||
|
||||
flavorId, err := region.syncFlavor(opts.InstanceType, opts.Cpu, opts.MemoryMB, opts.SysDisk.SizeGB)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
params["server"]["flavorRef"] = flavorId
|
||||
|
||||
if len(opts.PublicKey) > 0 {
|
||||
keypairName, err := region.syncKeypair(opts.Name, opts.PublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
params["server"]["key_name"] = keypairName
|
||||
}
|
||||
|
||||
resp, err := region.ecsCreate(opts.ProjectId, "/servers", params)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ecsCreate")
|
||||
}
|
||||
diskIds = []string{}
|
||||
instance := &SInstance{}
|
||||
err = resp.Unmarshal(instance, "server")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return instance, nil
|
||||
}
|
||||
|
||||
@@ -15,56 +15,80 @@
|
||||
package openstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/regutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
)
|
||||
|
||||
type SInstanceNic struct {
|
||||
instance *SInstance
|
||||
MacAddr string `json:"OS-EXT-IPS-MAC:mac_addr"`
|
||||
Version int `json:"version"`
|
||||
Addr string `json:"addr"`
|
||||
Type string `json:"OS-EXT-IPS:type"`
|
||||
MacAddr string `json:"OS-EXT-IPS-MAC:mac_addr"`
|
||||
Version int `json:"version"`
|
||||
Addr string `json:"addr"`
|
||||
Type string `json:"OS-EXT-IPS:type"`
|
||||
}
|
||||
|
||||
func (nic *SInstanceNic) GetIP() string {
|
||||
return nic.Addr
|
||||
type SFixedIp struct {
|
||||
IpAddress string
|
||||
SubnetId string
|
||||
}
|
||||
|
||||
func (nic *SInstanceNic) GetMAC() string {
|
||||
type SInstancePort struct {
|
||||
region *SRegion
|
||||
FixedIps []SFixedIp
|
||||
MacAddr string
|
||||
NetId string
|
||||
PortId string
|
||||
PortState string
|
||||
}
|
||||
|
||||
func (region *SRegion) GetInstancePorts(instanceId string) ([]SInstancePort, error) {
|
||||
resource := fmt.Sprintf("/servers/%s/os-interface", instanceId)
|
||||
resp, err := region.ecsList(resource, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ecsList")
|
||||
}
|
||||
ports := []SInstancePort{}
|
||||
err = resp.Unmarshal(&ports, "interfaceAttachments")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return ports, nil
|
||||
}
|
||||
|
||||
func (nic *SInstancePort) GetIP() string {
|
||||
for i := range nic.FixedIps {
|
||||
if regutils.MatchIPAddr(nic.FixedIps[i].IpAddress) {
|
||||
return nic.FixedIps[i].IpAddress
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (nic *SInstancePort) GetMAC() string {
|
||||
return nic.MacAddr
|
||||
}
|
||||
|
||||
func (nic *SInstanceNic) GetDriver() string {
|
||||
func (nic *SInstancePort) GetDriver() string {
|
||||
return "virtio"
|
||||
}
|
||||
|
||||
func (nic *SInstanceNic) InClassicNetwork() bool {
|
||||
func (nic *SInstancePort) InClassicNetwork() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (nic *SInstanceNic) GetINetwork() cloudprovider.ICloudNetwork {
|
||||
ports, err := nic.instance.host.zone.region.GetPorts(nic.MacAddr)
|
||||
if err == nil {
|
||||
for i := 0; i < len(ports); i++ {
|
||||
for j := 0; j < len(ports[i].FixedIps); j++ {
|
||||
if ports[i].FixedIps[j].IpAddress == nic.Addr {
|
||||
network, err := nic.instance.host.zone.region.GetNetwork(ports[i].FixedIps[j].SubnetID)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
wires, err := nic.instance.host.zone.GetIWires()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
for k := 0; k < len(wires); k++ {
|
||||
wire := wires[k].(*SWire)
|
||||
if net, _ := wire.GetINetworkById(network.ID); net != nil {
|
||||
return net
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (nic *SInstancePort) GetINetwork() cloudprovider.ICloudNetwork {
|
||||
for i := range nic.FixedIps {
|
||||
if regutils.MatchIPAddr(nic.FixedIps[i].IpAddress) {
|
||||
network, err := nic.region.GetNetwork(nic.FixedIps[i].SubnetId)
|
||||
if err != nil {
|
||||
log.Errorf("failed to found network by %s error: %v", nic.FixedIps[i].SubnetId, err)
|
||||
return nil
|
||||
}
|
||||
return network
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -16,12 +16,11 @@ package openstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/utils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/util/version"
|
||||
)
|
||||
|
||||
type SKeypair struct {
|
||||
@@ -36,48 +35,70 @@ type SKeyPair struct {
|
||||
}
|
||||
|
||||
func (region *SRegion) GetKeypairs() ([]SKeyPair, error) {
|
||||
_, resp, err := region.List("compute", "/os-keypairs", "", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keypairs := []SKeyPair{}
|
||||
return keypairs, resp.Unmarshal(&keypairs, "keypairs")
|
||||
resource := "/os-keypairs"
|
||||
query := url.Values{}
|
||||
for {
|
||||
resp, err := region.ecsList(resource, query)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ecsList")
|
||||
}
|
||||
part := struct {
|
||||
Keypairs []SKeyPair
|
||||
KeypairsLinks SNextLinks
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
keypairs = append(keypairs, part.Keypairs...)
|
||||
marker := part.KeypairsLinks.GetNextMark()
|
||||
if len(marker) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", marker)
|
||||
}
|
||||
return keypairs, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateKeypair(name, publicKey, Type string) (*SKeyPair, error) {
|
||||
if len(Type) > 0 && !utils.IsInStringArray(Type, []string{"ssh", "x509"}) {
|
||||
return nil, fmt.Errorf("only support ssh or x509 type")
|
||||
}
|
||||
params := map[string]map[string]string{
|
||||
"keypair": {
|
||||
"name": name,
|
||||
"public_key": publicKey,
|
||||
},
|
||||
}
|
||||
_, maxVersion, _ := region.GetVersion("compute")
|
||||
if len(Type) > 0 && version.GE(maxVersion, "2.2") {
|
||||
if len(Type) > 0 {
|
||||
params["keypair"]["type"] = Type
|
||||
}
|
||||
_, resp, err := region.Post("compute", "/os-keypairs", maxVersion, jsonutils.Marshal(params))
|
||||
resp, err := region.ecsPost("/os-keypairs", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "ecsPost")
|
||||
}
|
||||
keypair := &SKeyPair{}
|
||||
return keypair, resp.Unmarshal(keypair)
|
||||
err = resp.Unmarshal(keypair)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return keypair, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) DeleteKeypair(name string) error {
|
||||
_, err := region.Delete("compute", "/os-keypairs/"+name, "")
|
||||
_, err := region.ecsDelete("/os-keypairs/" + name)
|
||||
return err
|
||||
}
|
||||
|
||||
func (region *SRegion) GetKeypair(name string) (*SKeyPair, error) {
|
||||
_, resp, err := region.Get("compute", "/os-keypairs/"+name, "", nil)
|
||||
resp, err := region.ecsGet("/os-keypairs/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "ecsGet")
|
||||
}
|
||||
keypair := &SKeyPair{}
|
||||
return keypair, resp.Unmarshal(keypair)
|
||||
err = resp.Unmarshal(keypair)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return keypair, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) syncKeypair(namePrefix, publicKey string) (string, error) {
|
||||
|
||||
@@ -12,25 +12,32 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package shell
|
||||
package openstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
import "net/url"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/multicloud/openstack"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
)
|
||||
type SMessage struct {
|
||||
Id string
|
||||
MessageLevel string
|
||||
EventId string
|
||||
ResourceType string
|
||||
UserMessage string
|
||||
}
|
||||
|
||||
func init() {
|
||||
type VersionOptions struct {
|
||||
SERVICE string `help:"Service name" choices:"compute|volume|volumev2|volumev3"`
|
||||
func (region *SRegion) GetMessages(resourceId string) ([]SMessage, error) {
|
||||
messages := []SMessage{}
|
||||
resource := "messages"
|
||||
query := url.Values{}
|
||||
if len(resourceId) > 0 {
|
||||
query.Set("resource_uuid", resourceId)
|
||||
}
|
||||
shellutils.R(&VersionOptions{}, "version-show", "Show a service version", func(cli *openstack.SRegion, args *VersionOptions) error {
|
||||
minVersion, maxVersion, err := cli.GetVersion(args.SERVICE)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("min version: %s max version: %s\n", minVersion, maxVersion)
|
||||
return nil
|
||||
})
|
||||
resp, err := region.bsList(resource, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = resp.Unmarshal(&messages, "messages")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return messages, nil
|
||||
}
|
||||
@@ -15,6 +15,8 @@
|
||||
package openstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -33,6 +35,25 @@ type AllocationPool struct {
|
||||
End string
|
||||
}
|
||||
|
||||
type SNextLinks []SNextLink
|
||||
|
||||
func (links SNextLinks) GetNextMark() string {
|
||||
for _, link := range links {
|
||||
if link.Rel == "next" && len(link.Href) > 0 {
|
||||
href, err := url.Parse(link.Href)
|
||||
if err != nil {
|
||||
log.Errorf("failed parse next link %s error: %v", link.Href, err)
|
||||
continue
|
||||
}
|
||||
marker := href.Query().Get("marker")
|
||||
if len(marker) > 0 {
|
||||
return marker
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type SNextLink struct {
|
||||
Href string
|
||||
Rel string
|
||||
@@ -43,24 +64,24 @@ type SNetwork struct {
|
||||
|
||||
Name string
|
||||
EnableDhcp bool
|
||||
NetworkID string
|
||||
SegmentID string
|
||||
ProjectID string
|
||||
TenantID string
|
||||
NetworkId string
|
||||
SegmentId string
|
||||
ProjectId string
|
||||
TenantId string
|
||||
DnsNameservers []string
|
||||
AllocationPools []AllocationPool
|
||||
HostRoutes []string
|
||||
IpVersion int
|
||||
GatewayIP string
|
||||
CIDR string
|
||||
ID string
|
||||
Id string
|
||||
CreatedAt time.Time
|
||||
Description string
|
||||
Ipv6AddressMode string
|
||||
Ipv6RaMode string
|
||||
RevisionNumber int
|
||||
ServiceTypes []string
|
||||
SubnetpoolID string
|
||||
SubnetpoolId string
|
||||
Tags []string
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
@@ -70,18 +91,18 @@ func (network *SNetwork) GetMetadata() *jsonutils.JSONDict {
|
||||
}
|
||||
|
||||
func (network *SNetwork) GetId() string {
|
||||
return network.ID
|
||||
return network.Id
|
||||
}
|
||||
|
||||
func (network *SNetwork) GetName() string {
|
||||
if len(network.Name) > 0 {
|
||||
return network.Name
|
||||
}
|
||||
return network.ID
|
||||
return network.Id
|
||||
}
|
||||
|
||||
func (network *SNetwork) GetGlobalId() string {
|
||||
return network.ID
|
||||
return network.Id
|
||||
}
|
||||
|
||||
func (network *SNetwork) IsEmulated() bool {
|
||||
@@ -93,11 +114,12 @@ func (network *SNetwork) GetStatus() string {
|
||||
}
|
||||
|
||||
func (network *SNetwork) Delete() error {
|
||||
return network.wire.zone.region.DeleteNetwork(network.ID)
|
||||
return network.wire.zone.region.DeleteNetwork(network.Id)
|
||||
}
|
||||
|
||||
func (region *SRegion) DeleteNetwork(networkId string) error {
|
||||
_, err := region.Delete("network", "/v2.0/subnets/"+networkId, "")
|
||||
resource := fmt.Sprintf("/v2.0/subnets/%s", networkId)
|
||||
_, err := region.vpcDelete(resource)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -147,11 +169,14 @@ func (network *SNetwork) GetIpMask() int8 {
|
||||
}
|
||||
|
||||
func (network *SNetwork) GetIsPublic() bool {
|
||||
return false
|
||||
return network.wire.vpc.Shared
|
||||
}
|
||||
|
||||
func (network *SNetwork) GetPublicScope() rbacutils.TRbacScope {
|
||||
return rbacutils.ScopeProject
|
||||
if network.wire.vpc.Shared {
|
||||
return rbacutils.ScopeSystem
|
||||
}
|
||||
return rbacutils.ScopeNone
|
||||
}
|
||||
|
||||
func (network *SNetwork) GetServerType() string {
|
||||
@@ -159,63 +184,61 @@ func (network *SNetwork) GetServerType() string {
|
||||
}
|
||||
|
||||
func (region *SRegion) GetNetwork(networkId string) (*SNetwork, error) {
|
||||
_, resp, err := region.Get("network", "/v2.0/subnets/"+networkId, "", nil)
|
||||
resource := fmt.Sprintf("/v2.0/subnets/%s", networkId)
|
||||
resp, err := region.vpcGet(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
network := SNetwork{}
|
||||
return &network, resp.Unmarshal(&network, "subnet")
|
||||
network := &SNetwork{}
|
||||
err = resp.Unmarshal(network, "subnet")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return network, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetNetworks(vpcId string) ([]SNetwork, error) {
|
||||
url := "/v2.0/subnets"
|
||||
resource := "/v2.0/subnets"
|
||||
networks := []SNetwork{}
|
||||
for len(url) > 0 {
|
||||
_, resp, err := region.List("network", url, "", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_networks := []SNetwork{}
|
||||
err = resp.Unmarshal(&_networks, "subnets")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, `resp.Unmarshal(&_networks, "subnets")`)
|
||||
}
|
||||
networks = append(networks, _networks...)
|
||||
url = ""
|
||||
if resp.Contains("subnets_links") {
|
||||
nextLinks := []SNextLink{}
|
||||
err = resp.Unmarshal(&nextLinks, "subnets_links")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "resp.Unmarshal(subnets_links)")
|
||||
}
|
||||
for _, next := range nextLinks {
|
||||
if next.Rel == "next" {
|
||||
url = next.Href
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
query := url.Values{}
|
||||
if len(vpcId) > 0 {
|
||||
query.Set("network_id", vpcId)
|
||||
}
|
||||
for {
|
||||
resp, err := region.vpcList(resource, query)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "vpcList")
|
||||
}
|
||||
|
||||
result := []SNetwork{}
|
||||
for i := 0; i < len(networks); i++ {
|
||||
if len(vpcId) == 0 || vpcId == networks[i].NetworkID {
|
||||
result = append(result, networks[i])
|
||||
part := struct {
|
||||
Subnets []SNetwork
|
||||
SubnetsLinks SNextLinks
|
||||
}{}
|
||||
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
|
||||
networks = append(networks, part.Subnets...)
|
||||
marker := part.SubnetsLinks.GetNextMark()
|
||||
if len(marker) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", marker)
|
||||
}
|
||||
return result, nil
|
||||
return networks, nil
|
||||
}
|
||||
|
||||
func (network *SNetwork) Refresh() error {
|
||||
log.Debugf("network refresh %s", network.Name)
|
||||
new, err := network.wire.zone.region.GetNetwork(network.ID)
|
||||
_network, err := network.wire.zone.region.GetNetwork(network.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return jsonutils.Update(network, new)
|
||||
return jsonutils.Update(network, _network)
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateNetwork(vpcId string, name string, cidr string, desc string) (string, error) {
|
||||
func (region *SRegion) CreateNetwork(vpcId string, projectId, name string, cidr string, desc string) (*SNetwork, error) {
|
||||
params := map[string]map[string]interface{}{
|
||||
"subnet": {
|
||||
"name": name,
|
||||
@@ -225,13 +248,21 @@ func (region *SRegion) CreateNetwork(vpcId string, name string, cidr string, des
|
||||
"ip_version": 4,
|
||||
},
|
||||
}
|
||||
_, resp, err := region.Post("network", "/v2.0/subnets", "", jsonutils.Marshal(params))
|
||||
if err != nil {
|
||||
return "", err
|
||||
if len(projectId) > 0 {
|
||||
params["subnet"]["project_id"] = projectId
|
||||
}
|
||||
return resp.GetString("subnet", "id")
|
||||
resp, err := region.vpcPost("/v2.0/subnets", params)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "vpcPost")
|
||||
}
|
||||
network := &SNetwork{}
|
||||
err = resp.Unmarshal(network, "subnet")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return network, nil
|
||||
}
|
||||
|
||||
func (network *SNetwork) GetProjectId() string {
|
||||
return network.TenantID
|
||||
return network.TenantId
|
||||
}
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
// 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 openstack
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
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 SNovaDisk struct {
|
||||
multicloud.SDisk
|
||||
storage *SNovaStorage
|
||||
region *SRegion
|
||||
|
||||
instanceId string
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetId() string {
|
||||
return disk.instanceId
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) Delete(ctx context.Context) error {
|
||||
return cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) Resize(ctx context.Context, sizeMb int64) error {
|
||||
return cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetName() string {
|
||||
return fmt.Sprintf("Sys disk for instance %s", disk.instanceId)
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetGlobalId() string {
|
||||
return disk.instanceId
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetIStorage() (cloudprovider.ICloudStorage, error) {
|
||||
return disk.storage, nil
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetStatus() string {
|
||||
return api.DISK_READY
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) Refresh() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetDiskFormat() string {
|
||||
return "raw"
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetDiskSizeMB() int {
|
||||
instance, err := disk.region.GetInstance(disk.instanceId)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
if instance.Flavor.Disk != 0 {
|
||||
return instance.Flavor.Disk * 1024
|
||||
}
|
||||
if len(instance.Flavor.Id) > 0 {
|
||||
flavor, err := disk.region.GetFlavor(instance.Flavor.Id)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return flavor.Disk * 1024
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetIsAutoDelete() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetTemplateId() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetDiskType() string {
|
||||
return api.DISK_TYPE_SYS
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetFsFormat() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetIsNonPersistent() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetDriver() string {
|
||||
return "scsi"
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetCacheMode() string {
|
||||
return "none"
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetMountpoint() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) CreateISnapshot(ctx context.Context, name, desc string) (cloudprovider.ICloudSnapshot, error) {
|
||||
return nil, cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) {
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
|
||||
return []cloudprovider.ICloudSnapshot{}, nil
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) Reset(ctx context.Context, snapshotId string) (string, error) {
|
||||
return "", cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetBillingType() string {
|
||||
return billing_api.BILLING_TYPE_POSTPAID
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetCreatedAt() time.Time {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetExpiredAt() time.Time {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetAccessPath() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) Rebuild(ctx context.Context) error {
|
||||
return cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
func (disk *SNovaDisk) GetProjectId() string {
|
||||
instance, err := disk.region.GetInstance(disk.instanceId)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return instance.GetProjectId()
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
)
|
||||
|
||||
type SNovaStorage struct {
|
||||
host *SHypervisor
|
||||
zone *SZone
|
||||
}
|
||||
|
||||
@@ -32,7 +33,7 @@ func (storage *SNovaStorage) GetMetadata() *jsonutils.JSONDict {
|
||||
}
|
||||
|
||||
func (storage *SNovaStorage) GetId() string {
|
||||
return fmt.Sprintf("%s-%s-%s", storage.zone.region.client.cpcfg.Id, storage.zone.GetGlobalId(), storage.GetName())
|
||||
return fmt.Sprintf("%s-%s-%s", storage.zone.GetGlobalId(), storage.host.GetId(), storage.GetName())
|
||||
}
|
||||
|
||||
func (storage *SNovaStorage) GetName() string {
|
||||
@@ -64,7 +65,7 @@ func (storage *SNovaStorage) GetMediumType() string {
|
||||
}
|
||||
|
||||
func (storage *SNovaStorage) GetCapacityMB() int64 {
|
||||
return 1000000000
|
||||
return int64(storage.host.GetStorageSizeMB())
|
||||
}
|
||||
|
||||
func (storage *SNovaStorage) GetStorageConf() jsonutils.JSONObject {
|
||||
@@ -94,21 +95,7 @@ func (storage *SNovaStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (
|
||||
}
|
||||
|
||||
func (storage *SNovaStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) {
|
||||
instance, err := storage.zone.region.GetInstance(idStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
disk := SDisk{
|
||||
ID: instance.ID,
|
||||
Name: fmt.Sprintf("root disk for %s", instance.Name),
|
||||
Size: instance.Flavor.Disk,
|
||||
Status: DISK_STATUS_IN_USE,
|
||||
Bootable: true,
|
||||
CreatedAt: instance.Created,
|
||||
VolumeType: api.STORAGE_OPENSTACK_NOVA,
|
||||
}
|
||||
disk.nova = storage
|
||||
return &disk, nil
|
||||
return &SNovaDisk{region: storage.zone.region, storage: storage, instanceId: idStr}, nil
|
||||
}
|
||||
|
||||
func (storage *SNovaStorage) GetMountPoint() string {
|
||||
|
||||
@@ -19,11 +19,13 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
@@ -37,6 +39,14 @@ import (
|
||||
const (
|
||||
CLOUD_PROVIDER_OPENSTACK = api.CLOUD_PROVIDER_OPENSTACK
|
||||
OPENSTACK_DEFAULT_REGION = "RegionOne"
|
||||
|
||||
OPENSTACK_SERVICE_COMPUTE = "compute"
|
||||
OPENSTACK_SERVICE_NETWORK = "network"
|
||||
OPENSTACK_SERVICE_IDENTITY = "identity"
|
||||
OPENSTACK_SERVICE_VOLUMEV3 = "volumev3"
|
||||
OPENSTACK_SERVICE_VOLUMEV2 = "volumev2"
|
||||
OPENSTACK_SERVICE_VOLUME = "volume"
|
||||
OPENSTACK_SERVICE_IMAGE = "image"
|
||||
)
|
||||
|
||||
type OpenstackClientConfig struct {
|
||||
@@ -88,18 +98,48 @@ func (cfg *OpenstackClientConfig) Debug(debug bool) *OpenstackClientConfig {
|
||||
type SOpenStackClient struct {
|
||||
*OpenstackClientConfig
|
||||
|
||||
client *mcclient.Client
|
||||
tokenCredential mcclient.TokenCredential
|
||||
iregions []cloudprovider.ICloudRegion
|
||||
|
||||
defaultRegionName string
|
||||
|
||||
projects []SProject
|
||||
}
|
||||
|
||||
func NewOpenStackClient(cfg *OpenstackClientConfig) (*SOpenStackClient, error) {
|
||||
cli := &SOpenStackClient{
|
||||
OpenstackClientConfig: cfg,
|
||||
}
|
||||
err := cli.fetchToken()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchToken")
|
||||
}
|
||||
return cli, cli.fetchRegions()
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) getDefaultRegionName() string {
|
||||
return cli.defaultRegionName
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) getProjectToken(projectId, projectName string) (mcclient.TokenCredential, error) {
|
||||
s := cli.getDefaultSession("")
|
||||
roleId, err := modules.RolesV3.GetId(s, "admin", jsonutils.Marshal(map[string]string{}))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "RolesV3.GetId")
|
||||
}
|
||||
_, err = modules.RolesV3.PutInContexts(s, roleId, nil, []modulebase.ManagerContext{{InstanceManager: &modules.Projects, InstanceId: projectId}, {InstanceManager: &modules.UsersV3, InstanceId: s.GetUserId()}})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "RolesV3.PutInContexts")
|
||||
}
|
||||
|
||||
client := cli.getDefaultClient()
|
||||
tokenCredential, err := client.Authenticate(cli.username, cli.password, cli.domainName, projectName, cli.projectDomain)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Authenticate")
|
||||
}
|
||||
return tokenCredential, nil
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) GetCloudRegionExternalIdPrefix() string {
|
||||
return fmt.Sprintf("%s/%s/", CLOUD_PROVIDER_OPENSTACK, cli.cpcfg.Id)
|
||||
}
|
||||
@@ -116,138 +156,267 @@ func (cli *SOpenStackClient) GetSubAccounts() ([]cloudprovider.SSubAccount, erro
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) fetchRegions() error {
|
||||
if err := cli.connect(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
regions := cli.tokenCredential.GetRegions()
|
||||
cli.iregions = make([]cloudprovider.ICloudRegion, len(regions))
|
||||
for i := 0; i < len(regions); i++ {
|
||||
region := SRegion{client: cli, Name: regions[i]}
|
||||
cli.iregions[i] = ®ion
|
||||
cli.defaultRegionName = regions[0]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type OpenstackError struct {
|
||||
httputils.JSONClientError
|
||||
}
|
||||
|
||||
func (ce *OpenstackError) ParseErrorFromJsonResponse(statusCode int, body jsonutils.JSONObject) error {
|
||||
body.Unmarshal(ce)
|
||||
if ce.Code == 0 {
|
||||
ce.Code = statusCode
|
||||
}
|
||||
if len(ce.Details) == 0 {
|
||||
ce.Details = body.String()
|
||||
}
|
||||
if len(ce.Class) == 0 {
|
||||
ce.Class = http.StatusText(statusCode)
|
||||
}
|
||||
if statusCode == 404 {
|
||||
return errors.Wrap(cloudprovider.ErrNotFound, ce.Error())
|
||||
}
|
||||
return ce
|
||||
}
|
||||
|
||||
type sApiVersion struct {
|
||||
MinVersion string
|
||||
Version string
|
||||
}
|
||||
|
||||
type sApiVersions struct {
|
||||
Versions []sApiVersion
|
||||
Version sApiVersion
|
||||
}
|
||||
|
||||
func (v *sApiVersions) GetMaxVersion() string {
|
||||
maxVersion := v.Version.Version
|
||||
for _, _version := range v.Versions {
|
||||
if version.GT(_version.Version, maxVersion) {
|
||||
maxVersion = _version.Version
|
||||
}
|
||||
}
|
||||
return maxVersion
|
||||
}
|
||||
|
||||
func getApiVerion(token mcclient.TokenCredential, url string, debug bool) (string, error) {
|
||||
client := httputils.NewJsonClient(httputils.GetDefaultClient())
|
||||
req := httputils.NewJsonRequest(httputils.THttpMethod("GET"), strings.TrimSuffix(url, token.GetTenantId()), nil)
|
||||
header := http.Header{}
|
||||
header.Set("X-Auth-Token", token.GetTokenString())
|
||||
req.SetHeader(header)
|
||||
oe := &OpenstackError{}
|
||||
_, resp, err := client.Send(context.Background(), req, oe, debug)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "get api version")
|
||||
}
|
||||
versions := &sApiVersions{}
|
||||
resp.Unmarshal(&versions)
|
||||
return versions.GetMaxVersion(), nil
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) GetMaxVersion(region, service string) (string, error) {
|
||||
serviceUrl, err := cli.tokenCredential.GetServiceURL(service, region, "", cli.endpointType)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "GetServiceURL(%s, %s, %s)", service, region, cli.endpointType)
|
||||
}
|
||||
header := http.Header{}
|
||||
header.Set("X-Auth-Token", cli.tokenCredential.GetTokenString())
|
||||
return getApiVerion(cli.tokenCredential, serviceUrl, cli.debug)
|
||||
}
|
||||
|
||||
func jsonReuest(token mcclient.TokenCredential, service, region, endpointType string, method httputils.THttpMethod, resource string, query url.Values, body interface{}, debug bool) (jsonutils.JSONObject, error) {
|
||||
serviceUrl, err := token.GetServiceURL(service, region, "", endpointType)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetServiceURL(%s, %s, %s)", service, region, endpointType)
|
||||
}
|
||||
header := http.Header{}
|
||||
header.Set("X-Auth-Token", token.GetTokenString())
|
||||
apiVersion := ""
|
||||
if !utils.IsInStringArray(service, []string{OPENSTACK_SERVICE_IMAGE, OPENSTACK_SERVICE_IDENTITY}) {
|
||||
apiVersion, err = getApiVerion(token, serviceUrl, debug)
|
||||
if err != nil {
|
||||
log.Errorf("get service %s api version error: %v", service, err)
|
||||
}
|
||||
}
|
||||
if len(apiVersion) > 0 {
|
||||
switch service {
|
||||
case OPENSTACK_SERVICE_COMPUTE:
|
||||
header.Set("X-Openstack-Nova-API-Version", apiVersion)
|
||||
case OPENSTACK_SERVICE_IMAGE:
|
||||
header.Set("X-Openstack-Glance-API-Version", apiVersion)
|
||||
case OPENSTACK_SERVICE_VOLUME, OPENSTACK_SERVICE_VOLUMEV2, OPENSTACK_SERVICE_VOLUMEV3:
|
||||
header.Set("Openstack-API-Version", fmt.Sprintf("volume %s", apiVersion))
|
||||
case OPENSTACK_SERVICE_NETWORK:
|
||||
header.Set("X-Openstack-Neutron-API-Version", apiVersion)
|
||||
case OPENSTACK_SERVICE_IDENTITY:
|
||||
header.Set("X-Openstack-Identity-API-Version", apiVersion)
|
||||
}
|
||||
}
|
||||
|
||||
for _, region := range regions {
|
||||
if serviceURL, err := cli.tokenCredential.GetServiceURL("compute", region, "", cli.endpointType); err != nil || len(serviceURL) == 0 {
|
||||
for _, endpointType := range []string{"internal", "admin", "public"} {
|
||||
if serviceURL, err := cli.tokenCredential.GetServiceURL("compute", region, "", endpointType); err == nil && len(serviceURL) > 0 {
|
||||
cli.endpointType = endpointType
|
||||
return nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
requestUrl := resource
|
||||
if !strings.HasPrefix(resource, serviceUrl) {
|
||||
requestUrl = fmt.Sprintf("%s/%s", serviceUrl, resource)
|
||||
}
|
||||
|
||||
if query != nil {
|
||||
requestUrl = fmt.Sprintf("%s?%s", requestUrl, query.Encode())
|
||||
}
|
||||
|
||||
return _jsonRequest(method, requestUrl, header, body, debug)
|
||||
}
|
||||
|
||||
func _jsonRequest(method httputils.THttpMethod, url string, header http.Header, params interface{}, debug bool) (jsonutils.JSONObject, error) {
|
||||
client := httputils.NewJsonClient(httputils.GetDefaultClient())
|
||||
req := httputils.NewJsonRequest(method, url, params)
|
||||
req.SetHeader(header)
|
||||
oe := &OpenstackError{}
|
||||
_, resp, err := client.Send(context.Background(), req, oe, debug)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) ecsRequest(region string, method httputils.THttpMethod, resource string, query url.Values, body interface{}) (jsonutils.JSONObject, error) {
|
||||
token := cli.tokenCredential
|
||||
if method == httputils.POST && query != nil && len(query.Get("project_id")) > 0 {
|
||||
projectId := query.Get("project_id")
|
||||
var err error
|
||||
token, err = cli.getProjectTokenCredential(projectId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "getProjectTokenCredential(%s)", projectId)
|
||||
}
|
||||
}
|
||||
return jsonReuest(token, OPENSTACK_SERVICE_COMPUTE, region, cli.endpointType, method, resource, query, body, cli.debug)
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) ecsCreate(projectId, region, resource string, body interface{}) (jsonutils.JSONObject, error) {
|
||||
token := cli.tokenCredential
|
||||
if len(projectId) > 0 {
|
||||
var err error
|
||||
token, err = cli.getProjectTokenCredential(projectId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "getProjectTokenCredential(%s)", projectId)
|
||||
}
|
||||
}
|
||||
return jsonReuest(token, OPENSTACK_SERVICE_COMPUTE, region, cli.endpointType, httputils.POST, resource, nil, body, cli.debug)
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) ecsDo(projectId, region, resource string, body interface{}) (jsonutils.JSONObject, error) {
|
||||
token := cli.tokenCredential
|
||||
if len(projectId) > 0 {
|
||||
var err error
|
||||
token, err = cli.getProjectTokenCredential(projectId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "getProjectTokenCredential(%s)", projectId)
|
||||
}
|
||||
}
|
||||
return jsonReuest(token, OPENSTACK_SERVICE_COMPUTE, region, cli.endpointType, httputils.POST, resource, nil, body, cli.debug)
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) iamRequest(region string, method httputils.THttpMethod, resource string, query url.Values, body interface{}) (jsonutils.JSONObject, error) {
|
||||
return jsonReuest(cli.tokenCredential, OPENSTACK_SERVICE_IDENTITY, region, cli.endpointType, method, resource, query, body, cli.debug)
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) vpcRequest(region string, method httputils.THttpMethod, resource string, query url.Values, body interface{}) (jsonutils.JSONObject, error) {
|
||||
return jsonReuest(cli.tokenCredential, OPENSTACK_SERVICE_NETWORK, region, cli.endpointType, method, resource, query, body, cli.debug)
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) imageRequest(region string, method httputils.THttpMethod, resource string, query url.Values, body interface{}) (jsonutils.JSONObject, error) {
|
||||
return jsonReuest(cli.tokenCredential, OPENSTACK_SERVICE_IMAGE, region, cli.endpointType, method, resource, query, body, cli.debug)
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) bsRequest(region string, method httputils.THttpMethod, resource string, query url.Values, body interface{}) (jsonutils.JSONObject, error) {
|
||||
for _, service := range []string{OPENSTACK_SERVICE_VOLUMEV3, OPENSTACK_SERVICE_VOLUMEV2, OPENSTACK_SERVICE_VOLUME} {
|
||||
_, err := cli.tokenCredential.GetServiceURL(service, region, "", cli.endpointType)
|
||||
if err == nil {
|
||||
return jsonReuest(cli.tokenCredential, service, region, cli.endpointType, method, resource, query, body, cli.debug)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("no valid volume service endpoint")
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) bsCreate(projectId, region, resource string, body interface{}) (jsonutils.JSONObject, error) {
|
||||
token := cli.tokenCredential
|
||||
if len(projectId) > 0 {
|
||||
var err error
|
||||
token, err = cli.getProjectTokenCredential(projectId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "getProjectTokenCredential(%s)", projectId)
|
||||
}
|
||||
}
|
||||
for _, service := range []string{OPENSTACK_SERVICE_VOLUMEV3, OPENSTACK_SERVICE_VOLUMEV2, OPENSTACK_SERVICE_VOLUME} {
|
||||
_, err := token.GetServiceURL(service, region, "", cli.endpointType)
|
||||
if err == nil {
|
||||
return jsonReuest(token, service, region, cli.endpointType, httputils.POST, resource, nil, body, cli.debug)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("no valid volume service endpoint")
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) imageUpload(region, url string, body io.Reader) (*http.Response, error) {
|
||||
header := http.Header{}
|
||||
header.Set("Content-Type", "application/octet-stream")
|
||||
session := cli.getDefaultSession(region)
|
||||
return session.RawRequest(OPENSTACK_SERVICE_IMAGE, "", httputils.PUT, url, header, body)
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) fetchToken() error {
|
||||
if cli.tokenCredential != nil {
|
||||
return nil
|
||||
}
|
||||
var err error
|
||||
cli.tokenCredential, err = cli.getDefaultToken()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getDefaultToken")
|
||||
}
|
||||
return cli.checkEndpointType()
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) checkEndpointType() error {
|
||||
for _, regionName := range cli.tokenCredential.GetRegions() {
|
||||
_, err := cli.tokenCredential.GetServiceURL(OPENSTACK_SERVICE_COMPUTE, regionName, "", cli.endpointType)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("failed to find right endpoint type")
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) Request(projectId string, region, service, method string, url string, microversion string, body jsonutils.JSONObject) (http.Header, jsonutils.JSONObject, error) {
|
||||
header := http.Header{}
|
||||
if len(microversion) > 0 {
|
||||
header.Set("X-Openstack-Nova-API-Version", microversion)
|
||||
}
|
||||
|
||||
var session *mcclient.ClientSession = nil
|
||||
ctx := context.Background()
|
||||
if method == "POST" && len(projectId) > 0 {
|
||||
targetToken, err := cli.getProjectTokenCredential(projectId)
|
||||
if err != nil {
|
||||
log.Errorf("failed to get project %s token credential %v", projectId, err)
|
||||
} else {
|
||||
session = cli.client.NewSession(ctx, region, "", cli.endpointType, targetToken, "")
|
||||
}
|
||||
}
|
||||
if session == nil {
|
||||
session = cli.client.NewSession(ctx, region, "", cli.endpointType, cli.tokenCredential, "")
|
||||
}
|
||||
|
||||
serviceUrl, err := session.GetServiceURL(service, "")
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "GetServiceURL(%s)", service)
|
||||
}
|
||||
url = strings.TrimPrefix(url, serviceUrl)
|
||||
header, resp, err := session.JSONRequest(service, "", httputils.THttpMethod(method), url, header, body)
|
||||
if err != nil && body != nil {
|
||||
log.Errorf("microversion %s url: %s, params: %s", microversion, serviceUrl+url, body.PrettyString())
|
||||
}
|
||||
return header, resp, err
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) RawRequest(region, service, method string, url string, microversion string, body jsonutils.JSONObject) (*http.Response, error) {
|
||||
header := http.Header{}
|
||||
if len(microversion) > 0 {
|
||||
header.Set("X-Openstack-Nova-API-Version", microversion)
|
||||
}
|
||||
ctx := context.Background()
|
||||
session := cli.client.NewSession(ctx, region, "", cli.endpointType, cli.tokenCredential, "")
|
||||
data := strings.NewReader("")
|
||||
if body != nil {
|
||||
data = strings.NewReader(body.String())
|
||||
}
|
||||
return session.RawRequest(service, "", httputils.THttpMethod(method), url, header, data)
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) StreamRequest(region, service, method string, url string, microversion string, body io.Reader) (*http.Response, error) {
|
||||
header := http.Header{}
|
||||
if len(microversion) > 0 {
|
||||
header.Set("X-Openstack-Nova-API-Version", microversion)
|
||||
}
|
||||
header.Set("Content-Type", "application/octet-stream")
|
||||
ctx := context.Background()
|
||||
session := cli.client.NewSession(ctx, region, "", cli.endpointType, cli.tokenCredential, "")
|
||||
return session.RawRequest(service, "", httputils.THttpMethod(method), url, header, body)
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) getVersion(region string, service string) (string, string, error) {
|
||||
ctx := context.Background()
|
||||
session := cli.client.NewSession(ctx, region, "", cli.endpointType, cli.tokenCredential, "")
|
||||
uri, err := session.GetServiceURL(service, cli.endpointType)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
url := uri
|
||||
telnetID := cli.tokenCredential.GetTenantId()
|
||||
if strings.Index(uri, telnetID) > 0 {
|
||||
url = uri[0:strings.Index(uri, telnetID)]
|
||||
}
|
||||
_, resp, err := session.JSONRequest(url, "", "GET", "/", nil, nil)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
minVersion, _ := resp.GetString("version", "min_version")
|
||||
maxVersion, _ := resp.GetString("version", "version")
|
||||
if resp.Contains("versions") {
|
||||
minVersion, maxVersion = "1000.0", ""
|
||||
versions, _ := resp.GetArray("versions")
|
||||
for _, _version := range versions {
|
||||
if _minVersion, _ := _version.GetString("min_version"); len(_minVersion) > 0 {
|
||||
if version.LT(_minVersion, minVersion) {
|
||||
minVersion = _minVersion
|
||||
}
|
||||
}
|
||||
if _maxVersion, _ := _version.GetString("version"); len(_maxVersion) > 0 {
|
||||
if version.GT(_maxVersion, maxVersion) {
|
||||
maxVersion = _maxVersion
|
||||
}
|
||||
for _, endpointType := range []string{"internal", "admin", "public"} {
|
||||
_, err = cli.tokenCredential.GetServiceURL(OPENSTACK_SERVICE_COMPUTE, regionName, "", endpointType)
|
||||
if err == nil {
|
||||
cli.endpointType = endpointType
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if minVersion == "1000.0" {
|
||||
minVersion, maxVersion = "", ""
|
||||
}
|
||||
}
|
||||
return minVersion, maxVersion, nil
|
||||
return errors.Errorf("failed to find right endpoint type for compute service")
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) connect() error {
|
||||
cli.client = mcclient.NewClient(cli.authURL, 5, cli.debug, false, "", "")
|
||||
cli.client.SetHttpTransportProxyFunc(cli.cpcfg.ProxyFunc)
|
||||
tokenCredential, err := cli.client.Authenticate(cli.username, cli.password, cli.domainName, cli.project, cli.projectDomain)
|
||||
if err != nil {
|
||||
return err
|
||||
func (cli *SOpenStackClient) getDefaultSession(regionName string) *mcclient.ClientSession {
|
||||
if len(regionName) == 0 {
|
||||
regionName = cli.getDefaultRegionName()
|
||||
}
|
||||
cli.tokenCredential = tokenCredential
|
||||
return nil
|
||||
client := cli.getDefaultClient()
|
||||
return client.NewSession(context.Background(), regionName, "", cli.endpointType, cli.tokenCredential, "")
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) getDefaultClient() *mcclient.Client {
|
||||
client := mcclient.NewClient(cli.authURL, 5, cli.debug, false, "", "")
|
||||
client.SetHttpTransportProxyFunc(cli.cpcfg.ProxyFunc)
|
||||
return client
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) getDefaultToken() (mcclient.TokenCredential, error) {
|
||||
client := cli.getDefaultClient()
|
||||
token, err := client.Authenticate(cli.username, cli.password, cli.domainName, cli.project, cli.projectDomain)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Authenticate")
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) getProjectTokenCredential(projectId string) (mcclient.TokenCredential, error) {
|
||||
@@ -255,8 +424,8 @@ func (cli *SOpenStackClient) getProjectTokenCredential(projectId string) (mcclie
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetProject(%s)", projectId)
|
||||
}
|
||||
region := cli.iregions[0].(*SRegion)
|
||||
s := cli.client.NewSession(context.Background(), region.Name, "", cli.endpointType, cli.tokenCredential, "")
|
||||
|
||||
s := cli.getDefaultSession("")
|
||||
|
||||
roleId, err := modules.RolesV3.GetId(s, "admin", jsonutils.Marshal(map[string]string{}))
|
||||
if err != nil {
|
||||
@@ -267,13 +436,7 @@ func (cli *SOpenStackClient) getProjectTokenCredential(projectId string) (mcclie
|
||||
return nil, errors.Wrap(err, "RolesV3.PutInContexts")
|
||||
}
|
||||
|
||||
cli.client = mcclient.NewClient(cli.authURL, 5, cli.debug, false, "", "")
|
||||
cli.client.SetHttpTransportProxyFunc(cli.cpcfg.ProxyFunc)
|
||||
tokenCredential, err := cli.client.Authenticate(cli.username, cli.password, cli.domainName, project.Name, cli.projectDomain)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Authenticate")
|
||||
}
|
||||
return tokenCredential, nil
|
||||
return cli.getProjectToken(project.Id, project.Name)
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) GetRegion(regionId string) *SRegion {
|
||||
@@ -307,56 +470,47 @@ func (cli *SOpenStackClient) GetRegions() []SRegion {
|
||||
return regions
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) GetIProjects() ([]cloudprovider.ICloudProject, error) {
|
||||
if len(cli.iregions) > 0 {
|
||||
region := cli.iregions[0].(*SRegion)
|
||||
s := cli.client.NewSession(context.Background(), region.Name, "", cli.endpointType, cli.tokenCredential, "")
|
||||
result, err := modules.Projects.List(s, jsonutils.NewDict())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iprojects := []cloudprovider.ICloudProject{}
|
||||
for i := 0; i < len(result.Data); i++ {
|
||||
project := &SProject{}
|
||||
if err := result.Data[i].Unmarshal(project); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iprojects = append(iprojects, project)
|
||||
}
|
||||
return iprojects, nil
|
||||
func (cli *SOpenStackClient) fetchProjects() error {
|
||||
var err error
|
||||
cli.projects, err = cli.GetProjects()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetProjects")
|
||||
}
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) GetIProjects() ([]cloudprovider.ICloudProject, error) {
|
||||
err := cli.fetchProjects()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchProjects")
|
||||
}
|
||||
iprojects := []cloudprovider.ICloudProject{}
|
||||
for i := 0; i < len(cli.projects); i++ {
|
||||
cli.projects[i].client = cli
|
||||
iprojects = append(iprojects, &cli.projects[i])
|
||||
}
|
||||
return iprojects, nil
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) GetProject(id string) (*SProject, error) {
|
||||
if len(cli.iregions) > 0 {
|
||||
region := cli.iregions[0].(*SRegion)
|
||||
s := cli.client.NewSession(context.Background(), region.Name, "", cli.endpointType, cli.tokenCredential, "")
|
||||
result, err := modules.Projects.Get(s, id, jsonutils.NewDict())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
project := &SProject{}
|
||||
err = result.Unmarshal(project)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "result.Unmarshal")
|
||||
}
|
||||
return project, nil
|
||||
err := cli.fetchProjects()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchProjects")
|
||||
}
|
||||
return nil, fmt.Errorf("no region info")
|
||||
for i := 0; i < len(cli.projects); i++ {
|
||||
if cli.projects[i].Id == id {
|
||||
return &cli.projects[i], nil
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) CreateIProject(name string) (cloudprovider.ICloudProject, error) {
|
||||
if len(cli.iregions) > 0 {
|
||||
return cli.CreateProject(name, "")
|
||||
}
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
return cli.CreateProject(name, "")
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) CreateProject(name, desc string) (*SProject, error) {
|
||||
region := cli.iregions[0].(*SRegion)
|
||||
s := cli.client.NewSession(context.Background(), region.Name, "", cli.endpointType, cli.tokenCredential, "")
|
||||
|
||||
s := cli.getDefaultSession("")
|
||||
params := map[string]string{
|
||||
"name": name,
|
||||
"domain_id": s.GetDomainId(),
|
||||
@@ -368,7 +522,7 @@ func (cli *SOpenStackClient) CreateProject(name, desc string) (*SProject, error)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Projects.Create")
|
||||
}
|
||||
project := SProject{}
|
||||
project := SProject{client: cli}
|
||||
err = result.Unmarshal(&project)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "result.Unmarshal")
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
package openstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -144,7 +143,7 @@ func (port *SPort) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfac
|
||||
}
|
||||
|
||||
func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) {
|
||||
ports, err := region.GetPorts("")
|
||||
ports, err := region.GetPorts("", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -160,49 +159,47 @@ func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInt
|
||||
}
|
||||
|
||||
func (region *SRegion) GetPort(portId string) (*SPort, error) {
|
||||
_, resp, err := region.Get("network", "/v2.0/ports/"+portId, "", nil)
|
||||
resource := "/v2.0/ports/" + portId
|
||||
resp, err := region.vpcGet(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
port := &SPort{}
|
||||
return port, resp.Unmarshal(port, "port")
|
||||
err = resp.Unmarshal(port, "port")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return port, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetPorts(macAddress string) ([]SPort, error) {
|
||||
base := fmt.Sprintf("/v2.0/ports")
|
||||
params := url.Values{}
|
||||
func (region *SRegion) GetPorts(macAddress, deviceId string) ([]SPort, error) {
|
||||
resource, ports := "/v2.0/ports", []SPort{}
|
||||
query := url.Values{}
|
||||
if len(macAddress) > 0 {
|
||||
params.Set("mac_address", macAddress)
|
||||
query.Set("mac_address", macAddress)
|
||||
}
|
||||
url := fmt.Sprintf("%s?%s", base, params.Encode())
|
||||
|
||||
ports := []SPort{}
|
||||
for len(url) > 0 {
|
||||
_, resp, err := region.List("network", url, "", nil)
|
||||
if len(deviceId) > 0 {
|
||||
query.Set("device_id", deviceId)
|
||||
}
|
||||
for {
|
||||
resp, err := region.vpcList(resource, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "vpcList")
|
||||
}
|
||||
_ports := []SPort{}
|
||||
err = resp.Unmarshal(&_ports, "ports")
|
||||
part := struct {
|
||||
Ports []SPort
|
||||
PortsLinks SNextLinks
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, `resp.Unmarshal(&_ports, "ports")`)
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
ports = append(ports, _ports...)
|
||||
url = ""
|
||||
if resp.Contains("ports_links") {
|
||||
nextLink := []SNextLink{}
|
||||
err = resp.Unmarshal(&nextLink, "ports_links")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, `resp.Unmarshal(&nextLink, "ports_links")`)
|
||||
}
|
||||
for _, next := range nextLink {
|
||||
if next.Rel == "next" {
|
||||
url = next.Href
|
||||
break
|
||||
}
|
||||
}
|
||||
ports = append(ports, part.Ports...)
|
||||
marker := part.PortsLinks.GetNextMark()
|
||||
if len(marker) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", marker)
|
||||
}
|
||||
|
||||
return ports, nil
|
||||
}
|
||||
|
||||
@@ -15,20 +15,27 @@
|
||||
package openstack
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"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/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/httputils"
|
||||
)
|
||||
|
||||
type SProject struct {
|
||||
client *SOpenStackClient
|
||||
Description string
|
||||
Enabled bool
|
||||
ID string
|
||||
Id string
|
||||
Name string
|
||||
}
|
||||
|
||||
func (p *SProject) GetId() string {
|
||||
return p.ID
|
||||
return p.Id
|
||||
}
|
||||
|
||||
func (p *SProject) GetGlobalId() string {
|
||||
@@ -44,9 +51,18 @@ func (p *SProject) GetName() string {
|
||||
}
|
||||
|
||||
func (p *SProject) GetStatus() string {
|
||||
_, err := p.getToken()
|
||||
if err != nil {
|
||||
log.Errorf("get project %s token error: %v %T", p.Name, err, err)
|
||||
return api.EXTERNAL_PROJECT_STATUS_UNKNOWN
|
||||
}
|
||||
return api.EXTERNAL_PROJECT_STATUS_AVAILABLE
|
||||
}
|
||||
|
||||
func (p *SProject) getToken() (mcclient.TokenCredential, error) {
|
||||
return p.client.getProjectToken(p.Id, p.Name)
|
||||
}
|
||||
|
||||
func (p *SProject) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
@@ -54,3 +70,48 @@ func (p *SProject) IsEmulated() bool {
|
||||
func (p *SProject) Refresh() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type SProjectLinks struct {
|
||||
Next string
|
||||
Previous string
|
||||
Self string
|
||||
}
|
||||
|
||||
func (link SProjectLinks) GetNextMark() string {
|
||||
if len(link.Next) == 0 || link.Next == "null" {
|
||||
return ""
|
||||
}
|
||||
next, err := url.Parse(link.Next)
|
||||
if err != nil {
|
||||
log.Errorf("parse next link %s error: %v", link.Next, err)
|
||||
return ""
|
||||
}
|
||||
return next.Query().Get("marker")
|
||||
}
|
||||
|
||||
func (cli *SOpenStackClient) GetProjects() ([]SProject, error) {
|
||||
resource := "/v3/projects"
|
||||
projects := []SProject{}
|
||||
query := url.Values{}
|
||||
for {
|
||||
resp, err := cli.iamRequest("", httputils.GET, resource, query, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "iamRequest")
|
||||
}
|
||||
part := struct {
|
||||
Projects []SProject
|
||||
Links SProjectLinks
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "iamRequest")
|
||||
}
|
||||
projects = append(projects, part.Projects...)
|
||||
marker := part.Links.GetNextMark()
|
||||
if len(marker) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", marker)
|
||||
}
|
||||
return projects, nil
|
||||
}
|
||||
|
||||
@@ -102,6 +102,10 @@ func (self *SOpenStackProviderFactory) ValidateUpdateCloudaccountCredential(ctx
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func (self *SOpenStackProviderFactory) IsNeedForceAutoCreateProject() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SOpenStackProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) {
|
||||
accountInfo := strings.Split(cfg.Account, "/")
|
||||
if len(accountInfo) < 2 {
|
||||
@@ -200,7 +204,7 @@ func (self *SOpenStackProvider) GetIProjects() ([]cloudprovider.ICloudProject, e
|
||||
return self.client.GetIProjects()
|
||||
}
|
||||
|
||||
func (self *SOpenStackProvider) CreateProject(name string) (cloudprovider.ICloudProject, error) {
|
||||
func (self *SOpenStackProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) {
|
||||
return self.client.CreateIProject(name)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,9 @@ package openstack
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/util/version"
|
||||
)
|
||||
|
||||
type QuotaDetail struct {
|
||||
@@ -70,46 +68,44 @@ type SQuota struct {
|
||||
}
|
||||
|
||||
func (region *SRegion) GetQuota() (*QuotaSet, error) {
|
||||
_, resp, err := region.Get("compute", fmt.Sprintf("/os-quota-sets/%s/detail", region.client.tokenCredential.GetTenantId()), "", nil)
|
||||
resource := fmt.Sprintf("/os-quota-sets/%s/detail", region.client.tokenCredential.GetTenantId())
|
||||
resp, err := region.ecsGet(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "ecsGet")
|
||||
}
|
||||
quota := &QuotaSet{}
|
||||
return quota, resp.Unmarshal(quota, "quota_set")
|
||||
}
|
||||
|
||||
func (region *SRegion) SetQuota(quota *SQuota) error {
|
||||
_, maxVersion, _ := region.GetVersion("compute")
|
||||
params := map[string]map[string]interface{}{
|
||||
"quota_set": {
|
||||
"force": "True",
|
||||
},
|
||||
}
|
||||
|
||||
if version.GE(maxVersion, "2.35") {
|
||||
if quota.Floatingips > 0 {
|
||||
params["quota_set"]["floating_ips"] = quota.Floatingips
|
||||
}
|
||||
|
||||
if quota.SecurityGroups > 0 {
|
||||
params["quota_set"]["security_group"] = quota.SecurityGroups
|
||||
}
|
||||
|
||||
if quota.SecurityGroupRules > 0 {
|
||||
params["quota_set"]["security_group_rules"] = quota.SecurityGroupRules
|
||||
}
|
||||
|
||||
if quota.FixedIps > 0 {
|
||||
params["quota_set"]["fixed_ips"] = quota.FixedIps
|
||||
}
|
||||
|
||||
if quota.Networks > 0 {
|
||||
params["quota_set"]["networks"] = quota.Networks
|
||||
}
|
||||
|
||||
if quota.Floatingips > 0 {
|
||||
params["quota_set"]["floating_ips"] = quota.Floatingips
|
||||
}
|
||||
|
||||
_, _, err := region.Update("compute", "/os-quota-sets/"+region.client.tokenCredential.GetTenantId(), maxVersion, jsonutils.Marshal(params))
|
||||
if quota.SecurityGroups > 0 {
|
||||
params["quota_set"]["security_group"] = quota.SecurityGroups
|
||||
}
|
||||
|
||||
if quota.SecurityGroupRules > 0 {
|
||||
params["quota_set"]["security_group_rules"] = quota.SecurityGroupRules
|
||||
}
|
||||
|
||||
if quota.FixedIps > 0 {
|
||||
params["quota_set"]["fixed_ips"] = quota.FixedIps
|
||||
}
|
||||
|
||||
if quota.Networks > 0 {
|
||||
params["quota_set"]["networks"] = quota.Networks
|
||||
}
|
||||
|
||||
resource := "/os-quota-sets/" + region.client.tokenCredential.GetTenantId()
|
||||
_, err := region.ecsUpdate(resource, params)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
+150
-194
@@ -16,12 +16,10 @@ package openstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"io"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
@@ -37,8 +35,8 @@ type SRegion struct {
|
||||
|
||||
Name string
|
||||
|
||||
izones []cloudprovider.ICloudZone
|
||||
ivpcs []cloudprovider.ICloudVpc
|
||||
zones []SZone
|
||||
vpcs []SVpc
|
||||
|
||||
storageCache *SStoragecache
|
||||
routers []SRouter
|
||||
@@ -93,26 +91,16 @@ func (region *SRegion) Refresh() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetMaxVersion(service string) (string, error) {
|
||||
return region.client.GetMaxVersion(region.Name, service)
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateIVpc(name string, desc string, cidr string) (cloudprovider.ICloudVpc, error) {
|
||||
params := map[string]map[string]string{
|
||||
"network": {
|
||||
"name": name,
|
||||
"description": desc,
|
||||
},
|
||||
}
|
||||
_, resp, err := region.Post("network", "/v2.0/networks", "", jsonutils.Marshal(params))
|
||||
vpc, err := region.CreateVpc(name, desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "CreateVp")
|
||||
}
|
||||
err = region.fetchInfrastructure()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vpcId, err := resp.GetString("network", "id")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return region.GetIVpcById(vpcId)
|
||||
return vpc, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
|
||||
@@ -200,30 +188,37 @@ func (region *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache,
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
|
||||
return region.GetInstance(id)
|
||||
instance, err := region.GetInstance(id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetInstance(%s)", id)
|
||||
}
|
||||
return instance, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) {
|
||||
return region.GetDisk(id)
|
||||
disk, err := region.GetDisk(id)
|
||||
if err != nil {
|
||||
_, err := region.GetInstance(id)
|
||||
if err == nil {
|
||||
return &SNovaDisk{region: region, instanceId: id}, nil
|
||||
}
|
||||
return nil, errors.Wrapf(err, "GetDisk(%s)", id)
|
||||
}
|
||||
return disk, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
|
||||
ivpcs, err := region.GetIVpcs()
|
||||
vpc, err := region.GetVpc(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "GetVpc(%s)", id)
|
||||
}
|
||||
for i := 0; i < len(ivpcs); i++ {
|
||||
if ivpcs[i].GetGlobalId() == id {
|
||||
return ivpcs[i], nil
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
return vpc, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) {
|
||||
izones, err := region.GetIZones()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "GetIZones")
|
||||
}
|
||||
for i := 0; i < len(izones); i++ {
|
||||
if izones[i].GetGlobalId() == id {
|
||||
@@ -234,170 +229,129 @@ func (region *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error)
|
||||
}
|
||||
|
||||
func (region *SRegion) fetchZones() error {
|
||||
zone := &SZone{region: region, ZoneName: region.Name, cachedHosts: map[string][]string{}}
|
||||
_, resp, err := region.List("compute", "/os-availability-zone/detail", "", jsonutils.NewDict())
|
||||
if len(region.zones) > 0 {
|
||||
return nil
|
||||
}
|
||||
zones, err := region.GetZones()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
zones := []SZone{}
|
||||
if err := resp.Unmarshal(&zones, "availabilityZoneInfo"); err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "GetZones")
|
||||
}
|
||||
region.zones = []SZone{}
|
||||
for i := 0; i < len(zones); i++ {
|
||||
if zones[i].ZoneName == "internal" {
|
||||
continue
|
||||
}
|
||||
zone.cachedHosts[zones[i].ZoneName] = []string{}
|
||||
for hostname, hostInfo := range zones[i].Hosts {
|
||||
for k := range hostInfo {
|
||||
if k == "nova-compute" {
|
||||
zone.cachedHosts[zones[i].ZoneName] = append(zone.cachedHosts[zones[i].ZoneName], hostname)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
region.izones = []cloudprovider.ICloudZone{zone}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (region *SRegion) fetchIVpcs() error {
|
||||
vpcs, err := region.GetVpcs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
region.ivpcs = []cloudprovider.ICloudVpc{}
|
||||
for i := 0; i < len(vpcs); i++ {
|
||||
vpcs[i].region = region
|
||||
region.ivpcs = append(region.ivpcs, &vpcs[i])
|
||||
zones[i].region = region
|
||||
region.zones = append(region.zones, zones[i])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (region *SRegion) fetchInfrastructure() error {
|
||||
if len(region.izones) == 0 {
|
||||
if err := region.fetchZones(); err != nil {
|
||||
return err
|
||||
}
|
||||
func (region *SRegion) fetchVpcs() error {
|
||||
if len(region.vpcs) > 0 {
|
||||
return nil
|
||||
}
|
||||
if err := region.fetchIVpcs(); err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; i < len(region.ivpcs); i++ {
|
||||
for j := 0; j < len(region.izones); j++ {
|
||||
zone := region.izones[j].(*SZone)
|
||||
vpc := region.ivpcs[i].(*SVpc)
|
||||
wire := SWire{zone: zone, vpc: vpc}
|
||||
zone.addWire(&wire)
|
||||
vpc.addWire(&wire)
|
||||
}
|
||||
var err error
|
||||
region.vpcs, err = region.GetVpcs("")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetVpcs")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (region *SRegion) Get(service, url string, microversion string, body jsonutils.JSONObject) (http.Header, jsonutils.JSONObject, error) {
|
||||
if strings.HasSuffix(url, "/") {
|
||||
return nil, nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
header, resp, err := region.client.Request("", region.Name, service, "GET", url, microversion, body)
|
||||
if err != nil {
|
||||
if jsonErr, ok := err.(*httputils.JSONClientError); ok {
|
||||
if jsonErr.Code == 404 || strings.HasSuffix(jsonErr.Class, "NotFound") {
|
||||
return nil, nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
return header, resp, nil
|
||||
func (region *SRegion) ecsList(resource string, query url.Values) (jsonutils.JSONObject, error) {
|
||||
return region.client.ecsRequest(region.Name, httputils.GET, resource, query, nil)
|
||||
}
|
||||
|
||||
func (region *SRegion) List(service, url string, microversion string, body jsonutils.JSONObject) (http.Header, jsonutils.JSONObject, error) {
|
||||
header, resp, err := region.client.Request("", region.Name, service, "GET", url, microversion, body)
|
||||
if err != nil {
|
||||
if jsonErr, ok := err.(*httputils.JSONClientError); ok {
|
||||
if jsonErr.Code == 404 || strings.HasSuffix(jsonErr.Class, "NotFound") {
|
||||
return nil, nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
return header, resp, nil
|
||||
func (region *SRegion) ecsGet(resource string) (jsonutils.JSONObject, error) {
|
||||
return region.client.ecsRequest(region.Name, httputils.GET, resource, nil, nil)
|
||||
}
|
||||
|
||||
func (region *SRegion) Post(service, url string, microversion string, body jsonutils.JSONObject) (http.Header, jsonutils.JSONObject, error) {
|
||||
return region.client.Request("", region.Name, service, "POST", url, microversion, body)
|
||||
func (region *SRegion) ecsUpdate(resource string, params interface{}) (jsonutils.JSONObject, error) {
|
||||
return region.client.ecsRequest(region.Name, httputils.PUT, resource, nil, params)
|
||||
}
|
||||
|
||||
func (region *SRegion) PostWithProject(projectId string, service, url string, microversion string, body jsonutils.JSONObject) (http.Header, jsonutils.JSONObject, error) {
|
||||
return region.client.Request(projectId, region.Name, service, "POST", url, microversion, body)
|
||||
func (region *SRegion) ecsPost(resource string, params interface{}) (jsonutils.JSONObject, error) {
|
||||
return region.client.ecsRequest(region.Name, httputils.POST, resource, nil, params)
|
||||
}
|
||||
|
||||
func (region *SRegion) Update(service, url string, microversion string, body jsonutils.JSONObject) (http.Header, jsonutils.JSONObject, error) {
|
||||
return region.client.Request("", region.Name, service, "PUT", url, microversion, body)
|
||||
func (region *SRegion) ecsDo(projectId, resource string, params interface{}) (jsonutils.JSONObject, error) {
|
||||
return region.client.ecsDo(projectId, region.Name, resource, params)
|
||||
}
|
||||
|
||||
func (region *SRegion) Delete(service, url string, microversion string) (*http.Response, error) {
|
||||
return region.client.RawRequest(region.Name, service, "DELETE", url, microversion, nil)
|
||||
func (region *SRegion) ecsDelete(resource string) (jsonutils.JSONObject, error) {
|
||||
return region.client.ecsRequest(region.Name, httputils.DELETE, resource, nil, nil)
|
||||
}
|
||||
|
||||
func (region *SRegion) CinderList(url string, microversion string, body jsonutils.JSONObject) (http.Header, jsonutils.JSONObject, error) {
|
||||
for _, service := range []string{"volumev3", "volumev2", "volume"} {
|
||||
header, resp, err := region.Get(service, url, microversion, body)
|
||||
if err == nil || !strings.Contains(err.Error(), "No such service") {
|
||||
return header, resp, err
|
||||
}
|
||||
log.Debugf("failed to list %s by service %s error: %v, try another", url, service, err)
|
||||
}
|
||||
return nil, nil, fmt.Errorf("failed to get %s by cinder service", url)
|
||||
func (region *SRegion) ecsCreate(projectId, resource string, params interface{}) (jsonutils.JSONObject, error) {
|
||||
return region.client.ecsCreate(projectId, region.Name, resource, params)
|
||||
}
|
||||
|
||||
func (region *SRegion) CinderGet(url string, microversion string, body jsonutils.JSONObject) (http.Header, jsonutils.JSONObject, error) {
|
||||
if strings.HasSuffix(url, "/") {
|
||||
return nil, nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
for _, service := range []string{"volumev3", "volumev2", "volume"} {
|
||||
header, resp, err := region.Get(service, url, microversion, body)
|
||||
if err == nil || err == cloudprovider.ErrNotFound || !strings.Contains(err.Error(), "No such service") {
|
||||
return header, resp, err
|
||||
}
|
||||
log.Debugf("failed to get %s by service %s error: %v, try another", url, service, err)
|
||||
}
|
||||
return nil, nil, fmt.Errorf("failed to get %s by cinder service", url)
|
||||
func (region *SRegion) vpcList(resource string, query url.Values) (jsonutils.JSONObject, error) {
|
||||
return region.client.vpcRequest(region.Name, httputils.GET, resource, query, nil)
|
||||
}
|
||||
|
||||
func (region *SRegion) CinderCreate(projectId string, url string, microversion string, body jsonutils.JSONObject) (http.Header, jsonutils.JSONObject, error) {
|
||||
for _, service := range []string{"volumev3", "volumev2", "volume"} {
|
||||
header, resp, err := region.PostWithProject(projectId, service, url, microversion, body)
|
||||
if err == nil || !strings.Contains(err.Error(), "No such service") {
|
||||
return header, resp, err
|
||||
}
|
||||
log.Debugf("failed to create %s by service %s error: %v, try another", url, service, err)
|
||||
}
|
||||
return nil, nil, fmt.Errorf("failed to create %s by cinder service", url)
|
||||
func (region *SRegion) vpcGet(resource string) (jsonutils.JSONObject, error) {
|
||||
return region.client.vpcRequest(region.Name, httputils.GET, resource, nil, nil)
|
||||
}
|
||||
|
||||
func (region *SRegion) CinderDelete(url string, microversion string) (*http.Response, error) {
|
||||
if strings.HasSuffix(url, "/") {
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
for _, service := range []string{"volumev3", "volumev2", "volume"} {
|
||||
resp, err := region.Delete(service, url, microversion)
|
||||
if err == nil || !strings.Contains(err.Error(), "No such service") {
|
||||
return resp, err
|
||||
}
|
||||
log.Debugf("failed to delete %s by service %s error: %v, try another", url, service, err)
|
||||
}
|
||||
return nil, fmt.Errorf("failed to delete %s by cinder service", url)
|
||||
func (region *SRegion) vpcUpdate(resource string, params interface{}) (jsonutils.JSONObject, error) {
|
||||
return region.client.vpcRequest(region.Name, httputils.PUT, resource, nil, params)
|
||||
}
|
||||
|
||||
func (region *SRegion) CinderAction(url string, microversion string, body jsonutils.JSONObject) (http.Header, jsonutils.JSONObject, error) {
|
||||
for _, service := range []string{"volumev3", "volumev2", "volume"} {
|
||||
header, resp, err := region.Post(service, url, microversion, body)
|
||||
if err == nil || !strings.Contains(err.Error(), "No such service") {
|
||||
return header, resp, err
|
||||
}
|
||||
log.Debugf("failed to operate %s by service %s error: %v, try another", url, service, err)
|
||||
}
|
||||
return nil, nil, fmt.Errorf("failed to operate %s by cinder service", url)
|
||||
func (region *SRegion) vpcPost(resource string, params interface{}) (jsonutils.JSONObject, error) {
|
||||
return region.client.vpcRequest(region.Name, httputils.POST, resource, nil, params)
|
||||
}
|
||||
|
||||
func (region *SRegion) vpcDelete(resource string) (jsonutils.JSONObject, error) {
|
||||
return region.client.vpcRequest(region.Name, httputils.DELETE, resource, nil, nil)
|
||||
}
|
||||
|
||||
func (region *SRegion) imageList(resource string, query url.Values) (jsonutils.JSONObject, error) {
|
||||
return region.client.imageRequest(region.Name, httputils.GET, resource, query, nil)
|
||||
}
|
||||
|
||||
func (region *SRegion) imageGet(resource string) (jsonutils.JSONObject, error) {
|
||||
return region.client.imageRequest(region.Name, httputils.GET, resource, nil, nil)
|
||||
}
|
||||
|
||||
func (region *SRegion) imagePost(resource string, params interface{}) (jsonutils.JSONObject, error) {
|
||||
return region.client.imageRequest(region.Name, httputils.POST, resource, nil, params)
|
||||
}
|
||||
|
||||
func (region *SRegion) imageDelete(resource string) (jsonutils.JSONObject, error) {
|
||||
return region.client.imageRequest(region.Name, httputils.DELETE, resource, nil, nil)
|
||||
}
|
||||
|
||||
func (region *SRegion) imageUpload(url string, body io.Reader) error {
|
||||
resp, err := region.client.imageUpload(region.Name, url, body)
|
||||
_, _, err = httputils.ParseResponse("", resp, err, region.client.debug)
|
||||
return err
|
||||
}
|
||||
|
||||
// Block Storage
|
||||
func (region *SRegion) bsList(resource string, query url.Values) (jsonutils.JSONObject, error) {
|
||||
return region.client.bsRequest(region.Name, httputils.GET, resource, query, nil)
|
||||
}
|
||||
|
||||
func (region *SRegion) bsGet(resource string) (jsonutils.JSONObject, error) {
|
||||
return region.client.bsRequest(region.Name, httputils.GET, resource, nil, nil)
|
||||
}
|
||||
|
||||
func (region *SRegion) bsUpdate(resource string, params interface{}) (jsonutils.JSONObject, error) {
|
||||
return region.client.bsRequest(region.Name, httputils.PUT, resource, nil, params)
|
||||
}
|
||||
|
||||
func (region *SRegion) bsPost(resource string, params interface{}) (jsonutils.JSONObject, error) {
|
||||
return region.client.bsRequest(region.Name, httputils.POST, resource, nil, params)
|
||||
}
|
||||
|
||||
func (region *SRegion) bsDelete(resource string) (jsonutils.JSONObject, error) {
|
||||
return region.client.bsRequest(region.Name, httputils.DELETE, resource, nil, nil)
|
||||
}
|
||||
|
||||
func (region *SRegion) bsCreate(projectId, resource string, params interface{}) (jsonutils.JSONObject, error) {
|
||||
return region.client.bsCreate(projectId, region.Name, resource, params)
|
||||
}
|
||||
|
||||
func (region *SRegion) ProjectId() string {
|
||||
@@ -405,27 +359,32 @@ func (region *SRegion) ProjectId() string {
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) {
|
||||
if region.izones == nil {
|
||||
if err := region.fetchInfrastructure(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err := region.fetchZones()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return region.izones, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetVersion(service string) (string, string, error) {
|
||||
return region.client.getVersion(region.Name, service)
|
||||
izones := []cloudprovider.ICloudZone{}
|
||||
for i := range region.zones {
|
||||
izones = append(izones, ®ion.zones[i])
|
||||
}
|
||||
return izones, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) {
|
||||
if err := region.fetchInfrastructure(); err != nil {
|
||||
return nil, err
|
||||
err := region.fetchVpcs()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchVpcs")
|
||||
}
|
||||
return region.ivpcs, nil
|
||||
ivpcs := []cloudprovider.ICloudVpc{}
|
||||
for i := range region.vpcs {
|
||||
region.vpcs[i].region = region
|
||||
ivpcs = append(ivpcs, ®ion.vpcs[i])
|
||||
}
|
||||
return ivpcs, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) {
|
||||
eips, err := region.GetEips()
|
||||
eips, err := region.GetEips("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -438,7 +397,15 @@ func (region *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) {
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) {
|
||||
return region.CreateEip(eip)
|
||||
network, err := region.GetNetwork(eip.NetworkExternalId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetNetwork(%s)", eip.NetworkExternalId)
|
||||
}
|
||||
ieip, err := region.CreateEip(network.NetworkId, eip.NetworkExternalId, eip.IP, eip.ProjectId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "CreateEip")
|
||||
}
|
||||
return ieip, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) {
|
||||
@@ -522,8 +489,8 @@ func (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.I
|
||||
return region.GetSecurityGroup(secgroupId)
|
||||
}
|
||||
|
||||
func (region *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
secgroups, err := region.GetSecurityGroups(name)
|
||||
func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
secgroups, err := region.GetSecurityGroups(opts.ProjectId, opts.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -538,7 +505,7 @@ func (region *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloud
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
return region.CreateSecurityGroup(conf.Name, conf.Desc)
|
||||
return region.CreateSecurityGroup(conf.ProjectId, conf.Name, conf.Desc)
|
||||
}
|
||||
|
||||
func (region *SRegion) GetCapabilities() []string {
|
||||
@@ -546,9 +513,10 @@ func (region *SRegion) GetCapabilities() []string {
|
||||
}
|
||||
|
||||
func (region *SRegion) GetRouters() ([]SRouter, error) {
|
||||
_, resp, err := region.Get("network", "/v2.0/routers", "", nil)
|
||||
resource := "/v2.0/routers"
|
||||
resp, err := region.vpcList(resource, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "region.Get routes")
|
||||
return nil, errors.Wrap(err, "vpcList.routes")
|
||||
}
|
||||
routers := []SRouter{}
|
||||
err = resp.Unmarshal(&routers, "routers")
|
||||
@@ -556,7 +524,7 @@ func (region *SRegion) GetRouters() ([]SRouter, error) {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
for i := 0; i < len(routers); i++ {
|
||||
ports, err := region.GetPortsByDeviceId(routers[i].ID)
|
||||
ports, err := region.GetPorts("", routers[i].Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "vpc.region.GetPortsByDeviceId")
|
||||
}
|
||||
@@ -576,15 +544,3 @@ func (region *SRegion) fetchrouters() error {
|
||||
region.routers = routers
|
||||
return nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetPortsByDeviceId(routerId string) ([]SPort, error) {
|
||||
query := url.Values{}
|
||||
query.Set("device_id", routerId)
|
||||
_, resp, err := region.Get("network", "/v2.0/ports?"+query.Encode(), "", nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "region.Get routes")
|
||||
}
|
||||
ports := []SPort{}
|
||||
return ports, resp.Unmarshal(&ports, "ports")
|
||||
|
||||
}
|
||||
|
||||
@@ -16,12 +16,12 @@ package openstack
|
||||
|
||||
type SExternalFixedIP struct {
|
||||
IPAddress string `json:"ip_address"`
|
||||
SubnetID string `json:"subnet_id"`
|
||||
SubnetId string `json:"subnet_id"`
|
||||
}
|
||||
type SExternalGatewayInfo struct {
|
||||
EnableSnat bool `json:"enable_snat"`
|
||||
ExtrernalFiedIps []SExternalFixedIP `json:"external_fixed_ips"`
|
||||
NetworkID string `json:"network_id"`
|
||||
NetworkId string `json:"network_id"`
|
||||
}
|
||||
|
||||
type SConntrackHelper struct {
|
||||
@@ -33,13 +33,13 @@ type SRouter struct {
|
||||
ports []SPort
|
||||
AdminStateUp bool `json:"admin_state_up"`
|
||||
Description string `json:"description"`
|
||||
FlavorID string `json:"flavor_id"`
|
||||
ID string `json:"id"`
|
||||
FlavorId string `json:"flavor_id"`
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Routes []SRouteEntry `json:"routes"`
|
||||
Status string `json:"status"`
|
||||
ProjectID string `json:"project_id"`
|
||||
TenantID string `json:"tenant_id"`
|
||||
ProjectId string `json:"project_id"`
|
||||
TenantId string `json:"tenant_id"`
|
||||
Tags []string `json:"tags"`
|
||||
ConntrackHelpers []SConntrackHelper `json:"conntrack_helpers"`
|
||||
ExternalGatewayInfo SExternalGatewayInfo `json:"external_gateway_info"`
|
||||
|
||||
@@ -57,7 +57,7 @@ func (self *SRouteTable) GetId() string {
|
||||
}
|
||||
|
||||
func (self *SRouteTable) GetGlobalId() string {
|
||||
return self.router.ID
|
||||
return self.router.Id
|
||||
}
|
||||
|
||||
func (self *SRouteTable) GetName() string {
|
||||
|
||||
@@ -16,6 +16,7 @@ package openstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -37,17 +38,17 @@ const (
|
||||
type SSecurityGroupRule struct {
|
||||
Direction string
|
||||
Ethertype string
|
||||
ID string
|
||||
Id string
|
||||
PortRangeMax int
|
||||
PortRangeMin int
|
||||
Protocol string
|
||||
RemoteGroupID string
|
||||
RemoteGroupId string
|
||||
RemoteIpPrefix string
|
||||
SecurityGroupID string
|
||||
ProjectID string
|
||||
SecurityGroupId string
|
||||
ProjectId string
|
||||
RevisionNumber int
|
||||
Tags []string
|
||||
TenantID string
|
||||
TenantId string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Description string
|
||||
@@ -58,62 +59,61 @@ type SSecurityGroup struct {
|
||||
region *SRegion
|
||||
|
||||
Description string
|
||||
ID string
|
||||
Id string
|
||||
Name string
|
||||
SecurityGroupRules []SSecurityGroupRule
|
||||
ProjectID string
|
||||
ProjectId string
|
||||
RevisionNumber int
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Tags []string
|
||||
TenantID string
|
||||
TenantId string
|
||||
}
|
||||
|
||||
func (region *SRegion) GetSecurityGroup(secgroupId string) (*SSecurityGroup, error) {
|
||||
_, resp, err := region.Get("network", "/v2.0/security-groups/"+secgroupId, "", nil)
|
||||
resource := "/v2.0/security-groups/" + secgroupId
|
||||
resp, err := region.vpcGet(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "vpcGet")
|
||||
}
|
||||
secgroup := &SSecurityGroup{region: region}
|
||||
return secgroup, resp.Unmarshal(secgroup, "security_group")
|
||||
err = resp.Unmarshal(secgroup, "security_group")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return secgroup, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetSecurityGroups(name string) ([]SSecurityGroup, error) {
|
||||
url := "/v2.0/security-groups"
|
||||
if len(name) > 0 {
|
||||
url = fmt.Sprintf("%s?name=%s", url, name)
|
||||
}
|
||||
func (region *SRegion) GetSecurityGroups(projectId, name string) ([]SSecurityGroup, error) {
|
||||
secgroups := []SSecurityGroup{}
|
||||
for len(url) > 0 {
|
||||
_, resp, err := region.List("network", url, "", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_secgroups := []SSecurityGroup{}
|
||||
err = resp.Unmarshal(&_secgroups, "security_groups")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, `resp.Unmarshal(&_secgroups, "security_groups")`)
|
||||
}
|
||||
secgroups = append(secgroups, _secgroups...)
|
||||
url = ""
|
||||
if resp.Contains("security_groups_links") {
|
||||
nextLink := []SNextLink{}
|
||||
err = resp.Unmarshal(&nextLink, "security_groups_links")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, `resp.Unmarshal(&nextLink, "security_groups_links")`)
|
||||
}
|
||||
for _, next := range nextLink {
|
||||
if next.Rel == "next" {
|
||||
url = next.Href
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
resource := "/v2.0/security-groups"
|
||||
query := url.Values{}
|
||||
if len(name) > 0 {
|
||||
query.Set("name", name)
|
||||
}
|
||||
for i := range secgroups {
|
||||
secgroups[i].region = region
|
||||
if len(projectId) > 0 {
|
||||
query.Set("project_id", projectId)
|
||||
}
|
||||
for {
|
||||
resp, err := region.vpcList(resource, query)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "vpcList")
|
||||
}
|
||||
part := struct {
|
||||
SecurityGroups []SSecurityGroup
|
||||
SecurityGroupsLinks SNextLinks
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
secgroups = append(secgroups, part.SecurityGroups...)
|
||||
marker := part.SecurityGroupsLinks.GetNextMark()
|
||||
if len(marker) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", marker)
|
||||
}
|
||||
|
||||
return secgroups, nil
|
||||
}
|
||||
|
||||
@@ -126,11 +126,11 @@ func (secgroup *SSecurityGroup) GetVpcId() string {
|
||||
}
|
||||
|
||||
func (secgroup *SSecurityGroup) GetId() string {
|
||||
return secgroup.ID
|
||||
return secgroup.Id
|
||||
}
|
||||
|
||||
func (secgroup *SSecurityGroup) GetGlobalId() string {
|
||||
return secgroup.ID
|
||||
return secgroup.Id
|
||||
}
|
||||
|
||||
func (secgroup *SSecurityGroup) GetDescription() string {
|
||||
@@ -141,17 +141,17 @@ func (secgroup *SSecurityGroup) GetName() string {
|
||||
if len(secgroup.Name) > 0 {
|
||||
return secgroup.Name
|
||||
}
|
||||
return secgroup.ID
|
||||
return secgroup.Id
|
||||
}
|
||||
|
||||
func (secgrouprule *SSecurityGroupRule) toRules() ([]cloudprovider.SecurityRule, error) {
|
||||
rules := []cloudprovider.SecurityRule{}
|
||||
// 暂时忽略IPv6安全组规则,忽略远端也是安全组的规则
|
||||
if secgrouprule.Ethertype != "IPv4" || len(secgrouprule.RemoteGroupID) > 0 {
|
||||
return rules, fmt.Errorf("ethertype: %s remoteGroupId: %s", secgrouprule.Ethertype, secgrouprule.RemoteGroupID)
|
||||
if secgrouprule.Ethertype != "IPv4" || len(secgrouprule.RemoteGroupId) > 0 {
|
||||
return rules, fmt.Errorf("ethertype: %s remoteGroupId: %s", secgrouprule.Ethertype, secgrouprule.RemoteGroupId)
|
||||
}
|
||||
rule := cloudprovider.SecurityRule{
|
||||
ExternalId: secgrouprule.ID,
|
||||
ExternalId: secgrouprule.Id,
|
||||
SecurityRule: secrules.SecurityRule{
|
||||
Direction: secrules.DIR_IN,
|
||||
Action: secrules.SecurityRuleAllow,
|
||||
@@ -197,7 +197,7 @@ func (secgroup *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error)
|
||||
for _, rule := range secgroup.SecurityGroupRules {
|
||||
subRules, err := rule.toRules()
|
||||
if err != nil {
|
||||
log.Errorf("failed to convert rule %s for secgroup %s(%s) error: %v", rule.ID, secgroup.Name, secgroup.ID, err)
|
||||
log.Errorf("failed to convert rule %s for secgroup %s(%s) error: %v", rule.Id, secgroup.Name, secgroup.Id, err)
|
||||
continue
|
||||
}
|
||||
rules = append(rules, subRules...)
|
||||
@@ -214,7 +214,7 @@ func (secgroup *SSecurityGroup) IsEmulated() bool {
|
||||
}
|
||||
|
||||
func (secgroup *SSecurityGroup) Refresh() error {
|
||||
new, err := secgroup.region.GetSecurityGroup(secgroup.ID)
|
||||
new, err := secgroup.region.GetSecurityGroup(secgroup.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -222,7 +222,8 @@ func (secgroup *SSecurityGroup) Refresh() error {
|
||||
}
|
||||
|
||||
func (region *SRegion) delSecurityGroupRule(ruleId string) error {
|
||||
_, err := region.Delete("network", "/v2.0/security-group-rules/"+ruleId, "")
|
||||
resource := "/v2.0/security-group-rules/" + ruleId
|
||||
_, err := region.vpcDelete(resource)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -252,9 +253,10 @@ func (region *SRegion) addSecurityGroupRules(secgroupId string, rule cloudprovid
|
||||
for _, port := range rule.Ports {
|
||||
params["security_group_rule"]["port_range_max"] = port
|
||||
params["security_group_rule"]["port_range_min"] = port
|
||||
_, _, err := region.Post("network", "/v2.0/security-group-rules", "", jsonutils.Marshal(params))
|
||||
resource := "/v2.0/security-group-rules"
|
||||
_, err := region.vpcPost(resource, params)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "vpcPost")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -263,36 +265,44 @@ func (region *SRegion) addSecurityGroupRules(secgroupId string, rule cloudprovid
|
||||
params["security_group_rule"]["port_range_min"] = rule.PortStart
|
||||
params["security_group_rule"]["port_range_max"] = rule.PortEnd
|
||||
}
|
||||
_, _, err := region.Post("network", "/v2.0/security-group-rules", "", jsonutils.Marshal(params))
|
||||
_, err := region.vpcPost("/v2.0/security-group-rules", params)
|
||||
return err
|
||||
}
|
||||
|
||||
func (region *SRegion) DeleteSecurityGroup(secGroupId string) error {
|
||||
_, err := region.Delete("network", "/v2.0/security-groups/"+secGroupId, "")
|
||||
resource := "/v2.0/security-groups/" + secGroupId
|
||||
_, err := region.vpcDelete(resource)
|
||||
return err
|
||||
}
|
||||
|
||||
func (secgroup *SSecurityGroup) Delete() error {
|
||||
return secgroup.region.DeleteSecurityGroup(secgroup.ID)
|
||||
return secgroup.region.DeleteSecurityGroup(secgroup.Id)
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateSecurityGroup(name, description string) (*SSecurityGroup, error) {
|
||||
func (region *SRegion) CreateSecurityGroup(projectId, name, description string) (*SSecurityGroup, error) {
|
||||
params := map[string]map[string]interface{}{
|
||||
"security_group": {
|
||||
"name": name,
|
||||
"description": description,
|
||||
},
|
||||
}
|
||||
_, resp, err := region.Post("network", "/v2.0/security-groups", "", jsonutils.Marshal(params))
|
||||
if len(projectId) > 0 {
|
||||
params["security_group"]["project_id"] = projectId
|
||||
}
|
||||
resp, err := region.vpcPost("/v2.0/security-groups", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "vpcPost")
|
||||
}
|
||||
secgroup := &SSecurityGroup{region: region}
|
||||
return secgroup, resp.Unmarshal(secgroup, "security_group")
|
||||
err = resp.Unmarshal(secgroup, "security_group")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return secgroup, nil
|
||||
}
|
||||
|
||||
func (secgroup *SSecurityGroup) GetProjectId() string {
|
||||
return secgroup.TenantID
|
||||
return secgroup.TenantId
|
||||
}
|
||||
|
||||
func (secgroup *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error {
|
||||
@@ -303,7 +313,7 @@ func (secgroup *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDe
|
||||
}
|
||||
}
|
||||
for _, r := range append(inAdds, outAdds...) {
|
||||
err := secgroup.region.addSecurityGroupRules(secgroup.ID, r)
|
||||
err := secgroup.region.addSecurityGroupRules(secgroup.Id, r)
|
||||
if err != nil {
|
||||
if jsonError, ok := err.(*httputils.JSONClientError); ok {
|
||||
if jsonError.Class == "SecurityGroupRuleExists" {
|
||||
|
||||
@@ -21,11 +21,9 @@ import (
|
||||
|
||||
func init() {
|
||||
type DiskListOptions struct {
|
||||
Category string `help:"Storage type for disk"`
|
||||
BackendName string `help:"Storage backend eg:lvm, rbd"`
|
||||
}
|
||||
shellutils.R(&DiskListOptions{}, "disk-list", "List disks", func(cli *openstack.SRegion, args *DiskListOptions) error {
|
||||
disks, err := cli.GetDisks(args.Category, args.BackendName)
|
||||
disks, err := cli.GetDisks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -21,9 +21,10 @@ import (
|
||||
|
||||
func init() {
|
||||
type EipListOptions struct {
|
||||
Ip string
|
||||
}
|
||||
shellutils.R(&EipListOptions{}, "eip-list", "List eips", func(cli *openstack.SRegion, args *EipListOptions) error {
|
||||
eips, err := cli.GetEips()
|
||||
eips, err := cli.GetEips(args.Ip)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -38,4 +39,20 @@ func init() {
|
||||
return cli.DeleteEip(args.ID)
|
||||
})
|
||||
|
||||
type EipCreateOptions struct {
|
||||
NETWORK string
|
||||
SUBNET string
|
||||
Ip string
|
||||
TenantId string
|
||||
}
|
||||
|
||||
shellutils.R(&EipCreateOptions{}, "eip-create", "Create eip", func(cli *openstack.SRegion, args *EipCreateOptions) error {
|
||||
eip, err := cli.CreateEip(args.NETWORK, args.SUBNET, args.Ip, args.TenantId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(eip)
|
||||
return nil
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
package shell
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/multicloud/openstack"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
)
|
||||
@@ -25,7 +23,7 @@ func init() {
|
||||
type HostListOptions struct {
|
||||
}
|
||||
shellutils.R(&HostListOptions{}, "host-list", "List hosts", func(cli *openstack.SRegion, args *HostListOptions) error {
|
||||
hosts, err := cli.GetIHosts()
|
||||
hosts, err := cli.GetHosts()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -33,24 +31,6 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
type HostShowOptions struct {
|
||||
ID string `help:"Host name"`
|
||||
ZONE string `help:"Zone name"`
|
||||
REGION string `help:"Region name"`
|
||||
}
|
||||
shellutils.R(&HostShowOptions{}, "host-show", "Show host detail", func(cli *openstack.SRegion, args *HostShowOptions) error {
|
||||
zone, err := cli.GetIZoneById(fmt.Sprintf("%s/%s/%s", openstack.CLOUD_PROVIDER_OPENSTACK, args.REGION, args.ZONE))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
host, err := zone.GetIHostById(args.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(host)
|
||||
return nil
|
||||
})
|
||||
|
||||
type AggregateListOption struct {
|
||||
}
|
||||
|
||||
@@ -63,4 +43,16 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
type HypervisorListOption struct {
|
||||
}
|
||||
|
||||
shellutils.R(&HypervisorListOption{}, "hypervisor-list", "List os-hypervisor", func(cli *openstack.SRegion, args *HypervisorListOption) error {
|
||||
hypervisors, err := cli.GetHypervisors()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printList(hypervisors, 0, 0, 0, []string{})
|
||||
return nil
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
package shell
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/multicloud/openstack"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
)
|
||||
@@ -57,10 +61,16 @@ func init() {
|
||||
OsDistro string
|
||||
MinDiskSizeGB int
|
||||
MinRamMb int
|
||||
FILE string
|
||||
}
|
||||
|
||||
shellutils.R(&ImageCreateOptions{}, "image-create", "Create image", func(cli *openstack.SRegion, args *ImageCreateOptions) error {
|
||||
image, err := cli.CreateImage(args.NAME, args.OsType, args.OsDistro, args.MinDiskSizeGB, args.MinRamMb)
|
||||
file, err := os.Open(args.FILE)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "os.Open")
|
||||
}
|
||||
defer file.Close()
|
||||
image, err := cli.CreateImage(args.NAME, args.OsType, args.OsDistro, args.MinDiskSizeGB, args.MinRamMb, file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -37,6 +37,16 @@ func init() {
|
||||
type InstanceOptions struct {
|
||||
ID string `help:"Instance ID"`
|
||||
}
|
||||
|
||||
shellutils.R(&InstanceOptions{}, "instance-network-list", "List instance network", func(cli *openstack.SRegion, args *InstanceOptions) error {
|
||||
ports, err := cli.GetInstancePorts(args.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(ports)
|
||||
return nil
|
||||
})
|
||||
|
||||
shellutils.R(&InstanceOptions{}, "instance-show", "Show instance", func(cli *openstack.SRegion, args *InstanceOptions) error {
|
||||
instance, err := cli.GetInstance(args.ID)
|
||||
if err != nil {
|
||||
@@ -46,6 +56,15 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
shellutils.R(&InstanceOptions{}, "instance-metadata", "Show instance metadata", func(cli *openstack.SRegion, args *InstanceOptions) error {
|
||||
metadata, err := cli.GetInstanceMetadata(args.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(metadata)
|
||||
return nil
|
||||
})
|
||||
|
||||
shellutils.R(&InstanceOptions{}, "instance-vnc", "Show instance vnc url", func(cli *openstack.SRegion, args *InstanceOptions) error {
|
||||
url, err := cli.GetInstanceVNCUrl(args.ID)
|
||||
if err != nil {
|
||||
|
||||
+5
-5
@@ -20,15 +20,15 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
type InstanceNicListOptions struct {
|
||||
Mac string `help:"Mac address for filter nics"`
|
||||
type MessageListOptions struct {
|
||||
ResourceId string
|
||||
}
|
||||
shellutils.R(&InstanceNicListOptions{}, "instancenic-list", "List instance nics", func(cli *openstack.SRegion, args *InstanceNicListOptions) error {
|
||||
instances, err := cli.GetPorts(args.Mac)
|
||||
shellutils.R(&MessageListOptions{}, "message-list", "List messages", func(cli *openstack.SRegion, args *MessageListOptions) error {
|
||||
messages, err := cli.GetMessages(args.ResourceId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printList(instances, 0, 0, 0, nil)
|
||||
printList(messages, 0, 0, 0, []string{})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@@ -44,4 +44,20 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
type NetworkCreateOptions struct {
|
||||
VPCID string
|
||||
NAME string
|
||||
CIDR string
|
||||
Desc string
|
||||
ProjectId string
|
||||
}
|
||||
|
||||
shellutils.R(&NetworkCreateOptions{}, "network-create", "Create network", func(cli *openstack.SRegion, args *NetworkCreateOptions) error {
|
||||
network, err := cli.CreateNetwork(args.VPCID, args.ProjectId, args.NAME, args.CIDR, args.Desc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(network)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -21,10 +21,11 @@ import (
|
||||
|
||||
func init() {
|
||||
type PortListOptions struct {
|
||||
MacAddr string
|
||||
MacAddr string
|
||||
DeviceId string
|
||||
}
|
||||
shellutils.R(&PortListOptions{}, "port-list", "List ports", func(cli *openstack.SRegion, args *PortListOptions) error {
|
||||
ports, err := cli.GetPorts(args.MacAddr)
|
||||
ports, err := cli.GetPorts(args.MacAddr, args.DeviceId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ func init() {
|
||||
type ProjectListOptions struct {
|
||||
}
|
||||
shellutils.R(&ProjectListOptions{}, "project-list", "List project", func(cli *openstack.SRegion, args *ProjectListOptions) error {
|
||||
project, err := cli.GetClient().GetIProjects()
|
||||
project, err := cli.GetClient().GetProjects()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -21,10 +21,11 @@ import (
|
||||
|
||||
func init() {
|
||||
type SecurityGroupListOptions struct {
|
||||
Name string
|
||||
ProjectId string
|
||||
Name string
|
||||
}
|
||||
shellutils.R(&SecurityGroupListOptions{}, "security-group-list", "List security groups", func(cli *openstack.SRegion, args *SecurityGroupListOptions) error {
|
||||
secgroup, err := cli.GetSecurityGroups(args.Name)
|
||||
secgroup, err := cli.GetSecurityGroups(args.ProjectId, args.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -55,12 +56,13 @@ func init() {
|
||||
})
|
||||
|
||||
type SecurityGroupCreateOptions struct {
|
||||
NAME string `help:"Name of security group"`
|
||||
Desc string `help:"Description of security group"`
|
||||
ProjectId string
|
||||
NAME string `help:"Name of security group"`
|
||||
Desc string `help:"Description of security group"`
|
||||
}
|
||||
|
||||
shellutils.R(&SecurityGroupCreateOptions{}, "security-group-create", "Create security group", func(cli *openstack.SRegion, args *SecurityGroupCreateOptions) error {
|
||||
secgroup, err := cli.CreateSecurityGroup(args.NAME, args.Desc)
|
||||
secgroup, err := cli.CreateSecurityGroup(args.ProjectId, args.NAME, args.Desc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -15,23 +15,15 @@
|
||||
package shell
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/multicloud/openstack"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
)
|
||||
|
||||
func init() {
|
||||
type StorageListOptions struct {
|
||||
REGION string `help:"Region Name"`
|
||||
ZONE string `help:"Zone Name"`
|
||||
}
|
||||
shellutils.R(&StorageListOptions{}, "storage-list", "List storages", func(cli *openstack.SRegion, args *StorageListOptions) error {
|
||||
zone, err := cli.GetIZoneById(fmt.Sprintf("%s/%s/%s", openstack.CLOUD_PROVIDER_OPENSTACK, args.REGION, args.ZONE))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
storages, err := zone.GetIStorages()
|
||||
storages, err := cli.GetStorageTypes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -40,17 +32,10 @@ func init() {
|
||||
})
|
||||
|
||||
type CinderServiceListOptions struct {
|
||||
REGION string `help:"Region Name"`
|
||||
ZONE string `help:"Zone Name"`
|
||||
}
|
||||
|
||||
shellutils.R(&CinderServiceListOptions{}, "cinder-service-list", "List cinder services", func(cli *openstack.SRegion, args *CinderServiceListOptions) error {
|
||||
izone, err := cli.GetIZoneById(fmt.Sprintf("%s/%s/%s", openstack.CLOUD_PROVIDER_OPENSTACK, args.REGION, args.ZONE))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
zone := izone.(*openstack.SZone)
|
||||
services, err := zone.GetCinderServices()
|
||||
services, err := cli.GetCinderServices()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -21,9 +21,10 @@ import (
|
||||
|
||||
func init() {
|
||||
type VpcListOptions struct {
|
||||
TenantId string
|
||||
}
|
||||
shellutils.R(&VpcListOptions{}, "vpc-list", "List vpcs", func(cli *openstack.SRegion, args *VpcListOptions) error {
|
||||
vpcs, err := cli.GetVpcs()
|
||||
vpcs, err := cli.GetVpcs(args.TenantId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -31,10 +32,10 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
type VpcShowOptions struct {
|
||||
type VpcIdOptions struct {
|
||||
ID string `help:"ID of vpc"`
|
||||
}
|
||||
shellutils.R(&VpcShowOptions{}, "vpc-show", "Show vpc", func(cli *openstack.SRegion, args *VpcShowOptions) error {
|
||||
shellutils.R(&VpcIdOptions{}, "vpc-show", "Show vpc", func(cli *openstack.SRegion, args *VpcIdOptions) error {
|
||||
vpc, err := cli.GetVpc(args.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -43,4 +44,21 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
shellutils.R(&VpcIdOptions{}, "vpc-delete", "Delete vpc", func(cli *openstack.SRegion, args *VpcIdOptions) error {
|
||||
return cli.DeleteVpc(args.ID)
|
||||
})
|
||||
|
||||
type VpcCreateOptions struct {
|
||||
NAME string
|
||||
Desc string
|
||||
}
|
||||
|
||||
shellutils.R(&VpcCreateOptions{}, "vpc-create", "Create vpc", func(cli *openstack.SRegion, args *VpcCreateOptions) error {
|
||||
vpc, err := cli.CreateVpc(args.NAME, args.Desc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(vpc)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ func init() {
|
||||
type ZoneListOptions struct {
|
||||
}
|
||||
shellutils.R(&ZoneListOptions{}, "zone-list", "List zones", func(cli *openstack.SRegion, args *ZoneListOptions) error {
|
||||
zones, err := cli.GetIZones()
|
||||
zones, err := cli.GetZones()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -15,7 +15,11 @@
|
||||
package openstack
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
@@ -36,16 +40,16 @@ const (
|
||||
type SSnapshot struct {
|
||||
region *SRegion
|
||||
|
||||
ID string
|
||||
VolumeID string
|
||||
Id string
|
||||
VolumeId string
|
||||
|
||||
Status string
|
||||
Metadata Metadata
|
||||
|
||||
Progress string `json:"os-extended-snapshot-attributes:progress"`
|
||||
Name string
|
||||
UserID string
|
||||
ProjectID string `json:"os-extended-snapshot-attributes:project_id"`
|
||||
UserId string
|
||||
ProjectId string `json:"os-extended-snapshot-attributes:project_id"`
|
||||
//CreatedAt time.Time
|
||||
Size int32
|
||||
|
||||
@@ -54,13 +58,15 @@ type SSnapshot struct {
|
||||
}
|
||||
|
||||
func (region *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) {
|
||||
_, resp, err := region.CinderGet("/snapshots/"+snapshotId, "", nil)
|
||||
resource := "/snapshots/" + snapshotId
|
||||
resp, err := region.bsGet(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "bsGet")
|
||||
}
|
||||
snapshot := SSnapshot{region: region}
|
||||
if err := resp.Unmarshal(&snapshot, "snapshot"); err != nil {
|
||||
return nil, err
|
||||
err = resp.Unmarshal(&snapshot, "snapshot")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return &snapshot, nil
|
||||
}
|
||||
@@ -85,34 +91,56 @@ func (snapshot *SSnapshot) IsEmulated() bool {
|
||||
}
|
||||
|
||||
func (snapshot *SSnapshot) Refresh() error {
|
||||
_snapshot, err := snapshot.region.GetISnapshotById(snapshot.ID)
|
||||
_snapshot, err := snapshot.region.GetISnapshotById(snapshot.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return jsonutils.Update(snapshot, _snapshot)
|
||||
}
|
||||
|
||||
func (region *SRegion) GetSnapshots(diskId string) ([]cloudprovider.ICloudSnapshot, error) {
|
||||
_, resp, err := region.CinderList("/snapshots/detail", "", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func (region *SRegion) GetSnapshots(diskId string) ([]SSnapshot, error) {
|
||||
resource := "/snapshots/detail"
|
||||
query := url.Values{}
|
||||
query.Set("all_tenants", "true")
|
||||
if len(diskId) > 0 {
|
||||
query.Set("volume_id", diskId)
|
||||
}
|
||||
snapshots := []SSnapshot{}
|
||||
if err := resp.Unmarshal(&snapshots, "snapshots"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iSnapshots := []cloudprovider.ICloudSnapshot{}
|
||||
for i := 0; i < len(snapshots); i++ {
|
||||
if len(diskId) == 0 || snapshots[i].VolumeID == diskId {
|
||||
snapshots[i].region = region
|
||||
iSnapshots = append(iSnapshots, &snapshots[i])
|
||||
for {
|
||||
resp, err := region.bsList(resource, query)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "bsList")
|
||||
}
|
||||
part := struct {
|
||||
Snapshots []SSnapshot
|
||||
SnapshotsLinks SNextLinks
|
||||
}{}
|
||||
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
snapshots = append(snapshots, part.Snapshots...)
|
||||
marker := part.SnapshotsLinks.GetNextMark()
|
||||
if len(marker) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", marker)
|
||||
}
|
||||
return iSnapshots, nil
|
||||
return snapshots, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
|
||||
return region.GetSnapshots("")
|
||||
snapshots, err := region.GetSnapshots("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
isnapshots := []cloudprovider.ICloudSnapshot{}
|
||||
for i := range snapshots {
|
||||
snapshots[i].region = region
|
||||
isnapshots = append(isnapshots, &snapshots[i])
|
||||
}
|
||||
return isnapshots, nil
|
||||
}
|
||||
|
||||
func (snapshot *SSnapshot) GetMetadata() *jsonutils.JSONDict {
|
||||
@@ -124,41 +152,43 @@ func (snapshot *SSnapshot) GetSizeMb() int32 {
|
||||
}
|
||||
|
||||
func (snapshot *SSnapshot) GetDiskId() string {
|
||||
return snapshot.VolumeID
|
||||
return snapshot.VolumeId
|
||||
}
|
||||
|
||||
func (snapshot *SSnapshot) GetId() string {
|
||||
return snapshot.ID
|
||||
return snapshot.Id
|
||||
}
|
||||
|
||||
func (snapshot *SSnapshot) GetGlobalId() string {
|
||||
return snapshot.ID
|
||||
return snapshot.Id
|
||||
}
|
||||
|
||||
func (snapshot *SSnapshot) GetName() string {
|
||||
if len(snapshot.Name) == 0 {
|
||||
return snapshot.ID
|
||||
return snapshot.Id
|
||||
}
|
||||
return snapshot.Name
|
||||
}
|
||||
|
||||
func (snapshot *SSnapshot) Delete() error {
|
||||
return snapshot.region.DeleteSnapshot(snapshot.ID)
|
||||
return snapshot.region.DeleteSnapshot(snapshot.Id)
|
||||
}
|
||||
|
||||
func (snapshot *SSnapshot) GetDiskType() string {
|
||||
if len(snapshot.VolumeID) > 0 {
|
||||
if disk, err := snapshot.region.GetDisk(snapshot.VolumeID); err == nil {
|
||||
if disk.Bootable {
|
||||
return api.DISK_TYPE_SYS
|
||||
}
|
||||
if len(snapshot.VolumeId) > 0 {
|
||||
disk, err := snapshot.region.GetDisk(snapshot.VolumeId)
|
||||
if err != nil {
|
||||
log.Errorf("failed to get snapshot %s disk %s error: %v", snapshot.Name, snapshot.VolumeId, err)
|
||||
return api.DISK_TYPE_DATA
|
||||
}
|
||||
return disk.GetDiskType()
|
||||
}
|
||||
return api.DISK_TYPE_DATA
|
||||
}
|
||||
|
||||
func (region *SRegion) DeleteSnapshot(snapshotId string) error {
|
||||
_, err := region.CinderDelete("/snapshots/"+snapshotId, "")
|
||||
resource := "/snapshots/" + snapshotId
|
||||
_, err := region.bsDelete(resource)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -171,14 +201,18 @@ func (region *SRegion) CreateSnapshot(diskId, name, desc string) (*SSnapshot, er
|
||||
"force": true,
|
||||
},
|
||||
}
|
||||
_, resp, err := region.CinderCreate("", "/snapshots", "", jsonutils.Marshal(params))
|
||||
resp, err := region.bsPost("/snapshots", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "bsPost")
|
||||
}
|
||||
snapshot := &SSnapshot{region: region}
|
||||
return snapshot, resp.Unmarshal(snapshot, "snapshot")
|
||||
err = resp.Unmarshal(snapshot, "snapshot")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return snapshot, nil
|
||||
}
|
||||
|
||||
func (self *SSnapshot) GetProjectId() string {
|
||||
return self.ProjectID
|
||||
return self.ProjectId
|
||||
}
|
||||
|
||||
@@ -15,11 +15,13 @@
|
||||
package openstack
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
@@ -66,21 +68,23 @@ func (storage *SStorage) GetIZone() cloudprovider.ICloudZone {
|
||||
}
|
||||
|
||||
func (storage *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
|
||||
disks, err := storage.zone.region.GetDisks(storage.Name, storage.ExtraSpecs.VolumeBackendName)
|
||||
disks, err := storage.zone.region.GetDisks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iDisks := []cloudprovider.ICloudDisk{}
|
||||
idisks := []cloudprovider.ICloudDisk{}
|
||||
for i := 0; i < len(disks); i++ {
|
||||
disks[i].storage = storage
|
||||
iDisks = append(iDisks, &disks[i])
|
||||
if disks[i].VolumeType == storage.Name || strings.HasSuffix(disks[i].Host, "#"+storage.ExtraSpecs.VolumeBackendName) {
|
||||
disks[i].storage = storage
|
||||
idisks = append(idisks, &disks[i])
|
||||
}
|
||||
}
|
||||
return iDisks, nil
|
||||
return idisks, nil
|
||||
}
|
||||
|
||||
func (storage *SStorage) GetStorageType() string {
|
||||
if len(storage.ExtraSpecs.VolumeBackendName) == 0 {
|
||||
storage.ExtraSpecs.VolumeBackendName = DEFAULT_STORAGE_TYPE
|
||||
return DEFAULT_STORAGE_TYPE
|
||||
}
|
||||
return storage.ExtraSpecs.VolumeBackendName
|
||||
}
|
||||
@@ -102,10 +106,11 @@ func (storage *SStorage) GetStorageConf() jsonutils.JSONObject {
|
||||
}
|
||||
|
||||
func (storage *SStorage) GetStatus() string {
|
||||
if utils.IsInStringArray(storage.GetStorageType(), storage.zone.getAvailableStorages()) {
|
||||
return api.STORAGE_ONLINE
|
||||
ok, err := storage.zone.region.IsStorageAvailable(storage.GetStorageType())
|
||||
if err != nil || !ok {
|
||||
return api.STORAGE_OFFLINE
|
||||
}
|
||||
return api.STORAGE_OFFLINE
|
||||
return api.STORAGE_ONLINE
|
||||
}
|
||||
|
||||
func (storage *SStorage) Refresh() error {
|
||||
@@ -147,3 +152,100 @@ func (storage *SStorage) GetMountPoint() string {
|
||||
func (storage *SStorage) IsSysDiskStore() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (region *SRegion) GetStorageTypes() ([]SStorage, error) {
|
||||
resource := "/types"
|
||||
storages := []SStorage{}
|
||||
query := url.Values{}
|
||||
for {
|
||||
resp, err := region.bsList(resource, query)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "bsReqest")
|
||||
}
|
||||
part := struct {
|
||||
VolumeTypes []SStorage
|
||||
VolumeTypeLinks SNextLinks
|
||||
}{}
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
storages = append(storages, part.VolumeTypes...)
|
||||
marker := part.VolumeTypeLinks.GetNextMark()
|
||||
if len(marker) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", marker)
|
||||
}
|
||||
return storages, nil
|
||||
}
|
||||
|
||||
type SCinderService struct {
|
||||
ActiveBackendId string
|
||||
// cinder-volume
|
||||
Binary string
|
||||
DisabledReason string
|
||||
Frozen string
|
||||
Host string
|
||||
ReplicationStatus string
|
||||
State string
|
||||
Status string
|
||||
UpdatedAt time.Time
|
||||
Zone string
|
||||
}
|
||||
|
||||
func (region *SRegion) GetCinderServices() ([]SCinderService, error) {
|
||||
resp, err := region.bsList("/os-services", nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "bsList")
|
||||
}
|
||||
services := []SCinderService{}
|
||||
err = resp.Unmarshal(&services, "services")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) IsStorageAvailable(storageType string) (bool, error) {
|
||||
if utils.IsInStringArray(storageType, []string{DEFAULT_STORAGE_TYPE, api.STORAGE_OPENSTACK_NOVA}) {
|
||||
return true, nil
|
||||
}
|
||||
services, err := region.GetCinderServices()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "GetCinderServices")
|
||||
}
|
||||
for _, service := range services {
|
||||
if service.Binary == "cinder-volume" && strings.Contains(service.Host, "@") {
|
||||
hostInfo := strings.Split(service.Host, "@")
|
||||
if hostInfo[len(hostInfo)-1] == storageType {
|
||||
if service.State == "up" && service.Status == "enabled" {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Errorf("storage %s offline", storageType)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
type SCapabilities struct {
|
||||
}
|
||||
|
||||
type SPool struct {
|
||||
Name string
|
||||
Capabilities SCapabilities
|
||||
}
|
||||
|
||||
func (region *SRegion) GetSchedulerStatsPool() ([]SPool, error) {
|
||||
resp, err := region.bsList("/scheduler-stats/get_pools", nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "bsList")
|
||||
}
|
||||
pools := []SPool{}
|
||||
err = resp.Unmarshal(&pools, "pools")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return pools, nil
|
||||
}
|
||||
|
||||
@@ -151,18 +151,14 @@ func (cache *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.T
|
||||
minDiskSizeGB += 1
|
||||
}
|
||||
|
||||
img, err := cache.region.CreateImage(imageName, osType, osDist, int(minDiskSizeGB), int(minRamMb))
|
||||
img, err := cache.region.CreateImage(imageName, osType, osDist, int(minDiskSizeGB), int(minRamMb), reader)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
img.storageCache = cache
|
||||
|
||||
_, err = cache.region.client.StreamRequest(cache.region.Name, "image", "PUT", fmt.Sprintf("/v2/images/%s/file", img.ID), "", reader)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return img.ID, cloudprovider.WaitStatus(img, api.CACHED_IMAGE_STATUS_READY, 15*time.Second, 3600*time.Second)
|
||||
return img.Id, cloudprovider.WaitStatus(img, api.CACHED_IMAGE_STATUS_READY, 15*time.Second, 3600*time.Second)
|
||||
}
|
||||
|
||||
func (cache *SStoragecache) CreateIImage(snapshoutId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) {
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
package openstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -34,18 +36,14 @@ const (
|
||||
|
||||
type SVpc struct {
|
||||
multicloud.SVpc
|
||||
|
||||
region *SRegion
|
||||
|
||||
iwires []cloudprovider.ICloudWire
|
||||
secgroups []cloudprovider.ICloudSecurityGroup
|
||||
|
||||
AdminStateUp bool
|
||||
AvailabilityZoneHints []string
|
||||
AvailabilityZones []string
|
||||
CreatedAt time.Time
|
||||
DnsDomain string
|
||||
ID string
|
||||
Id string
|
||||
Ipv4AddressScope string
|
||||
Ipv6AddressScope string
|
||||
L2Adjacency bool
|
||||
@@ -69,23 +67,19 @@ type SVpc struct {
|
||||
SegmentationId string `json:"provider:segmentation_id"`
|
||||
}
|
||||
|
||||
func (vpc *SVpc) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vpc *SVpc) GetId() string {
|
||||
return vpc.ID
|
||||
return vpc.Id
|
||||
}
|
||||
|
||||
func (vpc *SVpc) GetName() string {
|
||||
if len(vpc.Name) > 0 {
|
||||
return vpc.Name
|
||||
}
|
||||
return vpc.ID
|
||||
return vpc.Id
|
||||
}
|
||||
|
||||
func (vpc *SVpc) GetGlobalId() string {
|
||||
return vpc.ID
|
||||
return vpc.Id
|
||||
}
|
||||
|
||||
func (vpc *SVpc) IsEmulated() bool {
|
||||
@@ -114,23 +108,30 @@ func (vpc *SVpc) GetStatus() string {
|
||||
}
|
||||
|
||||
func (vpc *SVpc) Delete() error {
|
||||
return vpc.region.DeleteVpc(vpc.ID)
|
||||
return vpc.region.DeleteVpc(vpc.Id)
|
||||
}
|
||||
|
||||
func (region *SRegion) DeleteVpc(vpcId string) error {
|
||||
_, err := region.Delete("network", "/v2.0/networks/"+vpcId, "")
|
||||
resource := fmt.Sprintf("/v2.0/networks/%s", vpcId)
|
||||
_, err := region.vpcDelete(resource)
|
||||
return err
|
||||
}
|
||||
|
||||
func (vpc *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) {
|
||||
secgroups, err := vpc.region.GetSecurityGroups("")
|
||||
err := vpc.region.client.fetchProjects()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "fetchProjects")
|
||||
}
|
||||
iSecgroups := []cloudprovider.ICloudSecurityGroup{}
|
||||
for i := 0; i < len(secgroups); i++ {
|
||||
secgroups[i].region = vpc.region
|
||||
iSecgroups = append(iSecgroups, &secgroups[i])
|
||||
for _, project := range vpc.region.client.projects {
|
||||
secgroups, err := vpc.region.GetSecurityGroups(project.Id, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetSecurityGroups(%s)", project.Id)
|
||||
}
|
||||
for i := 0; i < len(secgroups); i++ {
|
||||
secgroups[i].region = vpc.region
|
||||
iSecgroups = append(iSecgroups, &secgroups[i])
|
||||
}
|
||||
}
|
||||
return iSecgroups, nil
|
||||
}
|
||||
@@ -166,60 +167,30 @@ func (vpc *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) {
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (vpc *SVpc) fetchWires() error {
|
||||
if len(vpc.region.izones) == 0 {
|
||||
if err := vpc.region.fetchZones(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
wire := SWire{zone: vpc.region.izones[0].(*SZone), vpc: vpc}
|
||||
vpc.iwires = []cloudprovider.ICloudWire{&wire}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vpc *SVpc) getWire() *SWire {
|
||||
if vpc.iwires == nil {
|
||||
vpc.fetchWires()
|
||||
}
|
||||
return vpc.iwires[0].(*SWire)
|
||||
}
|
||||
|
||||
func (vpc *SVpc) fetchNetworks() error {
|
||||
networks, err := vpc.region.GetNetworks(vpc.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; i < len(networks); i++ {
|
||||
wire := vpc.getWire()
|
||||
networks[i].wire = wire
|
||||
wire.addNetwork(&networks[i])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vpc *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) {
|
||||
if vpc.iwires == nil {
|
||||
err := vpc.fetchNetworks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iwires, err := vpc.GetIWires()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetIWires")
|
||||
}
|
||||
for i := 0; i < len(vpc.iwires); i++ {
|
||||
if vpc.iwires[i].GetGlobalId() == wireId {
|
||||
return vpc.iwires[i], nil
|
||||
for i := range iwires {
|
||||
if iwires[i].GetGlobalId() == wireId {
|
||||
return iwires[i], nil
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (vpc *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) {
|
||||
if vpc.iwires == nil {
|
||||
err := vpc.fetchNetworks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err := vpc.region.fetchZones()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchZones")
|
||||
}
|
||||
return vpc.iwires, nil
|
||||
iwire := []cloudprovider.ICloudWire{}
|
||||
for i := range vpc.region.zones {
|
||||
wire := &SWire{vpc: vpc, zone: &vpc.region.zones[i]}
|
||||
iwire = append(iwire, wire)
|
||||
}
|
||||
return iwire, nil
|
||||
}
|
||||
|
||||
func (vpc *SVpc) GetRegion() cloudprovider.ICloudRegion {
|
||||
@@ -227,57 +198,75 @@ func (vpc *SVpc) GetRegion() cloudprovider.ICloudRegion {
|
||||
}
|
||||
|
||||
func (region *SRegion) GetVpc(vpcId string) (*SVpc, error) {
|
||||
_, resp, err := region.Get("network", "/v2.0/networks/"+vpcId, "", nil)
|
||||
vpc := &SVpc{region: region}
|
||||
resource := fmt.Sprintf("/v2.0/networks/%s", vpcId)
|
||||
resp, err := region.vpcGet(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "vpcGet(%s)", resource)
|
||||
}
|
||||
vpc := SVpc{}
|
||||
return &vpc, resp.Unmarshal(&vpc, "network")
|
||||
err = resp.Unmarshal(vpc, "network")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return vpc, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetVpcs() ([]SVpc, error) {
|
||||
url := "/v2.0/networks"
|
||||
func (region *SRegion) GetVpcs(projectId string) ([]SVpc, error) {
|
||||
vpcs := []SVpc{}
|
||||
for len(url) > 0 {
|
||||
_, resp, err := region.List("network", url, "", nil)
|
||||
resource := "/v2.0/networks"
|
||||
query := url.Values{}
|
||||
if len(projectId) > 0 {
|
||||
query.Set("tenant_id", projectId)
|
||||
}
|
||||
for {
|
||||
resp, err := region.vpcList(resource, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "vpcList.%s", resource)
|
||||
}
|
||||
_vpcs := []SVpc{}
|
||||
err = resp.Unmarshal(&_vpcs, "networks")
|
||||
|
||||
part := struct {
|
||||
Networks []SVpc
|
||||
NetworksLinks SNextLinks
|
||||
}{}
|
||||
|
||||
err = resp.Unmarshal(&part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, `resp.Unmarshal(&_vpcs, "networks")`)
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
vpcs = append(vpcs, _vpcs...)
|
||||
url = ""
|
||||
if resp.Contains("networks_links") {
|
||||
nextLink := []SNextLink{}
|
||||
err = resp.Unmarshal(&nextLink, "networks_links")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, `resp.Unmarshal(&nextLink, "networks_links")`)
|
||||
}
|
||||
for _, next := range nextLink {
|
||||
if next.Rel == "next" {
|
||||
url = next.Href
|
||||
break
|
||||
}
|
||||
}
|
||||
vpcs = append(vpcs, part.Networks...)
|
||||
marker := part.NetworksLinks.GetNextMark()
|
||||
if len(marker) == 0 {
|
||||
break
|
||||
}
|
||||
query.Set("marker", marker)
|
||||
}
|
||||
return vpcs, nil
|
||||
}
|
||||
|
||||
func (vpc *SVpc) Refresh() error {
|
||||
new, err := vpc.region.GetVpc(vpc.ID)
|
||||
_vpc, err := vpc.region.GetVpc(vpc.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrapf(err, "GetVpc(%s)", vpc.Id)
|
||||
}
|
||||
return jsonutils.Update(vpc, new)
|
||||
return jsonutils.Update(vpc, _vpc)
|
||||
}
|
||||
|
||||
func (vpc *SVpc) addWire(wire *SWire) {
|
||||
if vpc.iwires == nil {
|
||||
vpc.iwires = make([]cloudprovider.ICloudWire, 0)
|
||||
func (region *SRegion) CreateVpc(name, desc string) (*SVpc, error) {
|
||||
params := map[string]map[string]string{
|
||||
"network": {
|
||||
"name": name,
|
||||
"description": desc,
|
||||
},
|
||||
}
|
||||
vpc.iwires = append(vpc.iwires, wire)
|
||||
resource := "/v2.0/networks"
|
||||
resp, err := region.vpcPost(resource, params)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "vpcPost")
|
||||
}
|
||||
vpc := &SVpc{region: region}
|
||||
err = resp.Unmarshal(vpc, "network")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return vpc, nil
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
)
|
||||
@@ -26,8 +26,6 @@ import (
|
||||
type SWire struct {
|
||||
zone *SZone
|
||||
vpc *SVpc
|
||||
|
||||
inetworks []cloudprovider.ICloudNetwork
|
||||
}
|
||||
|
||||
func (wire *SWire) GetMetadata() *jsonutils.JSONDict {
|
||||
@@ -70,14 +68,13 @@ func (wire *SWire) GetBandwidth() int {
|
||||
return 10000
|
||||
}
|
||||
|
||||
func (wire *SWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) {
|
||||
networkId, err := wire.zone.region.CreateNetwork(wire.vpc.ID, name, cidr, desc)
|
||||
func (wire *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) {
|
||||
network, err := wire.zone.region.CreateNetwork(wire.vpc.Id, opts.ProjectId, opts.Name, opts.Cidr, opts.Desc)
|
||||
if err != nil {
|
||||
log.Errorf("CreateNetwork error %s", err)
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "CreateNetwork")
|
||||
}
|
||||
wire.inetworks = nil
|
||||
return wire.GetINetworkById(networkId)
|
||||
network.wire = wire
|
||||
return network, nil
|
||||
}
|
||||
|
||||
func (wire *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, error) {
|
||||
@@ -94,27 +91,14 @@ func (wire *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, e
|
||||
}
|
||||
|
||||
func (wire *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) {
|
||||
if wire.inetworks == nil {
|
||||
err := wire.vpc.fetchNetworks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return wire.inetworks, nil
|
||||
}
|
||||
|
||||
func (wire *SWire) addNetwork(network *SNetwork) {
|
||||
if wire.inetworks == nil {
|
||||
wire.inetworks = []cloudprovider.ICloudNetwork{}
|
||||
}
|
||||
find := false
|
||||
for i := 0; i < len(wire.inetworks); i++ {
|
||||
if wire.inetworks[i].GetGlobalId() == network.GetGlobalId() {
|
||||
find = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !find {
|
||||
wire.inetworks = append(wire.inetworks, network)
|
||||
networks, err := wire.vpc.region.GetNetworks(wire.vpc.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetNetworks(%s)", wire.vpc.Id)
|
||||
}
|
||||
inetworks := []cloudprovider.ICloudNetwork{}
|
||||
for i := range networks {
|
||||
networks[i].wire = wire
|
||||
inetworks = append(inetworks, &networks[i])
|
||||
}
|
||||
return inetworks, nil
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
@@ -31,18 +30,6 @@ type ZoneState struct {
|
||||
Available bool
|
||||
}
|
||||
|
||||
const (
|
||||
HYPERVISORS_VERSION = "2.28"
|
||||
)
|
||||
|
||||
type SCapabilities struct {
|
||||
}
|
||||
|
||||
type SPool struct {
|
||||
Name string
|
||||
Capabilities SCapabilities
|
||||
}
|
||||
|
||||
type HostState struct {
|
||||
Available bool
|
||||
Active bool
|
||||
@@ -52,18 +39,9 @@ type HostState struct {
|
||||
type SZone struct {
|
||||
region *SRegion
|
||||
|
||||
iwires []cloudprovider.ICloudWire
|
||||
istorages []cloudprovider.ICloudStorage
|
||||
|
||||
ZoneName string
|
||||
|
||||
cachedHosts map[string][]string
|
||||
|
||||
schedulerPools []SPool
|
||||
availableStorages []string
|
||||
unavailableStorages []string
|
||||
|
||||
Hosts map[string]map[string]HostState
|
||||
hosts []SHypervisor
|
||||
}
|
||||
|
||||
func (zone *SZone) GetMetadata() *jsonutils.JSONDict {
|
||||
@@ -100,228 +78,129 @@ func (zone *SZone) GetIRegion() cloudprovider.ICloudRegion {
|
||||
}
|
||||
|
||||
func (zone *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) {
|
||||
return zone.iwires, nil
|
||||
}
|
||||
|
||||
func (zone *SZone) fetchSchedulerStatsPool() error {
|
||||
var err error = nil
|
||||
zone.schedulerPools, err = zone.region.GetSchedulerStatsPool()
|
||||
err := zone.region.fetchVpcs()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetSchedulerStatsPool")
|
||||
return nil, errors.Wrap(err, "fetchVpcs")
|
||||
}
|
||||
return nil
|
||||
iwires := []cloudprovider.ICloudWire{}
|
||||
for i := range zone.region.vpcs {
|
||||
wire := &SWire{zone: zone, vpc: &zone.region.vpcs[i]}
|
||||
iwires = append(iwires, wire)
|
||||
}
|
||||
return iwires, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetSchedulerStatsPool() ([]SPool, error) {
|
||||
pools := []SPool{}
|
||||
for _, service := range []string{"volumev3", "volumev2", "volume"} {
|
||||
_, resp, err := region.List(service, "/scheduler-stats/get_pools", "", nil)
|
||||
if err == nil {
|
||||
if err := resp.Unmarshal(&pools, "pools"); err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal(&pools)")
|
||||
}
|
||||
return pools, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("failed to find scheduler-stats pool by cinder service")
|
||||
}
|
||||
|
||||
func (zone *SZone) getSchedulerStatsPool() ([]SPool, error) {
|
||||
if len(zone.schedulerPools) == 0 {
|
||||
return zone.schedulerPools, zone.fetchSchedulerStatsPool()
|
||||
}
|
||||
return zone.schedulerPools, nil
|
||||
}
|
||||
|
||||
func (zone *SZone) getStorageByCategory(category string) (*SStorage, error) {
|
||||
storages, err := zone.GetIStorages()
|
||||
func (zone *SZone) getStorageByCategory(category, host string) (*SStorage, error) {
|
||||
storages, err := zone.region.GetStorageTypes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "GetStorageTypes")
|
||||
}
|
||||
for i := 0; i < len(storages); i++ {
|
||||
storage, ok := storages[i].(*SStorage)
|
||||
if ok && strings.ToLower(storage.Name) == strings.ToLower(category) {
|
||||
return storage, nil
|
||||
for i := range storages {
|
||||
if storages[i].Name == category || storages[i].ExtraSpecs.VolumeBackendName == category {
|
||||
storages[i].zone = zone
|
||||
return &storages[i], nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("No such storage %s", category)
|
||||
}
|
||||
|
||||
func (zone *SZone) addWire(wire *SWire) {
|
||||
if zone.iwires == nil {
|
||||
zone.iwires = []cloudprovider.ICloudWire{}
|
||||
}
|
||||
zone.iwires = append(zone.iwires, wire)
|
||||
}
|
||||
|
||||
func (zone *SZone) fetchStorages() error {
|
||||
zone.istorages = []cloudprovider.ICloudStorage{}
|
||||
|
||||
for _, service := range []string{"volumev3", "volumev2", "volume"} {
|
||||
_, resp, err := zone.region.List(service, "/types", "", nil)
|
||||
if err == nil {
|
||||
storages := []SStorage{}
|
||||
if err := resp.Unmarshal(&storages, "volume_types"); err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; i < len(storages); i++ {
|
||||
storages[i].zone = zone
|
||||
zone.istorages = append(zone.istorages, &storages[i])
|
||||
}
|
||||
break
|
||||
}
|
||||
log.Debugf("failed to get volume types by service %s error: %v, try another", service, err)
|
||||
}
|
||||
nova := &SNovaStorage{zone: zone}
|
||||
zone.istorages = append(zone.istorages, nova)
|
||||
return fmt.Errorf("failed to find storage types by cinder service")
|
||||
}
|
||||
|
||||
type SCinderService struct {
|
||||
ActiveBackendId string
|
||||
// cinder-volume
|
||||
Binary string
|
||||
DisabledReason string
|
||||
Frozen string
|
||||
Host string
|
||||
ReplicationStatus string
|
||||
State string
|
||||
Status string
|
||||
UpdatedAt time.Time
|
||||
Zone string
|
||||
}
|
||||
|
||||
func (zone *SZone) GetCinderServices() ([]SCinderService, error) {
|
||||
_, resp, err := zone.region.CinderList("/os-services", "", nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "CinderList")
|
||||
}
|
||||
services := []SCinderService{}
|
||||
err = resp.Unmarshal(&services, "services")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func (zone *SZone) fetchCinderSerivces() error {
|
||||
services, err := zone.GetCinderServices()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetCinderServices")
|
||||
}
|
||||
zone.availableStorages = []string{DEFAULT_STORAGE_TYPE, api.STORAGE_OPENSTACK_NOVA}
|
||||
zone.unavailableStorages = []string{}
|
||||
for _, service := range services {
|
||||
if service.Binary == "cinder-volume" && strings.Contains(service.Host, "@") {
|
||||
hostInfo := strings.Split(service.Host, "@")
|
||||
storage := hostInfo[len(hostInfo)-1]
|
||||
if service.State == "up" && service.Status == "enabled" {
|
||||
zone.availableStorages = append(zone.availableStorages, storage)
|
||||
continue
|
||||
}
|
||||
zone.unavailableStorages = append(zone.unavailableStorages, storage)
|
||||
for i := range storages {
|
||||
if strings.HasSuffix(host, "#"+storages[i].Name) || strings.HasSuffix(host, "#"+storages[i].ExtraSpecs.VolumeBackendName) {
|
||||
storages[i].zone = zone
|
||||
return &storages[i], nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (zone *SZone) getAvailableStorages() []string {
|
||||
if zone.availableStorages == nil {
|
||||
err := zone.fetchCinderSerivces()
|
||||
if err != nil {
|
||||
log.Errorf("fetchCinderSerivces error: %v", err)
|
||||
}
|
||||
}
|
||||
return zone.availableStorages
|
||||
}
|
||||
|
||||
func (zone *SZone) getUnavailableStorage() []string {
|
||||
if zone.unavailableStorages == nil {
|
||||
err := zone.fetchCinderSerivces()
|
||||
if err != nil {
|
||||
log.Errorf("fetchCinderSerivces error: %v", err)
|
||||
}
|
||||
}
|
||||
return zone.unavailableStorages
|
||||
return nil, fmt.Errorf("No such storage [%s]", category)
|
||||
}
|
||||
|
||||
func (zone *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
|
||||
if zone.istorages == nil {
|
||||
zone.fetchStorages()
|
||||
storages, err := zone.region.GetStorageTypes()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetStorageTypes")
|
||||
}
|
||||
return zone.istorages, nil
|
||||
istorages := []cloudprovider.ICloudStorage{}
|
||||
for i := range storages {
|
||||
storages[i].zone = zone
|
||||
istorages = append(istorages, &storages[i])
|
||||
}
|
||||
err = zone.fetchHosts()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchHosts")
|
||||
}
|
||||
for i := range zone.hosts {
|
||||
nova := &SNovaStorage{host: &zone.hosts[i], zone: zone}
|
||||
istorages = append(istorages, nova)
|
||||
}
|
||||
return istorages, nil
|
||||
}
|
||||
|
||||
func (zone *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
|
||||
if zone.istorages == nil {
|
||||
zone.fetchStorages()
|
||||
istorages, err := zone.GetIStorages()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetIStorages")
|
||||
}
|
||||
for i := 0; i < len(zone.istorages); i++ {
|
||||
if zone.istorages[i].GetGlobalId() == id {
|
||||
return zone.istorages[i], nil
|
||||
for i := 0; i < len(istorages); i++ {
|
||||
if istorages[i].GetGlobalId() == id {
|
||||
return istorages[i], nil
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
type SOsHost struct {
|
||||
Zone string
|
||||
HostName string
|
||||
Service string
|
||||
func (zone *SZone) fetchHosts() error {
|
||||
if len(zone.hosts) > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
zone.hosts = []SHypervisor{}
|
||||
hypervisors, err := zone.region.GetHypervisors()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetHypervisors")
|
||||
}
|
||||
for i := range hypervisors {
|
||||
hypervisor := strings.ToLower(hypervisors[i].HypervisorType)
|
||||
// 过滤vmware的机器
|
||||
if strings.Index(hypervisor, "vmware") != -1 {
|
||||
continue
|
||||
}
|
||||
zone.hosts = append(zone.hosts, hypervisors[i])
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (zone *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) {
|
||||
ihosts := []cloudprovider.ICloudHost{}
|
||||
hosts := []SHost{}
|
||||
|
||||
// 尽可能的优先使用 os-hypervisor, 里面的信息更全些, 实在不行再使用 os-host
|
||||
_, resp, err := zone.region.List("compute", "/os-hypervisors/detail", "", nil)
|
||||
if err == nil {
|
||||
if err := resp.Unmarshal(&hosts, "hypervisors"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < len(hosts); i++ {
|
||||
// 过滤vmware的机器
|
||||
hypervisor := strings.ToLower(hosts[i].HypervisorType)
|
||||
if strings.Index(hypervisor, "vmware") != -1 {
|
||||
continue
|
||||
}
|
||||
hosts[i].zone = zone
|
||||
ihosts = append(ihosts, &hosts[i])
|
||||
}
|
||||
return ihosts, nil
|
||||
}
|
||||
_, resp, err = zone.region.List("compute", "/os-hosts", "", nil)
|
||||
err := zone.fetchHosts()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "fetchHosts")
|
||||
}
|
||||
|
||||
_hosts := []SOsHost{}
|
||||
|
||||
if err := resp.Unmarshal(&_hosts, "hosts"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < len(_hosts); i++ {
|
||||
if _hosts[i].Service == "compute" {
|
||||
host := SHost{HostName: _hosts[i].HostName, Zone: _hosts[i].Zone, zone: zone}
|
||||
ihosts = append(ihosts, &host)
|
||||
}
|
||||
ihosts := []cloudprovider.ICloudHost{}
|
||||
for i := range zone.hosts {
|
||||
zone.hosts[i].zone = zone
|
||||
ihosts = append(ihosts, &zone.hosts[i])
|
||||
}
|
||||
return ihosts, nil
|
||||
}
|
||||
|
||||
func (zone *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
|
||||
host := &SHost{zone: zone}
|
||||
_, resp, err := zone.region.Get("compute", "/os-hypervisors/"+id, "", nil)
|
||||
if err == nil {
|
||||
return host, resp.Unmarshal(&host, "hypervisor")
|
||||
}
|
||||
|
||||
host.HostName = id
|
||||
host.Resource = []map[string]SResource{}
|
||||
_, resp, err = zone.region.Get("compute", "/os-hosts/"+id, "", nil)
|
||||
ihosts, err := zone.GetIHosts()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "GetIHosts")
|
||||
}
|
||||
return host, resp.Unmarshal(&(host.Resource), "host")
|
||||
for i := range ihosts {
|
||||
if ihosts[i].GetGlobalId() == id {
|
||||
return ihosts[i], nil
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (region *SRegion) GetZones() ([]SZone, error) {
|
||||
zones := []SZone{}
|
||||
resp, err := region.ecsList("os-availability-zone/detail", nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ecsList.os-availability-zone")
|
||||
}
|
||||
err = resp.Unmarshal(&zones, "availabilityZoneInfo")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Unmarshal")
|
||||
}
|
||||
return zones, nil
|
||||
}
|
||||
|
||||
@@ -934,8 +934,8 @@ func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICl
|
||||
return self.GetSecurityGroupDetails(secgroupId)
|
||||
}
|
||||
|
||||
func (self *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
secgroups, total, err := self.GetSecurityGroups(vpcId, name, 0, 0)
|
||||
func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
secgroups, total, err := self.GetSecurityGroups(opts.VpcId, opts.Name, 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -86,8 +86,8 @@ func (self *SWire) GetNetworkById(networkId string) *SNetwork {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) {
|
||||
networkId, err := self.zone.region.CreateNetwork(self.zone.Zone, self.vpc.VpcId, name, cidr, desc)
|
||||
func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) {
|
||||
networkId, err := self.zone.region.CreateNetwork(self.zone.Zone, self.vpc.VpcId, opts.Name, opts.Cidr, opts.Desc)
|
||||
if err != nil {
|
||||
log.Errorf("CreateNetwork error %s", err)
|
||||
return nil, err
|
||||
|
||||
@@ -200,8 +200,8 @@ func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICl
|
||||
return self.GetSecurityGroupById(secgroupId)
|
||||
}
|
||||
|
||||
func (self *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
secgroups, err := self.GetSecurityGroups("", "", name)
|
||||
func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
secgroups, err := self.GetSecurityGroups("", "", opts.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -94,8 +94,8 @@ func (self *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, e
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/vpc2.0-api/create_subnet
|
||||
func (self *SWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) {
|
||||
return self.region.CreateNetwork(self.vpc.GetId(), name, cidr, desc)
|
||||
func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) {
|
||||
return self.region.CreateNetwork(self.vpc.GetId(), opts.Name, opts.Cidr, opts.Desc)
|
||||
}
|
||||
|
||||
func (self *SWire) addNetwork(network *SNetwork) {
|
||||
|
||||
@@ -199,12 +199,11 @@ func (network *SNetwork) GetIpMask() int8 {
|
||||
}
|
||||
|
||||
func (network *SNetwork) GetIsPublic() bool {
|
||||
// return network.IsDefault
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope {
|
||||
return rbacutils.ScopeProject
|
||||
return rbacutils.ScopeSystem
|
||||
}
|
||||
|
||||
func (network *SNetwork) GetServerType() string {
|
||||
|
||||
@@ -362,8 +362,8 @@ func (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.I
|
||||
return region.GetSecurityGroup(secgroupId)
|
||||
}
|
||||
|
||||
func (region *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
secgroups, err := region.GetSecurityGroups("", "", name)
|
||||
func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) {
|
||||
secgroups, err := region.GetSecurityGroups("", "", opts.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -126,8 +126,8 @@ func (wire *SWire) GetBandwidth() int {
|
||||
return 10000
|
||||
}
|
||||
|
||||
func (wire *SWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) {
|
||||
network, err := wire.vpc.region.CreateNetwork(name, cidr, wire.UUID, desc)
|
||||
func (wire *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) {
|
||||
network, err := wire.vpc.region.CreateNetwork(opts.Name, opts.Cidr, wire.UUID, opts.Desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user