Merge pull request #7318 from ioito/hotfix/qx-fix-openstack-project

fix: openstack多项目问题
This commit is contained in:
Zexi Li
2020-07-30 15:53:25 +08:00
committed by GitHub
80 changed files with 2717 additions and 2090 deletions
+1 -1
View File
@@ -180,7 +180,7 @@ type CloudaccountCreateInput struct {
// 自动同步间隔时间
SyncIntervalSeconds int `json:"sync_interval_seconds"`
// 自动根据云上项目或订阅创建本地项目
// 自动根据云上项目或订阅创建本地项目, OpenStack此参数为true
// default: false
AutoCreateProject *bool `json:"auto_create_project"`
+1 -1
View File
@@ -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}
+6
View File
@@ -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
}
+1 -1
View File
@@ -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
}
+22
View File
@@ -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
}
+9 -5
View File
@@ -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
+11 -4
View File
@@ -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 {
+11 -2
View File
@@ -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")
}
+13 -5
View File
@@ -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
+1 -1
View File
@@ -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")
}
+16 -2
View File
@@ -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)
+4 -2
View File
@@ -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
+13 -7
View File
@@ -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
+7 -2
View File
@@ -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")
}
+22 -13
View File
@@ -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")
}
+5
View File
@@ -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
}
+13 -1
View File
@@ -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
+2 -2
View File
@@ -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
}
+2 -2
View File
@@ -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
+2 -2
View File
@@ -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
}
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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
+4 -4
View File
@@ -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
}
+2 -2
View File
@@ -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
}
+3 -3
View File
@@ -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
}
}
+2 -2
View File
@@ -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")
}
+3 -3
View File
@@ -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
}
}
+2 -2
View File
@@ -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
}
+1
View File
@@ -15,6 +15,7 @@
package multicloud
type SHostBase struct {
SResourceBase
}
func (self *SHostBase) GetCpuCmtbound() float32 {
+2 -2
View File
@@ -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
}
+2 -2
View File
@@ -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
+98 -115
View File
@@ -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
}
+64 -66
View File
@@ -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
}
+42 -36
View File
@@ -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 {
+16 -474
View File
@@ -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
}
+351
View File
@@ -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
}
+43 -27
View File
@@ -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 {
+349 -191
View File
@@ -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
}
+56 -32
View File
@@ -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
+41 -20
View File
@@ -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
}
+87 -56
View File
@@ -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
}
+174
View File
@@ -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()
}
+4 -17
View File
@@ -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 {
+321 -167
View File
@@ -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] = &region
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")
+29 -32
View File
@@ -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
}
+63 -2
View File
@@ -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)
}
+23 -27
View File
@@ -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
View File
@@ -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, &region.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, &region.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")
}
+6 -6
View File
@@ -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"`
+1 -1
View File
@@ -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 {
+74 -64
View File
@@ -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" {
+1 -3
View File
@@ -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
}
+18 -1
View File
@@ -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
})
}
+13 -21
View File
@@ -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
})
}
+11 -1
View File
@@ -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 {
@@ -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
})
}
+16
View File
@@ -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
})
}
+3 -2
View File
@@ -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
}
+1 -1
View File
@@ -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
}
+2 -17
View File
@@ -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 -3
View File
@@ -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
})
}
+1 -1
View File
@@ -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
}
+72 -38
View File
@@ -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
}
+111 -9
View File
@@ -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
}
+2 -6
View File
@@ -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) {
+86 -97
View File
@@ -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
}
+15 -31
View File
@@ -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
}
+91 -212
View File
@@ -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
}
+2 -2
View File
@@ -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
}
+2 -2
View File
@@ -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
+2 -2
View File
@@ -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
}
+2 -2
View File
@@ -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) {
+2 -3
View File
@@ -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 {
+2 -2
View File
@@ -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
}
+2 -2
View File
@@ -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
}